File Coverage

blib/lib/Parse/YALALR/Dump.pl
Criterion Covered Total %
statement 16 261 6.1
branch 1 124 0.8
condition 0 57 0.0
subroutine 4 21 19.0
pod 0 18 0.0
total 21 481 4.3


line stmt bran cond sub pod time code
1             # This is really a -*- cperl -*- extension package to Parse::YALALR::Build,
2              
3             package Parse::YALALR::Parser;
4 1     1   6 use strict;
  1         2  
  1         486  
5              
6             sub register_dump {
7 6 50   6 0 46 shift if (ref $_[0]); # Optional object
8 6         9 my ($type, $sub) = @_;
9 6         16 $Parse::YALALR::Parser::dumpsub{$type} = $sub;
10             }
11              
12             sub dump_pseudo {
13 0     0 0   my ($self, $ph) = @_;
14              
15 0           my %h;
16 0           my $r = ref $ph;
17 0           while (my ($field, $slot) = each %{ $ph->[0] }) {
  0            
18 0           $h{$field} = $self->dump($ph->[$slot]);
19             }
20 0           return bless \%h, $r;
21             }
22              
23             sub dump {
24 0     0 0   my ($self, @v) = @_;
25 0 0         return "" if @v == 0;
26              
27 0           my $asXML = $self->{dump_format};
28 0 0         return map { $self->dump($_) } @v if @v > 1;
  0            
29 0           my ($v) = @v;
30              
31 0 0         if (!ref $v) {
32 0 0         return (undef) if !defined $v;
33 0 0         return "" if $v eq "";
34 0 0         if ($v =~ /^\d+$/) {
    0          
35 0           my $v2;
36 0 0         defined ($v2 = $self->dump_sym($v, $asXML)) && return $v2;
37 0 0         defined ($v2 = $self->dump_item($v, $asXML)) && return $v2;
38             } elsif ($v =~ /[^-+.\/\w\s]/) {
39 0           return $self->dump_symvec($v, $asXML);
40             }
41 0           return $v;
42             }
43              
44 0 0         if (defined $Parse::YALALR::Parser::dumpsub{ref $v}) {
45 0           return $Parse::YALALR::Parser::dumpsub{ref $v}->($self, $v, $asXML);
46             }
47              
48 0 0         if (UNIVERSAL::isa($v, 'ARRAY')) {
    0          
49 0 0         if (ref $v ne 'ARRAY') {
50 0           my $r = ref $v;
51 1     1   6 no strict 'refs';
  1         2  
  1         3230  
52 0 0         if (exists ${$r.'::'}{FIELDS}) {
  0            
53 0           return $self->dump_pseudo($r, $asXML);
54             } else {
55 0           return bless [ map { $self->dump($_) } @$v ], $r;
  0            
56             }
57             } else {
58 0           return [ map { $self->dump($_) } @$v ];
  0            
59             }
60             } elsif (UNIVERSAL::isa($v, 'HASH')) {
61 0           my %h;
62 0           while (my ($k, $val) = each %$v) {
63 0 0         $k = $self->dump($k) if ($k =~ /^\d+$/);
64 0 0         $k = $self->dump_symvec($k, $asXML) if ($k =~ /\0/);
65 0           $h{$k} = $self->dump($val);
66             }
67 0 0         if (ref $v ne 'HASH') {
68 0           return bless \%h, ref $v;
69             } else {
70 0           my $ret = \%h;
71             # print "Returning $ret\n";
72 0           return $ret;
73             }
74             } else {
75 0           return $v;
76             }
77             }
78              
79             sub dump_NULLABLE {
80 0     0 0   my ($self) = @_;
81 0           my $nullable = $self->{nullable};
82 0           my $why_nullable = $self->{why_nullable};
83 0           my $nil = $self->{nil};
84 0           my $str = "";
85              
86 0           foreach my $null (keys %$nullable) {
87 0 0         if ($null == $nil) {
    0          
88 0           $str .= $self->dump_sym($null).
89             " is nullable by definition\n";
90             } elsif ($why_nullable->{$null} eq 'is an action') {
91 0           $str .= "is nullable because it is an action\n";
92             } else {
93 0           $str .= $self->dump_sym($null).
94             " is nullable because of rule ".
95             $self->dump_rule($why_nullable->{$null})."\n";
96             }
97             }
98              
99 0           return $str;
100             }
101              
102             sub dump_action {
103 0     0 0   my ($self, $action, $asXML) = @_;
104 0           my $str = "";
105              
106 0 0         if (ref $action eq 'reduce') {
107 0           my ($rule, $lhs, $sz_rhs) = @$action;
108 0           $str = "pop $sz_rhs syms, push ".$self->dump_sym($lhs, $asXML).", rule ";
109 0           $str .= $self->dump_rule($rule, $asXML);
110             } else {
111 0           $str = "shift, goto state $action";
112             }
113              
114 0           return $str;
115             }
116              
117             sub dump_rule {
118 0     0 0   my ($self, $rule, $arrow, $format) = @_;
119 0           my $grammar = $self->{grammar};
120 0           my $nil = $self->{nil};
121              
122 0   0       my $asXML = $format && $format =~ /xml/;
123 0   0       my $brief = $format && $format =~ /brief/;
124              
125 0   0       $arrow ||= '->';
126 0 0         $arrow = $E{$arrow} if $asXML;
127              
128 0           my $prec = $self->{rule_precedence}->[$rule];
129 0           my $precstr = "";
130 0 0         $precstr = "(prec $prec->[0])" if defined $prec;
131              
132 0           my $str = "";
133 0           $str .= $self->dump_sym($grammar->[$rule], $asXML);
134 0           $str .= " $arrow ";
135 0           my $has_rhs = 0;
136 0           while ($grammar->[++$rule] != $nil) {
137 0           $str .= $self->dump_sym($grammar->[$rule], $asXML)." ";
138 0           $has_rhs = 1;
139             }
140 0 0         $str .= "/*empty*/ " if !$has_rhs;
141 0 0         $str .= $precstr unless $brief;
142 0           $str =~ s/\s+$//;
143 0           return $str;
144             }
145              
146             sub dump_lr0item {
147 0     0 0   my ($self, $item, $format) = @_;
148 0   0       $format ||= 0;
149 0   0       my $asXML = ($format =~ /xml/) && 'xml';
150              
151 0           my $grammar = $self->{grammar};
152 0           my $nil = $self->{nil};
153              
154 0           my $rule = $item;
155 0   0       --$rule while $rule && ($grammar->[$rule - 1] != $nil);
156              
157 0           my $str;
158 0 0 0       $str .= "" if ($asXML && $asXML !~ /untagged/);
159 0           $str .= $self->dump_sym($grammar->[$rule], $asXML);
160 0 0         $str .= $asXML ? " &arrow; " : " -> ";
161              
162 0           $rule++;
163 0           while (1) {
164 0 0         $str .= ". " if $rule == $item;
165 0 0         last if $grammar->[$rule] == $nil;
166 0           $str .= $self->dump_sym($grammar->[$rule], $asXML)." ";
167 0           $rule++;
168             }
169              
170 0 0 0       $str .= "" if ($asXML && $asXML !~ /untagged/);
171              
172 0           return $str;
173             }
174              
175             sub dump_lr1item {
176 0     0 0   my ($self, $item, $format) = @_;
177 0   0       $format ||= 0;
178 0   0       my $asXML = ($format =~ /xml/) && 'xml';
179 0           my $str;
180 0 0         $str .= "{GRAMIDX}>" if $asXML;
181 0 0         $str .= $self->dump_lr0item($item->{GRAMIDX}, $asXML ? "untaggedxml" : 0);
182              
183 0 0         if ($format !~ /brief/) {
184 0           $str .= ", ";
185 0 0         $str .= "" if $asXML;
186 0           $str .= $self->dump_symvec($item->{LA}, $asXML);
187 0 0         $str .= "" if $asXML;
188             }
189              
190 0 0         $str .= "" if $asXML;
191              
192 0           return $str;
193             }
194              
195             sub dump_item {
196 0 0 0 0 0   if (ref $_[1] && ref $_[1] eq 'item') {
197 0           &dump_lr1item;
198             } else {
199 0           &dump_lr0item;
200             }
201             }
202              
203             sub dump_xitem {
204 0     0 0   my Parse::YALALR::Parser $self = shift;
205 0           my ($xitem, $format) = @_;
206              
207 0   0       my $asXML = (defined $format && $format =~ /xml/);
208 0           my $str =
209             "XITEM($xitem->{item}) = ".$self->dump_item($xitem->{item}, $asXML);
210              
211 0 0 0       if ($format && ($format eq 'very' || $format eq 'brief')) {
      0        
212 0 0         return $str if ($format eq 'very');
213 0           return $str.", ".join(" ", map { $self->dump_sym($_, $asXML) }
  0            
214 0           grep { ! /^item|parent0$/ }
215             (keys %$xitem));
216             }
217              
218             # ARGH! Avoid colliding with the iterator for %$xitem (shared with
219             # the enclosed dump_xitem with the brief flag set)
220 0 0         my $brief_format = $asXML ? 'briefxml' : 'brief';
221 0           foreach my $t (keys %$xitem) {
222 0 0         next if $t eq 'item';
223 0 0         next if $t eq 'parent0';
224 0           my $cause = $xitem->{$t};
225 0           $str .= "\n ".$self->dump_sym($t, $asXML)." : ";
226 0 0         if ($cause->[0] eq 'kernel') {
227 0           $str .= "(kernel item)";
228             } else {
229 0           $str .= $cause->[0]." ";
230 0 0         $str .= ($cause->[0] eq 'generated') ? 'by ' : 'from ';
231 0           $str .= $self->dump_xitem($cause->[1], $brief_format);
232             }
233             }
234              
235 0           return $str;
236             }
237              
238             sub dump_expansion {
239 0     0 0   my Parse::YALALR::Parser $self = shift;
240 0           my ($xitems, $format) = @_;
241              
242 0           my $str = '';
243 0           foreach (values %$xitems) {
244 0           $str .= $self->dump_xitem($_, $format)."\n";
245             }
246 0           chomp($str);
247 0           return $str;
248             }
249              
250             sub dump_xstate {
251 0     0 0   my Parse::YALALR::Parser $self = shift;
252 0           my ($kernel, $xstate, $format) = @_;
253 0 0 0       my $asXML = ($format && $format =~ /xml/) ? 'xml' : undef;
254              
255 0           my $str;
256              
257             my @kernel;
258 0           my @generated;
259            
260 0           foreach (values %$xstate) {
261 0 0         (defined $_->{parent0}) ? push(@generated, $_) : push(@kernel, $_);
262             }
263              
264             # Do something vaguely like a topological sort
265 0           my %parental_intuition;
266 0           foreach (@generated) {
267 0   0       $parental_intuition{$_->{parent0}->{item}} +=
268             ($parental_intuition{$_->{item}} || 1);
269             }
270 0           foreach (@generated) {
271 0   0       $parental_intuition{$_->{parent0}->{item}} +=
272             ($parental_intuition{$_->{item}} || 1);
273             }
274 0   0       @generated = sort { ($parental_intuition{$b->{item}} || 0) <=>
  0   0        
275             ($parental_intuition{$a->{item}} || 0) } @generated;
276              
277 0           my $grammar = $self->{grammar};
278 0           my $nil = $self->{nil};
279              
280 0 0         $str .= "{id}>" if $asXML;
281 0           $str .= "State $kernel->{id}";
282 0 0         $str .= "" if $asXML;
283 0           $str .= ": ".(0+@kernel)." kernel items, ";
284 0           $str .= (@kernel + @generated)." total:\n";
285              
286 0           my $inkernel = 1;
287 0           foreach my $xitem (@kernel, "---", @generated) {
288 0 0         if (!ref $xitem) {
289 0           $str .= ("-" x 20);
290 0           $inkernel = 0;
291             } else {
292 0           my $idx = $xitem->{item};
293 0           $str .= $self->dump_item($idx, $asXML);
294 0           $str .= ",";
295              
296 0           foreach (keys %$xitem) {
297 0 0         next if $_ eq 'item';
298 0 0         next if $_ eq 'parent0';
299 0           $str .= " ";
300              
301 0 0 0       $str .= "{id} item=$idx>"
302             if $asXML && $inkernel;
303 0           $str .= $self->dump_sym($_, $asXML);
304 0 0 0       $str .= "" if $asXML && $inkernel;
305             }
306              
307 0           my $rule = $idx;
308 0   0       $rule-- while ($rule && $grammar->[$rule] != $nil);
309 0 0         $rule++ if $rule;
310              
311 0 0         if (defined (my $prec = $self->{rule_precedence}->[$rule])) {
312 0           $str .= " ";
313 0 0         $str .= "[0] assoc=$prec->[1]>"
314             if $asXML;
315 0           $str .= "\%$prec->[1] $prec->[0]";
316 0 0         $str .= "" if $asXML;
317             }
318             }
319              
320 0           $str .= "\n";
321             }
322              
323 0           return $str;
324             }
325              
326             # Weird calling convention
327             # In scalar context: args are self, symbol, asxml flag
328             # In list context: args are self, symbol list (no asxml flag available)
329             sub dump_sym {
330 0     0 0   my Parse::YALALR::Parser $self = shift;
331 0 0         if (wantarray) {
332 0           my (@syms) = @_;
333 0           return map { $self->{symmap}->get_value($_) } @syms;
  0            
334             } else {
335 0           my ($sym, $asXML) = @_;
336 0           my $symname = $self->{symmap}->get_value($sym);
337 0 0         return $asXML ? "$E{$symname}" : $symname;
338             }
339             }
340              
341             sub dump_symvec {
342 0     0 0   my ($self, $vec, $asXML) = @_;
343 0           my @syms = $self->{symmap}->get_indices($vec);
344 0           return "VEC(".join("|", map("".$self->dump_sym($_, $asXML), @syms)).")";
345             }
346              
347             sub dump_FIRST {
348 0     0 0   my ($self, $nt) = @_;
349 0           return "FIRST(".$self->dump_sym($nt).") = ".
350             join(" ", $self->{symmap}->get_values($self->{FIRST}->{$nt}));
351             }
352              
353             sub dump_FIRSTs {
354 0     0 0   my Parse::YALALR::Parser $self = shift;
355 0           my $str = "";
356              
357 0           foreach my $nt (@{$self->{nonterminals}}) {
  0            
358 0           $str .= $self->dump_FIRST($nt)."\n";
359             }
360              
361 0           return $str;
362             }
363              
364             sub dump_kernel {
365 0     0 0   my Parse::YALALR::Parser $self = shift;
366 0           my ($K, $asXML) = @_;
367 0           my $n = @{$K->{items}};
  0            
368 0           my $id = $K->{id};
369 0           my $str;
370              
371 0 0         $str .= "" if $asXML;
372 0           $str .= "State $id";
373 0 0         $str .= "" if $asXML;
374 0           $str .= ": $n $P{'item', $n}\n";
375              
376 0           $str .= " ".$self->dump_item($_, $asXML)."\n"
377 0           foreach @{$K->{items}};
378 0           chomp($str);
379              
380 0 0         $str .= "" if $asXML;
381 0           return $str;
382             }
383              
384             sub dump_parser {
385 0     0 0   my Parse::YALALR::Parser $self = shift;
386 0           my $str = "";
387 0           my $symmap = $self->{symmap};
388              
389 0           my $i;
390 0           for my $i (0..$#{$self->{states}}) {
  0            
391 0           my $state = $self->{states}->[$i];
392 0           $str .= $self->dump_kernel($state)."\n";
393 0           $str .= "Actions:\n";
394              
395 0           while (my ($sym, $kernel) = each %{$state->{shifts}}) {
  0            
396 0           $str .= "shift ".$self->dump_sym($sym).", go to state $kernel\n";
397             }
398              
399 0           foreach (@{$state->{reduces}}) {
  0            
400 0           my ($la, $rule, $item) = @$_;
401 0           $str .= "reduce by ".$self->dump_rule($rule)." on la ".$self->dump_symvec($la)."\n";
402             }
403              
404 0           $str .= "\n";
405             }
406              
407 0           return $str;
408             }
409              
410             BEGIN {
411 1     1   4 register_dump('item', \&dump_lr1item);
412 1         3 register_dump('Parse::YALALR::Kernel', \&dump_kernel);
413 1         2 register_dump('shift', \&dump_action);
414 1         2 register_dump('reduce', \&dump_action);
415 1         3 register_dump('xitem', \&dump_xitem);
416 1         4 register_dump('xreason', \&dump_xreason);
417 1         25 *dump_state = \&dump_kernel;
418             }
419              
420             1;