File Coverage

blib/lib/Parse/Eyapp/Grammar.pm
Criterion Covered Total %
statement 241 352 68.4
branch 72 132 54.5
condition 14 31 45.1
subroutine 26 34 76.4
pod 0 24 0.0
total 353 573 61.6


line stmt bran cond sub pod time code
1             #
2             # Module Parse::Eyapp::Grammar
3             #
4             # Copyright © 2006, 2007, 2008, 2009, 2010, 2011, 2012 Casiano Rodriguez-Leon.
5             # Copyright © 2017 William N. Braswell, Jr.
6             # All Rights Reserved.
7             #
8             # Parse::Yapp is Copyright © 1998, 1999, 2000, 2001, Francois Desarmenien.
9             # Parse::Yapp is Copyright © 2017 William N. Braswell, Jr.
10             # All Rights Reserved.
11             package Parse::Eyapp::Grammar;
12             @ISA=qw( Parse::Eyapp::Options );
13              
14             require 5.004;
15              
16 61     61   364 use Carp;
  61         127  
  61         2952  
17 61     61   868 use strict;
  61         136  
  61         1405  
18 61     61   19154 use Parse::Eyapp::Options;
  61         164  
  61         1585  
19 61     61   33206 use Parse::Eyapp::Parse;
  61         213  
  61         2699  
20 61     61   424 use Scalar::Util qw{reftype};
  61         127  
  61         3246  
21 61     61   367 use Data::Dumper;
  61         117  
  61         195647  
22              
23             ###############
24             # Constructor #
25             ###############
26             sub new {
27 54     54 0 149 my($class)=shift;
28 54         117 my($values);
29              
30 54         492 my($self)=$class->SUPER::new(@_);
31              
32 54         426 my($parser)=new Parse::Eyapp::Parse;
33              
34 54 50       459 defined($self->Option('input'))
35             or croak "No input grammar";
36              
37 54         217 $values = $parser->Parse($self->Option('input'), # 1 input
38             $self->Option('firstline'), # 2 Line where the grammar source starts
39             $self->Option('inputfile'), # 3 The file or program containing the grammar
40             $self->Option('tree'), # 4 %tree activated
41             $self->Option('nocompact'), # 5 %nocompact
42             $self->Option('lexerisdefined'), # 6 lexer is defined
43             $self->Option('prefix'), # 7 accept prefix
44             $self->Option('start'), # 8 specify start symbol
45             #$self->Option('prefixname'), # yyprefix
46             #$self->Option('buildingtree') # If building AST
47             );
48              
49 54         18883 undef($parser);
50              
51 54         423 $$self{GRAMMAR}=_ReduceGrammar($values);
52              
53 54 50       207 ref($class)
54             and $class=ref($class);
55              
56 54         159 bless($self, $class);
57              
58 54         155 my $ns = $self->{GRAMMAR}{NAMINGSCHEME} ;
59 54 50 33     251 if ($ns && reftype($ns) eq 'ARRAY') {
60 0         0 $ns = eval "sub { $ns->[0]; }; ";
61 0 0       0 warn "Error in \%namingscheme directive $@" if $@;
62 0         0 $ns = $ns->($self);
63             }
64 54   50     459 $ns ||= \&give_default_name;
65 54         116 $self->{GRAMMAR}{NAMINGSCHEME} = $ns; # added to allow programmable production naming schemes (%name)
66              
67 54         568 $self;
68             }
69              
70             ###########
71             # Methods #
72             ###########
73             ##########################
74             # Method To View Grammar #
75             ##########################
76             sub ShowRules {
77 0     0 0 0 my($self)=shift;
78 0         0 my($rules)=$$self{GRAMMAR}{RULES};
79 0         0 my($ruleno)=-1;
80 0         0 my($text);
81              
82 0         0 for (@$rules) {
83 0         0 my($lhs,$rhs)=@$_;
84              
85 0         0 $text.=++$ruleno.":\t".$lhs." -> ";
86 0 0       0 if(@$rhs) {
87 0 0       0 $text.=join(' ',map { $_ eq chr(0) ? '$end' : $_ } @$rhs);
  0         0  
88             }
89             else {
90 0         0 $text.="/* empty */";
91             }
92 0         0 $text.="\n";
93             }
94 0         0 $text;
95             }
96              
97             sub give_default_name {
98 376     376 0 717 my ($self, $index, $lhs) = @_;
99              
100 376         787 my $name = "$lhs"."_$index";
101 376         720 return $name;
102             }
103              
104             sub give_lhs_name {
105 0     0 0 0 my ($self, $index, $lhs, $rhs) = @_;
106              
107 0         0 my $name = $lhs;
108 0         0 return $name;
109             }
110              
111             sub give_token_name {
112 0     0 0 0 my ($self, $index, $lhs, $rhs) = @_;
113              
114 0         0 my @rhs = @$rhs;
115 0         0 $rhs = '';
116              
117 0 0       0 unless (@rhs) { # Empty RHS
118 0         0 return $lhs.'_is_empty';
119             }
120              
121 0   0     0 my $names = $self->{GRAMMAR}{TOKENNAMES} || {};
122 0         0 for (@rhs) {
123 0 0       0 if ($self->is_token($_)) {
124 0         0 s/^'(.*)'$/$1/;
125 0   0     0 my $name = $names->{$_} || '';
126 0 0       0 unless ($name) {
127 0 0       0 $name = $_ if /^\w+$/;
128             }
129 0 0       0 $rhs .= "_$name" if $name;
130             }
131             }
132              
133 0 0       0 unless ($rhs) { # no 'word' tokens in the RHS
134 0         0 for (@rhs) {
135 0 0       0 $rhs .= "_$_" if /^\w+$/;
136             }
137             }
138              
139             # check if another production with such name exists?
140 0         0 my $name = $lhs.'_is'.$rhs;
141 0         0 return $name;
142             }
143              
144             sub camelize
145             {
146 0     0 0 0 my $s = shift;
147              
148 0         0 my @a = split(/(?<=[A-Za-z])_(?=[A-Za-z])|\b/, $s);
149 0         0 my $a = shift @a;
150 0         0 @a = map { ucfirst $_ } @a;
  0         0  
151 0         0 join('', ($a, @a));
152             }
153              
154             sub give_rhs_name {
155 0     0 0 0 my ($self, $index, $lhs, $rhs) = @_;
156              
157 0         0 my @rhs = @$rhs;
158 0         0 $rhs = '';
159              
160 0 0       0 unless (@rhs) { # Empty RHS
161 0         0 return camelize($lhs).'_is_empty';
162             }
163              
164 0   0     0 my $names = $self->{GRAMMAR}{TOKENNAMES} || {};
165 0         0 for (@rhs) {
166 0 0       0 if ($self->is_token($_)) {
167             # remove apostrophes
168 0         0 s/^'(.*)'$/$1/;
169              
170             # explicit name given ?
171 0   0     0 my $name = $names->{$_} || '';
172              
173             # no name was given, use symbol if is an ID
174 0 0       0 unless ($name) {
175 0 0       0 $name = $_ if /^\w+$/;
176             }
177 0 0       0 $rhs .= "_$name" if $name;
178             }
179             else { # syntactic variable
180 0 0       0 next if exists $self->{GRAMMAR}{CONFLICTHANDLERS}{$_};
181 0 0       0 $rhs .= '_'.camelize($_) if /^\w*$/;
182             }
183             }
184              
185             # check if another production with such name exists?
186 0         0 my $name = camelize($lhs).'_is'.$rhs;
187 0         0 return $name;
188             }
189              
190             sub classname {
191 1382     1382 0 2523 my ($self, $name, $index, $lhs, $rhs) = @_;
192              
193 1382         2247 $name = $name->[0];
194              
195 1382 100       3050 unless (defined($name)) {
196 556 100       2818 if ($lhs =~ /\$start/) {
    100          
    100          
    100          
    100          
    50          
197 108         237 $name = "_SUPERSTART"
198             }
199             elsif ($lhs =~ /\@(\d+)-(\d+)/) {
200 16         35 $name = "_CODE"
201             }
202             elsif ($lhs =~ /PAREN-(\d+)/) {
203 16         34 $name = "_PAREN"
204             }
205             elsif ($lhs =~ /STAR-(\d+)/) {
206 16         32 $name = "_STAR_LIST"
207             }
208             elsif ($lhs =~ /PLUS-(\d+)/) {
209 24         49 $name = "_PLUS_LIST"
210             }
211             elsif ($lhs =~ /OPTIONAL-(\d+)/) {
212 0         0 $name = "_OPTIONAL"
213             }
214             }
215              
216 1382         2263 my $naming_scheme = $self->{GRAMMAR}{NAMINGSCHEME};
217 1382 100       3638 if (!$name) {
    50          
218 376         799 $name = $naming_scheme->($self, $index, $lhs, $rhs);
219             }
220             elsif ($name =~ /^:/) { # it is a label only
221 0         0 $name = $naming_scheme->($self, $index, $lhs, $rhs).$name;
222             }
223              
224 1382         2593 return $name;
225             }
226              
227             # Added by Casiano
228             #####################################
229             # Method To Return the Grammar Rules#
230             #####################################
231             sub Rules { # TODO: find proper names
232 54     54 0 157 my($self)=shift;
233 54         159 my($rules)=$$self{GRAMMAR}{RULES};
234 54         132 my($text) = "[#[productionNameAndLabel => lhs, [ rhs], bypass]]\n";
235 54         118 my $packages = q{'TERMINAL', '_OPTIONAL', '_STAR_LIST', '_PLUS_LIST', };
236              
237 54         114 my $index = 0;
238 54         122 my $label = "{\n"; # To huild a reverse map label => production number
239 54         186 for (@$rules) {
240 691         1472 my($lhs,$rhs,$prec,$name)=@$_;
241              
242 691         1175 my $bypass = $name->[2];
243 691 100       1989 $bypass = $self->Bypass unless defined($bypass);
244              
245 691 50 66     2594 $label .= " '$1' => $index,\n" if defined($name->[0]) and $name->[0] =~ /(:.*)/;
246              
247             # find an acceptable perl identifier as name
248 691         1392 $name = $self->classname($name, $index, $lhs, $rhs);
249 691         1613 $label .= " '$name' => $index,\n";
250              
251 691         1419 $packages .= "\n".(" "x9)."'$name', ";
252              
253 691         1364 $text.= " [ '$name' => '$lhs', [ ";
254 691 100       1335 $text.=join(', ',map { $_ eq chr(0) ? "'\$end'" : $_ =~ m{^'} ? $_ : "'$_'" } @$rhs);
  1483 100       4888  
255 691         1360 $text.=" ], $bypass ],\n";
256 691         1226 $index++;
257             }
258 54         137 $text .= ']';
259 54         123 $label .= '}';
260 54         243 return ($text, $packages, $label);
261             }
262              
263             # Added by Casiano
264             #####################################
265             # Method To Return the Grammar Terms#
266             #####################################
267             sub Terms {
268 54     54 0 143 my($self)=shift;
269 54         122 my(@terms)= sort(keys(%{$$self{GRAMMAR}{TERM}}));
  54         502  
270 54         148 my %semantic = %{$self->{GRAMMAR}{SEMANTIC}};
  54         540  
271              
272 54         172 my $text = "{ ";
273             $text .= join(",\n\t",
274             # Warning! bug. Before: map { $_ eq chr(0) ? "'\$end' => 0" : "$_ => $semantic{$_}"} @terms);
275 54 100       161 map { $_ eq chr(0) ? "'' => { ISSEMANTIC => 0 }" : "$_ => { ISSEMANTIC => $semantic{$_} }"} @terms);
  570         1751  
276 54         357 $text .= ",\n\terror => { ISSEMANTIC => 0 },\n}";
277             }
278              
279             sub conflictHandlers {
280 54     54 0 139 my $self = shift;
281              
282 54         364 my $t = Dumper $self->{GRAMMAR}{CONFLICTHANDLERS};
283 54         4801 $t =~ s/^\$VAR\d*\s*=\s*//;
284 54         217 $t =~s/;$//;
285 54         157 $t =~s/\\'//g; # quotes inside quotes
286 54         194 $t;
287             }
288              
289              
290             # produces the text mapping states to conflicthandlers
291             sub stateConflict {
292 54     54 0 139 my $self = shift;
293              
294 54         149 my $c = $self->{GRAMMAR}{CONFLICTHANDLERS};
295 54         112 my %stateConflict;
296              
297 54         156 my %t = ();
298 54         196 for my $cn (keys %$c) {
299 0         0 my $ce = $c->{$cn};
300 0         0 my $codeh = $ce->{codeh};
301 0         0 $codeh = "sub { $codeh }";
302 0 0       0 my @s = defined($ce->{states}) ? @{$ce->{states}} : ();
  0         0  
303 0         0 for my $s (@s) {
304 0         0 my ($sn) = keys %$s;
305             #my ($tokens) = values %$s;
306             #$tokens = join ',', @$tokens;
307 0 0       0 $t{$sn} = '' unless defined($t{$sn});
308 0         0 $t{$sn} .= << "NEWSTATECONFLICTENTRY";
309             {
310             name => '$cn',
311             codeh => $codeh,
312             },
313             NEWSTATECONFLICTENTRY
314             } #for states
315             } #for conflict names
316            
317 54         137 my $t = '{ ';
318 54         149 for my $s (keys %t) {
319 0         0 $t .= "$s => [ $t{$s} ],";
320             }
321 54         229 $t .= ' }';
322             }
323              
324             #####################################
325             # Method To Return the Bypass Option#
326             #####################################
327             sub Bypass {
328 388     388 0 648 my($self)=shift;
329            
330             return $$self{GRAMMAR}{BYPASS}
331 388         752 }
332              
333             #####################################
334             # Method To Return the Prefix Option#
335             #####################################
336             sub Prefix {
337 54     54 0 141 my($self)=shift;
338            
339             return $$self{GRAMMAR}{PREFIX}
340 54         234 }
341              
342              
343             sub Buildingtree {
344 54     54 0 147 my($self)=shift;
345            
346             return $$self{GRAMMAR}{BUILDINGTREE}
347 54         175 }
348              
349             sub Prompt {
350 54     54 0 139 my $self = shift;
351              
352 54 50       236 return "our \$PROMPT = $$self{GRAMMAR}{INCREMENTAL};\n" if defined($$self{GRAMMAR}{INCREMENTAL});
353 54         158 return '';
354             }
355              
356             sub is_token {
357 0     0 0 0 my($self)=shift;
358              
359 0         0 exists($self->{GRAMMAR}{TERM}{$_[0]})
360             }
361              
362             #####################################
363             # Method To Return the ACCESSORS
364             #####################################
365             sub Accessors {
366 54     54 0 136 my($self)=shift;
367            
368             return $$self{GRAMMAR}{ACCESSORS}
369 54         179 }
370              
371             ###########################
372             # Method To View Warnings #
373             ###########################
374             sub Warnings {
375 4     4 0 12 my($self)=shift;
376              
377 4 50       16 return '' if $self->Option('start');
378              
379 4         11 my($text) = '';
380 4         13 my($grammar)=$$self{GRAMMAR};
381              
382             exists($$grammar{UUTERM})
383 4 50       18 and do {
384 0         0 $text="Unused terminals:\n\n";
385 0         0 for (@{$$grammar{UUTERM}}) {
  0         0  
386 0         0 $text.="\t$$_[0], declared line $$_[1]\n";
387             }
388 0         0 $text.="\n";
389             };
390             exists($$grammar{UUNTERM})
391 4 50       17 and do {
392 0         0 $text.="Useless non-terminals:\n\n";
393 0         0 for (@{$$grammar{UUNTERM}}) {
  0         0  
394 0         0 $text.="\t$$_[0], declared line $$_[1]\n";
395             }
396 0         0 $text.="\n";
397             };
398             exists($$grammar{UURULES})
399 4 50       16 and do {
400 0         0 $text.="Useless rules:\n\n";
401 0         0 for (@{$$grammar{UURULES}}) {
  0         0  
402 0         0 $text.="\t$$_[0] -> ".join(' ',@{$$_[1]})."\n";
  0         0  
403             }
404 0         0 $text.="\n";
405             };
406 4         12 $text;
407             }
408              
409             ######################################
410             # Method to get summary about parser #
411             ######################################
412             sub Summary {
413 0     0 0 0 my($self)=shift;
414 0         0 my($text);
415              
416             $text ="Number of rules : ".
417 0         0 scalar(@{$$self{GRAMMAR}{RULES}})."\n";
  0         0  
418             $text.="Number of terminals : ".
419 0         0 scalar(keys(%{$$self{GRAMMAR}{TERM}}))."\n";
  0         0  
420             $text.="Number of non-terminals : ".
421 0         0 scalar(keys(%{$$self{GRAMMAR}{NTERM}}))."\n";
  0         0  
422 0         0 $text;
423             }
424              
425             ###############################
426             # Method to Ouput rules table #
427             ###############################
428             sub RulesTable {
429 54     54 0 172 my($self)=shift;
430 54         208 my($inputfile)=$self->Option('inputfile');
431 54         222 my($linenums)=$self->Option('linenumbers');
432 54         153 my($rules)=$$self{GRAMMAR}{RULES};
433 54         118 my $ruleno = 0;
434 54         114 my($text);
435              
436 54 50       191 defined($inputfile)
437             or $inputfile = 'unknown';
438              
439 54         121 $text="[\n\t";
440              
441             $text.=join(",\n\t",
442             map {
443 54         168 my($lhs,$rhs,$rname,$code)=@$_[0,1,3,4];
  691         1624  
444 691         1085 my($len)=scalar(@$rhs);
445              
446 691         954 my($text);
447              
448 691         1553 $rname = $self->classname($rname, $ruleno, $lhs, $rhs);
449              
450 691         1028 $ruleno++;
451 691         1619 $text.="[#Rule $rname\n\t\t '$lhs', $len,";
452 691 100       1304 if($code) {
453 635 100       2150 $text.= "\nsub {".
454             ( $linenums
455             ? qq(\n#line $$code[1] "$inputfile"\n)
456             : " ").
457             "$$code[0]}";
458             }
459             else {
460 56         134 $text.=' undef';
461             }
462 691         1305 $text.="\n$Parse::Eyapp::Output::pattern\n\t]";
463              
464 691         1825 $text;
465             } @$rules);
466              
467 54         211 $text.="\n]";
468              
469 54         249 $text;
470             }
471              
472             ################################
473             # Methods to get HEAD and TAIL #
474             ################################
475             sub Head {
476 54     54 0 149 my($self)=shift;
477 54         208 my($inputfile)=$self->Option('inputfile');
478 54         281 my($linenums)=$self->Option('linenumbers');
479 54         127 my($text);
480              
481 54 100       308 $$self{GRAMMAR}{HEAD}[0]
482             or return '';
483              
484 34 50       181 defined($inputfile)
485             or $inputfile = 'unkown';
486              
487 34         73 for (@{$$self{GRAMMAR}{HEAD}}) {
  34         125  
488 34 50       239 $linenums
489             and $text.=qq(#line $$_[1] "$inputfile"\n);
490 34         131 $text.=$$_[0];
491             }
492             $text
493 34         110 }
494              
495             sub Tail {
496 54     54 0 162 my($self)=shift;
497 54         272 my($inputfile)=$self->Option('inputfile');
498 54         209 my($linenums)=$self->Option('linenumbers');
499 54         125 my($text);
500              
501             ((reftype $$self{GRAMMAR}{TAIL} eq 'ARRAY') and
502 54 50 33     920 $$self{GRAMMAR}{TAIL}[0])
503             or return '';
504              
505 54 50       217 defined($inputfile)
506             or $inputfile = 'unkown';
507              
508 54 100       346 $linenums
509             and $text=qq(#line $$self{GRAMMAR}{TAIL}[1] "$inputfile"\n);
510 54         270 $text.=$$self{GRAMMAR}{TAIL}[0];
511              
512 54         197 $text
513             }
514              
515              
516             #################
517             # Private Stuff #
518             #################
519              
520             sub _UsefulRules {
521 54     54   155 my($rules,$nterm) = @_;
522 54         181 my($ufrules,$ufnterm);
523 54         0 my($done);
524              
525 54         328 $ufrules=pack('b'.@$rules);
526 54         133 $ufnterm={};
527              
528 54         277 vec($ufrules,0,1)=1; #start rules IS always useful
529              
530             RULE:
531 54         238 for (1..$#$rules) { # Ignore start rule
532 637         897 for my $sym (@{$$rules[$_][1]}) {
  637         1159  
533 803 100       1958 exists($$nterm{$sym})
534             and next RULE;
535             }
536 155         341 vec($ufrules,$_,1)=1;
537 155         427 ++$$ufnterm{$$rules[$_][0]};
538             }
539              
540 54         131 do {
541 114         219 $done=1;
542              
543             RULE:
544 114         296 for (grep { vec($ufrules,$_,1) == 0 } 1..$#$rules) {
  1757         3130  
545 632         916 for my $sym (@{$$rules[$_][1]}) {
  632         1097  
546             exists($$nterm{$sym})
547 1432 100 100     4703 and not exists($$ufnterm{$sym})
548             and next RULE;
549             }
550 482         992 vec($ufrules,$_,1)=1;
551             exists($$ufnterm{$$rules[$_][0]})
552 482 100       1465 or do {
553 109         187 $done=0;
554 109         260 ++$$ufnterm{$$rules[$_][0]};
555             };
556             }
557              
558             }until($done);
559              
560 54         208 ($ufrules,$ufnterm)
561              
562             }#_UsefulRules
563              
564             sub _Reachable {
565 54     54   186 my($rules,$nterm,$term,$ufrules,$ufnterm)=@_;
566 54         121 my($reachable);
567 54         149 my(@fifo)=( 0 );
568              
569 54         170 $reachable={ '$start' => 1 }; #$start is always reachable
570              
571 54         196 while(@fifo) {
572 683         1074 my($ruleno)=shift(@fifo);
573              
574 683         925 for my $sym (@{$$rules[$ruleno][1]}) {
  683         1227  
575              
576             exists($$term{$sym})
577 1483 100       3024 and do {
578 604         1018 ++$$reachable{$sym};
579 604         1077 next;
580             };
581              
582             ( not exists($$ufnterm{$sym})
583 879 100 100     3496 or exists($$reachable{$sym}) )
584             and next;
585              
586 223         436 ++$$reachable{$sym};
587 223         329 push(@fifo, grep { vec($ufrules,$_,1) } @{$$nterm{$sym}});
  629         1176  
  223         456  
588             }
589             }
590              
591             $reachable
592              
593 54         164 }#_Reachable
594              
595             sub _SetNullable {
596 54     54   163 my($rules,$term,$nullable) = @_;
597 54         224 my(@nrules);
598             my($done);
599              
600             RULE:
601 54         172 for (@$rules) {
602 691         1179 my($lhs,$rhs)=@$_;
603              
604 691 100       1438 exists($$nullable{$lhs})
605             and next;
606              
607 659         1058 for (@$rhs) {
608 976 100       2192 exists($$term{$_})
609             and next RULE;
610             }
611 128         338 push(@nrules,[$lhs,$rhs]);
612             }
613              
614 54         124 do {
615 59         118 $done=1;
616              
617             RULE:
618 59         161 for (@nrules) {
619 184         350 my($lhs,$rhs)=@$_;
620              
621 184 100       499 exists($$nullable{$lhs})
622             and next;
623              
624 172         305 for (@$rhs) {
625 165 100       599 exists($$nullable{$_})
626             or next RULE;
627             }
628 12         23 $done=0;
629 12         29 ++$$nullable{$lhs};
630             }
631              
632             }until($done);
633             }
634              
635             sub _ReduceGrammar {
636 54     54   183 my($values)=@_;
637 54         140 my($ufrules,$ufnterm,$reachable);
638              
639             my($grammar)= bless {
640             HEAD => $values->{HEAD},
641             TAIL => $values->{TAIL},
642             EXPECT => $values->{EXPECT},
643             # Casiano modifications
644             SEMANTIC => $values->{SEMANTIC}, # added to simplify AST
645             BYPASS => $values->{BYPASS}, # added to simplify AST
646             BUILDINGTREE => $values->{BUILDINGTREE}, # influences the semantic of lists * + ?
647             ACCESSORS => $values->{ACCESSORS}, # getter-setter for %tree and %metatree
648             PREFIX => $values->{PREFIX}, # yyprefix
649             NAMINGSCHEME => $values->{NAMINGSCHEME}, # added to allow programmable production naming schemes (%name)
650             NOCOMPACT => $values->{NOCOMPACT}, # Do not compact action tables. No DEFAULT field for "STATES"
651             CONFLICTHANDLERS => $values->{CONFLICTHANDLERS}, # list of conflict handlers
652             TERMDEF => $values->{TERMDEF}, # token => associated regular expression (for lexical analyzer)
653             WHITES => $values->{WHITES}, # string with the code to skip whites (for lexical analyzer)
654             LEXERISDEFINED => $values->{LEXERISDEFINED}, # true if %lexer was used
655             INCREMENTAL => $values->{INCREMENTAL}, # true if '%incremental lexer' was used
656             MODULINO => $values->{MODULINO}, # hash perlpath => path, prompt => question
657             STRICT => $values->{STRICT}, # true if %stric
658             DUMMY => $values->{DUMMY}, # array ref
659 54         773 TOKENNAMES => {}, # for naming schemes
660             }, __PACKAGE__;
661              
662 54         219 my($rules,$nterm,$term) = @$values {'RULES', 'NTERM', 'TERM'};
663              
664 54         316 ($ufrules,$ufnterm) = _UsefulRules($rules,$nterm);
665              
666             exists($$ufnterm{$values->{START}})
667 54 50       317 or die "*Fatal* Start symbol $values->{START} derives nothing, at eof\n";
668              
669 54         318 $reachable = _Reachable($rules,$nterm,$term,$ufrules,$ufnterm);
670              
671 54         461 $$grammar{TERM}{chr(0)}=undef;
672 54         249 for my $sym (keys %$term) {
673             ( exists($$reachable{$sym})
674             or exists($values->{PREC}{$sym}) )
675 516 50 66     1397 and do {
676             $$grammar{TERM}{$sym}
677 516 100       1187 = defined($$term{$sym}[0]) ? $$term{$sym} : undef;
678 516         800 next;
679             };
680 0         0 push(@{$$grammar{UUTERM}},[ $sym, $values->{SYMS}{$sym} ]);
  0         0  
681             }
682              
683 54         184 $$grammar{NTERM}{'$start'}=[];
684 54         207 for my $sym (keys %$nterm) {
685             exists($$reachable{$sym})
686 223 50       566 and do {
687             exists($values->{NULL}{$sym})
688 223 100       567 and ++$$grammar{NULLABLE}{$sym};
689 223         412 $$grammar{NTERM}{$sym}=[];
690 223         425 next;
691             };
692 0         0 push(@{$$grammar{UUNTERM}},[ $sym, $values->{SYMS}{$sym} ]);
  0         0  
693             }
694              
695 54         210 for my $ruleno (0..$#$rules) {
696             vec($ufrules,$ruleno,1)
697             and exists($$grammar{NTERM}{$$rules[$ruleno][0]})
698 691 50 33     2630 and do {
699 691         1243 push(@{$$grammar{RULES}},$$rules[$ruleno]);
  691         1188  
700 691         981 push(@{$$grammar{NTERM}{$$rules[$ruleno][0]}},$#{$$grammar{RULES}});
  691         1111  
  691         1098  
701 691         1177 next;
702             };
703 0         0 push(@{$$grammar{UURULES}},[ @{$$rules[$ruleno]}[0,1] ]);
  0         0  
  0         0  
704             }
705              
706 54         310 _SetNullable(@$grammar{'RULES', 'TERM', 'NULLABLE'});
707              
708 54         256 $grammar;
709             }#_ReduceGrammar
710              
711             sub tokennames {
712 0     0 0   my $self = shift;
713              
714 0           my $grammar = $self->{GRAMMAR};
715 0 0         $grammar->{TOKENNAMES} = { (%{$grammar->{TOKENNAMES}}, @_) } if (@_);
  0            
716             $grammar->{TOKENNAMES}
717 0           }
718              
719             1;
720