File Coverage

blib/lib/Parse/Yapp/Driver.pm
Criterion Covered Total %
statement 209 255 81.9
branch 108 156 69.2
condition 18 36 50.0
subroutine 16 24 66.6
pod 0 14 0.0
total 351 485 72.3


line stmt bran cond sub pod time code
1             #
2             # Module Parse::Yapp::Driver
3             #
4             # This module is part of the Parse::Yapp package available on your
5             # nearest CPAN
6             #
7             # Any use of this module in a standalone parser make the included
8             # text under the same copyright as the Parse::Yapp module itself.
9             #
10             # This notice should remain unchanged.
11             #
12             # Copyright © 1998, 1999, 2000, 2001, Francois Desarmenien.
13             # Copyright © 2017 William N. Braswell, Jr.
14             # (see the pod text in Parse::Yapp module for use and distribution rights)
15             #
16              
17             package Parse::Yapp::Driver;
18              
19             require 5.004;
20              
21 3     3   17 use strict;
  3         4  
  3         79  
22              
23 3     3   16 use vars qw ( $VERSION $COMPATIBLE $FILENAME );
  3         5  
  3         152  
24              
25             $VERSION = '1.06';
26             $COMPATIBLE = '0.07';
27             $FILENAME=__FILE__;
28              
29 3     3   12 use Carp;
  3         6  
  3         2194  
30              
31             #Known parameters, all starting with YY (leading YY will be discarded)
32             my(%params)=(YYLEX => 'CODE', 'YYERROR' => 'CODE', YYVERSION => '',
33             YYRULES => 'ARRAY', YYSTATES => 'ARRAY', YYDEBUG => '');
34             #Mandatory parameters
35             my(@params)=('LEX','RULES','STATES');
36              
37             sub new {
38 19     19 0 4365 my($class)=shift;
39 19         43 my($errst,$nberr,$token,$value,$check,$dotpos);
40 19         114 my($self)={ ERROR => \&_Error,
41             ERRST => \$errst,
42             NBERR => \$nberr,
43             TOKEN => \$token,
44             VALUE => \$value,
45             DOTPOS => \$dotpos,
46             STACK => [],
47             DEBUG => 0,
48             CHECK => \$check };
49              
50 19         85 _CheckParams( [], \%params, \@_, $self );
51              
52             exists($$self{VERSION})
53 19 50 33     143 and $$self{VERSION} < $COMPATIBLE
54             and croak "Yapp driver version $VERSION ".
55             "incompatible with version $$self{VERSION}:\n".
56             "Please recompile parser module.";
57              
58 19 50       49 ref($class)
59             and $class=ref($class);
60              
61 19         66 bless($self,$class);
62             }
63              
64             sub YYParse {
65 22     22 0 119 my($self)=shift;
66 22         39 my($retval);
67              
68 22         65 _CheckParams( \@params, \%params, \@_, $self );
69              
70 22 100       58 if($$self{DEBUG}) {
71 1         4 _DBLoad();
72 1         63 $retval = eval '$self->_DBParse()';#Do not create stab entry on compile
73 1 50       5 $@ and die $@;
74             }
75             else {
76 21         67 $retval = $self->_Parse();
77             }
78 22         63 $retval
79             }
80              
81             sub YYData {
82 489     489 0 1534 my($self)=shift;
83              
84             exists($$self{USER})
85 489 100       862 or $$self{USER}={};
86              
87 489         950 $$self{USER};
88            
89             }
90              
91             sub YYErrok {
92 3     3 0 14 my($self)=shift;
93              
94 3         6 ${$$self{ERRST}}=0;
  3         9  
95 3         23 undef;
96             }
97              
98             sub YYNberr {
99 1     1 0 12 my($self)=shift;
100              
101 1         2 ${$$self{NBERR}};
  1         3  
102             }
103              
104             sub YYRecovering {
105 0     0 0 0 my($self)=shift;
106              
107 0         0 ${$$self{ERRST}} != 0;
  0         0  
108             }
109              
110             sub YYAbort {
111 0     0 0 0 my($self)=shift;
112              
113 0         0 ${$$self{CHECK}}='ABORT';
  0         0  
114 0         0 undef;
115             }
116              
117             sub YYAccept {
118 22     22 0 40 my($self)=shift;
119              
120 22         36 ${$$self{CHECK}}='ACCEPT';
  22         48  
121 22         55 undef;
122             }
123              
124             sub YYError {
125 0     0 0 0 my($self)=shift;
126              
127 0         0 ${$$self{CHECK}}='ERROR';
  0         0  
128 0         0 undef;
129             }
130              
131             sub YYSemval {
132 6     6 0 20 my($self)=shift;
133 6         7 my($index)= $_[0] - ${$$self{DOTPOS}} - 1;
  6         12  
134              
135             $index < 0
136 6         29 and -$index <= @{$$self{STACK}}
137 6 50 33     16 and return $$self{STACK}[$index][1];
138              
139 0         0 undef; #Invalid index
140             }
141              
142             sub YYCurtok {
143 0     0 0 0 my($self)=shift;
144              
145             @_
146 0 0       0 and ${$$self{TOKEN}}=$_[0];
  0         0  
147 0         0 ${$$self{TOKEN}};
  0         0  
148             }
149              
150             sub YYCurval {
151 0     0 0 0 my($self)=shift;
152              
153             @_
154 0 0       0 and ${$$self{VALUE}}=$_[0];
  0         0  
155 0         0 ${$$self{VALUE}};
  0         0  
156             }
157              
158             sub YYExpect {
159 0     0 0 0 my($self)=shift;
160              
161 0         0 keys %{$self->{STATES}[$self->{STACK}[-1][0]]{ACTIONS}}
  0         0  
162             }
163              
164             sub YYLexer {
165 0     0 0 0 my($self)=shift;
166              
167 0         0 $$self{LEX};
168             }
169              
170              
171             #################
172             # Private stuff #
173             #################
174              
175              
176             sub _CheckParams {
177 41     41   85 my($mandatory,$checklist,$inarray,$outhash)=@_;
178 41         63 my($prm,$value);
179 41         77 my($prmlst)={};
180              
181 41         151 while(($prm,$value)=splice(@$inarray,0,2)) {
182 101         171 $prm=uc($prm);
183 101 50       272 exists($$checklist{$prm})
184             or croak("Unknow parameter '$prm'");
185 101 50       252 ref($value) eq $$checklist{$prm}
186             or croak("Invalid value for parameter '$prm'");
187 101         263 $prm=unpack('@2A*',$prm);
188 101         341 $$outhash{$prm}=$value;
189             }
190 41         107 for (@$mandatory) {
191 66 50       204 exists($$outhash{$_})
192             or croak("Missing mandatory parameter '".lc($_)."'");
193             }
194             }
195              
196             sub _Error {
197 0     0   0 print "Parse error.\n";
198             }
199              
200             sub _DBLoad {
201             {
202 3     3   21 no strict 'refs';
  3     1   4  
  3         1984  
  1         2  
203              
204 1         8 exists(${__PACKAGE__.'::'}{_DBParse})#Already loaded ?
205 1 50       2 and return;
206             }
207 1         2 my($fname)=__FILE__;
208 1         2 my(@drv);
209 1 50       71 open(DRV,"<$fname") or die "Report this as a BUG: Cannot open $fname";
210 1         53 while() {
211             /^\s*sub\s+_Parse\s*{\s*$/ .. /^\s*}\s*#\s*_Parse\s*$/
212 472 100       1099 and do {
213 243         392 s/^#DBG>//;
214 243         610 push(@drv,$_);
215             }
216             }
217 1         26 close(DRV);
218              
219 1         6 $drv[0]=~s/_P/_DBP/;
220 1 100 66 1   965 eval join('',@drv);
  1 50 33 32   3  
  1 50 33     4  
  1 50 66     3  
  1 100 66     3  
  1 100 66     2  
  1 100 66     5  
  32 50 33     55  
  32 100       79  
  55 50       221  
  32 50       80  
  1 100       2  
  1 100       2  
  1 100       2  
  1 100       4  
  1 100       2  
  1 0       2  
  59 50       95  
  59 100       91  
  59 100       90  
  59 100       91  
  59 50       137  
  59 100       142  
  296 0       527  
  59 50       136  
  41 50       118  
  30 50       65  
  30 100       752  
  41 50       115  
  18 0       29  
  18 100       41  
  59 50       127  
  56 50       113  
  28 100       70  
  28 0       64  
  1 50       2  
  1 50       9  
  0 100       0  
  0 50       0  
  28 0       62  
  28 50       66  
  28 50       48  
  28         40  
  28         43  
  28         59  
  28         132  
  28         62  
  28         45  
  28         84  
  0         0  
  0         0  
  28         91  
  55         123  
  28         84  
  28         321  
  28         70  
  1         5  
  1         13  
  27         55  
  0         0  
  0         0  
  27         76  
  27         59  
  27         76  
  27         111  
  1         3  
  1         2  
  27         67  
  27         44  
  27         53  
  0         0  
  0         0  
  3         9  
  1         3  
  1         4  
  1         5  
  1         4  
  1         3  
  1         2  
  1         2  
  3         7  
  2         6  
  0         0  
  0         0  
  2         11  
  2         4  
  3         5  
  3         27  
  3         11  
  3         23  
  3         8  
  0         0  
  0         0  
  3         11  
  3         9  
  0            
221             }
222              
223             #Note that for loading debugging version of the driver,
224             #this file will be parsed from 'sub _Parse' up to '}#_Parse' inclusive.
225             #So, DO NOT remove comment at end of sub !!!
226             sub _Parse {
227 21     21   37 my($self)=shift;
228              
229             my($rules,$states,$lex,$error)
230 21         58 = @$self{ 'RULES', 'STATES', 'LEX', 'ERROR' };
231             my($errstatus,$nberror,$token,$value,$stack,$check,$dotpos)
232 21         83 = @$self{ 'ERRST', 'NBERR', 'TOKEN', 'VALUE', 'STACK', 'CHECK', 'DOTPOS' };
233              
234             #DBG> my($debug)=$$self{DEBUG};
235             #DBG> my($dbgerror)=0;
236              
237             #DBG> my($ShowCurToken) = sub {
238             #DBG> my($tok)='>';
239             #DBG> for (split('',$$token)) {
240             #DBG> $tok.= (ord($_) < 32 or ord($_) > 126)
241             #DBG> ? sprintf('<%02X>',ord($_))
242             #DBG> : $_;
243             #DBG> }
244             #DBG> $tok.='<';
245             #DBG> };
246              
247 21         59 $$errstatus=0;
248 21         31 $$nberror=0;
249 21         42 ($$token,$$value)=(undef,undef);
250 21         68 @$stack=( [ 0, undef ] );
251 21         45 $$check='';
252              
253 21         33 while(1) {
254 16339         24553 my($actions,$act,$stateno);
255              
256 16339         23708 $stateno=$$stack[-1][0];
257 16339         22747 $actions=$$states[$stateno];
258              
259             #DBG> print STDERR ('-' x 40),"\n";
260             #DBG> $debug & 0x2
261             #DBG> and print STDERR "In state $stateno:\n";
262             #DBG> $debug & 0x08
263             #DBG> and print STDERR "Stack:[".
264             #DBG> join(',',map { $$_[0] } @$stack).
265             #DBG> "]\n";
266              
267              
268 16339 100       29609 if (exists($$actions{ACTIONS})) {
269              
270             defined($$token)
271 6037 100       12402 or do {
272 4183         8602 ($$token,$$value)=&$lex($self);
273             #DBG> $debug & 0x01
274             #DBG> and print STDERR "Need token. Got ".&$ShowCurToken."\n";
275             };
276              
277             $act= exists($$actions{ACTIONS}{$$token})
278             ? $$actions{ACTIONS}{$$token}
279             : exists($$actions{DEFAULT})
280             ? $$actions{DEFAULT}
281 6037 100       16907 : undef;
    100          
282             }
283             else {
284 10302         14905 $act=$$actions{DEFAULT};
285             #DBG> $debug & 0x01
286             #DBG> and print STDERR "Don't need token.\n";
287             }
288              
289             defined($act)
290 16339 100       32341 and do {
291              
292             $act > 0
293 16324 100       32082 and do { #shift
294              
295             #DBG> $debug & 0x04
296             #DBG> and print STDERR "Shift and go to state $act.\n";
297              
298             $$errstatus
299 4171 100       8202 and do {
300 3         5 --$$errstatus;
301              
302             #DBG> $debug & 0x10
303             #DBG> and $dbgerror
304             #DBG> and $$errstatus == 0
305             #DBG> and do {
306             #DBG> print STDERR "**End of Error recovery.\n";
307             #DBG> $dbgerror=0;
308             #DBG> };
309             };
310              
311              
312 4171         8079 push(@$stack,[ $act, $$value ]);
313              
314 4171 100       9580 $$token ne '' #Don't eat the eof
315             and $$token=$$value=undef;
316 4171         6676 next;
317             };
318              
319             #reduce
320 12153         17561 my($lhs,$len,$code,@sempar,$semval);
321 12153         16446 ($lhs,$len,$code)=@{$$rules[-$act]};
  12153         22986  
322              
323             #DBG> $debug & 0x04
324             #DBG> and $act
325             #DBG> and print STDERR "Reduce using rule ".-$act." ($lhs,$len): ";
326              
327 12153 100       24462 $act
328             or $self->YYAccept();
329              
330 12153         17618 $$dotpos=$len;
331              
332             unpack('A1',$lhs) eq '@' #In line rule
333 12153 100       33985 and do {
334 3 50       14 $lhs =~ /^\@[0-9]+\-([0-9]+)$/
335             or die "In line rule name '$lhs' ill formed: ".
336             "report it as a BUG.\n";
337 3         6 $$dotpos = $1;
338             };
339              
340             @sempar = $$dotpos
341 12153 100       30279 ? map { $$_[1] } @$stack[ -$$dotpos .. -1 ]
  16311         33409  
342             : ();
343              
344 12153 100       31266 $semval = $code ? &$code( $self, @sempar )
    100          
345             : @sempar ? $sempar[0] : undef;
346              
347 12153         20879 splice(@$stack,-$len,$len);
348              
349             $$check eq 'ACCEPT'
350 12153 100       27146 and do {
351              
352             #DBG> $debug & 0x04
353             #DBG> and print STDERR "Accept.\n";
354              
355 21         64 return($semval);
356             };
357              
358             $$check eq 'ABORT'
359 12132 50       24377 and do {
360              
361             #DBG> $debug & 0x04
362             #DBG> and print STDERR "Abort.\n";
363              
364 0         0 return(undef);
365              
366             };
367              
368             #DBG> $debug & 0x04
369             #DBG> and print STDERR "Back to state $$stack[-1][0], then ";
370              
371             $$check eq 'ERROR'
372 12132 50       24590 or do {
373             #DBG> $debug & 0x04
374             #DBG> and print STDERR
375             #DBG> "go to state $$states[$$stack[-1][0]]{GOTOS}{$lhs}.\n";
376              
377             #DBG> $debug & 0x10
378             #DBG> and $dbgerror
379             #DBG> and $$errstatus == 0
380             #DBG> and do {
381             #DBG> print STDERR "**End of Error recovery.\n";
382             #DBG> $dbgerror=0;
383             #DBG> };
384              
385             push(@$stack,
386 12132         27234 [ $$states[$$stack[-1][0]]{GOTOS}{$lhs}, $semval ]);
387 12132         19535 $$check='';
388 12132         22253 next;
389             };
390              
391             #DBG> $debug & 0x04
392             #DBG> and print STDERR "Forced Error recovery.\n";
393              
394 0         0 $$check='';
395              
396             };
397              
398             #Error
399             $$errstatus
400 15 100       33 or do {
401              
402 3         6 $$errstatus = 1;
403 3         10 &$error($self);
404 3 50       11 $$errstatus # if 0, then YYErrok has been called
405             or next; # so continue parsing
406              
407             #DBG> $debug & 0x10
408             #DBG> and do {
409             #DBG> print STDERR "**Entering Error recovery.\n";
410             #DBG> ++$dbgerror;
411             #DBG> };
412              
413 3         6 ++$$nberror;
414              
415             };
416              
417             $$errstatus == 3 #The next token is not valid: discard it
418 15 100       35 and do {
419             $$token eq '' # End of input: no hope
420 12 50       27 and do {
421             #DBG> $debug & 0x10
422             #DBG> and print STDERR "**At eof: aborting.\n";
423 0         0 return(undef);
424             };
425              
426             #DBG> $debug & 0x10
427             #DBG> and print STDERR "**Dicard invalid token ".&$ShowCurToken.".\n";
428              
429 12         20 $$token=$$value=undef;
430             };
431              
432 15         20 $$errstatus=3;
433              
434 15   66     93 while( @$stack
      33        
435             and ( not exists($$states[$$stack[-1][0]]{ACTIONS})
436             or not exists($$states[$$stack[-1][0]]{ACTIONS}{error})
437             or $$states[$$stack[-1][0]]{ACTIONS}{error} <= 0)) {
438              
439             #DBG> $debug & 0x10
440             #DBG> and print STDERR "**Pop state $$stack[-1][0].\n";
441              
442 16         118 pop(@$stack);
443             }
444              
445             @$stack
446 15 50       37 or do {
447              
448             #DBG> $debug & 0x10
449             #DBG> and print STDERR "**No state left on stack: aborting.\n";
450              
451 0         0 return(undef);
452             };
453              
454             #shift the error token
455              
456             #DBG> $debug & 0x10
457             #DBG> and print STDERR "**Shift \$error token and go to state ".
458             #DBG> $$states[$$stack[-1][0]]{ACTIONS}{error}.
459             #DBG> ".\n";
460              
461 15         35 push(@$stack, [ $$states[$$stack[-1][0]]{ACTIONS}{error}, undef ]);
462              
463             }
464              
465             #never reached
466 0         0 croak("Error in driver logic. Please, report it as a BUG");
467              
468             }#_Parse
469             #DO NOT remove comment
470              
471             1;
472