1 # GENERATE RECURSIVE DESCENT PARSER OBJECTS FROM A GRAMMARC
2 # SEE RecDescent.pod FOR FULL DETAILS
7 package Parse::RecDescent;
9 use Text::Balanced qw ( extract_codeblock extract_bracketed extract_quotelike extract_delimited );
11 use vars qw ( $skip );
13 *defskip = \ '\s*'; # DEFAULT SEPARATOR IS OPTIONAL WHITESPACE
14 $skip = '\s*'; # UNIVERSAL SEPARATOR IS OPTIONAL WHITESPACE
15 my $MAXREP = 100_000_000; # REPETITIONS MATCH AT MOST 100,000,000 TIMES
18 sub import # IMPLEMENT PRECOMPILER BEHAVIOUR UNDER:
19 # perl -MParse::RecDescent - <grammarfile> <classname>
21 local *_die = sub { print @_, "\n"; exit };
23 my ($package, $file, $line) = caller;
24 if (substr($file,0,1) eq '-' && $line == 0)
26 _die("Usage: perl -MLocalTest - <grammarfile> <classname>")
29 my ($sourcefile, $class) = @ARGV;
33 or _die("Can't open grammar file '$sourcefile'");
35 my $grammar = join '', <IN>;
37 Parse::RecDescent->Precompile($grammar, $class, $sourcefile);
44 my ($self, $class) = @_;
46 $self->Precompile(undef,$class);
52 my ($self, $grammar, $class, $sourcefile) = @_;
54 $class =~ /^(\w+::)*\w+$/ or croak("Bad class name: $class");
56 my $modulefile = $class;
57 $modulefile =~ s/.*:://;
60 open OUT, ">$modulefile"
61 or croak("Can't write to new module file '$modulefile'");
63 print STDERR "precompiling grammar from file '$sourcefile'\n",
64 "to class $class in module file '$modulefile'\n"
65 if $grammar && $sourcefile;
67 # local $::RD_HINT = 1;
68 $self = Parse::RecDescent->new($grammar,1,$class)
69 || croak("Can't compile bad grammar")
72 foreach ( keys %{$self->{rules}} )
73 { $self->{rules}{$_}{changed} = 1 }
75 print OUT "package $class;\nuse Parse::RecDescent;\n\n";
77 print OUT "{ my \$ERRORS;\n\n";
79 print OUT $self->_code();
81 print OUT "}\npackage $class; sub new { ";
85 print OUT Data::Dumper->Dump([$self], [qw(self)]);
90 or croak("Can't write to new module file '$modulefile'");
94 package Parse::RecDescent::LineCounter;
97 sub TIESCALAR # ($classname, \$text, $thisparser, $prevflag)
110 my $parser = $_[0]->{parser};
111 my $from = $parser->{fulltextlen}-length(${$_[0]->{text}})-$_[0]->{prev}
114 unless (exists $counter_cache{$from}) {
115 $parser->{lastlinenum} = $parser->{offsetlinenum}
116 - Parse::RecDescent::_linecount(substr($parser->{fulltext},$from))
118 $counter_cache{$from} = $parser->{lastlinenum};
120 return $counter_cache{$from};
125 my $parser = $_[0]->{parser};
126 $parser->{offsetlinenum} -= $parser->{lastlinenum} - $_[1];
130 sub resync # ($linecounter)
132 my $self = tied($_[0]);
133 die "Tried to alter something other than a LineCounter\n"
134 unless $self =~ /Parse::RecDescent::LineCounter/;
136 my $parser = $self->{parser};
137 my $apparently = $parser->{offsetlinenum}
138 - Parse::RecDescent::_linecount(${$self->{text}})
141 $parser->{offsetlinenum} += $parser->{lastlinenum} - $apparently;
145 package Parse::RecDescent::ColCounter;
147 sub TIESCALAR # ($classname, \$text, $thisparser, $prevflag)
158 my $parser = $_[0]->{parser};
159 my $missing = $parser->{fulltextlen}-length(${$_[0]->{text}})-$_[0]->{prev}+1;
160 substr($parser->{fulltext},0,$missing) =~ m/^(.*)\Z/m;
166 die "Can't set column number via \$thiscolumn\n";
170 package Parse::RecDescent::OffsetCounter;
172 sub TIESCALAR # ($classname, \$text, $thisparser, $prev)
183 my $parser = $_[0]->{parser};
184 return $parser->{fulltextlen}-length(${$_[0]->{text}})+$_[0]->{prev};
189 die "Can't set current offset via \$thisoffset or \$prevoffset\n";
194 package Parse::RecDescent::Rule;
198 my $class = ref($_[0]) || $_[0];
204 if (defined $owner->{"rules"}{$name})
206 my $self = $owner->{"rules"}{$name};
207 if ($replace && !$self->{"changed"})
215 return $owner->{"rules"}{$name} =
232 @{$_[0]->{"prods"}} = ();
233 @{$_[0]->{"calls"}} = ();
234 $_[0]->{"changed"} = 0;
235 $_[0]->{"impcount"} = 0;
236 $_[0]->{"opcount"} = 0;
237 $_[0]->{"vars"} = "";
244 my ($self, $ref) = @_;
247 foreach $prod ( @{$self->{"prods"}} )
249 return 1 if $prod->hasleftmost($ref);
255 sub leftmostsubrules($)
261 foreach $prod ( @{$self->{"prods"}} )
263 push @subrules, $prod->leftmostsubrule();
275 foreach $prod ( @{$self->{"prods"}} )
277 my $next = $prod->expected();
278 unless (! $next or _contains($next,@expected) )
280 push @expected, $next;
284 return join ', or ', @expected;
291 foreach $item ( @_ ) { return 1 if $target eq $item; }
297 my ( $self, $subrule ) = @_;
298 unless ( _contains($subrule, @{$self->{"calls"}}) )
300 push @{$self->{"calls"}}, $subrule;
306 my ( $self, $prod ) = @_;
307 push @{$self->{"prods"}}, $prod;
308 $self->{"changed"} = 1;
309 $self->{"impcount"} = 0;
310 $self->{"opcount"} = 0;
311 $prod->{"number"} = $#{$self->{"prods"}};
317 my ( $self, $var, $parser ) = @_;
318 if ($var =~ /\A\s*local\s+([%@\$]\w+)/)
320 $parser->{localvars} .= " $1";
321 $self->{"vars"} .= "$var;\n" }
323 { $self->{"vars"} .= "my $var;\n" }
324 $self->{"changed"} = 1;
330 my ( $self, $code ) = @_;
331 $self->{"autoscore"} = $code;
332 $self->{"changed"} = 1;
339 my $prodcount = scalar @{$self->{"prods"}};
340 my $opcount = ++$self->{"opcount"};
341 return "_operator_${opcount}_of_production_${prodcount}_of_rule_$self->{name}";
347 my $prodcount = scalar @{$self->{"prods"}};
348 my $impcount = ++$self->{"impcount"};
349 return "_alternation_${impcount}_of_production_${prodcount}_of_rule_$self->{name}";
355 my ($self, $namespace, $parser) = @_;
357 eval 'undef &' . $namespace . '::' . $self->{"name"} unless $parser->{saving};
361 # ARGS ARE: ($parser, $text; $repeating, $_noactions, \@args)
362 sub ' . $namespace . '::' . $self->{"name"} . '
364 my $thisparser = $_[0];
365 use vars q{$tracelevel};
366 local $tracelevel = ($tracelevel||0)+1;
368 my $thisrule = $thisparser->{"rules"}{"' . $self->{"name"} . '"};
370 Parse::RecDescent::_trace(q{Trying rule: [' . $self->{"name"} . ']},
371 Parse::RecDescent::_tracefirst($_[1]),
372 q{' . $self->{"name"} . '},
374 if defined $::RD_TRACE;
376 ' . ($parser->{deferrable}
377 ? 'my $def_at = @{$thisparser->{deferred}};'
380 my $err_at = @{$thisparser->{errors}};
390 my $repeating = defined($_[2]) && $_[2];
391 my $_noactions = defined($_[3]) && $_[3];
392 my @arg = defined $_[4] ? @{ &{$_[4]} } : ();
393 my %arg = ($#arg & 01) ? @arg : (@arg, undef);
396 my $expectation = new Parse::RecDescent::Expectation($thisrule->expected());
397 $expectation->at($_[1]);
398 '. ($parser->{_check}{thisoffset}?'
400 tie $thisoffset, q{Parse::RecDescent::OffsetCounter}, \$text, $thisparser;
401 ':'') . ($parser->{_check}{prevoffset}?'
403 tie $prevoffset, q{Parse::RecDescent::OffsetCounter}, \$text, $thisparser, 1;
404 ':'') . ($parser->{_check}{thiscolumn}?'
406 tie $thiscolumn, q{Parse::RecDescent::ColCounter}, \$text, $thisparser;
407 ':'') . ($parser->{_check}{prevcolumn}?'
409 tie $prevcolumn, q{Parse::RecDescent::ColCounter}, \$text, $thisparser, 1;
410 ':'') . ($parser->{_check}{prevline}?'
412 tie $prevline, q{Parse::RecDescent::LineCounter}, \$text, $thisparser, 1;
415 tie $thisline, q{Parse::RecDescent::LineCounter}, \$text, $thisparser;
421 foreach $prod ( @{$self->{"prods"}} )
423 $prod->addscore($self->{autoscore},0,0) if $self->{autoscore};
424 next unless $prod->checkleftmost();
425 $code .= $prod->code($namespace,$self,$parser);
427 $code .= $parser->{deferrable}
429 @{$thisparser->{deferred}}, $def_at unless $_matched;
436 unless ( $_matched || defined($return) || defined($score) )
438 ' .($parser->{deferrable}
439 ? ' splice @{$thisparser->{deferred}}, $def_at;
443 $_[1] = $text; # NOT SURE THIS IS NEEDED
444 Parse::RecDescent::_trace(q{<<Didn\'t match rule>>},
445 Parse::RecDescent::_tracefirst($_[1]),
446 q{' . $self->{"name"} .'},
448 if defined $::RD_TRACE;
451 if (!defined($return) && defined($score))
453 Parse::RecDescent::_trace(q{>>Accepted scored production<<}, "",
454 q{' . $self->{"name"} .'},
456 if defined $::RD_TRACE;
457 $return = $score_return;
459 splice @{$thisparser->{errors}}, $err_at;
460 $return = $item[$#item] unless defined $return;
461 if (defined $::RD_TRACE)
463 Parse::RecDescent::_trace(q{>>Matched rule<< (return value: [} .
465 q{' . $self->{"name"} .'},
467 Parse::RecDescent::_trace(q{(consumed: [} .
468 Parse::RecDescent::_tracemax(substr($_[1],0,-length($text))) . q{])},
469 Parse::RecDescent::_tracefirst($text),
470 , q{' . $self->{"name"} .'},
484 my ($self, $rules) = @_;
485 my $root = $self->{"name"};
486 @left = $self->leftmostsubrules();
488 foreach $next ( @left )
490 next unless defined $rules->{$next}; # SKIP NON-EXISTENT RULES
491 return 1 if $next eq $root;
493 foreach $child ( $rules->{$next}->leftmostsubrules() )
496 if ! _contains($child, @left) ;
502 package Parse::RecDescent::Production;
506 return join ' ', map { $_->describe($_[1]) or () } @{$_[0]->{items}};
511 my ($self, $line, $uncommit, $error) = @_;
512 my $class = ref($self) || $self;
517 "uncommit" => $uncommit,
529 my $itemcount = scalar @{$_[0]->{"items"}};
530 return ($itemcount) ? $_[0]->{"items"}[0]->describe(1) : '';
535 my ($self, $ref) = @_;
536 return ${$self->{"items"}}[0] eq $ref if scalar @{$self->{"items"}};
540 sub leftmostsubrule($)
544 if ( $#{$self->{"items"}} >= 0 )
546 my $subrule = $self->{"items"}[0]->issubrule();
547 return $subrule if defined $subrule;
555 my @items = @{$_[0]->{"items"}};
556 if (@items==1 && ref($items[0]) =~ /\AParse::RecDescent::Error/
557 && $items[0]->{commitonly} )
559 Parse::RecDescent::_warn(2,"Lone <error?> in production treated
560 as <error?> <reject>");
561 Parse::RecDescent::_hint("A production consisting of a single
562 conditional <error?> directive would
563 normally succeed (with the value zero) if the
564 rule is not 'commited' when it is
565 tried. Since you almost certainly wanted
566 '<error?> <reject>' Parse::RecDescent
567 supplied it for you.");
568 push @{$_[0]->{items}},
569 Parse::RecDescent::UncondReject->new(0,0,'<reject>');
571 elsif (@items==1 && ($items[0]->describe||"") =~ /<rulevar|<autoscore/)
576 ( ref($items[0]) =~ /\AParse::RecDescent::UncondReject/
577 || ($items[0]->describe||"") =~ /<autoscore/
580 Parse::RecDescent::_warn(1,"Optimizing away production: [". $_[0]->describe ."]");
581 my $what = $items[0]->describe =~ /<rulevar/
582 ? "a <rulevar> (which acts like an unconditional <reject> during parsing)"
583 : $items[0]->describe =~ /<autoscore/
584 ? "an <autoscore> (which acts like an unconditional <reject> during parsing)"
585 : "an unconditional <reject>";
586 my $caveat = $items[0]->describe =~ /<rulevar/
587 ? " after the specified variable was set up"
589 my $advice = @items > 1
590 ? "However, there were also other (useless) items after the leading "
591 . $items[0]->describe
592 . ", so you may have been expecting some other behaviour."
593 : "You can safely ignore this message.";
594 Parse::RecDescent::_hint("The production starts with $what. That means that the
595 production can never successfully match, so it was
596 optimized out of the final parser$caveat. $advice");
605 foreach $item (@{$_[0]->{"items"}})
607 if (ref($item) =~ /Parse::RecDescent::(Action|Directive)/)
609 return 1 if $item->{code} =~ /\$skip/;
617 my ( $self, $whichop, $line, $name ) = @_;
619 { type=>$whichop, line=>$line, name=>$name,
620 offset=> scalar(@{$self->{items}}) };
625 my ( $self, $code, $lookahead, $line ) = @_;
626 $self->additem(Parse::RecDescent::Directive->new(
628 my \$thisscore = do { $code } + 0;
629 if (!defined(\$score) || \$thisscore>\$score)
630 { \$score=\$thisscore; \$score_return=\$item[-1]; }
631 undef;", $lookahead, $line,"<score: $code>") )
632 unless $self->{items}[-1]->describe =~ /<score/;
638 my ( $self, $line ) = @_;
641 while (my $next = pop @{$self->{op}})
643 Parse::RecDescent::_error("Incomplete <$next->{type}op:...>.", $line);
644 Parse::RecDescent::_hint(
645 "The current production ended without completing the
646 <$next->{type}op:...> directive that started near line
647 $next->{line}. Did you forget the closing '>'?");
655 my ( $self, $line, $minrep, $maxrep ) = @_;
658 Parse::RecDescent::_error("Unmatched > found.", $line);
659 Parse::RecDescent::_hint(
660 "A '>' angle bracket was encountered, which typically
661 indicates the end of a directive. However no suitable
662 preceding directive was encountered. Typically this
663 indicates either a extra '>' in the grammar, or a
664 problem inside the previous directive.");
667 my $op = pop @{$self->{op}};
668 my $span = @{$self->{items}} - $op->{offset};
669 if ($op->{type} =~ /left|right/)
673 Parse::RecDescent::_error(
674 "Incorrect <$op->{type}op:...> specification:
675 expected 3 args, but found $span instead", $line);
676 Parse::RecDescent::_hint(
677 "The <$op->{type}op:...> directive requires a
678 sequence of exactly three elements. For example:
679 <$op->{type}op:leftarg /op/ rightarg>");
683 push @{$self->{items}},
684 Parse::RecDescent::Operator->new(
685 $op->{type}, $minrep, $maxrep, splice(@{$self->{"items"}}, -3));
686 $self->{items}[-1]->sethashname($self);
687 $self->{items}[-1]{name} = $op->{name};
694 my ( $self, $line ) = @_;
695 unless (@{$self->{items}})
697 Parse::RecDescent::_error(
698 "Incorrect <return:...> specification:
699 expected item missing", $line);
700 Parse::RecDescent::_hint(
701 "The <return:...> directive requires a
702 sequence of at least one item. For example:
706 push @{$self->{items}},
707 Parse::RecDescent::Result->new();
712 my ( $self, $item ) = @_;
713 $item->sethashname($self);
714 push @{$self->{"items"}}, $item;
723 push @itempos, {'offset' => {'from'=>$thisoffset, 'to'=>undef},
724 'line' => {'from'=>$thisline, 'to'=>undef},
725 'column' => {'from'=>$thiscolumn, 'to'=>undef} };
733 $itempos[$#itempos]{'offset'}{'from'} += length($1);
734 $itempos[$#itempos]{'line'}{'from'} = $thisline;
735 $itempos[$#itempos]{'column'}{'from'} = $thiscolumn;
743 $itempos[$#itempos]{'offset'}{'to'} = $prevoffset;
744 $itempos[$#itempos]{'line'}{'to'} = $prevline;
745 $itempos[$#itempos]{'column'}{'to'} = $prevcolumn;
751 my ($self,$namespace,$rule,$parser) = @_;
755 . (defined $self->{"uncommit"} ? '' : ' && !$commit')
759 ($self->changesskip()
760 ? 'local $skip = defined($skip) ? $skip : $Parse::RecDescent::skip;'
762 Parse::RecDescent::_trace(q{Trying production: ['
763 . $self->describe . ']},
764 Parse::RecDescent::_tracefirst($_[1]),
765 q{' . $rule ->{name}. '},
767 if defined $::RD_TRACE;
768 my $thisprod = $thisrule->{"prods"}[' . $self->{"number"} . '];
769 ' . (defined $self->{"error"} ? '' : '$text = $_[1];' ) . '
771 @item = (q{' . $rule->{"name"} . '});
772 %item = (__RULE__ => q{' . $rule->{"name"} . '});
777 ' my @itempos = ({});
778 ' if $parser->{_check}{itempos};
783 for ($i = 0; $i < @{$self->{"items"}}; $i++)
785 $item = ${$self->{items}}[$i];
787 $code .= preitempos() if $parser->{_check}{itempos};
789 $code .= $item->code($namespace,$rule,$parser->{_check});
791 $code .= postitempos() if $parser->{_check}{itempos};
795 if ($parser->{_AUTOACTION} && defined($item) && !$item->isa("Parse::RecDescent::Action"))
797 $code .= $parser->{_AUTOACTION}->code($namespace,$rule);
798 Parse::RecDescent::_warn(1,"Autogenerating action in rule
800 $parser->{_AUTOACTION}{code}")
802 Parse::RecDescent::_hint("The \$::RD_AUTOACTION was defined,
803 so any production not ending in an
804 explicit action has the specified
805 \"auto-action\" automatically
808 elsif ($parser->{_AUTOTREE} && defined($item) && !$item->isa("Parse::RecDescent::Action"))
810 if ($i==1 && $item->isterminal)
812 $code .= $parser->{_AUTOTREE}{TERMINAL}->code($namespace,$rule);
816 $code .= $parser->{_AUTOTREE}{NODE}->code($namespace,$rule);
818 Parse::RecDescent::_warn(1,"Autogenerating tree-building action in rule
821 Parse::RecDescent::_hint("The directive <autotree> was specified,
822 so any production not ending
823 in an explicit action has
824 some parse-tree building code
825 automatically appended.");
831 Parse::RecDescent::_trace(q{>>Matched production: ['
832 . $self->describe . ']<<},
833 Parse::RecDescent::_tracefirst($text),
834 q{' . $rule->{name} . '},
836 if defined $::RD_TRACE;
847 package Parse::RecDescent::Action;
849 sub describe { undef }
851 sub sethashname { $_[0]->{hashname} = '__ACTION' . ++$_[1]->{actcount} .'__'; }
855 my $class = ref($_[0]) || $_[0];
859 "lookahead" => $_[2],
864 sub issubrule { undef }
869 my ($self, $namespace, $rule) = @_;
872 Parse::RecDescent::_trace(q{Trying action},
873 Parse::RecDescent::_tracefirst($text),
874 q{' . $rule->{name} . '},
876 if defined $::RD_TRACE;
877 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' ) .'
879 $_tok = ($_noactions) ? 0 : do ' . $self->{"code"} . ';
880 ' . ($self->{"lookahead"}<0?'if':'unless') . ' (defined $_tok)
882 Parse::RecDescent::_trace(q{<<Didn\'t match action>> (return value: [undef])})
883 if defined $::RD_TRACE;
886 Parse::RecDescent::_trace(q{>>Matched action<< (return value: [}
888 Parse::RecDescent::_tracefirst($text))
889 if defined $::RD_TRACE;
891 ' . ($self->{line}>=0 ? '$item{'. $self->{hashname} .'}=$_tok;' : '' ) .'
892 ' . ($self->{"lookahead"} ? '$text = $_savetext;' : '' ) .'
899 package Parse::RecDescent::Directive;
901 sub sethashname { $_[0]->{hashname} = '__DIRECTIVE' . ++$_[1]->{dircount} . '__'; }
903 sub issubrule { undef }
905 sub describe { $_[1] ? '' : $_[0]->{name} }
909 my $class = ref($_[0]) || $_[0];
913 "lookahead" => $_[2],
921 my ($self, $namespace, $rule) = @_;
924 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' ) .'
926 Parse::RecDescent::_trace(q{Trying directive: ['
927 . $self->describe . ']},
928 Parse::RecDescent::_tracefirst($text),
929 q{' . $rule->{name} . '},
931 if defined $::RD_TRACE; ' .'
932 $_tok = do { ' . $self->{"code"} . ' };
935 Parse::RecDescent::_trace(q{>>Matched directive<< (return value: [}
937 Parse::RecDescent::_tracefirst($text))
938 if defined $::RD_TRACE;
942 Parse::RecDescent::_trace(q{<<Didn\'t match directive>>},
943 Parse::RecDescent::_tracefirst($text))
944 if defined $::RD_TRACE;
946 ' . ($self->{"lookahead"} ? '$text = $_savetext and ' : '' ) .'
948 . ($self->{"lookahead"}<0?'if':'unless') . ' defined $_tok;
949 push @item, $item{'.$self->{hashname}.'}=$_tok;
950 ' . ($self->{"lookahead"} ? '$text = $_savetext;' : '' ) .'
956 package Parse::RecDescent::UncondReject;
958 sub issubrule { undef }
960 sub describe { $_[1] ? '' : $_[0]->{name} }
961 sub sethashname { $_[0]->{hashname} = '__DIRECTIVE' . ++$_[1]->{dircount} . '__'; }
965 my $class = ref($_[0]) || $_[0];
968 "lookahead" => $_[1],
974 # MARK, YOU MAY WANT TO OPTIMIZE THIS.
979 my ($self, $namespace, $rule) = @_;
982 Parse::RecDescent::_trace(q{>>Rejecting production<< (found '
983 . $self->describe . ')},
984 Parse::RecDescent::_tracefirst($text),
985 q{' . $rule->{name} . '},
987 if defined $::RD_TRACE;
989 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' ) .'
992 ' . ($self->{"lookahead"} ? '$text = $_savetext and ' : '' ) .'
994 . ($self->{"lookahead"}<0?'if':'unless') . ' defined $_tok;
1000 package Parse::RecDescent::Error;
1002 sub issubrule { undef }
1003 sub isterminal { 0 }
1004 sub describe { $_[1] ? '' : $_[0]->{commitonly} ? '<error?:...>' : '<error...>' }
1005 sub sethashname { $_[0]->{hashname} = '__DIRECTIVE' . ++$_[1]->{dircount} . '__'; }
1009 my $class = ref($_[0]) || $_[0];
1013 "lookahead" => $_[2],
1014 "commitonly" => $_[3],
1021 my ($self, $namespace, $rule) = @_;
1025 if ($self->{"msg"}) # ERROR MESSAGE SUPPLIED
1027 #WAS: $action .= "Parse::RecDescent::_error(qq{$self->{msg}}" . ',$thisline);';
1028 $action .= 'push @{$thisparser->{errors}}, [qq{'.$self->{msg}.'},$thisline];';
1031 else # GENERATE ERROR MESSAGE DURING PARSE
1034 my $rule = $item[0];
1036 #WAS: Parse::RecDescent::_error("Invalid $rule: " . $expectation->message() ,$thisline);
1037 push @{$thisparser->{errors}}, ["Invalid $rule: " . $expectation->message() ,$thisline];
1042 new Parse::RecDescent::Directive('if (' .
1043 ($self->{"commitonly"} ? '$commit' : '1') .
1044 ") { do {$action} unless ".' $_noactions; undef } else {0}',
1045 $self->{"lookahead"},0,$self->describe);
1046 $dir->{hashname} = $self->{hashname};
1047 return $dir->code($namespace, $rule, 0);
1052 package Parse::RecDescent::Token;
1054 sub sethashname { $_[0]->{hashname} = '__PATTERN' . ++$_[1]->{patcount} . '__'; }
1056 sub issubrule { undef }
1057 sub isterminal { 1 }
1058 sub describe ($) { shift->{'description'}}
1061 # ARGS ARE: $self, $pattern, $left_delim, $modifiers, $lookahead, $linenum
1064 my $class = ref($_[0]) || $_[0];
1065 my $pattern = $_[1];
1069 $rdel =~ tr/{[(</}])>/;
1075 if ($ldel eq '/') { $desc = "$ldel$pattern$rdel$mod" }
1076 else { $desc = "m$ldel$pattern$rdel$mod" }
1077 $desc =~ s/\\/\\\\/g;
1078 $desc =~ s/\$$/\\\$/g;
1082 if (!eval "no strict;
1083 local \$SIG{__WARN__} = sub {0};
1084 '' =~ m$ldel$pattern$rdel" and $@)
1086 Parse::RecDescent::_warn(3, "Token pattern \"m$ldel$pattern$rdel\"
1087 may not be a valid regular expression",
1089 $@ =~ s/ at \(eval.*/./;
1090 Parse::RecDescent::_hint($@);
1093 # QUIETLY PREVENT (WELL-INTENTIONED) CALAMITY
1095 $pattern =~ s/(\A|[^\\])\\G/$1/g;
1099 "pattern" => $pattern,
1103 "lookahead" => $_[4],
1105 "description" => $desc,
1112 my ($self, $namespace, $rule, $check) = @_;
1113 my $ldel = $self->{"ldelim"};
1114 my $rdel = $self->{"rdelim"};
1116 my $mod = $self->{"mod"};
1118 $sdel =~ s/[[{(<]/{}/;
1121 Parse::RecDescent::_trace(q{Trying terminal: [' . $self->describe
1122 . ']}, Parse::RecDescent::_tracefirst($text),
1123 q{' . $rule->{name} . '},
1125 if defined $::RD_TRACE;
1127 $expectation->is(q{' . ($rule->hasleftmost($self) ? ''
1128 : $self->describe ) . '})->at($text);
1129 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' ) . '
1131 ' . ($self->{"lookahead"}<0?'if':'unless')
1132 . ' ($text =~ s/\A($skip)/$lastsep=$1 and ""/e and '
1133 . ($check->{itempos}? 'do {'.Parse::RecDescent::Production::incitempos().' 1} and ' : '')
1134 . ' $text =~ s' . $ldel . '\A(?:' . $self->{"pattern"} . ')'
1135 . $rdel . $sdel . $mod . ')
1137 '.($self->{"lookahead"} ? '$text = $_savetext;' : '').'
1138 $expectation->failed();
1139 Parse::RecDescent::_trace(q{<<Didn\'t match terminal>>},
1140 Parse::RecDescent::_tracefirst($text))
1141 if defined $::RD_TRACE;
1145 Parse::RecDescent::_trace(q{>>Matched terminal<< (return value: [}
1147 Parse::RecDescent::_tracefirst($text))
1148 if defined $::RD_TRACE;
1149 push @item, $item{'.$self->{hashname}.'}=$&;
1150 ' . ($self->{"lookahead"} ? '$text = $_savetext;' : '' ) .'
1158 package Parse::RecDescent::Literal;
1160 sub sethashname { $_[0]->{hashname} = '__STRING' . ++$_[1]->{strcount} . '__'; }
1162 sub issubrule { undef }
1163 sub isterminal { 1 }
1164 sub describe ($) { shift->{'description'} }
1168 my $class = ref($_[0]) || $_[0];
1170 my $pattern = $_[1];
1172 my $desc = $pattern;
1179 "pattern" => $pattern,
1180 "lookahead" => $_[2],
1182 "description" => "'$desc'",
1189 my ($self, $namespace, $rule, $check) = @_;
1192 Parse::RecDescent::_trace(q{Trying terminal: [' . $self->describe
1194 Parse::RecDescent::_tracefirst($text),
1195 q{' . $rule->{name} . '},
1197 if defined $::RD_TRACE;
1199 $expectation->is(q{' . ($rule->hasleftmost($self) ? ''
1200 : $self->describe ) . '})->at($text);
1201 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' ) . '
1203 ' . ($self->{"lookahead"}<0?'if':'unless')
1204 . ' ($text =~ s/\A($skip)/$lastsep=$1 and ""/e and '
1205 . ($check->{itempos}? 'do {'.Parse::RecDescent::Production::incitempos().' 1} and ' : '')
1206 . ' $text =~ s/\A' . quotemeta($self->{"pattern"}) . '//)
1208 '.($self->{"lookahead"} ? '$text = $_savetext;' : '').'
1209 $expectation->failed();
1210 Parse::RecDescent::_trace(qq{<<Didn\'t match terminal>>},
1211 Parse::RecDescent::_tracefirst($text))
1212 if defined $::RD_TRACE;
1215 Parse::RecDescent::_trace(q{>>Matched terminal<< (return value: [}
1217 Parse::RecDescent::_tracefirst($text))
1218 if defined $::RD_TRACE;
1219 push @item, $item{'.$self->{hashname}.'}=$&;
1220 ' . ($self->{"lookahead"} ? '$text = $_savetext;' : '' ) .'
1228 package Parse::RecDescent::InterpLit;
1230 sub sethashname { $_[0]->{hashname} = '__STRING' . ++$_[1]->{strcount} . '__'; }
1232 sub issubrule { undef }
1233 sub isterminal { 1 }
1234 sub describe ($) { shift->{'description'} }
1238 my $class = ref($_[0]) || $_[0];
1240 my $pattern = $_[1];
1241 $pattern =~ s#/#\\/#g;
1243 my $desc = $pattern;
1250 "pattern" => $pattern,
1251 "lookahead" => $_[2],
1253 "description" => "'$desc'",
1259 my ($self, $namespace, $rule, $check) = @_;
1262 Parse::RecDescent::_trace(q{Trying terminal: [' . $self->describe
1264 Parse::RecDescent::_tracefirst($text),
1265 q{' . $rule->{name} . '},
1267 if defined $::RD_TRACE;
1269 $expectation->is(q{' . ($rule->hasleftmost($self) ? ''
1270 : $self->describe ) . '})->at($text);
1271 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' ) . '
1273 ' . ($self->{"lookahead"}<0?'if':'unless')
1274 . ' ($text =~ s/\A($skip)/$lastsep=$1 and ""/e and '
1275 . ($check->{itempos}? 'do {'.Parse::RecDescent::Production::incitempos().' 1} and ' : '')
1276 . ' do { $_tok = "' . $self->{"pattern"} . '"; 1 } and
1277 substr($text,0,length($_tok)) eq $_tok and
1278 do { substr($text,0,length($_tok)) = ""; 1; }
1281 '.($self->{"lookahead"} ? '$text = $_savetext;' : '').'
1282 $expectation->failed();
1283 Parse::RecDescent::_trace(q{<<Didn\'t match terminal>>},
1284 Parse::RecDescent::_tracefirst($text))
1285 if defined $::RD_TRACE;
1288 Parse::RecDescent::_trace(q{>>Matched terminal<< (return value: [}
1290 Parse::RecDescent::_tracefirst($text))
1291 if defined $::RD_TRACE;
1292 push @item, $item{'.$self->{hashname}.'}=$_tok;
1293 ' . ($self->{"lookahead"} ? '$text = $_savetext;' : '' ) .'
1301 package Parse::RecDescent::Subrule;
1303 sub issubrule ($) { return $_[0]->{"subrule"} }
1304 sub isterminal { 0 }
1309 my $desc = $_[0]->{"implicit"} || $_[0]->{"subrule"};
1310 $desc = "<matchrule:$desc>" if $_[0]->{"matchrule"};
1316 if ($_[0]->{"matchrule"})
1318 return "&{'$_[1]'.qq{$_[0]->{subrule}}}";
1322 return $_[1].$_[0]->{"subrule"};
1328 my $class = ref($_[0]) || $_[0];
1332 "lookahead" => $_[2],
1334 "implicit" => $_[4] || undef,
1335 "matchrule" => $_[5],
1336 "argcode" => $_[6] || undef,
1343 my ($self, $namespace, $rule) = @_;
1346 Parse::RecDescent::_trace(q{Trying subrule: [' . $self->{"subrule"} . ']},
1347 Parse::RecDescent::_tracefirst($text),
1348 q{' . $rule->{"name"} . '},
1350 if defined $::RD_TRACE;
1351 if (1) { no strict qw{refs};
1352 $expectation->is(' . ($rule->hasleftmost($self) ? 'q{}'
1353 # WAS : 'qq{'.$self->describe.'}' ) . ')->at($text);
1354 : 'q{'.$self->describe.'}' ) . ')->at($text);
1355 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' )
1356 . ($self->{"lookahead"}<0?'if':'unless')
1357 . ' (defined ($_tok = '
1358 . $self->callsyntax($namespace.'::')
1359 . '($thisparser,$text,$repeating,'
1360 . ($self->{"lookahead"}?'1':'$_noactions')
1361 . ($self->{argcode} ? ",sub { return $self->{argcode} }"
1362 : ',sub { \\@arg }')
1365 '.($self->{"lookahead"} ? '$text = $_savetext;' : '').'
1366 Parse::RecDescent::_trace(q{<<Didn\'t match subrule: ['
1367 . $self->{subrule} . ']>>},
1368 Parse::RecDescent::_tracefirst($text),
1369 q{' . $rule->{"name"} .'},
1371 if defined $::RD_TRACE;
1372 $expectation->failed();
1375 Parse::RecDescent::_trace(q{>>Matched subrule: ['
1376 . $self->{subrule} . ']<< (return value: [}
1379 Parse::RecDescent::_tracefirst($text),
1380 q{' . $rule->{"name"} .'},
1382 if defined $::RD_TRACE;
1383 $item{q{' . $self->{subrule} . '}} = $_tok;
1385 ' . ($self->{"lookahead"} ? '$text = $_savetext;' : '' ) .'
1390 package Parse::RecDescent::Repetition;
1392 sub issubrule ($) { return $_[0]->{"subrule"} }
1393 sub isterminal { 0 }
1398 my $desc = $_[0]->{"expected"} || $_[0]->{"subrule"};
1399 $desc = "<matchrule:$desc>" if $_[0]->{"matchrule"};
1405 if ($_[0]->{matchrule})
1406 { return "sub { goto &{''.qq{$_[1]$_[0]->{subrule}}} }"; }
1408 { return "\\&$_[1]$_[0]->{subrule}"; }
1411 sub new ($$$$$$$$$$)
1413 my ($self, $subrule, $repspec, $min, $max, $lookahead, $line, $parser, $matchrule, $argcode) = @_;
1414 my $class = ref($self) || $self;
1415 ($max, $min) = ( $min, $max) if ($max<$min);
1418 if ($subrule=~/\A_alternation_\d+_of_production_\d+_of_rule/)
1419 { $desc = $parser->{"rules"}{$subrule}->expected }
1425 return new Parse::RecDescent::Subrule($subrule,$lookahead,$line,$desc,$matchrule,$argcode);
1429 Parse::RecDescent::_error("Not symbol (\"!\") before
1430 \"$subrule\" doesn't make
1432 Parse::RecDescent::_hint("Lookahead for negated optional
1433 repetitions (such as
1434 \"!$subrule($repspec)\" can never
1435 succeed, since optional items always
1436 match (zero times at worst).
1437 Did you mean a single \"!$subrule\",
1443 "subrule" => $subrule,
1444 "repspec" => $repspec,
1447 "lookahead" => $lookahead,
1449 "expected" => $desc,
1450 "argcode" => $argcode || undef,
1451 "matchrule" => $matchrule,
1457 my ($self, $namespace, $rule) = @_;
1459 my ($subrule, $repspec, $min, $max, $lookahead) =
1460 @{$self}{ qw{subrule repspec min max lookahead} };
1463 Parse::RecDescent::_trace(q{Trying repeated subrule: [' . $self->describe . ']},
1464 Parse::RecDescent::_tracefirst($text),
1465 q{' . $rule->{"name"} . '},
1467 if defined $::RD_TRACE;
1468 $expectation->is(' . ($rule->hasleftmost($self) ? 'q{}'
1469 # WAS : 'qq{'.$self->describe.'}' ) . ')->at($text);
1470 : 'q{'.$self->describe.'}' ) . ')->at($text);
1471 ' . ($self->{"lookahead"} ? '$_savetext = $text;' : '' ) .'
1472 unless (defined ($_tok = $thisparser->_parserepeat($text, '
1473 . $self->callsyntax($namespace.'::')
1474 . ', ' . $min . ', ' . $max . ', '
1475 . ($self->{"lookahead"}?'1':'$_noactions')
1477 . ($self->{argcode} ? "sub { return $self->{argcode} }"
1481 Parse::RecDescent::_trace(q{<<Didn\'t match repeated subrule: ['
1482 . $self->describe . ']>>},
1483 Parse::RecDescent::_tracefirst($text),
1484 q{' . $rule->{"name"} .'},
1486 if defined $::RD_TRACE;
1489 Parse::RecDescent::_trace(q{>>Matched repeated subrule: ['
1490 . $self->{subrule} . ']<< (}
1491 . @$_tok . q{ times)},
1493 Parse::RecDescent::_tracefirst($text),
1494 q{' . $rule->{"name"} .'},
1496 if defined $::RD_TRACE;
1497 $item{q{' . "$self->{subrule}($self->{repspec})" . '}} = $_tok;
1499 ' . ($self->{"lookahead"} ? '$text = $_savetext;' : '' ) .'
1504 package Parse::RecDescent::Result;
1507 sub isterminal { 0 }
1512 my ($class, $pos) = @_;
1519 my ($self, $namespace, $rule) = @_;
1522 $return = $item[-1];
1526 package Parse::RecDescent::Operator;
1528 my @opertype = ( " non-optional", "n optional" );
1531 sub isterminal { 0 }
1533 sub describe { $_[0]->{"expected"} }
1534 sub sethashname { $_[0]->{hashname} = '__DIRECTIVE' . ++$_[1]->{dircount} . '__'; }
1539 my ($class, $type, $minrep, $maxrep, $leftarg, $op, $rightarg) = @_;
1543 "type" => "${type}op",
1544 "leftarg" => $leftarg,
1548 "rightarg" => $rightarg,
1549 "expected" => "<${type}op: ".$leftarg->describe." ".$op->describe." ".$rightarg->describe.">",
1555 my ($self, $namespace, $rule) = @_;
1557 my ($leftarg, $op, $rightarg) =
1558 @{$self}{ qw{leftarg op rightarg} };
1561 Parse::RecDescent::_trace(q{Trying operator: [' . $self->describe . ']},
1562 Parse::RecDescent::_tracefirst($text),
1563 q{' . $rule->{"name"} . '},
1565 if defined $::RD_TRACE;
1566 $expectation->is(' . ($rule->hasleftmost($self) ? 'q{}'
1567 # WAS : 'qq{'.$self->describe.'}' ) . ')->at($text);
1568 : 'q{'.$self->describe.'}' ) . ')->at($text);
1577 if ($self->{type} eq "leftop" )
1581 ' . $leftarg->code(@_[1..2]) . '
1585 my $savetext = $text;
1588 # MATCH (OP RIGHTARG)(s)
1589 while ($repcount < ' . $self->{max} . ')
1592 ' . $op->code(@_[1..2]) . '
1593 ' . ($op->isterminal() ? 'pop @item;' : '$backtrack=1;' ) . '
1594 ' . (ref($op) eq 'Parse::RecDescent::Token'
1595 ? 'if (defined $1) {push @item, $item{'.($self->{name}||$self->{hashname}).'}=$1; $backtrack=1;}'
1597 ' . $rightarg->code(@_[1..2]) . '
1602 pop @item if $backtrack;
1609 my $savetext = $text;
1611 # MATCH (LEFTARG OP)(s)
1612 while ($repcount < ' . $self->{max} . ')
1615 ' . $leftarg->code(@_[1..2]) . '
1618 ' . $op->code(@_[1..2]) . '
1620 ' . ($op->isterminal() ? 'pop @item;' : "" ) . '
1621 ' . (ref($op) eq 'Parse::RecDescent::Token' ? 'do { push @item, $item{'.($self->{name}||$self->{hashname}).'}=$1; } if defined $1;' : "" ) . '
1624 pop @item if $backtrack;
1627 ' . $rightarg->code(@_[1..2]) . '
1632 $code .= 'unless (@item) { undef $_tok; last }' unless $self->{min}==0;
1639 unless ($repcount>='.$self->{min}.')
1641 Parse::RecDescent::_trace(q{<<Didn\'t match operator: ['
1644 Parse::RecDescent::_tracefirst($text),
1645 q{' . $rule->{"name"} .'},
1647 if defined $::RD_TRACE;
1648 $expectation->failed();
1651 Parse::RecDescent::_trace(q{>>Matched operator: ['
1653 . ']<< (return value: [}
1654 . qq{@{$_tok||[]}} . q{]},
1655 Parse::RecDescent::_tracefirst($text),
1656 q{' . $rule->{"name"} .'},
1658 if defined $::RD_TRACE;
1660 push @item, $item{'.($self->{name}||$self->{hashname}).'}=$_tok||[];
1667 package Parse::RecDescent::Expectation;
1675 "lastexpected" => "",
1676 "lastunexpected" => "",
1677 "defexpected" => $_[1],
1683 $_[0]->{lastexpected} = $_[1]; return $_[0];
1688 $_[0]->{lastunexpected} = $_[1]; return $_[0];
1693 return unless $_[0]->{lastexpected};
1694 $_[0]->{expected} = $_[0]->{lastexpected} unless $_[0]->{failed};
1695 $_[0]->{unexpected} = $_[0]->{lastunexpected} unless $_[0]->{failed};
1696 $_[0]->{failed} = 1;
1702 $self->{expected} = $self->{defexpected} unless $self->{expected};
1703 $self->{expected} =~ s/_/ /g;
1704 if (!$self->{unexpected} || $self->{unexpected} =~ /\A\s*\Z/s)
1706 return "Was expecting $self->{expected}";
1710 $self->{unexpected} =~ /\s*(.*)/;
1711 return "Was expecting $self->{expected} but found \"$1\" instead";
1717 package Parse::RecDescent;
1720 use vars qw ( $AUTOLOAD $VERSION );
1728 my $nextnamespace = "namespace000001";
1730 sub _nextnamespace()
1732 return "Parse::RecDescent::" . $nextnamespace++;
1737 my $class = ref($_[0]) || $_[0];
1738 local $Parse::RecDescent::compiling = $_[2];
1739 my $name_space_name = defined $_[3]
1740 ? "Parse::RecDescent::".$_[3]
1745 "namespace" => $name_space_name,
1748 "_AUTOACTION" => undef,
1749 "_AUTOTREE" => undef,
1751 if ($::RD_AUTOACTION)
1753 my $sourcecode = $::RD_AUTOACTION;
1754 $sourcecode = "{ $sourcecode }"
1755 unless $sourcecode =~ /\A\s*\{.*\}\s*\Z/;
1756 $self->{_check}{itempos} =
1757 $sourcecode =~ /\@itempos\b|\$itempos\s*\[/;
1758 $self->{_AUTOACTION}
1759 = new Parse::RecDescent::Action($sourcecode,0,-1)
1762 bless $self, $class;
1764 return $self->Replace(@_)
1769 die "Compilation of Parse::RecDescent grammars not yet implemented\n";
1772 sub DESTROY {} # SO AUTOLOADER IGNORES IT
1774 # BUILDING A GRAMMAR....
1778 splice(@_, 2, 0, 1);
1779 return _generate(@_);
1784 splice(@_, 2, 0, 0);
1785 return _generate(@_);
1790 _error("Ruleless $_[0] at start of grammar.",$_[1]);
1791 my $desc = $_[2] ? "\"$_[2]\"" : "";
1792 _hint("You need to define a rule for the $_[0] $desc
1796 my $NEGLOOKAHEAD = '\G(\s*\.\.\.\!)';
1797 my $POSLOOKAHEAD = '\G(\s*\.\.\.)';
1798 my $RULE = '\G\s*(\w+)[ \t]*:';
1799 my $PROD = '\G\s*([|])';
1800 my $TOKEN = q{\G\s*/((\\\\/|[^/])*)/([cgimsox]*)};
1801 my $MTOKEN = q{\G\s*(m\s*[^\w\s])};
1802 my $LITERAL = q{\G\s*'((\\\\['\\\\]|[^'])*)'};
1803 my $INTERPLIT = q{\G\s*"((\\\\["\\\\]|[^"])*)"};
1804 my $SUBRULE = '\G\s*(\w+)';
1805 my $MATCHRULE = '\G(\s*<matchrule:)';
1806 my $SIMPLEPAT = '((\\s+/[^/\\\\]*(?:\\\\.[^/\\\\]*)*/)?)';
1807 my $OPTIONAL = '\G\((\?)'.$SIMPLEPAT.'\)';
1808 my $ANY = '\G\((s\?)'.$SIMPLEPAT.'\)';
1809 my $MANY = '\G\((s|\.\.)'.$SIMPLEPAT.'\)';
1810 my $EXACTLY = '\G\(([1-9]\d*)'.$SIMPLEPAT.'\)';
1811 my $BETWEEN = '\G\((\d+)\.\.([1-9]\d*)'.$SIMPLEPAT.'\)';
1812 my $ATLEAST = '\G\((\d+)\.\.'.$SIMPLEPAT.'\)';
1813 my $ATMOST = '\G\(\.\.([1-9]\d*)'.$SIMPLEPAT.'\)';
1814 my $BADREP = '\G\((-?\d+)?\.\.(-?\d+)?'.$SIMPLEPAT.'\)';
1815 my $ACTION = '\G\s*\{';
1816 my $IMPLICITSUBRULE = '\G\s*\(';
1817 my $COMMENT = '\G\s*(#.*)';
1818 my $COMMITMK = '\G\s*<commit>';
1819 my $UNCOMMITMK = '\G\s*<uncommit>';
1820 my $QUOTELIKEMK = '\G\s*<perl_quotelike>';
1821 my $CODEBLOCKMK = '\G\s*<perl_codeblock(?:\s+([][()<>{}]+))?>';
1822 my $VARIABLEMK = '\G\s*<perl_variable>';
1823 my $NOCHECKMK = '\G\s*<nocheck>';
1824 my $AUTOTREEMK = '\G\s*<autotree>';
1825 my $AUTOSTUBMK = '\G\s*<autostub>';
1826 my $AUTORULEMK = '\G\s*<autorule:(.*?)>';
1827 my $REJECTMK = '\G\s*<reject>';
1828 my $CONDREJECTMK = '\G\s*<reject:';
1829 my $SCOREMK = '\G\s*<score:';
1830 my $AUTOSCOREMK = '\G\s*<autoscore:';
1831 my $SKIPMK = '\G\s*<skip:';
1832 my $OPMK = '\G\s*<(left|right)op(?:=(\'.*?\'))?:';
1833 my $ENDDIRECTIVEMK = '\G\s*>';
1834 my $RESYNCMK = '\G\s*<resync>';
1835 my $RESYNCPATMK = '\G\s*<resync:';
1836 my $RULEVARPATMK = '\G\s*<rulevar:';
1837 my $DEFERPATMK = '\G\s*<defer:';
1838 my $TOKENPATMK = '\G\s*<token:';
1839 my $AUTOERRORMK = '\G\s*<error(\??)>';
1840 my $MSGERRORMK = '\G\s*<error(\??):';
1841 my $UNCOMMITPROD = $PROD.'\s*<uncommit';
1842 my $ERRORPROD = $PROD.'\s*<error';
1843 my $LONECOLON = '\G\s*:';
1844 my $OTHER = '\G\s*([^\s]+)';
1848 sub _generate($$$;$$)
1850 my ($self, $grammar, $replace, $isimplicit, $isleftop) = (@_, 0);
1854 my $lookaheadspec = "";
1855 $lines = _linecount($grammar) unless $lines;
1856 $self->{_check}{itempos} = ($grammar =~ /\@itempos\b|\$itempos\s*\[/)
1857 unless $self->{_check}{itempos};
1858 for (qw(thisoffset thiscolumn prevline prevoffset prevcolumn))
1860 $self->{_check}{$_} =
1861 ($grammar =~ /\$$_/) || $self->{_check}{itempos}
1862 unless $self->{_check}{$_};
1869 my $lastgreedy = '';
1873 while (pos $grammar < length $grammar)
1875 $line = $lines - _linecount($grammar) + 1;
1878 my @components = ();
1879 if ($grammar =~ m/$COMMENT/gco)
1881 _parse("a comment",0,$line);
1884 elsif ($grammar =~ m/$NEGLOOKAHEAD/gco)
1886 _parse("a negative lookahead",$aftererror,$line);
1887 $lookahead = $lookahead ? -$lookahead : -1;
1888 $lookaheadspec .= $1;
1889 next; # SKIP LOOKAHEAD RESET AT END OF while LOOP
1891 elsif ($grammar =~ m/$POSLOOKAHEAD/gco)
1893 _parse("a positive lookahead",$aftererror,$line);
1894 $lookahead = $lookahead ? $lookahead : 1;
1895 $lookaheadspec .= $1;
1896 next; # SKIP LOOKAHEAD RESET AT END OF while LOOP
1898 elsif ($grammar =~ m/(?=$ACTION)/gco
1899 and do { ($code) = extract_codeblock($grammar); $code })
1901 _parse("an action", $aftererror, $line, $code);
1902 $item = new Parse::RecDescent::Action($code,$lookahead,$line);
1903 $prod and $prod->additem($item)
1904 or $self->_addstartcode($code);
1906 elsif ($grammar =~ m/(?=$IMPLICITSUBRULE)/gco
1907 and do { ($code) = extract_codeblock($grammar,'{([',undef,'(',1);
1910 $code =~ s/\A\s*\(|\)\Z//g;
1911 _parse("an implicit subrule", $aftererror, $line,
1913 my $implicit = $rule->nextimplicit;
1914 $self->_generate("$implicit : $code",$replace,1);
1915 my $pos = pos $grammar;
1916 substr($grammar,$pos,0,$implicit);
1917 pos $grammar = $pos;;
1919 elsif ($grammar =~ m/$ENDDIRECTIVEMK/gco)
1922 # EXTRACT TRAILING REPETITION SPECIFIER (IF ANY)
1924 my ($minrep,$maxrep) = (1,$MAXREP);
1925 if ($grammar =~ m/\G[(]/gc)
1929 if ($grammar =~ m/$OPTIONAL/gco)
1930 { ($minrep, $maxrep) = (0,1) }
1931 elsif ($grammar =~ m/$ANY/gco)
1933 elsif ($grammar =~ m/$EXACTLY/gco)
1934 { ($minrep, $maxrep) = ($1,$1) }
1935 elsif ($grammar =~ m/$BETWEEN/gco)
1936 { ($minrep, $maxrep) = ($1,$2) }
1937 elsif ($grammar =~ m/$ATLEAST/gco)
1939 elsif ($grammar =~ m/$ATMOST/gco)
1941 elsif ($grammar =~ m/$MANY/gco)
1943 elsif ($grammar =~ m/$BADREP/gco)
1945 _parse("an invalid repetition specifier", 0,$line);
1946 _error("Incorrect specification of a repeated directive",
1948 _hint("Repeated directives cannot have
1949 a maximum repetition of zero, nor can they have
1950 negative components in their ranges.");
1954 $prod && $prod->enddirective($line,$minrep,$maxrep);
1956 elsif ($grammar =~ m/\G\s*<[^m]/gc)
1960 if ($grammar =~ m/$OPMK/gco)
1963 _parse("a $1-associative operator directive", $aftererror, $line, "<$1op:...>");
1964 $prod->adddirective($1, $line,$2||'');
1966 elsif ($grammar =~ m/$UNCOMMITMK/gco)
1968 _parse("an uncommit marker", $aftererror,$line);
1969 $item = new Parse::RecDescent::Directive('$commit=0;1',
1970 $lookahead,$line,"<uncommit>");
1971 $prod and $prod->additem($item)
1972 or _no_rule("<uncommit>",$line);
1974 elsif ($grammar =~ m/$QUOTELIKEMK/gco)
1976 _parse("an perl quotelike marker", $aftererror,$line);
1977 $item = new Parse::RecDescent::Directive(
1979 ($match,$text,undef,@res) =
1980 Text::Balanced::extract_quotelike($text,$skip);
1981 $match ? \@res : undef;
1982 ', $lookahead,$line,"<perl_quotelike>");
1983 $prod and $prod->additem($item)
1984 or _no_rule("<perl_quotelike>",$line);
1986 elsif ($grammar =~ m/$CODEBLOCKMK/gco)
1988 my $outer = $1||"{}";
1989 _parse("an perl codeblock marker", $aftererror,$line);
1990 $item = new Parse::RecDescent::Directive(
1991 'Text::Balanced::extract_codeblock($text,undef,$skip,\''.$outer.'\');
1992 ', $lookahead,$line,"<perl_codeblock>");
1993 $prod and $prod->additem($item)
1994 or _no_rule("<perl_codeblock>",$line);
1996 elsif ($grammar =~ m/$VARIABLEMK/gco)
1998 _parse("an perl variable marker", $aftererror,$line);
1999 $item = new Parse::RecDescent::Directive(
2000 'Text::Balanced::extract_variable($text,$skip);
2001 ', $lookahead,$line,"<perl_variable>");
2002 $prod and $prod->additem($item)
2003 or _no_rule("<perl_variable>",$line);
2005 elsif ($grammar =~ m/$NOCHECKMK/gco)
2007 _parse("a disable checking marker", $aftererror,$line);
2010 _error("<nocheck> directive not at start of grammar", $line);
2011 _hint("The <nocheck> directive can only
2012 be specified at the start of a
2013 grammar (before the first rule
2018 local $::RD_CHECK = 1;
2021 elsif ($grammar =~ m/$AUTOSTUBMK/gco)
2023 _parse("an autostub marker", $aftererror,$line);
2024 $::RD_AUTOSTUB = "";
2026 elsif ($grammar =~ m/$AUTORULEMK/gco)
2028 _parse("an autorule marker", $aftererror,$line);
2029 $::RD_AUTOSTUB = $1;
2031 elsif ($grammar =~ m/$AUTOTREEMK/gco)
2033 _parse("an autotree marker", $aftererror,$line);
2036 _error("<autotree> directive not at start of grammar", $line);
2037 _hint("The <autotree> directive can only
2038 be specified at the start of a
2039 grammar (before the first rule
2044 undef $self->{_AUTOACTION};
2045 $self->{_AUTOTREE}{NODE}
2046 = new Parse::RecDescent::Action(q{{bless \%item, $item[0]}},0,-1);
2047 $self->{_AUTOTREE}{TERMINAL}
2048 = new Parse::RecDescent::Action(q{{bless {__VALUE__=>$item[1]}, $item[0]}},0,-1);
2052 elsif ($grammar =~ m/$REJECTMK/gco)
2054 _parse("an reject marker", $aftererror,$line);
2055 $item = new Parse::RecDescent::UncondReject($lookahead,$line,"<reject>");
2056 $prod and $prod->additem($item)
2057 or _no_rule("<reject>",$line);
2059 elsif ($grammar =~ m/(?=$CONDREJECTMK)/gco
2060 and do { ($code) = extract_codeblock($grammar,'{',undef,'<');
2063 _parse("a (conditional) reject marker", $aftererror,$line);
2064 $code =~ /\A\s*<reject:(.*)>\Z/s;
2065 $item = new Parse::RecDescent::Directive(
2066 "($1) ? undef : 1", $lookahead,$line,"<reject:$code>");
2067 $prod and $prod->additem($item)
2068 or _no_rule("<reject:$code>",$line);
2070 elsif ($grammar =~ m/(?=$SCOREMK)/gco
2071 and do { ($code) = extract_codeblock($grammar,'{',undef,'<');
2074 _parse("a score marker", $aftererror,$line);
2075 $code =~ /\A\s*<score:(.*)>\Z/s;
2076 $prod and $prod->addscore($1, $lookahead, $line)
2077 or _no_rule($code,$line);
2079 elsif ($grammar =~ m/(?=$AUTOSCOREMK)/gco
2080 and do { ($code) = extract_codeblock($grammar,'{',undef,'<');
2084 _parse("an autoscore specifier", $aftererror,$line,$code);
2085 $code =~ /\A\s*<autoscore:(.*)>\Z/s;
2087 $rule and $rule->addautoscore($1,$self)
2088 or _no_rule($code,$line);
2090 $item = new Parse::RecDescent::UncondReject($lookahead,$line,$code);
2091 $prod and $prod->additem($item)
2092 or _no_rule($code,$line);
2094 elsif ($grammar =~ m/$RESYNCMK/gco)
2096 _parse("a resync to newline marker", $aftererror,$line);
2097 $item = new Parse::RecDescent::Directive(
2098 'if ($text =~ s/\A[^\n]*\n//) { $return = 0; $& } else { undef }',
2099 $lookahead,$line,"<resync>");
2100 $prod and $prod->additem($item)
2101 or _no_rule("<resync>",$line);
2103 elsif ($grammar =~ m/(?=$RESYNCPATMK)/gco
2104 and do { ($code) = extract_bracketed($grammar,'<');
2107 _parse("a resync with pattern marker", $aftererror,$line);
2108 $code =~ /\A\s*<resync:(.*)>\Z/s;
2109 $item = new Parse::RecDescent::Directive(
2110 'if ($text =~ s/\A'.$1.'//) { $return = 0; $& } else { undef }',
2111 $lookahead,$line,$code);
2112 $prod and $prod->additem($item)
2113 or _no_rule($code,$line);
2115 elsif ($grammar =~ m/(?=$SKIPMK)/gco
2116 and do { ($code) = extract_codeblock($grammar,'<');
2119 _parse("a skip marker", $aftererror,$line);
2120 $code =~ /\A\s*<skip:(.*)>\Z/s;
2121 $item = new Parse::RecDescent::Directive(
2122 'my $oldskip = $skip; $skip='.$1.'; $oldskip',
2123 $lookahead,$line,$code);
2124 $prod and $prod->additem($item)
2125 or _no_rule($code,$line);
2127 elsif ($grammar =~ m/(?=$RULEVARPATMK)/gco
2128 and do { ($code) = extract_codeblock($grammar,'{',undef,'<');
2132 _parse("a rule variable specifier", $aftererror,$line,$code);
2133 $code =~ /\A\s*<rulevar:(.*)>\Z/s;
2135 $rule and $rule->addvar($1,$self)
2136 or _no_rule($code,$line);
2138 $item = new Parse::RecDescent::UncondReject($lookahead,$line,$code);
2139 $prod and $prod->additem($item)
2140 or _no_rule($code,$line);
2142 elsif ($grammar =~ m/(?=$DEFERPATMK)/gco
2143 and do { ($code) = extract_codeblock($grammar,'{',undef,'<');
2147 _parse("a deferred action specifier", $aftererror,$line,$code);
2148 $code =~ s/\A\s*<defer:(.*)>\Z/$1/s;
2149 if ($code =~ /\A\s*[^{]|[^}]\s*\Z/)
2154 $item = new Parse::RecDescent::Directive(
2155 "push \@{\$thisparser->{deferred}}, sub $code;",
2156 $lookahead,$line,"<defer:$code>");
2157 $prod and $prod->additem($item)
2158 or _no_rule("<defer:$code>",$line);
2160 $self->{deferrable} = 1;
2162 elsif ($grammar =~ m/(?=$TOKENPATMK)/gco
2163 and do { ($code) = extract_codeblock($grammar,'{',undef,'<');
2167 _parse("a token constructor", $aftererror,$line,$code);
2168 $code =~ s/\A\s*<token:(.*)>\Z/$1/s;
2170 my $types = eval 'no strict; local $SIG{__WARN__} = sub {0}; my @arr=('.$code.'); @arr' || ();
2173 _error("Incorrect token specification: \"$@\"", $line);
2174 _hint("The <token:...> directive requires a list
2175 of one or more strings representing possible
2176 types of the specified token. For example:
2177 <token:NOUN,VERB>");
2181 $item = new Parse::RecDescent::Directive(
2183 $return = { text => $item[-1] };
2184 @{$return->{type}}{'.$code.'} = (1..'.$types.');',
2185 $lookahead,$line,"<token:$code>");
2186 $prod and $prod->additem($item)
2187 or _no_rule("<token:$code>",$line);
2190 elsif ($grammar =~ m/$COMMITMK/gco)
2192 _parse("an commit marker", $aftererror,$line);
2193 $item = new Parse::RecDescent::Directive('$commit = 1',
2194 $lookahead,$line,"<commit>");
2195 $prod and $prod->additem($item)
2196 or _no_rule("<commit>",$line);
2198 elsif ($grammar =~ m/$AUTOERRORMK/gco)
2201 _parse("an error marker", $aftererror,$line);
2202 $item = new Parse::RecDescent::Error('',$lookahead,$1,$line);
2203 $prod and $prod->additem($item)
2204 or _no_rule("<error>",$line);
2205 $aftererror = !$commitonly;
2207 elsif ($grammar =~ m/(?=$MSGERRORMK)/gco
2208 and do { $commitonly = $1;
2209 ($code) = extract_bracketed($grammar,'<');
2212 _parse("an error marker", $aftererror,$line,$code);
2213 $code =~ /\A\s*<error\??:(.*)>\Z/s;
2214 $item = new Parse::RecDescent::Error($1,$lookahead,$commitonly,$line);
2215 $prod and $prod->additem($item)
2216 or _no_rule("$code",$line);
2217 $aftererror = !$commitonly;
2219 elsif (do { $commitonly = $1;
2220 ($code) = extract_bracketed($grammar,'<');
2223 if ($code =~ /^<[A-Z_]+>$/)
2225 _error("Token items are not yet
2226 supported: \"$code\"",
2228 _hint("Items like $code that consist of angle
2229 brackets enclosing a sequence of
2230 uppercase characters will eventually
2231 be used to specify pre-lexed tokens
2232 in a grammar. That functionality is not
2233 yet implemented. Or did you misspell
2238 _error("Untranslatable item encountered: \"$code\"",
2240 _hint("Did you misspell \"$code\"
2241 or forget to comment it out?");
2245 elsif ($grammar =~ m/$RULE/gco)
2247 _parseunneg("a rule declaration", 0,
2248 $lookahead,$line) or next;
2250 if ($rulename =~ /Replace|Extend|Precompile|Save/ )
2252 _warn(2,"Rule \"$rulename\" hidden by method
2253 Parse::RecDescent::$rulename",$line)
2255 _hint("The rule named \"$rulename\" cannot be directly
2256 called through the Parse::RecDescent object
2257 for this grammar (although it may still
2258 be used as a subrule of other rules).
2259 It can't be directly called because
2260 Parse::RecDescent::$rulename is already defined (it
2261 is the standard method of all
2264 $rule = new Parse::RecDescent::Rule($rulename,$self,$line,$replace);
2265 $prod->check_pending($line) if $prod;
2266 $prod = $rule->addprod( new Parse::RecDescent::Production );
2269 elsif ($grammar =~ m/$UNCOMMITPROD/gco)
2272 _parseunneg("a new (uncommitted) production",
2273 0, $lookahead, $line) or next;
2275 $prod->check_pending($line) if $prod;
2276 $prod = new Parse::RecDescent::Production($line,1);
2277 $rule and $rule->addprod($prod)
2278 or _no_rule("<uncommit>",$line);
2281 elsif ($grammar =~ m/$ERRORPROD/gco)
2284 _parseunneg("a new (error) production", $aftererror,
2285 $lookahead,$line) or next;
2286 $prod->check_pending($line) if $prod;
2287 $prod = new Parse::RecDescent::Production($line,0,1);
2288 $rule and $rule->addprod($prod)
2289 or _no_rule("<error>",$line);
2292 elsif ($grammar =~ m/$PROD/gco)
2294 _parseunneg("a new production", 0,
2295 $lookahead,$line) or next;
2297 and (!$prod || $prod->check_pending($line))
2298 and $prod = $rule->addprod(new Parse::RecDescent::Production($line))
2299 or _no_rule("production",$line);
2302 elsif ($grammar =~ m/$LITERAL/gco)
2304 ($code = $1) =~ s/\\\\/\\/g;
2305 _parse("a literal terminal", $aftererror,$line,$1);
2306 $item = new Parse::RecDescent::Literal($code,$lookahead,$line);
2307 $prod and $prod->additem($item)
2308 or _no_rule("literal terminal",$line,"'$1'");
2310 elsif ($grammar =~ m/$INTERPLIT/gco)
2312 _parse("an interpolated literal terminal", $aftererror,$line);
2313 $item = new Parse::RecDescent::InterpLit($1,$lookahead,$line);
2314 $prod and $prod->additem($item)
2315 or _no_rule("interpolated literal terminal",$line,"'$1'");
2317 elsif ($grammar =~ m/$TOKEN/gco)
2319 _parse("a /../ pattern terminal", $aftererror,$line);
2320 $item = new Parse::RecDescent::Token($1,'/',$3?$3:'',$lookahead,$line);
2321 $prod and $prod->additem($item)
2322 or _no_rule("pattern terminal",$line,"/$1/");
2324 elsif ($grammar =~ m/(?=$MTOKEN)/gco
2325 and do { ($code, undef, @components)
2326 = extract_quotelike($grammar);
2331 _parse("an m/../ pattern terminal", $aftererror,$line,$code);
2332 $item = new Parse::RecDescent::Token(@components[3,2,8],
2334 $prod and $prod->additem($item)
2335 or _no_rule("pattern terminal",$line,$code);
2337 elsif ($grammar =~ m/(?=$MATCHRULE)/gco
2338 and do { ($code) = extract_bracketed($grammar,'<');
2341 or $grammar =~ m/$SUBRULE/gco
2346 if (substr($name,0,1) eq '<')
2348 $name =~ s/$MATCHRULE\s*//;
2349 $name =~ s/\s*>\Z//;
2353 # EXTRACT TRAILING ARG LIST (IF ANY)
2355 my ($argcode) = extract_codeblock($grammar, "[]",'') || '';
2357 # EXTRACT TRAILING REPETITION SPECIFIER (IF ANY)
2359 if ($grammar =~ m/\G[(]/gc)
2363 if ($grammar =~ m/$OPTIONAL/gco)
2365 _parse("an zero-or-one subrule match", $aftererror,$line,"$code$argcode($1)");
2366 $item = new Parse::RecDescent::Repetition($name,$1,0,1,
2371 $prod and $prod->additem($item)
2372 or _no_rule("repetition",$line,"$code$argcode($1)");
2374 !$matchrule and $rule and $rule->addcall($name);
2376 elsif ($grammar =~ m/$ANY/gco)
2378 _parse("a zero-or-more subrule match", $aftererror,$line,"$code$argcode($1)");
2381 my $pos = pos $grammar;
2382 substr($grammar,$pos,0,
2383 "<leftop='$name(s?)': $name $2 $name>(s?) ");
2385 pos $grammar = $pos;
2389 $item = new Parse::RecDescent::Repetition($name,$1,0,$MAXREP,
2394 $prod and $prod->additem($item)
2395 or _no_rule("repetition",$line,"$code$argcode($1)");
2397 !$matchrule and $rule and $rule->addcall($name);
2399 _check_insatiable($name,$1,$grammar,$line) if $::RD_CHECK;
2402 elsif ($grammar =~ m/$MANY/gco)
2404 _parse("a one-or-more subrule match", $aftererror,$line,"$code$argcode($1)");
2408 my $pos = pos $grammar;
2409 substr($grammar,$pos,0,
2410 "<leftop='$name(s)': $name $2 $name> ");
2412 pos $grammar = $pos;
2416 $item = new Parse::RecDescent::Repetition($name,$1,1,$MAXREP,
2422 $prod and $prod->additem($item)
2423 or _no_rule("repetition",$line,"$code$argcode($1)");
2425 !$matchrule and $rule and $rule->addcall($name);
2427 _check_insatiable($name,$1,$grammar,$line) if $::RD_CHECK;
2430 elsif ($grammar =~ m/$EXACTLY/gco)
2432 _parse("an exactly-$1-times subrule match", $aftererror,$line,"$code$argcode($1)");
2435 my $pos = pos $grammar;
2436 substr($grammar,$pos,0,
2437 "<leftop='$name($1)': $name $2 $name>($1) ");
2439 pos $grammar = $pos;
2443 $item = new Parse::RecDescent::Repetition($name,$1,$1,$1,
2448 $prod and $prod->additem($item)
2449 or _no_rule("repetition",$line,"$code$argcode($1)");
2451 !$matchrule and $rule and $rule->addcall($name);
2454 elsif ($grammar =~ m/$BETWEEN/gco)
2456 _parse("a $1-to-$2 subrule match", $aftererror,$line,"$code$argcode($1..$2)");
2459 my $pos = pos $grammar;
2460 substr($grammar,$pos,0,
2461 "<leftop='$name($1..$2)': $name $3 $name>($1..$2) ");
2463 pos $grammar = $pos;
2467 $item = new Parse::RecDescent::Repetition($name,"$1..$2",$1,$2,
2472 $prod and $prod->additem($item)
2473 or _no_rule("repetition",$line,"$code$argcode($1..$2)");
2475 !$matchrule and $rule and $rule->addcall($name);
2478 elsif ($grammar =~ m/$ATLEAST/gco)
2480 _parse("a $1-or-more subrule match", $aftererror,$line,"$code$argcode($1..)");
2483 my $pos = pos $grammar;
2484 substr($grammar,$pos,0,
2485 "<leftop='$name($1..)': $name $2 $name>($1..) ");
2487 pos $grammar = $pos;
2491 $item = new Parse::RecDescent::Repetition($name,"$1..",$1,$MAXREP,
2496 $prod and $prod->additem($item)
2497 or _no_rule("repetition",$line,"$code$argcode($1..)");
2499 !$matchrule and $rule and $rule->addcall($name);
2500 _check_insatiable($name,"$1..",$grammar,$line) if $::RD_CHECK;
2503 elsif ($grammar =~ m/$ATMOST/gco)
2505 _parse("a one-to-$1 subrule match", $aftererror,$line,"$code$argcode(..$1)");
2508 my $pos = pos $grammar;
2509 substr($grammar,$pos,0,
2510 "<leftop='$name(..$1)': $name $2 $name>(..$1) ");
2512 pos $grammar = $pos;
2516 $item = new Parse::RecDescent::Repetition($name,"..$1",1,$1,
2521 $prod and $prod->additem($item)
2522 or _no_rule("repetition",$line,"$code$argcode(..$1)");
2524 !$matchrule and $rule and $rule->addcall($name);
2527 elsif ($grammar =~ m/$BADREP/gco)
2529 _parse("an subrule match with invalid repetition specifier", 0,$line);
2530 _error("Incorrect specification of a repeated subrule",
2532 _hint("Repeated subrules like \"$code$argcode$&\" cannot have
2533 a maximum repetition of zero, nor can they have
2534 negative components in their ranges.");
2539 _parse("a subrule match", $aftererror,$line,$code);
2541 if ($name=~/\A_alternation_\d+_of_production_\d+_of_rule/)
2542 { $desc = $self->{"rules"}{$name}->expected }
2543 $item = new Parse::RecDescent::Subrule($name,
2550 $prod and $prod->additem($item)
2551 or _no_rule("(sub)rule",$line,$name);
2553 !$matchrule and $rule and $rule->addcall($name);
2556 elsif ($grammar =~ m/$LONECOLON/gco )
2558 _error("Unexpected colon encountered", $line);
2559 _hint("Did you mean \"|\" (to start a new production)?
2560 Or perhaps you forgot that the colon
2561 in a rule definition must be
2562 on the same line as the rule name?");
2564 elsif ($grammar =~ m/$ACTION/gco ) # BAD ACTION, ALREADY FAILED
2566 _error("Malformed action encountered",
2568 _hint("Did you forget the closing curly bracket
2569 or is there a syntax error in the action?");
2571 elsif ($grammar =~ m/$OTHER/gco )
2573 _error("Untranslatable item encountered: \"$1\"",
2575 _hint("Did you misspell \"$1\"
2576 or forget to comment it out?");
2579 if ($lookaheadspec =~ tr /././ > 3)
2581 $lookaheadspec =~ s/\A\s+//;
2582 $lookahead = $lookahead<0
2583 ? 'a negative lookahead ("...!")'
2584 : 'a positive lookahead ("...")' ;
2585 _warn(1,"Found two or more lookahead specifiers in a
2588 _hint("Multiple positive and/or negative lookaheads
2589 are simply multiplied together to produce a
2590 single positive or negative lookahead
2591 specification. In this case the sequence
2592 \"$lookaheadspec\" was reduced to $lookahead.
2593 Was this your intention?");
2596 $lookaheadspec = "";
2598 $grammar =~ m/\G\s+/gc;
2601 unless ($ERRORS or $isimplicit or !$::RD_CHECK)
2603 $self->_check_grammar();
2606 unless ($ERRORS or $isimplicit or $Parse::RecDescent::compiling)
2608 my $code = $self->_code();
2609 if (defined $::RD_TRACE)
2611 print STDERR "printing code (", length($code),") to RD_TRACE\n";
2613 open TRACE_FILE, ">RD_TRACE"
2614 and print TRACE_FILE "my \$ERRORS;\n$code"
2615 and close TRACE_FILE;
2618 unless ( eval "$code 1" )
2620 _error("Internal error in generated parser code!");
2621 $@ =~ s/at grammar/in grammar at/;
2626 if ($ERRORS and !_verbosity("HINT"))
2628 local $::RD_HINT = 1;
2629 _hint('Set $::RD_HINT (or -RD_HINT if you\'re using "perl -s")
2630 for hints on fixing these problems.');
2632 if ($ERRORS) { $ERRORS=0; return }
2637 sub _addstartcode($$)
2639 my ($self, $code) = @_;
2640 $code =~ s/\A\s*\{(.*)\}\Z/$1/s;
2642 $self->{"startcode"} .= "$code;\n";
2645 # CHECK FOR GRAMMAR PROBLEMS....
2647 sub _check_insatiable($$$$)
2649 my ($subrule,$repspec,$grammar,$line) = @_;
2650 pos($grammar)=pos($_[2]);
2651 return if $grammar =~ m/$OPTIONAL/gco || $grammar =~ m/$ANY/gco;
2653 if ( $grammar =~ m/$MANY/gco
2654 || $grammar =~ m/$EXACTLY/gco
2655 || $grammar =~ m/$ATMOST/gco
2656 || $grammar =~ m/$BETWEEN/gco && do { $min=$2; 1 }
2657 || $grammar =~ m/$ATLEAST/gco && do { $min=$2; 1 }
2658 || $grammar =~ m/$SUBRULE(?!\s*:)/gco
2661 return unless $1 eq $subrule && $min > 0;
2662 _warn(3,"Subrule sequence \"$subrule($repspec) $&\" will
2663 (almost certainly) fail.",$line)
2665 _hint("Unless subrule \"$subrule\" performs some cunning
2666 lookahead, the repetition \"$subrule($repspec)\" will
2667 insatiably consume as many matches of \"$subrule\" as it
2668 can, leaving none to match the \"$&\" that follows.");
2672 sub _check_grammar ($)
2675 my $rules = $self->{"rules"};
2677 foreach $rule ( values %$rules )
2679 next if ! $rule->{"changed"};
2681 # CHECK FOR UNDEFINED RULES
2684 foreach $call ( @{$rule->{"calls"}} )
2686 if (!defined ${$rules}{$call}
2687 &&!defined &{"Parse::RecDescent::$call"})
2689 if (!defined $::RD_AUTOSTUB)
2691 _warn(3,"Undefined (sub)rule \"$call\"
2692 used in a production.")
2694 _hint("Will you be providing this rule
2695 later, or did you perhaps
2696 misspell \"$call\"? Otherwise
2697 it will be treated as an
2698 immediate <reject>.");
2699 eval "sub $self->{namespace}::$call {undef}";
2703 my $rule = $::RD_AUTOSTUB || qq{'$call'};
2704 _warn(1,"Autogenerating rule: $call")
2706 _hint("A call was made to a subrule
2707 named \"$call\", but no such
2708 rule was specified. However,
2709 since \$::RD_AUTOSTUB
2710 was defined, a rule stub
2712 automatically created.");
2714 $self->_generate("$call : $rule",0,1);
2719 # CHECK FOR LEFT RECURSION
2721 if ($rule->isleftrec($rules))
2723 _error("Rule \"$rule->{name}\" is left-recursive.");
2724 _hint("Redesign the grammar so it's not left-recursive.
2725 That will probably mean you need to re-implement
2726 repetitions using the '(s)' notation.
2727 For example: \"$rule->{name}(s)\".");
2733 # GENERATE ACTUAL PARSER CODE
2739 package $self->{namespace};
2741 use vars qw(\$skip \$AUTOLOAD $self->{localvars} );
2746 local \$SIG{__WARN__} = sub {0};
2747 # PRETEND TO BE IN Parse::RecDescent NAMESPACE
2748 *$self->{namespace}::AUTOLOAD = sub
2751 \$AUTOLOAD =~ s/^$self->{namespace}/Parse::RecDescent/;
2757 $code .= "push \@$self->{namespace}\::ISA, 'Parse::RecDescent';";
2758 $self->{"startcode"} = '';
2761 foreach $rule ( values %{$self->{"rules"}} )
2763 if ($rule->{"changed"})
2765 $code .= $rule->code($self->{"namespace"},$self);
2766 $rule->{"changed"} = 0;
2774 # EXECUTING A PARSE....
2776 sub AUTOLOAD # ($parser, $text; $linenum, @args)
2778 croak "Could not find method: $AUTOLOAD\n" unless ref $_[0];
2779 my $class = ref($_[0]) || $_[0];
2780 my $text = ref($_[1]) ? ${$_[1]} : $_[1];
2781 $_[0]->{lastlinenum} = $_[2]||_linecount($_[1]);
2782 $_[0]->{lastlinenum} = _linecount($_[1]);
2783 $_[0]->{lastlinenum} += $_[2] if @_ > 2;
2784 $_[0]->{offsetlinenum} = $_[0]->{lastlinenum};
2785 $_[0]->{fulltext} = $text;
2786 $_[0]->{fulltextlen} = length $text;
2787 $_[0]->{deferred} = [];
2788 $_[0]->{errors} = [];
2789 my @args = @_[3..$#_];
2790 my $args = sub { [ @args ] };
2792 $AUTOLOAD =~ s/$class/$_[0]->{namespace}/;
2795 croak "Unknown starting rule ($AUTOLOAD) called\n"
2796 unless defined &$AUTOLOAD;
2797 my $retval = &{$AUTOLOAD}($_[0],$text,undef,undef,$args);
2799 if (defined $retval)
2801 foreach ( @{$_[0]->{deferred}} ) { &$_; }
2805 foreach ( @{$_[0]->{errors}} ) { _error(@$_); }
2808 if (ref $_[1]) { ${$_[1]} = $text }
2814 sub _parserepeat($$$$$$$$$$) # RETURNS A REF TO AN ARRAY OF MATCHES
2816 my ($parser, $text, $prod, $min, $max, $_noactions, $expectation, $argcode) = @_;
2820 for ($reps=0; $reps<$max;)
2822 $_[6]->at($text); # $_[6] IS $expectation FROM CALLER
2823 my $_savetext = $text;
2824 my $prevtextlen = length $text;
2826 if (! defined ($_tok = &$prod($parser,$text,1,$_noactions,$argcode)))
2831 push @tokens, $_tok if defined $_tok;
2832 last if ++$reps >= $min and $prevtextlen == length $text;
2835 do { $_[6]->failed(); return undef} if $reps<$min;
2842 # ERROR REPORTING....
2847 open (ERROR, ">&STDERR");
2849 @>>>>>>>>>>>>>>>>>>>>: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2850 $errorprefix, $errortext
2851 ~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
2863 use vars '$tracelevel';
2865 open (TRACE, ">&STDERR");
2867 @>|@|||||||||@^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<|
2868 $tracelevel, $tracerulename, '|', $tracemsg
2869 | ~~ |^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<|
2876 open (TRACECONTEXT, ">&STDERR");
2877 format TRACECONTEXT =
2878 @>|@|||||||||@ |^<<<<<<<<<<<<<<<<<<<<<<<<<<<
2879 $tracelevel, $tracerulename, '|', $tracecontext
2880 | ~~ | |^<<<<<<<<<<<<<<<<<<<<<<<<<<<
2885 select TRACECONTEXT;
2893 or defined $::RD_HINT and $_[0] =~ /ERRORS|WARN|HINT/
2894 or defined $::RD_WARN and $_[0] =~ /ERRORS|WARN/
2895 or defined $::RD_ERRORS and $_[0] =~ /ERRORS/
2901 return 0 if ! _verbosity("ERRORS");
2903 $errorprefix = "ERROR" . ($_[1] ? " (line $_[1])" : "");
2904 $errortext =~ s/\s+/ /g;
2905 print ERROR "\n" if _verbosity("WARN");
2912 return 0 unless _verbosity("WARN") && ($::RD_HINT || $_[0] >= ($::RD_WARN||1));
2914 $errorprefix = "Warning" . ($_[2] ? " (line $_[2])" : "");
2916 $errortext =~ s/\s+/ /g;
2923 return 0 unless defined $::RD_HINT;
2924 $errortext = "$_[0])";
2925 $errorprefix = "(Hint";
2926 $errortext =~ s/\s+/ /g;
2933 if (defined $::RD_TRACE
2934 && $::RD_TRACE =~ /\d+/
2936 && $::RD_TRACE+10<length($_[0]))
2938 my $count = length($_[0]) - $::RD_TRACE;
2939 return substr($_[0],0,$::RD_TRACE/2)
2941 . substr($_[0],-$::RD_TRACE/2);
2951 if (defined $::RD_TRACE
2952 && $::RD_TRACE =~ /\d+/
2954 && $::RD_TRACE+10<length($_[0]))
2956 my $count = length($_[0]) - $::RD_TRACE;
2957 return substr($_[0],0,$::RD_TRACE) . "...<+$count>";
2965 my $lastcontext = '';
2966 my $lastrulename = '';
2972 $tracecontext = $_[1]||$lastcontext;
2973 $tracerulename = $_[2]||$lastrulename;
2974 $tracelevel = $_[3]||$lastlevel;
2975 if ($tracerulename) { $lastrulename = $tracerulename }
2976 if ($tracelevel) { $lastlevel = $tracelevel }
2978 $tracecontext =~ s/\n/\\n/g;
2979 $tracecontext =~ s/\s+/ /g;
2980 $tracerulename = qq{$tracerulename};
2982 if ($tracecontext ne $lastcontext)
2986 $lastcontext = _tracefirst($tracecontext);
2987 $tracecontext = qq{"$tracecontext"};
2991 $tracecontext = qq{<NO TEXT LEFT>};
2997 sub _parseunneg($$$$)
2999 _parse($_[0],$_[1],$_[3]);
3002 _error("Can't negate \"$&\".",$_[3]);
3003 _hint("You can't negate $_[0]. Remove the \"...!\" before
3012 my $what = $_[3] || $&;
3016 _warn(3,"Found $_[0] ($what) after an unconditional <error>",$_[2])
3018 _hint("An unconditional <error> always causes the
3019 production containing it to immediately fail.
3020 \u$_[0] that follows an <error>
3021 will never be reached. Did you mean to use
3022 <error?> instead?");
3025 return if ! _verbosity("TRACE");
3026 $errortext = "Treating \"$what\" as $_[0]";
3027 $errorprefix = "Parse::RecDescent";
3028 $errortext =~ s/\s+/ /g;
3033 scalar substr($_[0], pos $_[0]||0) =~ tr/\n//
3039 use vars qw ( $RD_ERRORS $RD_WARN $RD_HINT $RD_TRACE $RD_CHECK );