The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Default lexical analyzer
%lexer {
      m{\G(\s+)}gc and $self->tokenline($1 =~ tr{\n}{});

      m{\G(type|\.\.|\-|\+|\;|\/|\,|\=|\(|\*|\))}gc and return ($1, $1);

      /\G([A-Za-z]\w*)/gc and return ('ID', $1);
      /\G(\d+)/gc and return ('NUM', $1);


      return ('', undef) if ($_ eq '') || (defined(pos($_)) && (pos($_) >= length($_)));
      /\G\s*(\S+)/;
      my $near = substr($1,0,10); 
      die( "Error inside the lexical analyzer near '". $near
          ."'. Line: ".$self->line()
          .". File: '".$self->YYFilename()."'. No match found.\n");
}

%{
my $enum = 0;

sub rangeORenum {
  # Goal. Towrite this code as: 
  #           $enum = $self->YYPreParse('enum');
  #  Will parse using as start symbol 'enum', without changing the 
  #  parsing position. Returns true if it matches. Has the same effect
  #  than the following code:
  use Enum;

  my $self = shift;

  my $np = Enum->new();

  my $pos = pos(${$self->{INPUT}});
  $np->input($self->input());

  $enum = 1;
  eval {
    $np->YYParse( yyerror => sub { $enum = 0; });
  };

}

%}

%conflict rangeORenum {
  if ($enum) { $self->YYSetReduce([',', ')'], 'ID:ENUM' ); }
  else { $self->YYSetReduce([',', ')'], 'ID:RANGE' ); }
} 

%token ID  = /([A-Za-z]\w*)/
%token NUM = /(\d+)/

%left   ','
%left   '-' '+'
%left   '*' '/'

#%expect-rr 2

%%

type_decl : 'type' ID '=' type ';'
;

type : 
      %name ENUM
      # %code rangeORenum
      PRErangeORenum '(' id_list ')'
    | %name RANGE
      # %code rangeORenum
      PRErangeORenum expr '..' expr
;

enum:
      '(' ids ')' ';'
;

ids : 
      ID       
    | ids ',' ID
;


PRErangeORenum:
   /* empty */  
     {
       goto &rangeORenum;
     }
;

id_list : 
      %name ID:ENUM
      ID                      %PREC rangeORenum
    | id_list ',' ID
;

expr : '(' expr ')'   { $_[2] } /* bypass */
    | %name PLUS     expr '+' expr
    | %name MINUS    expr '-' expr
    | %name TIMES    expr '*' expr
    | %name DIV      expr '/' expr
    | %name COMMA    expr ',' expr
    | %name ID:RANGE
      ID                     %PREC rangeORenum
    | %name NUM      NUM
;

%%


=head1 SYNOPSIS

See 

=over 2

=item * File pascalenumeratedvsrange.eyp in examples/debuggintut/

=item * The Bison manual L<http://www.gnu.org/software/bison/manual/html_mono/bison.html>

=back

Compile it with something like:

      eyapp -TC pascalenumeratedvsrangesolvedviapreconflictsolver.eyp

Run it with this options:

    $ ./pascalenumeratedvsrangesolvedviapreconflictsolver.pm -t -i -m 1 -c 'type e = (x, y, z);'

Try also these inputs:

                type e = (x) .. (y);
                type r = (x) ..  y ;
                type r = (x+2)*3 ..  y/2 ;
                type e = (x, y, z);
                type e = (x);
                type e = (x, y, z) .. (u+v);

=cut