#################################################################### # # This file was generated using Parse::Yapp version 1.05. # # Don't edit this file, use source file instead. # # ANY CHANGE MADE HERE WILL BE LOST ! # #################################################################### package yagg::NonterminalParser; use vars qw ( @ISA ); use strict; @ISA= qw ( Parse::Yapp::Driver ); use Parse::Yapp::Driver; #line 1 "etc/nonterminal_parser_grammar.yp" # (c) Copyright David Coppit 2004, all rights reserved. # (see COPYRIGHT in yagg documentation for use and distribution # rights) # # Written by David Coppit # # This grammar is based on that of Bison 1.05. I've left out undocumented # features, and definitions that are unused. A version of this file was # submitted to Francois Desarmenien, the author of Parse::Yapp. Hopefully he # will decide to use it to update his grammar parser. # # Use: yapp -m 'yagg::NonterminalParser' -o lib/yagg/NonterminalParser.pm etc/nonterminal_parser_grammar.yp # # to generate the Parser module. # #line 19 "etc/nonterminal_parser_grammar.yp" require 5.004; use Carp; my($input,$lexlevel,@lineno,$nberr,$prec,$precedences,$labelno); my($syms,$declarations,$epilogue,$token,$term,$nterm,$rules,$precterm,$start,$nullable,$aliases); my($expect); sub new { my($class)=shift; ref($class) and $class=ref($class); my($self)=$class->SUPER::new( yyversion => '1.05', yystates => [ {#State 0 DEFAULT => -3, GOTOS => { 'input' => 1, 'declarations' => 2 } }, {#State 1 ACTIONS => { '' => 3 } }, {#State 2 ACTIONS => { 'PERCENT_FILE_PREFIX' => 4, 'PERCENT_PARSE_PARAM' => 5, 'PERCENT_YACC' => 6, 'PERCENT_OUTPUT' => 8, 'PERCENT_DEFINES' => 9, 'PERCENT_LEFT' => 11, 'PERCENT_VERBOSE' => 12, 'PERCENT_DEBUG' => 13, 'PERCENT_PURE_PARSER' => 14, 'PERCENT_TOKEN_TABLE' => 17, 'SEMICOLON' => 16, 'PERCENT_TOKEN' => 15, 'PERCENT_TYPE' => 19, 'PERCENT_START' => 21, "%%" => 22, 'PERCENT_LOCATIONS' => 23, 'PERCENT_UNION' => 24, 'PERCENT_NO_LINES' => 25, 'PERCENT_EXPECT' => 26, 'PERCENT_NAME_PREFIX' => 29, 'PROLOGUE' => 28, 'PERCENT_NONASSOC' => 30, 'PERCENT_RIGHT' => 31 }, GOTOS => { 'precedence_declaration' => 7, 'grammar_declaration' => 27, 'symbol_declaration' => 18, 'declaration' => 10, 'precedence_declarator' => 20 } }, {#State 3 DEFAULT => 0 }, {#State 4 ACTIONS => { 'EQUAL' => 32 } }, {#State 5 DEFAULT => -15 }, {#State 6 DEFAULT => -19 }, {#State 7 DEFAULT => -21 }, {#State 8 DEFAULT => -14 }, {#State 9 DEFAULT => -8 }, {#State 10 DEFAULT => -4 }, {#State 11 DEFAULT => -29 }, {#State 12 DEFAULT => -18 }, {#State 13 DEFAULT => -7 }, {#State 14 DEFAULT => -16 }, {#State 15 ACTIONS => { 'TYPE' => 36, 'IDENT' => 35 }, GOTOS => { 'ID' => 33, 'symbol_def' => 34, 'symbol_defs_1' => 37 } }, {#State 16 DEFAULT => -20 }, {#State 17 DEFAULT => -17 }, {#State 18 DEFAULT => -22 }, {#State 19 ACTIONS => { 'TYPE' => 38 } }, {#State 20 ACTIONS => { 'TYPE' => 40 }, DEFAULT => -32, GOTOS => { 'type_opt' => 39 } }, {#State 21 ACTIONS => { 'IDENT' => 35, 'STRING' => 42 }, GOTOS => { 'ID' => 41, 'symbol' => 44, 'string_as_id' => 43 } }, {#State 22 ACTIONS => { 'ERROR' => 46, 'ID_COLON' => 48, 'SEMICOLON' => 47 }, DEFAULT => -2, GOTOS => { 'grammar' => 49, 'rules_or_grammar_declaration' => 50, 'rules' => 45 } }, {#State 23 DEFAULT => -11 }, {#State 24 ACTIONS => { 'BRACED_CODE' => 51 } }, {#State 25 DEFAULT => -13 }, {#State 26 ACTIONS => { 'INT' => 52 } }, {#State 27 DEFAULT => -5 }, {#State 28 DEFAULT => -6 }, {#State 29 ACTIONS => { 'EQUAL' => 53 } }, {#State 30 DEFAULT => -31 }, {#State 31 DEFAULT => -30 }, {#State 32 ACTIONS => { 'STRING' => 54 }, GOTOS => { 'string_content' => 55 } }, {#State 33 ACTIONS => { 'STRING' => 42, 'INT' => 57 }, DEFAULT => -36, GOTOS => { 'string_as_id' => 56 } }, {#State 34 DEFAULT => -40 }, {#State 35 DEFAULT => -64 }, {#State 36 ACTIONS => { 'IDENT' => 35 }, GOTOS => { 'ID' => 33, 'symbol_def' => 34, 'symbol_defs_1' => 58 } }, {#State 37 ACTIONS => { 'IDENT' => 35 }, DEFAULT => -25, GOTOS => { 'ID' => 33, 'symbol_def' => 59 } }, {#State 38 ACTIONS => { 'IDENT' => 35, 'STRING' => 42 }, GOTOS => { 'ID' => 41, 'symbols_1' => 61, 'symbol' => 60, 'string_as_id' => 43 } }, {#State 39 ACTIONS => { 'IDENT' => 35, 'STRING' => 42 }, GOTOS => { 'ID' => 41, 'symbols_1' => 62, 'symbol' => 60, 'string_as_id' => 43 } }, {#State 40 DEFAULT => -33 }, {#State 41 DEFAULT => -55 }, {#State 42 DEFAULT => -60 }, {#State 43 DEFAULT => -56 }, {#State 44 DEFAULT => -23 }, {#State 45 DEFAULT => -44 }, {#State 46 ACTIONS => { 'IDENT' => 35, 'SEMICOLON' => 63, 'STRING' => 42 }, GOTOS => { 'ID' => 41, 'symbol' => 64, 'string_as_id' => 43 } }, {#State 47 DEFAULT => -47 }, {#State 48 DEFAULT => -51, GOTOS => { 'rhses_1' => 66, 'rhs' => 65 } }, {#State 49 ACTIONS => { 'ERROR' => 46, 'ID_COLON' => 48, "%%" => 67, 'SEMICOLON' => 47 }, DEFAULT => -62, GOTOS => { 'rules_or_grammar_declaration' => 69, 'rules' => 45, 'epilogue_opt' => 68 } }, {#State 50 DEFAULT => -42 }, {#State 51 DEFAULT => -24 }, {#State 52 DEFAULT => -9 }, {#State 53 ACTIONS => { 'STRING' => 54 }, GOTOS => { 'string_content' => 70 } }, {#State 54 DEFAULT => -61 }, {#State 55 DEFAULT => -10 }, {#State 56 DEFAULT => -38 }, {#State 57 ACTIONS => { 'STRING' => 42 }, DEFAULT => -37, GOTOS => { 'string_as_id' => 71 } }, {#State 58 ACTIONS => { 'IDENT' => 35 }, DEFAULT => -26, GOTOS => { 'ID' => 33, 'symbol_def' => 59 } }, {#State 59 DEFAULT => -41 }, {#State 60 DEFAULT => -34 }, {#State 61 ACTIONS => { 'IDENT' => 35, 'STRING' => 42 }, DEFAULT => -27, GOTOS => { 'ID' => 41, 'symbol' => 72, 'string_as_id' => 43 } }, {#State 62 ACTIONS => { 'IDENT' => 35, 'STRING' => 42 }, DEFAULT => -28, GOTOS => { 'ID' => 41, 'symbol' => 72, 'string_as_id' => 43 } }, {#State 63 DEFAULT => -46 }, {#State 64 ACTIONS => { 'SEMICOLON' => 73 } }, {#State 65 ACTIONS => { 'IDENT' => 35, 'BRACED_CODE' => -57, 'PERCENT_PREC' => 75, 'STRING' => 42, 'BRACED_CODE_WITH_BRACED_CODE_FOLLOWING' => 77 }, DEFAULT => -49, GOTOS => { 'ID' => 41, 'symbol' => 76, 'action_opt' => 74, 'string_as_id' => 43 } }, {#State 66 ACTIONS => { 'PIPE' => 78 }, DEFAULT => -48 }, {#State 67 ACTIONS => { 'EPILOGUE' => 79 } }, {#State 68 DEFAULT => -1 }, {#State 69 DEFAULT => -43 }, {#State 70 DEFAULT => -12 }, {#State 71 DEFAULT => -39 }, {#State 72 DEFAULT => -35 }, {#State 73 DEFAULT => -45 }, {#State 74 ACTIONS => { 'BRACED_CODE' => 80 }, GOTOS => { 'action' => 81 } }, {#State 75 ACTIONS => { 'IDENT' => 35, 'STRING' => 42 }, GOTOS => { 'ID' => 41, 'symbol' => 82, 'string_as_id' => 43 } }, {#State 76 DEFAULT => -52 }, {#State 77 DEFAULT => -58 }, {#State 78 DEFAULT => -51, GOTOS => { 'rhs' => 83 } }, {#State 79 DEFAULT => -63 }, {#State 80 DEFAULT => -59 }, {#State 81 DEFAULT => -53 }, {#State 82 DEFAULT => -54 }, {#State 83 ACTIONS => { 'IDENT' => 35, 'BRACED_CODE' => -57, 'PERCENT_PREC' => 75, 'STRING' => 42, 'BRACED_CODE_WITH_BRACED_CODE_FOLLOWING' => 77 }, DEFAULT => -50, GOTOS => { 'ID' => 41, 'symbol' => 76, 'action_opt' => 74, 'string_as_id' => 43 } } ], yyrules => [ [#Rule 0 '$start', 2, undef ], [#Rule 1 'input', 4, sub #line 74 "etc/nonterminal_parser_grammar.yp" { $start or $start=$$rules[1][0]; ref($$nterm{$start}) or _SyntaxError(2,"Start symbol $start not found ". "in rules section",$_[4][1]); $$rules[0]=[ '$start', [ $start, chr(0) ], undef, undef ]; } ], [#Rule 2 'input', 2, sub #line 85 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(2,"No rules in input grammar",$_[2][1]); } ], [#Rule 3 'declarations', 0, undef ], [#Rule 4 'declarations', 2, undef ], [#Rule 5 'declaration', 1, undef ], [#Rule 6 'declaration', 1, sub #line 100 "etc/nonterminal_parser_grammar.yp" { push(@$declarations,$_[1]); undef } ], [#Rule 7 'declaration', 1, sub #line 101 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%debug\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 8 'declaration', 1, sub #line 105 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%defines\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 9 'declaration', 2, sub #line 109 "etc/nonterminal_parser_grammar.yp" { $expect=$_[2][0]; undef } ], [#Rule 10 'declaration', 3, sub #line 110 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%file-prefix\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 11 'declaration', 1, sub #line 114 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%locations\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 12 'declaration', 3, sub #line 118 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%name-prefix\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 13 'declaration', 1, sub #line 122 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%no-lines\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 14 'declaration', 1, sub #line 126 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%output\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 15 'declaration', 1, sub #line 130 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%parse-param\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 16 'declaration', 1, sub #line 134 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%pure-parser\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 17 'declaration', 1, sub #line 138 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%token-table\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 18 'declaration', 1, sub #line 142 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%verbose\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 19 'declaration', 1, sub #line 146 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"Parser option \"\%yacc\" is not supported. ". "It will be ignored",$_[1][1]); } ], [#Rule 20 'declaration', 1, undef ], [#Rule 21 'grammar_declaration', 1, undef ], [#Rule 22 'grammar_declaration', 1, undef ], [#Rule 23 'grammar_declaration', 2, sub #line 157 "etc/nonterminal_parser_grammar.yp" { $start=$_[2][0]; undef } ], [#Rule 24 'grammar_declaration', 2, sub #line 161 "etc/nonterminal_parser_grammar.yp" { undef } ], [#Rule 25 'symbol_declaration', 2, sub #line 168 "etc/nonterminal_parser_grammar.yp" { for (@{$_[2]}) { my($symbol,$lineno)=@$_; exists($$token{$symbol}) and do { _SyntaxError(0, "Token $symbol redefined: ". "Previously defined line $$token{$symbol}", $lineno); next; }; $$token{$symbol}=$lineno; $$term{$symbol} = [ ]; } undef } ], [#Rule 26 'symbol_declaration', 3, sub #line 186 "etc/nonterminal_parser_grammar.yp" { for (@{$_[3]}) { my($symbol,$lineno)=@$_; exists($$token{$symbol}) and do { _SyntaxError(0, "Token $symbol redefined: ". "Previously defined line $$token{$symbol}", $lineno); next; }; $$token{$symbol}=$lineno; $$term{$symbol} = [ ]; } undef } ], [#Rule 27 'symbol_declaration', 3, sub #line 204 "etc/nonterminal_parser_grammar.yp" { for ( @{$_[3]} ) { my($symbol,$lineno)=@$_; exists($$nterm{$symbol}) and do { _SyntaxError(0, "Non-terminal $symbol redefined: ". "Previously defined line $$nterm{$symbol}", $lineno); next; }; delete($$term{$symbol}); #not a terminal $$nterm{$symbol}=undef; #is a non-terminal } } ], [#Rule 28 'precedence_declaration', 3, sub #line 224 "etc/nonterminal_parser_grammar.yp" { for (@{$_[3]}) { my($symbol,$lineno)=@$_; defined($$precedences{$symbol}) and do { _SyntaxError(1, "Precedence for symbol $symbol redefined: ". "Previously defined line $$precedences{$symbol}", $lineno); next; }; $$token{$symbol}=$lineno; $$term{$symbol} = [ $_[1][0], $prec ]; $$precedences{$symbol} = $prec; } ++$prec; undef } ], [#Rule 29 'precedence_declarator', 1, undef ], [#Rule 30 'precedence_declarator', 1, undef ], [#Rule 31 'precedence_declarator', 1, undef ], [#Rule 32 'type_opt', 0, undef ], [#Rule 33 'type_opt', 1, undef ], [#Rule 34 'symbols_1', 1, sub #line 259 "etc/nonterminal_parser_grammar.yp" { [ $_[1] ] } ], [#Rule 35 'symbols_1', 2, sub #line 260 "etc/nonterminal_parser_grammar.yp" { push(@{$_[1]},$_[2]); $_[1] } ], [#Rule 36 'symbol_def', 1, undef ], [#Rule 37 'symbol_def', 2, sub #line 267 "etc/nonterminal_parser_grammar.yp" { _SyntaxError(0,"User-defined numeric token codes are not supported. ". "The value \"$_[2][0]\" will be ignored",$_[2][1]); $_[1]; } ], [#Rule 38 'symbol_def', 2, sub #line 273 "etc/nonterminal_parser_grammar.yp" { $$aliases{$_[2][0]} = $_[1][0]; delete $$term{$_[2][0]}; $_[1]; } ], [#Rule 39 'symbol_def', 3, sub #line 279 "etc/nonterminal_parser_grammar.yp" { $$aliases{$_[3][0]} = $_[1][0]; delete $$term{$_[3][0]}; _SyntaxError(0,"User-defined numeric token codes are not supported. ". "The value \"$_[2][0]\" will be ignored",$_[2][1]); $_[1]; } ], [#Rule 40 'symbol_defs_1', 1, sub #line 291 "etc/nonterminal_parser_grammar.yp" { [ $_[1] ] } ], [#Rule 41 'symbol_defs_1', 2, sub #line 293 "etc/nonterminal_parser_grammar.yp" { push(@{$_[1]},$_[2]); $_[1]; } ], [#Rule 42 'grammar', 1, undef ], [#Rule 43 'grammar', 2, undef ], [#Rule 44 'rules_or_grammar_declaration', 1, undef ], [#Rule 45 'rules_or_grammar_declaration', 3, sub #line 318 "etc/nonterminal_parser_grammar.yp" { $_[0]->YYErrok } ], [#Rule 46 'rules_or_grammar_declaration', 2, sub #line 322 "etc/nonterminal_parser_grammar.yp" { $_[0]->YYErrok } ], [#Rule 47 'rules_or_grammar_declaration', 1, undef ], [#Rule 48 'rules', 2, sub #line 330 "etc/nonterminal_parser_grammar.yp" { # For some reason Parse::Yapp treats the last code array as a # non-reference. i.e. instead of # [ ['SYMB',...], ['BRACED_CODE',...], ['SYMB',...], ['BRACED_CODE',['x',4]] ] # it has # [ ['SYMB',...], ['BRACED_CODE',...], ['SYMB',...], 'x',4 ] my $code; for(my $i=0;$i<=$#{$_[2]};$i++) { unless (defined $_[2][$i]) { splice(@{$_[2]},$i,1,[undef,undef]); next; } # Get the precedence, if any my $precedence = undef; for(my $j=0;$j<=$#{$_[2][$i]};$j++) { if ($_[2][$i][$j][0] eq 'PERCENT_PREC') { if(defined $precedence) { _SyntaxError(2,"\%prec can only appear once in a rule", $_[1][1]); } else { $precedence = $_[2][$i][$j][1]; splice(@{$_[2][$i]},$j,1), } } } # Dereference last code block my $code_block_found = 0; if(@{$_[2][$i]} >= 1) { if ($_[2][$i][-1][0] eq 'BRACED_CODE') { $code_block_found = 1; # Merge the lists if there was an unaction block too. (We # need to make sure we do this in a way that doesn't freak # Parse::Yapp out.) my @code_and_line_numbers = @{ $_[2][$i][-1][1] }; push @code_and_line_numbers, @{ $_[2][$i][-1][2] } if defined $_[2][$i][-1][2]; splice(@{$_[2][$i]},-1,1,($precedence,\@code_and_line_numbers)); } } # Append undef, undef if no code block was found push @{$_[2][$i]}, $precedence, undef unless $code_block_found; for(my $j=0;$j<=$#{$_[2][$i]}-2;$j++) { $_[2][$i][$j][0] = 'CODE' if $_[2][$i][$j][0] eq 'BRACED_CODE'; } } _AddRules($_[1],$_[2]); undef; } ], [#Rule 49 'rhses_1', 1, sub #line 399 "etc/nonterminal_parser_grammar.yp" { [ $_[1] ] } ], [#Rule 50 'rhses_1', 3, sub #line 400 "etc/nonterminal_parser_grammar.yp" { push(@{$_[1]},$_[3]); $_[1] } ], [#Rule 51 'rhs', 0, sub #line 405 "etc/nonterminal_parser_grammar.yp" { } ], [#Rule 52 'rhs', 2, sub #line 407 "etc/nonterminal_parser_grammar.yp" { push(@{$_[1]},[ 'SYMB', $_[2] ]); $_[1]; } ], [#Rule 53 'rhs', 3, sub #line 412 "etc/nonterminal_parser_grammar.yp" { if (defined $_[2]) { push(@{$_[1]}, [ 'BRACED_CODE', $_[2], $_[3] ] ); } else { push(@{$_[1]}, [ 'BRACED_CODE', $_[3] ] ); } $_[1]; } ], [#Rule 54 'rhs', 3, sub #line 424 "etc/nonterminal_parser_grammar.yp" { defined($$precedences{$_[3][0]}) or do { _SyntaxError(1,"No precedence for symbol $_[3][0]", $_[3][1]); return undef; }; ++$$precterm{$_[3][0]}; my $temp = $$precedences{$_[3][0]}; push(@{$_[1]}, [ 'PERCENT_PREC', $temp ] ); $_[1]; } ], [#Rule 55 'symbol', 1, undef ], [#Rule 56 'symbol', 1, sub #line 443 "etc/nonterminal_parser_grammar.yp" { if (exists $$aliases{$_[1][0]}) { $_[1][0] = $$aliases{$_[1][0]}; } else { # Must be a literal, in which case we don't touch it. } $_[1]; } ], [#Rule 57 'action_opt', 0, undef ], [#Rule 58 'action_opt', 1, undef ], [#Rule 59 'action', 1, undef ], [#Rule 60 'string_as_id', 1, sub #line 468 "etc/nonterminal_parser_grammar.yp" { if (exists $$aliases{$_[1][0]}) { exists($$syms{$$aliases{$_[1][0]}}) or do { $$syms{$$aliases{$_[1][0]}} = $_[1][1]; $$term{$$aliases{$_[1][0]}} = undef; }; } else { exists($$syms{$_[1][0]}) or do { $$syms{$_[1][0]} = $_[1][1]; $$term{$_[1][0]} = undef; }; } $_[1] } ], [#Rule 61 'string_content', 1, sub #line 492 "etc/nonterminal_parser_grammar.yp" { $_[1][0] =~ s/.(.*)./$1/; $_[1] } ], [#Rule 62 'epilogue_opt', 0, undef ], [#Rule 63 'epilogue_opt', 2, sub #line 501 "etc/nonterminal_parser_grammar.yp" { $epilogue=$_[2] } ], [#Rule 64 'ID', 1, sub #line 506 "etc/nonterminal_parser_grammar.yp" { exists($$syms{$_[1][0]}) or do { $$syms{$_[1][0]} = $_[1][1]; $$term{$_[1][0]} = undef; }; $_[1] } ] ], @_); bless($self,$class); } #line 516 "etc/nonterminal_parser_grammar.yp" sub _Error { my($value)=$_[0]->YYCurval; my($what)= $token ? "input: '$$value[0]'" : "end of input"; _SyntaxError(1,"Unexpected $what",$$value[1]); } sub _Lexer { #At EOF pos($$input) >= length($$input) and return('',[ undef, -1 ]); #In Epilogue section $lexlevel > 1 and do { my($pos)=pos($$input); $lineno[0]=$lineno[1]; $lineno[1]=-1; pos($$input)=length($$input); return('EPILOGUE',[ substr($$input,$pos), $lineno[0] ]); }; #Skip blanks $$input=~m{\G((?: \s+ # any white space char | \#[^\n]*\n # Perl like comments | /\*.*?\*/ # C like comments | //[^\n]*\n # C++ like comments )+)}xsgc and do { my($blanks)=$1; #Maybe At EOF pos($$input) >= length($$input) and return('',[ undef, -1 ]); $lineno[1]+= $blanks=~tr/\n//; }; $lineno[0]=$lineno[1]; $$input=~/\G<([A-Za-z_.][A-Za-z0-9_.]*)>/gc and return('TYPE',[ $1, $lineno[0] ]); $$input=~m{\G ([A-Za-z_.][A-Za-z0-9_.]*) #identifier ((?: \s+ # any white space char | \#[^\n]*\n # Perl like comments | /\*.*?\*/ # C like comments | //[^\n]*\n # C++ like comments )*) : # colon }xsgc and do { my($blanks)=$2; $lineno[1]+= $blanks=~tr/\n//; return('ID_COLON',[ $1, $lineno[0] ]); }; $$input=~/\G([A-Za-z_.][A-Za-z0-9_.]*)/gc and do { $1 eq 'error' and do { return('ERROR',[ 'error', $lineno[0] ]); }; return('IDENT',[ $1, $lineno[0] ]); }; $$input=~/\G('(?:[^'\\]|\\\\|\\'|\\)+?')/gc and do { $1 eq "'error'" and do { _SyntaxError(0,"Literal 'error' ". "will be treated as error token",$lineno[0]); return('ERROR',[ 'error', $lineno[0] ]); }; return('STRING',[ $1, $lineno[0] ]); }; $$input=~/\G("(?:[^"\\]|\\\\|\\"|\\)+?")/gc and do { $1 eq '"error"' and do { _SyntaxError(0,'Literal "error" '. "will be treated as error token",$lineno[0]); return('ERROR',[ 'error', $lineno[0] ]); }; return('STRING',[ $1, $lineno[0] ]); }; $$input=~/\G(%%)/gc and do { ++$lexlevel; return($1, [ $1, $lineno[0] ]); }; $$input=~/\G{/gc and do { my $code; my $level = 1; my $from=pos($$input); my $to; while($$input =~ /\G(.*? (?: \#[^\n]*\n # Perl like comments | \/\*.*?\*\/ # C like comments | \/\/[^\n]*\n # C++ like comments | (?[$level]. "* $message, at ". ($lineno < 0 ? "eof" : "line $lineno"). ".\n"; $level > 1 and die $message; warn $message; $level > 0 and ++$nberr; $nberr == 20 and die "*Fatal* Too many errors detected.\n" } sub _AddRules { my($lhs,$lineno)=@{$_[0]}; my($rhss)=$_[1]; ref($$nterm{$lhs}) and do { _SyntaxError(1,"Non-terminal $lhs redefined: ". "Previously declared line $$syms{$lhs}",$lineno); return; }; ref($$term{$lhs}) and do { my($where) = exists($$token{$lhs}) ? $$token{$lhs} : $$syms{$lhs}; _SyntaxError(1,"Non-terminal $lhs previously ". "declared as token line $where",$lineno); return; }; ref($$nterm{$lhs}) #declared through %type or do { $$syms{$lhs}=$lineno; #Say it's declared here delete($$term{$lhs}); #No more a terminal }; $$nterm{$lhs}=[]; #It's a non-terminal now my($epsrules)=0; #To issue a warning if more than one epsilon rule for my $rhs (@$rhss) { my($tmprule)=[ $lhs, [ ], splice(@$rhs,-2) ]; #Init rule @$rhs or do { ++$$nullable{$lhs}; ++$epsrules; }; for (0..$#$rhs) { my($what,$value)=@{$$rhs[$_]}; $what eq 'CODE' and do { my($name)='@'.++$labelno."-$_"; push(@$rules,[ $name, [], undef, $value ]); push(@{$$tmprule[1]},$name); next; }; push(@{$$tmprule[1]},$$value[0]); } push(@$rules,$tmprule); push(@{$$nterm{$lhs}},$#$rules); } $epsrules > 1 and _SyntaxError(0,"More than one empty rule for symbol $lhs",$lineno); } sub Parse { my($self)=shift; @_ > 0 or croak("No input grammar\n"); my($parsed)={}; $input=\$_[0]; $lexlevel=0; @lineno=(1,1); $nberr=0; $prec=0; $labelno=0; $declarations=(); $epilogue=""; $syms={}; $token={}; $term={}; $precedences={}; $nterm={}; $rules=[ undef ]; #reserve slot 0 for start rule $precterm={}; $start=""; $nullable={}; $aliases={}; $expect=0; pos($$input)=0; $self->YYParse(yylex => \&_Lexer, yyerror => \&_Error); $nberr and _SyntaxError(2,"Errors detected: No output",-1); @$parsed{ 'HEAD', 'TAIL', 'RULES', 'NTERM', 'TERM', 'NULL', 'PREC', 'SYMS', 'START', 'EXPECT' } = ( $declarations, $epilogue, $rules, $nterm, $term, $nullable, $precterm, $syms, $start, $expect); undef($input); undef($lexlevel); undef(@lineno); undef($nberr); undef($prec); undef($labelno); undef($declarations); undef($epilogue); undef($syms); undef($token); undef($term); undef($precedences); undef($nterm); undef($rules); undef($precterm); undef($start); undef($nullable); undef($aliases); undef($expect); $parsed } 1;