File Coverage

blib/lib/Parse/Stallion.pm
Criterion Covered Total %
statement 1058 1137 93.0
branch 447 520 85.9
condition 272 348 78.1
subroutine 66 77 85.7
pod 12 59 20.3
total 1855 2141 86.6


line stmt bran cond sub pod time code
1             #Copyright 2007-10 Arthur S Goldstein
2              
3             package Parse::Stallion::Talon;
4 32     32   833999 use Carp;
  32         83  
  32         4867  
5 32     32   202 use strict;
  32         68  
  32         1065  
6 32     32   262 use warnings;
  32         69  
  32         1017  
7 32     32   935 use 5.006;
  32         111  
  32         12061  
8              
9             sub stringify {
10 1423     1423   4093 my $self = shift;
11 1423         1660 my $parameters = shift;
12 1423   100     6209 my $values = $parameters->{values} || ['steps','name','parse_match'];
13 1423   100     3441 my $spaces = $parameters->{spaces} || '';
14 1423         1586 my $value_separator = '|';
15 1423 50       2977 if (defined $parameters->{value_separator}) {
16 0         0 $value_separator = $parameters->{value_separator};
17             }
18 1423         1829 my $line = $spaces;
19              
20 1423         2003 foreach my $value (@$values) {
21 4239 100       7160 if (defined $self->{$value}) {
22 3123         6306 $line .= $self->{$value}.$value_separator;
23             }
24             else {
25 1116         2398 $line .= $value_separator;
26             }
27             }
28              
29 1423         1931 $line .= "\n";
30 1423         1761 foreach my $child (@{$self->{children}}) {
  1423         3209  
31 1298         2118 $parameters->{spaces} = $spaces.' ';
32 1298         2360 $line .= stringify($child,$parameters);
33             }
34              
35 1423         5518 return $line;
36             }
37              
38             package Parse::Stallion::Parser;
39 32     32   188 use Carp;
  32         61  
  32         2819  
40 32     32   188 use strict;
  32         52  
  32         1135  
41 32     32   362 use warnings;
  32         51  
  32         120944  
42              
43             sub new {
44 424     424   628 my $type = shift;
45 424   33     1879 my $class = ref($type) || $type;
46 424         711 my $parameters = shift;
47 424         2416 my $parsing_info = {parse_stallion => $parameters};
48 424         1835 return bless $parsing_info, $class;
49             }
50              
51              
52             sub parse_leaf {
53 25     25   32 my $parsing_info = shift;
54 25         30 my $parameters = shift;
55 25         29 my $start_rule_name = shift;
56 25         34 my $parse_stallion = $parsing_info->{parse_stallion};
57 25         32 my $parse_hash = $parameters->{parse_hash};
58 25         54 my $parse_this_ref = $parse_hash->{parse_this_ref} =
59             $parameters->{parse_this_ref};
60 25         75 my $parse_this_length = $parse_hash->{__parse_this_length};
61 25         30 my $must_parse_length = $parse_hash->{__match_length};
62 25         29 my $do_evaluation_in_parsing = $parse_stallion->{do_evaluation_in_parsing};
63 25         45 my $start_node = $parse_stallion->{rule}->{$start_rule_name};
64 25         34 my $initial_position = $parse_hash->{__initial_position};
65              
66 25         27 my $tree;
67             my @bottom_up_left_to_right;
68 0         0 my $current_position;
69 0         0 my $continue_forward;
70 0         0 my $match;
71 0         0 my $delta_position;
72              
73 25 50       77 if (my $pf = $start_node->{parse_forward}) {
    50          
74 0         0 $current_position = $parse_hash->{current_position} = $initial_position;
75 0         0 $parse_hash->{rule_name} = $start_rule_name;
76 0         0 ($continue_forward, $match, $delta_position) = &{$pf}($parse_hash);
  0         0  
77 0 0       0 if (defined $delta_position) {
78 0 0       0 if ($delta_position < 0) {
79 0         0 croak ("Parse forward on $start_rule_name resulted in
80             backward progress ($initial_position, $delta_position)");
81             }
82             else {
83 0         0 $current_position += $delta_position;
84             }
85             }
86             }
87             elsif (my $x = $start_node->{regex_match}) {
88 25         64 pos $$parse_this_ref = $initial_position;
89 25 100       160 if ($$parse_this_ref =~ m/$x/cg) {
90 22 100       57 if (defined $2) {$match = $2;}
  18         35  
  4         12  
91             else {$match = $1;}
92 22         21 $continue_forward = 1;
93 22         30 $current_position = pos $$parse_this_ref;
94             }
95             else {
96 3         6 $continue_forward = 0;
97             }
98             }
99             else {
100 0         0 croak ("Cannot handle leaf $start_rule_name");
101             }
102 25 100       58 if ($continue_forward) {
103 22         158 $tree = {
104             name => $start_rule_name,
105             alias => $start_node->{alias},
106             steps => 1,
107             parent => undef,
108             position_when_entered => $initial_position,
109             __nodes_when_entered => 0,
110             position_when_completed => $current_position,
111             parse_match => $match,
112             child_count => 0
113             };
114 22 50       60 if ($do_evaluation_in_parsing) {
115 0         0 $parameters->{nodes} = [$tree];
116 0         0 $parse_hash->{current_position} = $current_position;
117 0 0       0 if ($parse_stallion->new_evaluate_tree_node($parameters)) {
118 0         0 $continue_forward = 0; #rejection
119             }
120             }
121 22 100 100     105 if (($parse_this_length != $current_position) && $must_parse_length) {
122 1         3 $continue_forward = 0;
123             }
124             }
125 25         54 my $tree_size;
126 25 100       46 if ($continue_forward) {
127 21         34 push @bottom_up_left_to_right, $tree;
128 21         25 $tree_size = 1;
129             }
130             else {
131 4         8 $tree = undef;
132 4         9 $tree_size = 0;
133             }
134              
135 25         32 my $results = $parameters->{parse_info};
136 25         38 $results->{start_rule} = $start_rule_name;
137 25         37 $results->{number_of_steps} = 1;
138 25         34 $results->{final_position} = $current_position;
139 25         30 $results->{final_position_rule} = $start_rule_name;
140 25         29 $results->{parse_backtrack_value} = undef;
141 25         31 $results->{maximum_position} = $current_position;
142 25         32 $results->{maximum_position_rule} = $start_rule_name;
143 25         47 $results->{parse_succeeded} = $continue_forward;
144 25         41 $results->{tree} = $tree;
145 25         26 $results->{tree_size} = $tree_size;
146 25         39 $results->{bottom_up_left_to_right} = \@bottom_up_left_to_right;
147 25 50       60 if ($do_evaluation_in_parsing) {
148 0         0 $results->{parsing_evaluation} = $tree->{computed_value};
149             }
150 25         91 return $results;
151             }
152              
153             sub parse {
154 704     704   917 my $parsing_info = shift;
155 704         1336 my $parse_stallion = $parsing_info->{parse_stallion};
156 704         849 my $parameters = shift;
157 704         1257 my $rule = $parse_stallion->{rule};
158 704         951 my $start_rule;
159 704 50       1823 if (defined $parameters->{start_rule}) {
160 0 0       0 if (!defined $rule->{$parameters->{start_rule}}) {
161 0         0 croak ("Unknown start rule ".$parameters->{start_rule});
162             }
163 0         0 $start_rule = $parameters->{start_rule};
164             }
165             else {
166 704         1429 $start_rule = $parse_stallion->{start_rule};
167             }
168 704 100       4372 if ($rule->{$start_rule}->{leaf_rule}) {
169 25         87 return $parsing_info->parse_leaf($parameters, $start_rule);
170             }
171 679   66     3148 my $parse_trace_routine = $parameters->{parse_trace_routine}
172             || $parse_stallion->{parse_trace_routine};
173 679         1084 my $parse_hash = $parameters->{parse_hash};
174 679         1451 my $parse_this_ref = $parse_hash->{parse_this_ref} =
175             $parameters->{parse_this_ref};
176 679         1135 my $parse_this_length = $parse_hash->{__parse_this_length};
177 679   66     4222 my $max_steps = $parameters->{max_steps} || $parse_stallion->{max_steps};
178 679         934 my $no_max_steps = 0;
179 679 50       1755 if ($max_steps < 0) {
180 0         0 $no_max_steps = 1;
181 0         0 $max_steps = 1000000;
182             }
183 679         833 my $bottom_up_left_to_right;
184 679         781 my $move_back_mode = 0;
185 679         832 my $not_move_back_mode = 1;
186              
187 679         1678 my $first_alias =
188             'b'.$parse_stallion->{separator}.$parse_stallion->{separator};
189              
190 679         1066 my $current_position = $parse_hash->{__initial_position};
191 679         947 my $results = $parameters->{parse_info};
192 679         914 my $maximum_position = $current_position;
193 679         1068 my $maximum_position_rule = $start_rule;
194              
195 679         1602 my $must_parse_length = $parse_hash->{__match_length};
196 679         1178 my $any_minimize_children = $parse_stallion->{any_minimize_children};
197 679         1080 my $not_any_minimize_children = !$any_minimize_children;
198 679         1452 my $any_maximum_child = $parse_stallion->{any_maximum_child};
199 679         1924 my $not_any_maximum_child = !$any_maximum_child;
200 679         1149 my $any_minimum_child = $parse_stallion->{any_minimum_child};
201 679         1143 my $not_any_minimum_child = !$any_minimum_child;
202 679         954 my $any_match_once = $parse_stallion->{any_match_once};
203 679         871 my $any_parse_forward = $parse_stallion->{any_parse_forward};
204 679         865 my $any_parse_backtrack = $parse_stallion->{any_parse_backtrack};
205 679         969 my $fast_move_back = $parse_stallion->{fast_move_back};
206 679         1091 my $delta_tree_size = $parse_stallion->{max_nodes_before_size_must_change};
207 679         863 my $do_evaluation_in_parsing = $parse_stallion->{do_evaluation_in_parsing};
208 679         701 my $bottom_up;
209 679 100 66     4380 if ($do_evaluation_in_parsing || $parse_stallion->{no_evaluation}) {
210 75         116 $bottom_up = 0;
211             }
212             else {
213 604         856 $bottom_up = 1;
214             }
215              
216              
217 679         852 my ($tree,
218             $current_node,
219             $moving_forward,
220             $moving_down,
221             $steps,
222             $message,
223             $new_rule_name,
224             $new_alias,
225             $position_tree_size,
226             $node_completed,
227             $create_child,
228             $move_back_to_child,
229             $remove_node,
230             $new_rule,
231             $new_sub_rule,
232             $continue_forward,
233             $match,
234             $previous_position,
235             $current_node_name,
236             $current_rule,
237             $end_parse_now,
238             $tree_size);
239              
240 679 100       1442 if (defined $parse_hash->{__steps_ref}) {
241 274         382 $steps = ${$parse_hash->{__steps_ref}};
  274         490  
242             }
243             else {
244 405         587 $steps = 0;
245             }
246              
247 679         3470 my $continue_parse = $parameters->{continue_parse};
248 679 100       1452 if ($continue_parse) {
249 87         106 $tree = $parse_hash->{__tree};
250 87         145 $current_node = $parse_hash->{__current_node};
251 87         86 $moving_forward = ${$parse_hash->{__moving_forward_ref}};
  87         130  
252 87         92 $moving_down = ${$parse_hash->{__moving_down_ref}};
  87         122  
253 87         90 $current_position = ${$parse_hash->{__current_position_ref}};
  87         123  
254 87         96 $message = ${$parse_hash->{__message_ref}};
  87         202  
255 87         109 $position_tree_size = $parse_hash->{__position_tree_size};
256 87         87 $continue_forward = ${$parse_hash->{__continue_forward_ref}};
  87         132  
257 87         89 $tree_size = ${$parse_hash->{__tree_size_ref}};
  87         137  
258 87         229 $bottom_up_left_to_right = $parse_hash->{__bottom_up_left_to_right};
259             }
260             else {
261 592         6366 $tree = {
262             name => $start_rule,
263             steps => $steps,
264             alias => $first_alias,
265             position_when_entered => $current_position,
266             __nodes_when_entered => 0,
267             parent => undef,
268             children => [],
269             child_count => 0
270             };
271 592         1825 bless($tree, 'Parse::Stallion::Talon');
272 592         1126 $parse_hash->{__tree} = $tree;
273            
274 592         997 $bottom_up_left_to_right = [];
275 592         869 $current_node = $tree;
276 592         1103 $moving_forward = 1;
277 592         859 $moving_down = 1;
278 592         771 $message = 'Start of Parse';
279 592         974 $continue_forward = 1;
280 592         817 $tree_size = 1;
281 592         2481 $position_tree_size = {};
282 592         1184 $parse_hash->{__position_tree_size} = $position_tree_size;
283             }
284 679         935 $node_completed = 0;
285 679         750 $create_child = 0;
286 679         777 $move_back_to_child = 0;
287 679         794 $remove_node = 0;
288 679         1355 $current_node_name = $current_node->{name};
289 679         1044 $current_rule = $rule->{$current_node_name};
290              
291 679         1598 $parse_hash->{__current_node_ref} = \$current_node;
292 679         1165 $parse_hash->{__current_node} = $current_node;
293 679         2500 $parse_hash->{__current_node_name_ref} = \$current_node_name;
294 679         1251 $parse_hash->{__moving_forward_ref} = \$moving_forward;
295 679         1735 $parse_hash->{__moving_down_ref} = \$moving_down;
296 679         4674 $parse_hash->{__current_position_ref} = \$current_position;
297 679         1185 $parse_hash->{__message_ref} = \$message;
298 679         1079 $parse_hash->{__steps_ref} = \$steps;
299 679         1796 $parse_hash->{__continue_forward_ref} = \$continue_forward;
300 679         1251 $parse_hash->{__tree_size_ref} = \$tree_size;
301 679         1369 $parse_hash->{__current_rule_ref} = \$current_rule;
302 679         1146 $parse_hash->{__bottom_up} = $bottom_up;
303 679         1092 $parse_hash->{__bottom_up_left_to_right} = $bottom_up_left_to_right;
304 679         1188 $parse_hash->{__parse_trace_routine} = $parse_trace_routine;
305              
306 679   100     3734 while (($steps < $max_steps) && $current_node) {
307 798   100     4713 while ($current_node && (++$steps <= $max_steps)) {
308 28772 100       58952 if ($parse_trace_routine) {
309 202         1463 &{$parse_trace_routine}($parse_hash);
  202         2008  
310             }
311 28772 100       46075 if ($moving_forward) {
312 17810 100 100     56391 if ($current_rule->{or_rule}) {
    100 100        
    100 66        
    100 100        
      100        
313 3736 100       5509 if ($moving_down) {
314 1979         3442 $new_sub_rule = $current_rule->{subrule_list}->[0];
315 1979         3057 $new_rule_name = $new_sub_rule->{name};
316 1979         4583 $new_alias = $new_sub_rule->{alias};
317 1979         3147 $current_node->{or_child_number} = 0;
318 1979         2448 $create_child = 1;
319             }
320             else {
321 1757         2270 $node_completed = 1;
322             }
323             }
324             elsif ($current_rule->{and_rule}) {
325 12304 100       26122 if ($current_node->{child_count} ==
326             $current_rule->{subrule_list_count}) {
327 2724         3775 $node_completed = 1;
328             }
329             else {
330 9580         29771 $new_sub_rule = $current_rule->{subrule_list}->[
331             $current_node->{child_count}];
332 9580         15415 $new_rule_name = $new_sub_rule->{name};
333 9580         14914 $new_alias = $new_sub_rule->{alias};
334 9580         12631 $create_child = 1;
335             }
336             }
337             elsif ($any_minimize_children && $current_rule->{minimize_children} &&
338             ($not_any_minimum_child ||
339             $current_rule->{minimum_child} <= $current_node->{child_count})) {
340 89         133 $node_completed = 1;
341             }
342             elsif ($any_maximum_child && $current_rule->{maximum_child} &&
343             $current_rule->{maximum_child} == $current_node->{child_count}) {
344 106         421 $node_completed = 1;
345             }
346             else {
347 1575         2680 $new_rule_name = $current_rule->{sub_rule_name};
348 1575         2500 $new_alias = $current_rule->{sub_alias};
349 1575         2266 $create_child = 1;
350             }
351             }
352             else { # !$moving_forward
353 10962 100 100     45005 if ($current_rule->{leaf_rule}) {
    100 66        
    100 100        
    100 66        
    100 100        
    100 66        
      100        
      100        
      100        
      66        
354 972         2097 $remove_node = 1;
355             }
356             elsif ($current_rule->{or_rule}) {
357 3724 100       5624 if ($moving_down) {
358 379         485 $move_back_to_child = 1;
359             }
360             else {
361 3345 100 66     14522 if ($not_move_back_mode && (++$current_node->{or_child_number} <
362             $current_rule->{subrule_list_count})) {
363 2746         5096 $new_sub_rule = $current_rule->{subrule_list}->[
364             $current_node->{or_child_number}];
365 2746         4415 $new_rule_name = $new_sub_rule->{name};
366 2746         4376 $new_alias = $new_sub_rule->{alias};
367 2746         4387 $create_child = 1;
368             }
369             else {
370 599         900 $remove_node = 1;
371             }
372             }
373             }
374             elsif ($current_rule->{and_rule}) {
375 4802 100       8318 if ($current_node->{child_count}) {
376 1449         1957 $move_back_to_child = 1;
377             }
378             else {
379 3353         4085 $remove_node = 1;
380             }
381             }
382             elsif
383             (
384             (
385             (
386             !$moving_down &&
387             ($not_any_minimize_children || !$current_rule->{minimize_children})
388             ) &&
389             ($not_any_minimum_child || !$current_rule->{minimum_child} ||
390             ($current_rule->{minimum_child} <= $current_node->{child_count}))
391             )
392             && $not_move_back_mode
393             ) {
394 948         1404 $node_completed = 1;
395             }
396             elsif ($any_minimize_children && $not_move_back_mode &&
397             $current_rule->{minimize_children} && $moving_down &&
398             ($not_any_maximum_child || !$current_rule->{maximum_child} ||
399             ($current_rule->{maximum_child} > $current_node->{child_count}))) {
400 49         89 $new_rule_name = $current_rule->{sub_rule_name};
401 49         71 $new_alias = $current_rule->{sub_alias};
402 49         202 $create_child = 1;
403             }
404             elsif ($current_node->{child_count}) {
405 233         382 $move_back_to_child = 1;
406             }
407             else {
408 234         334 $remove_node = 1;
409             }
410 10962 100       26140 if ($move_back_to_child) {
411 2061         2228 $move_back_to_child = 0;
412 2061 100       4449 $message .= " Backtracking to child" if $parse_trace_routine;
413 2061         2273 $moving_down = 1;
414 2061         2104 $moving_forward = 0;
415 2061 100       3906 pop @$bottom_up_left_to_right if $bottom_up;
416 2061         4113 $current_node =
417             $current_node->{children}->[$current_node->{child_count}-1];
418 2061         3325 $current_node_name = $current_node->{name};
419 2061         3220 $current_rule = $rule->{$current_node_name};
420 2061 100       4315 if ($do_evaluation_in_parsing) {
421 461         626 $parameters->{node} = $current_node;
422 461         1687 $parse_stallion->new_unevaluate_tree_node($parameters);
423             }
424 2061 100 100     12372 if ($any_match_once && $not_move_back_mode
      66        
425             && $rule->{$current_node_name}->{match_once}) {
426            
427 14 100       26 if ($fast_move_back) {
428 11         15 $remove_node = 1;
429 11 50       28 $message .= ". Fast Move Back " if $parse_trace_routine;
430             }
431             else {
432 3         5 $move_back_mode = 1;
433 3         4 $not_move_back_mode = 0;
434 3         74 $current_node->{__move_back_to} = 1;
435 3 50       10 $message .= ". Move Back Mode Enabled " if $parse_trace_routine;
436             }
437             }
438             }
439             }
440              
441 28772 100       58959 if ($create_child) {
    100          
442 15929         18227 $create_child = 0;
443 15929         25718 $new_rule = $rule->{$new_rule_name};
444 15929         20081 $previous_position = $current_position;
445 15929 100 100     77094 if ($any_parse_forward && (my $pf = $new_rule->{parse_forward})) {
    100          
446 1000         933 my $delta_position;
447 1000         1482 $parse_hash->{current_position} = $current_position;
448 1000         1397 $parse_hash->{rule_name} = $new_rule_name;
449 1000         3549 ($continue_forward, $match, $delta_position) =
450 1000         1177 &{$pf}($parse_hash);
451 1000 100       6270 if (defined $delta_position) {
452 936 50       1539 if ($delta_position < 0) {
453 0         0 croak ("Parse forward on $new_rule_name resulted in
454             backward progress ($previous_position, $delta_position)");
455             }
456             else {
457 936         1514 $current_position += $delta_position;
458             }
459             }
460             }
461             elsif (my $x = $new_rule->{regex_match}) {
462 7048         17461 pos $$parse_this_ref = $current_position;
463 7048 100       42044 if ($$parse_this_ref =~ m/$x/g) {
464 3321 100       21881 if (defined $2) {$match = $2;}
  94         196  
  3227         7236  
465             else {$match = $1;}
466 3321         3917 $continue_forward = 1;
467 3321         4641 $current_position = pos $$parse_this_ref;
468 3321 100       6769 $message .= 'Leaf matched' if $parse_trace_routine;
469             }
470             else {
471 3727         4179 $continue_forward = 0;
472 3727 100       11085 $message .= 'Leaf not matched' if $parse_trace_routine;
473             }
474             }
475             else {
476 7881         9564 $match = undef;
477             }
478              
479 15929 100       31072 if ($continue_forward) {
480 12158 100       23248 if ($current_position > $maximum_position) {
481 2538         3249 $maximum_position = $current_position;
482 2538         3365 $maximum_position_rule = $new_rule_name;
483             }
484 12158 100       25775 if ($current_position == $previous_position) {
485 9226 100       20708 if (defined $position_tree_size->{$current_position}) {
486 7120 100       17410 if ($position_tree_size->{$current_position} <
487             $tree_size - $delta_tree_size) {
488 2         420 croak
489             ("$new_rule_name duplicated position $current_position");
490             }
491             }
492             else {
493 2106         5363 $position_tree_size->{$current_position} = $tree_size;
494             }
495             }
496 12156         94343 my $new_node = {
497             name => $new_rule_name,
498             alias => $new_alias,
499             steps => $steps,
500             parent => $current_node,
501             position_when_entered => $previous_position,
502             __nodes_when_entered => $tree_size,
503             parse_match => $match,
504             child_count => 0
505             };
506 12156 100       41087 if ($new_rule->{leaf_rule}) {
507 4275         5217 $node_completed = 1;
508             }
509             else {
510 7881         8903 $moving_forward = 1;
511 7881         9285 $moving_down = 1;
512             }
513 12156         12403 push @{$current_node->{children}}, $new_node;
  12156         29692  
514 12156         17012 $current_node->{child_count}++;
515 12156         13870 $current_node = $new_node;
516 12156         12247 $tree_size++;
517 12156         14597 $current_node_name = $new_rule_name;
518 12156         18443 $current_rule = $rule->{$current_node_name};
519 12156 100       28562 $message = "Creating child $new_rule_name on step $steps for ".
520             "node created on step "
521             .$current_node->{steps} if $parse_trace_routine;
522             }
523             else {
524 3771         4554 $continue_forward = 1;
525 3771         5125 $moving_forward = 0;
526 3771         5088 $moving_down = 0;
527             }
528             }
529             elsif ($remove_node) {
530 5169         9952 $remove_node = 0;
531 5169         5141 $moving_forward = 0;
532 5169         10314 $moving_down = 0;
533 5169         8362 $current_position = $current_node->{position_when_entered};
534 5169 100       10945 if ($bottom_up) {
535 4564         16215 my $change_in_tree =
536             $tree_size - $current_node->{__nodes_when_entered};
537 4564 100       9588 if ($change_in_tree > 1) {
538 9         41 splice (@$bottom_up_left_to_right, 1 - $change_in_tree);
539             }
540             }
541 5169         6874 $tree_size = $current_node->{__nodes_when_entered};
542 5169 100 100     23573 if (defined $position_tree_size->{$current_position}
543             && ($position_tree_size->{$current_position} == $tree_size)) {
544 537         1271 delete $position_tree_size->{$current_position};
545             }
546 5169 100       10049 $message .= " Removed node created on step ".$current_node->{steps}
547             if $parse_trace_routine;
548 5169         11031 $parse_hash->{parse_match} = $current_node->{parse_match};
549 5169 100 100     12132 if ($move_back_mode && $current_node->{__move_back_to}) {
550 3         5 $move_back_mode = 0;
551 3         4 $not_move_back_mode = 1;
552 3 50       23 $message .= ". Move Back Mode Completed"
553             if $parse_trace_routine;
554             }
555 5169         7665 $current_node = $current_node->{parent};
556 5169 100       10383 if (defined $current_node) {
557 4866         5125 pop @{$current_node->{children}};
  4866         8101  
558 4866         32202 $current_node->{child_count}--;
559 4866 100 100     11162 if ($any_parse_backtrack && $current_rule->{parse_backtrack}) {
560 12         31 $parse_hash->{current_position} = $current_position;
561 12         25 $parse_hash->{rule_name} = $current_node_name;
562 12         18 $end_parse_now = &{$current_rule->{parse_backtrack}}
  12         78  
563             ($parse_hash);
564 12 100       1221 if ($end_parse_now) {
565 3         6 $current_node = undef;
566 3         6 $moving_forward = 0;
567 3         7 last;
568             }
569             }
570 4863         7355 $current_node_name = $current_node->{name};
571 4863         13011 $current_rule = $rule->{$current_node_name};
572             }
573 5166         10130 delete $parse_hash->{parse_match};
574             }
575              
576 28767 100       123153 if ($node_completed) {
577 9899         10150 $node_completed = 0;
578 9899         14058 my $parent = $current_node->{parent};
579 9899 100 100     50403 if ($current_position == $current_node->{position_when_entered}
      100        
      33        
      66        
580             && $parent &&
581             (defined $rule->{$parent->{name}}->{minimum_child})
582             && ($not_any_minimum_child || ($parent->{child_count} >
583             $rule->{$parent->{name}}->{minimum_child}))
584             ) {
585 2 50       5 $message .= " Last child empty, Child of multiple cannot be empty "
586             if $parse_trace_routine;
587 2         3 $moving_forward = 0;
588 2         10 $moving_down = 1;
589             }
590             else {
591 9897         12157 my $reject;
592 9897 100       23268 if ($do_evaluation_in_parsing) {
593 1242         4262 $parameters->{nodes} = [$current_node];
594 1242         2658 $parse_hash->{current_position} = $current_position;
595 1242 100       2899 if ($parse_stallion->new_evaluate_tree_node($parameters)) {
596 70         98 $moving_forward = 0;
597 70         119 $moving_down = 1;
598 70 50       148 $message .= " Node rejected" if $parse_trace_routine;
599 70         383 next;
600             }
601             }
602 9827 100       30319 push @$bottom_up_left_to_right, $current_node if $bottom_up;
603 9827 100       17044 $message .= " Completed node created on step ".
604             $current_node->{steps} if $parse_trace_routine;
605 9827         10699 $moving_down = 0;
606 9827         9388 $moving_forward = 1;
607 9827         24301 $current_node->{position_when_completed} = $current_position;
608 9827 100       39564 if ($current_node = $parent) {
609 9338         13065 $current_node_name = $current_node->{name};
610 9338         54207 $current_rule = $rule->{$current_node_name};
611             }
612             }
613             }
614             }
615 796 100 100     6280 if (!$current_node && $moving_forward && $must_parse_length &&
      100        
      100        
616             ($parse_this_length != $current_position)) {
617 120         149 $moving_forward = 0;
618 120         144 $moving_down = 1;
619 120         152 $current_node = $tree;
620 120         300 $current_node_name = $current_node->{name};
621 120 100       331 $message .= ' . At top of tree but did not parse entire object'
622             if $parse_trace_routine;
623 120 100       350 pop @$bottom_up_left_to_right if $bottom_up;
624 120 100 66     314 if ($any_match_once
625             && $rule->{$current_node_name}->{match_once}) {
626 1 50       4 if ($fast_move_back) {
627 1         2 $current_node = undef;
628 1 50       4 $message .= ". Fast Move Back " if $parse_trace_routine;
629             }
630             else {
631 0         0 $move_back_mode = 1;
632 0         0 $not_move_back_mode = 0;
633 0         0 $current_node->{__move_back_to} = 1;
634 0 0       0 $message .= ". Move Back Mode Enabled " if $parse_trace_routine;
635             }
636             }
637             }
638 796 50 33     4937 if ($no_max_steps && ($steps == $max_steps)) {
639 0         0 $max_steps += 1000000;
640             }
641             }
642 677         1665 $results->{start_rule} = $start_rule;
643 677         1182 $results->{number_of_steps} = $steps;
644 677         1206 $results->{final_position} = $current_position;
645 677         1259 $results->{final_position_rule} = $current_node_name;
646 677         1315 $results->{parse_backtrack_value} = $end_parse_now;
647 677         1295 $results->{maximum_position} = $maximum_position;
648 677         1653 $results->{maximum_position_rule} = $maximum_position_rule;
649 677 100 66     2684 if (!$moving_forward && !$current_node) {
650 307         768 $results->{tree} = {};
651             }
652             else {
653 370         1213 $results->{tree} = $tree;
654             }
655 677         1455 $results->{tree_size} = $tree_size;
656 677         1741 $results->{bottom_up_left_to_right} = $bottom_up_left_to_right;
657 677 100       1824 if ($steps >= $max_steps) {
658 1         219 croak ("Not enough steps to do parse, max set at $max_steps");
659             }
660 676 100       1762 if ($moving_forward) {
661 369         687 $results->{parse_succeeded} = 1;
662 369 100       1328 if ($do_evaluation_in_parsing) {
663 51         128 $results->{parsing_evaluation} = $tree->{computed_value};
664             }
665             }
666             else {
667 307         507 $results->{parse_succeeded} = 0;
668             }
669 676         4120 return $results;
670             }
671              
672             package Parse::Stallion;
673             require Exporter;
674             our $VERSION = '2.01';
675             our @ISA = qw(Exporter);
676             our @EXPORT =
677             qw(A AND O OR LEAF L MATCHED_STRING
678             MATCH_MIN_FIRST MATCH_ONCE M MULTIPLE OPTIONAL
679             ZERO_OR_ONE Z
680             E EVALUATION U UNEVALUATION PF PARSE_FORWARD PB PARSE_BACKTRACK
681             RULE_INFO R TERMINAL TOKEN
682             LEAF_DISPLAY USE_STRING_MATCH LOCATION SE STRING_EVALUATION
683             I IN INC INCORPORATE
684             );
685 32     32   298 use strict;
  32         69  
  32         1286  
686 32     32   176 use warnings;
  32         60  
  32         1159  
687 32     32   616 use Carp;
  32         76  
  32         328700  
688              
689             sub new {
690 159     159 0 28769 my $type = shift;
691 159   33     1075 my $class = ref($type) || $type;
692 159         350 my $rules_to_set_up_hash = shift;
693 159         271 my $parameters = shift;
694 159         320 my $self = {};
695              
696 159         487 bless $self, $class;
697 159         726 $self->{separator} = '__XZ__';
698 159   50     990 $self->{max_steps} = $parameters->{max_steps} || 1000000;
699 159   50     955 $self->{parse_trace_routine} = $parameters->{parse_trace_routine} || undef;
700 159         410 $self->{multiple_rule_mins} = 0;
701 159         419 $self->{any_match_once} = 0;
702 159         357 $self->{any_minimize_children} = 0;
703 159         377 $self->{any_unevaluation} = 0;
704 159         492 $self->{any_parse_forward} = 0;
705 159         450 $self->{any_parse_backtrack} = 0;
706 159         387 $self->{any_maximum_child} = 0;
707 159         434 $self->{any_minimum_child} = 0;
708 159         413 $self->{self} = $self;
709 159 50 50     1040 if ($self->{no_evaluation} = $parameters->{no_evaluation} || 0) {
710 0         0 $self->{do_evaluation_in_parsing} = 0;
711             }
712             else {
713 159   100     941 $self->{do_evaluation_in_parsing} = $parameters->{do_evaluation_in_parsing}
714             || 0;
715             }
716 159   50     1734 $self->{unreachable_rules_allowed} = $parameters->{unreachable_rules_allowed}
717             || 0;
718 159   100     1150 $self->{do_not_compress_eval} = $parameters->{do_not_compress_eval} || 0;
719 159   66     786 $self->{separator} = $parameters->{separator} || $self->{separator};
720 159 100       491 if (defined $parameters->{parse_forward}) {
721 1         3 $self->{leaf_parse_forward} = $parameters->{parse_forward};
722 1         2 $self->{any_parse_forward} = 1;
723             }
724 159 100       622 if (defined $parameters->{parse_backtrack}) {
725 1         3 $self->{leaf_parse_backtrack} = $parameters->{parse_backtrack};
726 1         2 $self->{any_parse_backtrack} = 1;
727             }
728 159 100       424 if (defined $parameters->{length_routine}) {
729 1         3 $self->{length_routine} = $parameters->{length_routine};
730             }
731             else {
732 500     500   730 $self->{length_routine} = sub {return length(${$_[0]});}
  500         1818  
733 158         987 }
734 159 100       567 $self->incorporate_others($parameters->{incorporate})
735             if defined $parameters->{incorporate};
736 158         829 $self->set_up_full_rule_set($rules_to_set_up_hash, $parameters);
737 147         215 my $number_of_rules = scalar(keys %{$self->{rule}});
  147         706  
738 147         261 my $min_multiplier = $number_of_rules;
739 147         538 $self->{max_nodes_before_size_must_change} = $number_of_rules +
740             $min_multiplier * $self->{multiple_rule_mins};
741 147   100     1379 $self->{fast_move_back} = $parameters->{fast_move_back} ||
742             !($self->{any_parse_backtrack} || $self->{any_unevaluation});
743 147         689 return $self;
744             }
745              
746             sub copy_tree_node_list {
747 65     65 0 94 my $list = shift;
748 65         70 my @new_list;
749             my %parent_hash;
750 65         193 my $node_count = scalar @$list - 1;
751 65         106 my $node_to_copy = $list->[$node_count];
752 65         472 $new_list[$node_count] = {
753             name => $node_to_copy->{name},
754             alias => $node_to_copy->{alias},
755             parse_match => $node_to_copy->{parse_match},
756             position_when_entered => $node_to_copy->{position_when_entered},
757             position_when_completed => $node_to_copy->{position_when_completed}
758             };
759 65         204 $parent_hash{$node_to_copy} = $node_count;
760 65         371 for (my $i = $node_count-1; $i > -1; $i--) {
761 149         185 $node_to_copy = $list->[$i];
762 149         318 $parent_hash{$node_to_copy} = $i;
763 149         2073 $new_list[$i] = {
764             name => $node_to_copy->{name},
765             alias => $node_to_copy->{alias},
766             parse_match => $node_to_copy->{parse_match},
767             position_when_entered => $node_to_copy->{position_when_entered},
768             position_when_completed => $node_to_copy->{position_when_completed},
769             parent => $new_list[$parent_hash{$node_to_copy->{parent}}],
770             };
771             }
772 65         243 return \@new_list;
773             }
774              
775             sub parse_and_evaluate {
776 424     424 0 211075 my $self = shift;
777 424   100     2840 my $parameters = $_[1] || {};
778 424         676 my $in_is_string = 0;
779 424   100     3025 $parameters->{parse_info} = $parameters->{parse_info} || {};
780 424   50     3421 $parameters->{parse_hash} = $parameters->{parse_hash} || {};
781 424         718 my $initial_position = 0;
782 424 50       1360 if (defined $_[0]) {
783 424         946 $parameters->{parse_this_ref} = \$_[0];
784 424 50       1278 if (ref $_[0] eq '') {
785 424         565 $in_is_string = 1;
786 424   100     2339 $initial_position = pos $_[0] || 0;
787             }
788             }
789 424         545 my $find_all;
790 424 100       1827 if (defined $parameters->{find_all}) {
    100          
791 4         10 $find_all = $parameters->{find_all};
792             }
793             elsif ($parameters->{global}) {
794 18 100       44 if (wantarray) {
795 4         11 $find_all = 1;
796             }
797             else {
798 14         22 $find_all = 0;
799             }
800             }
801 424 100       1105 if (defined $parameters->{start_position}) {
802 10         15 $initial_position = $parameters->{start_position};
803             }
804 424         519 my $not_match_start;
805 424 100       1170 if (!defined $parameters->{match_start}) {
806 399         569 $not_match_start = 0;
807             }
808             else {
809 25         53 $not_match_start = !$parameters->{match_start};
810             }
811 424 100       1002 if (!defined $parameters->{match_length}) {
812 377         1192 $parameters->{parse_hash}->{__match_length} = 1;
813             }
814             else {
815 47         120 $parameters->{parse_hash}->{__match_length} = $parameters->{match_length};
816             }
817 424         1618 $parameters->{parse_hash}->{__initial_position} = $initial_position;
818 424         691 my $parse_this_ref = $parameters->{parse_this_ref};
819 424         1477 my $parse_this_length = $parameters->{parse_hash}->{__parse_this_length} =
820             $self->{length_routine}($parse_this_ref);
821 424         1758 my $parser = new Parse::Stallion::Parser($self);
822 424         632 my $substitution_subroutine;
823             my $substitute;
824 424 50 100     2909 if (defined $parameters->{substitution}) {
    100          
825 0         0 $substitute = 1;
826 0 0       0 if (ref $parameters->{substitution} eq 'CODE') {
827 0         0 $substitution_subroutine = $parameters->{substitution};
828             }
829             else {
830 0     0   0 $substitution_subroutine = sub {return $parameters->{substitution}};
  0         0  
831             }
832             }
833             elsif ($substitute = $parameters->{substitute} || 0) {
834 40     40   90 $substitution_subroutine = sub {return $_[0];}
835 13         178 }
836 424         1381 $parameters->{parse_hash}->{rule_info} =
837             $self->{rule_info};
838 424         517 my $parser_results;
839 424 100       1087 if ($parameters->{parse_trace}) {
840             $parameters->{parse_trace_routine} = sub {
841 123     123   161 my $parse_hash = shift;
842 123         141 my $parent_step = 0;
843 123         245 my $current_node = ${$parse_hash->{__current_node_ref}};
  123         311  
844 123 100       315 if ($current_node->{parent}) {
845 104         358 $parent_step = $current_node->{parent}->{steps};
846             }
847 123         211 push @{$parameters->{parse_trace}}, {
  123         191  
848 123         315 rule_name => ${$parse_hash->{__current_node_name_ref}},
849 123         162 moving_forward => ${$parse_hash->{__moving_forward_ref}},
850 123         210 moving_down => ${$parse_hash->{__moving_down_ref}},
851 123         319 position => ${$parse_hash->{__current_position_ref}},
852             node_creation_step => $current_node->{steps},
853             parent_node_creation_step => $parent_step,
854 123         131 message => ${$parse_hash->{__message_ref}},
855             tree => $parse_hash->{__tree}->stringify,
856             };
857 5         40 };
858             }
859 424         572 my $match_position;
860 424         668 my $match_maximum = $parameters->{match_maximum};
861 424         793 my $match_minimum = $parameters->{match_minimum};
862 424 50 66     1429 if ($match_maximum && $match_minimum) {
863 0         0 croak "Cannot match both maximum and minimum";
864             }
865 424 100 100     2043 if ($match_maximum || $match_minimum) {
866 23         42 $parameters->{parse_hash}->{__match_length} = 0;
867             }
868 424         617 my $tree_to_evaluate = undef;
869 424         539 my $to_return;
870             my @results_array;
871 424         515 my $continue_to_parse = 1;
872 424         498 my $parse_succeeded;
873 424         927 while ($continue_to_parse) {
874 466         636 $continue_to_parse = 0;
875 466 100       1428 if ($match_maximum) {
    100          
876 22         30 $match_position = -1;
877             }
878             elsif ($match_minimum) {
879 23         27 $match_position = $parse_this_length;
880             }
881 466         538 $parse_succeeded = 0;
882 466         541 my $root_node;
883 466         611 my $repeat_parse_by_start = 1;
884 466         1075 while ($repeat_parse_by_start) {
885 617         700 $repeat_parse_by_start = 0;
886 617         722 my $repeat_parse = 1;
887 617         1438 while ($repeat_parse) {
888 704         854 $repeat_parse = 0;
889 704         953 $parser_results = eval {$parser->parse($parameters)};
  704         1865  
890 704 100       2065 if ($@) {croak ($@)};
  3         418  
891 701 100       2307 if ($parser_results->{parse_succeeded}) {
892 390         580 $parse_succeeded = 1;
893 390 100 100     2528 if ($match_maximum &&
    100 66        
    100          
894             ($parser_results->{final_position} < $parse_this_length)) {
895 39 100       94 if ($parser_results->{final_position} > $match_position) {
896 29         36 $match_position = $parser_results->{final_position};
897 29 50       61 if ($self->{do_evaluation_in_parsing}) {
898 0         0 $to_return = $parser_results->{parsing_evaluation};
899             }
900             else {
901 29         82 $tree_to_evaluate = copy_tree_node_list(
902             $parser_results->{bottom_up_left_to_right});
903 29         87 $root_node =
904             $tree_to_evaluate->[$parser_results->{tree_size}-1];
905             }
906             }
907 39         55 $repeat_parse = 1;
908 39         135 $parameters->{continue_parse} = 1;
909 39         46 ${$parameters->{parse_hash}->{__moving_forward_ref}} = 0;
  39         140  
910 39         50 ${$parameters->{parse_hash}->{__moving_down_ref}} = 1;
  39         60  
911 39         84 $parameters->{parse_hash}->{current_node} =
912             $parameters->{parse_hash}->{tree};
913 39 50       96 ${$parameters->{parse_hash}->{__message_ref}} .=
  0         0  
914             ' . Looking for longer match '
915             if $parameters->{parse_hash}->{__parse_trace_routine};
916 39 50       90 pop @{$parser_results->{bottom_up_left_to_right}}
  39         115  
917             if $parameters->{parse_hash}->{__bottom_up};
918             }
919             elsif ($match_minimum &&
920             ($parser_results->{final_position} > $initial_position)) {
921 48 100       116 if ($parser_results->{final_position} < $match_position) {
922 36         48 $match_position = $parser_results->{final_position};
923 36 50       552 if ($self->{do_evaluation_in_parsing}) {
924 0         0 $to_return = $parser_results->{parsing_evaluation};
925             }
926             else {
927 36         89 $tree_to_evaluate = copy_tree_node_list(
928             $parser_results->{bottom_up_left_to_right});
929 36         132 $root_node =
930             $tree_to_evaluate->[$parser_results->{tree_size}-1];
931             }
932             }
933 48         72 $repeat_parse = 1;
934 48         137 $parameters->{continue_parse} = 1;
935 48         50 ${$parameters->{parse_hash}->{__moving_forward_ref}} = 0;
  48         85  
936 48         58 ${$parameters->{parse_hash}->{__moving_down_ref}} = 1;
  48         73  
937 48         88 $parameters->{parse_hash}->{current_node} =
938             $parameters->{parse_hash}->{tree};
939 48 50       111 ${$parameters->{parse_hash}->{__message_ref}} .=
  0         0  
940             ' . Looking for shorter match '
941             if $parameters->{parse_hash}->{__parse_trace_routine};
942 48 50       101 pop @{$parser_results->{bottom_up_left_to_right}}
  48         252  
943             if $parameters->{parse_hash}->{__bottom_up};
944             }
945             elsif ($self->{do_evaluation_in_parsing}) {
946 51         98 $match_position = $parser_results->{final_position};
947 51         180 $to_return = $parser_results->{parsing_evaluation};
948             }
949             else {
950 252         517 $match_position = $parser_results->{final_position};
951 252         413 $tree_to_evaluate = $parser_results->{bottom_up_left_to_right};
952 252         2596 $root_node = $parser_results->{tree};
953             }
954             }
955             }
956 614 100 100     4163 if (!($parse_succeeded) && $not_match_start &&
      100        
957             ($parse_this_length > $initial_position)) {
958 151         338 $parameters->{parse_hash}->{__initial_position}++;
959 151         159 $initial_position++;
960 151         2367 $parameters->{continue_parse} = 0;
961 151         350 $repeat_parse_by_start = 1;
962             }
963             }
964            
965 463   100     2077 $parser_results->{parse_succeeded} =
966             $parser_results->{parse_succeeded} || $parse_succeeded;
967 463 100 66     3255 if (!($parse_succeeded) || $self->{no_evaluation}) {
    100          
968 123         206 $to_return = undef;
969             }
970             elsif ($self->{do_evaluation_in_parsing}) {
971 51 50       130 if (!defined $to_return) {$to_return = ''};
  0         0  
972             }
973             else {
974 289         618 $parameters->{nodes} = $tree_to_evaluate;
975 289         1296 $self->new_evaluate_tree_node($parameters);
976             #$to_return = $parser_results->{tree}->{computed_value};
977 288         511 $to_return = $root_node->{computed_value};
978 288 100       3020 if (!defined $to_return) {$to_return = ''};
  7         12  
979             }
980 462 100 100     2249 if ((defined $to_return) && ($substitute) ) {
981 40         69 my $replaced_length = $match_position - $initial_position;
982 40         283 my $to_sub = &{$substitution_subroutine}($to_return);
  40         97  
983 40         56 substr(${$parameters->{parse_this_ref}}, $initial_position,
  40         131  
984             $replaced_length) = $to_sub;
985 40         225 $match_position += $self->{length_routine}(\$to_sub) - $replaced_length;
986 40         90 $parameters->{parse_hash}->{__parse_this_length} = $parse_this_length =
987             $self->{length_routine}($parse_this_ref);
988             }
989 462 100 100     2321 if ($find_all && $parse_succeeded) {
990 43         85 push @results_array, $to_return;
991 43 100       94 if ($match_position == $initial_position) {
992 3         4 $match_position++;
993             }
994 43         84 $initial_position = $parameters->{parse_hash}->{__initial_position}
995             = $match_position;
996 43 100       97 if ($match_position <= $parse_this_length) {
997 42         53 $continue_to_parse = 1;
998 42         122 $parameters->{continue_parse} = 0;
999             }
1000             }
1001             }
1002 420 50       1120 if ($in_is_string) {
1003 420 100 100     1458 if ($parameters->{global} && $parse_succeeded) {
1004 13         35 pos $_[0] = $match_position;
1005             }
1006             else {
1007 407         1242 pos $_[0] = undef;
1008             }
1009             }
1010              
1011 420 100       1160 if ($find_all) {
1012 8         82 return @results_array;
1013             }
1014 412         7362 return $to_return;
1015             }
1016              
1017             sub search {
1018 12     12 0 2590 my $self = shift;
1019 12   100     61 my $parameters = $_[1] || {};
1020 12 50       47 if (!defined $parameters->{match_start}) {
1021 12         34 $parameters->{match_start} = 0;
1022             }
1023 12 100       41 if (!defined $parameters->{match_length}) {
1024 10         21 $parameters->{match_length} = 0;
1025             }
1026 12   100     84 $parameters->{parse_info} = $parameters->{parse_info} || {};
1027 12 100 100     60 if ($parameters->{global} && wantarray) {
1028 2         10 return $self->parse_and_evaluate($_[0], $parameters);
1029             }
1030             else {
1031 10         37 $self->parse_and_evaluate($_[0], $parameters);
1032 10 100       44 if ($parameters->{parse_info}->{parse_succeeded}) {
1033 7         176 return 1;
1034             }
1035             else {
1036 3         29 return '';
1037             }
1038             }
1039             }
1040              
1041             sub search_and_substitute {
1042 7     7 0 4884 my $self = shift;
1043 7   100     44 my $parameters = $_[1] || {};
1044 7         20 $parameters->{substitute} = 1;
1045 7 100       26 if ($parameters->{global}) {
1046 2         10 my @substitutions = $self->search($_[0], $parameters);
1047 2         12 return scalar(@substitutions);
1048             }
1049             else {
1050 5         23 return $self->search($_[0], $parameters);
1051             }
1052             }
1053              
1054             #package rules
1055             sub ri_sub {
1056 0     0 0 0 return ['RULE_INFO', @_];
1057             }
1058              
1059 0     0 0 0 sub R {ri_sub(@_)}
1060 0     0 0 0 sub RULE_INFO {ri_sub(@_)}
1061              
1062             sub eval_sub {
1063 364     364 0 1705 return ['EVAL', @_];
1064             }
1065              
1066 342     342 0 79036 sub E {eval_sub(@_)}
1067 22     22 1 101 sub EVALUATION {eval_sub(@_)}
1068              
1069             sub string_eval_sub {
1070 43     43 0 240 return ['SEVAL', @_];
1071             }
1072              
1073 43     43 0 159 sub SE {string_eval_sub(@_)}
1074 0     0 1 0 sub STRING_EVALUATION {string_eval_sub(@_)}
1075              
1076             sub uneval_sub {
1077 3     3 0 16 return ['UNEVAL', @_];
1078             }
1079              
1080 3     3 0 8 sub U {uneval_sub(@_)}
1081 0     0 0 0 sub UNEVALUATION {uneval_sub(@_)}
1082              
1083             sub parse_forward_sub {
1084 57     57 0 302 return ['PARSE_FORWARD', @_];
1085             }
1086              
1087 53     53 0 4596 sub PF {parse_forward_sub(@_)}
1088 4     4 1 14 sub PARSE_FORWARD {parse_forward_sub(@_)}
1089              
1090             sub parse_backtrack_sub {
1091 15     15 0 103 return ['PARSE_BACKTRACK', @_];
1092             }
1093              
1094 15     15 0 46 sub PB {parse_backtrack_sub(@_)}
1095 0     0 0 0 sub PARSE_BACKTRACK {parse_backtrack_sub(@_)}
1096              
1097 7     7 0 34 sub USE_STRING_MATCH {return ['USE_STRING_MATCH']}
1098              
1099 18     18 1 4341 sub MATCH_ONCE {return ['MATCH_ONCE', @_]}
1100              
1101 13     13 1 6220 sub MATCH_MIN_FIRST {return ['MATCH_MIN_FIRST']}
1102              
1103             sub and_sub {
1104 492     492 0 3450 return ['AND', @_];
1105             }
1106              
1107 63     63 1 3108 sub AND {and_sub(@_)}
1108 429     429 0 18049 sub A {and_sub(@_)}
1109              
1110             sub or_sub {
1111 117     117 0 890 return ['OR', @_];
1112             }
1113              
1114 24     24 1 89 sub OR {or_sub(@_)}
1115 93     93 0 5144 sub O {or_sub(@_)}
1116              
1117             sub LEAF_DISPLAY {
1118 711     711 1 6156 return ['LEAF_DISPLAY', $_[0]];
1119             }
1120              
1121             sub leaf {
1122 768     768 0 904 my @p;
1123             my @q;
1124 768         1306 foreach my $parm (@_) {
1125 902 100       1990 if (ref $parm eq 'ARRAY') {
1126 187         441 push @q, $parm;
1127             }
1128             else {
1129 715         1775 push @p, $parm;
1130             }
1131             }
1132 768 100       2103 if (ref $p[0] eq 'Regexp') {
1133 703         24696 return ['LEAF', qr/\G($p[0])/, LEAF_DISPLAY($p[0]), @q];
1134             }
1135             else {
1136 65         681 return ['LEAF', @p, @q];
1137             }
1138             }
1139              
1140 506     506 1 1123 sub LEAF {leaf(@_)}
1141 0     0 0 0 sub TOKEN {leaf(@_)}
1142 0     0 0 0 sub TERMINAL {leaf(@_)}
1143 262     262 0 3349 sub L {leaf(@_)}
1144              
1145             sub multiple {
1146 139     139 0 218 my @p;
1147             my @q;
1148 139         289 foreach my $parm (@_) {
1149 264 100 100     3218 if ((ref $parm eq 'ARRAY') &&
      66        
1150             ($parm->[0] eq 'EVAL' || $parm->[0] eq 'UNEVAL' || $parm->[0] eq 'SEVAL'
1151             || $parm->[0] eq 'RULE_INFO' || $parm->[0] eq 'MATCH_ONCE'
1152             || $parm->[0] eq 'MATCH_MIN_FIRST'
1153             || $parm->[0] eq 'USE_STRING_MATCH')) {
1154 37         111 push @q, $parm;
1155             }
1156             else {
1157 227         521 push @p, $parm;
1158             }
1159             }
1160 139 100       584 if ($#p == 0) {
    50          
1161 95         864 return ['MULTIPLE', 0, 0, $p[0], @q];
1162             }
1163             elsif ($#p == 2) {
1164 44         450 return ['MULTIPLE', $p[1], $p[2], $p[0], @q];
1165             }
1166 0         0 croak "Malformed MULTIPLE; arguments: ".join(", ", @_);
1167             }
1168              
1169 14     14 1 43 sub MULTIPLE {multiple(@_)}
1170 125     125 0 9744 sub M {multiple(@_)}
1171              
1172             sub optional {
1173 57     57 0 405 return ['MULTIPLE', 0, 1, @_];
1174             }
1175 1     1 0 3 sub OPTIONAL {optional(@_)}
1176 0     0 0 0 sub ZERO_OR_ONE {optional(@_)}
1177 56     56 0 657 sub Z {optional(@_)}
1178              
1179             sub update_count {
1180 2168     2168 0 2940 my $rule_type = shift;
1181 2168         2466 my $rule_hash = shift;
1182 2168         2549 my $subrule_alias = shift;
1183 2168   50     6780 my $subrule_count = shift || 0;
1184 2168 100 66     9358 if ($subrule_count > 1) {
    100 66        
    100 66        
    100 33        
    100          
1185 263         1175 $rule_hash->{rule_count}->{$subrule_alias} = 2;
1186             }
1187             elsif ($rule_type eq 'AND') {
1188 1201         4251 $rule_hash->{rule_count}->{$subrule_alias} += $subrule_count;
1189             }
1190             elsif ($rule_type eq 'MULTIPLE' && ($rule_hash->{maximum_child} != 1 ||
1191             $subrule_count > 1)) {
1192 234         998 $rule_hash->{rule_count}->{$subrule_alias} = 2;
1193             }
1194             elsif ($rule_type eq 'MULTIPLE') {
1195 81   50     595 $rule_hash->{rule_count}->{$subrule_alias} =
1196             $rule_hash->{rule_count}->{$subrule_alias} || 1;
1197             }
1198             elsif ($rule_type eq 'OR' &&
1199             (!defined $rule_hash->{rule_count}->{$subrule_alias} ||
1200             ($subrule_count > $rule_hash->{rule_count}->{$subrule_alias}))) {
1201 341         1297 $rule_hash->{rule_count}->{$subrule_alias} = $subrule_count;
1202             }
1203             }
1204              
1205             sub incorporate_others {
1206 7     7 0 16 my $self = shift;
1207 7         18 my $incorporate_list = shift;
1208 7 50       31 if (ref $incorporate_list ne 'ARRAY') {
1209 0         0 croak "Must pass array to incorporate";
1210             }
1211 7         20 foreach my $to_incorporate (@$incorporate_list) {
1212 10         32 $self->copy_rules_from_grammar($to_incorporate);
1213             }
1214             }
1215              
1216             sub copy_rules_from_grammar {
1217 10     10 0 15 my $self = shift;
1218 10         17 my $parameters = shift;
1219 10         16 my $parser_to_incorporate = $parameters->{grammar_source};
1220 10 50       30 if (!defined $parser_to_incorporate) {
1221 0         0 croak "Need to define grammar_source to incorporate";
1222             }
1223 10         21 my $rules_to_copy = $parser_to_incorporate->{rule};
1224 10         15 my $prefix;
1225 10 100       26 if (defined $parameters->{prefix}) {
1226 4         11 $prefix = $parameters->{prefix};
1227             }
1228             else {
1229 6         12 $prefix = '';
1230             }
1231 10         14 foreach my $rule_name (keys %{$rules_to_copy}) {
  10         39  
1232 42 100       141 if (defined $self->{rule}->{$prefix.$rule_name}) {
1233 1         364 croak ("Rule $prefix$rule_name in extraction already exists");
1234             }
1235 41         74 my $rule_to_copy = $rules_to_copy->{$rule_name};
1236 41         45 my %copied_rule = %{$rule_to_copy};
  41         536  
1237 41 100       176 $copied_rule{sub_rule_name} = $prefix.$rule_to_copy->{sub_rule_name}
1238             if defined $rule_to_copy->{sub_rule_name};
1239 41 100       119 if (defined $rule_to_copy->{rule_count}) {
1240 26         33 $copied_rule{rule_count} = {%{$rule_to_copy->{rule_count}}};
  26         112  
1241 26         51 $copied_rule{subrule_list} = [];
1242 26         65 for my $i (1..$copied_rule{subrule_list_count}) {
1243 41         97 $copied_rule{subrule_list}[$i-1] = {};
1244 41         129 $copied_rule{subrule_list}->[$i-1]->{'alias'} =
1245             $rule_to_copy->{subrule_list}->[$i-1]->{'alias'};
1246 41         1166 $copied_rule{subrule_list}->[$i-1]->{'name'} = $prefix.
1247             $rule_to_copy->{subrule_list}->[$i-1]->{'name'};
1248             }
1249             }
1250 41         3669 $self->{rule}->{$prefix.$rule_name} = \%copied_rule;
1251             }
1252 9         33 $self->{multiple_rule_mins} += $parser_to_incorporate->{multiple_rule_mins};
1253 9   100     62 $self->{do_evaluation_in_parsing} = $self->{do_evaluation_in_parsing} ||
1254             $parser_to_incorporate->{do_evaluation_in_parsing};
1255 9   33     44 $self->{any_unevaluation} = $self->{any_unevaluation} ||
1256             $parser_to_incorporate->{any_unevaluation};
1257 9   33     47 $self->{any_minimize_children} = $self->{any_minimize_children} ||
1258             $parser_to_incorporate->{any_minimize_children};
1259 9   33     46 $self->{any_match_once} = $self->{any_match_once} ||
1260             $parser_to_incorporate->{any_match_once};
1261 9   33     89 $self->{any_parse_forward} = $self->{any_parse_forward} ||
1262             $parser_to_incorporate->{any_parse_forward};
1263 9   33     46 $self->{any_parse_backtrack} = $self->{any_parse_backtrack} ||
1264             $parser_to_incorporate->{any_parse_backtrack};
1265 9   33     39 $self->{any_maximum_child} = $self->{any_maximum_child} ||
1266             $parser_to_incorporate->{any_maximum_child};
1267 9   33     57 $self->{any_minimum_child} = $self->{any_minimum_child} ||
1268             $parser_to_incorporate->{any_minimum_child};
1269 9   66     56 $self->{fast_move_back} = $self->{fast_move_back} ||
1270             $parser_to_incorporate->{fast_move_back};
1271 9   33     74 $self->{no_evaluation} = $self->{no_evaluation} ||
1272             $parser_to_incorporate->{no_evaluation};
1273             }
1274              
1275             sub add_rule {
1276 1626     1626 0 2280 my $self = shift;
1277 1626         1882 my $parameters = shift;
1278 1626   33     3996 my $rule_name = $parameters->{rule_name} || croak ("Empty rule name");
1279 1626         2124 my $rule = $parameters->{rule_definition};
1280 1626 100       3912 if ($self->{rule}->{$rule_name}) {
1281 1         281 croak ("Rule $rule_name already exists");
1282             }
1283 1625 100       5252 if (ref $rule eq 'Regexp') {
    50          
1284 58         166 $rule = LEAF($rule);
1285             }
1286             elsif (ref $rule eq '') {
1287 0         0 $rule = AND($rule);
1288             }
1289              
1290 1625 50       3680 if (ref $rule ne 'ARRAY') {
1291 0         0 croak ("Bad format of rule $rule_name, cannot create.");
1292             }
1293              
1294 1625         2846 my $separator = $self->{separator};
1295 1625         1915 my $base_rule = $rule_name;
1296 1625 100       4336 if (defined $parameters->{generated_name}) {
    100          
1297 848         3199 $self->{rule}->{$rule_name}->{generated} = 1;
1298 848         2354 $self->{rule}->{$rule_name}->{base_rule} =
1299             $base_rule = $parameters->{generated_name};
1300             }
1301             elsif (index($rule_name, $separator) != -1) {
1302 1         176 croak ("rule name $rule_name contains separator $separator");
1303             }
1304             else {
1305 776         2450 $self->{rule}->{$rule_name}->{base_rule} = $rule_name;
1306             }
1307 1624         2159 my $default_alias = '';
1308 1624         1764 my @copy_of_rule; #to prevent changing input
1309 1624         3985 my $rule_type = $self->{rule}->{$rule_name}->{rule_type} = $rule->[0];
1310 1624         2696 foreach my $sub_rule (@$rule) {
1311 5892 100 100     103801 if (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'EVAL') {
    100 100        
    100 100        
    100 100        
    100 100        
    50 66        
    100 100        
    100 100        
    100 100        
    100 100        
    50          
1312 381         552 my $what_to_eval = $sub_rule->[1];
1313 381 50       1220 if ($self->{rule}->{$rule_name}->{parsing_evaluation}) {
1314 0         0 croak ("Rule $rule_name has more than one evaluation routine");
1315             }
1316 381 100       1113 if (ref $sub_rule->[1] eq 'CODE') {
1317 374         1473 $self->{rule}->{$rule_name}->{parsing_evaluation} = $what_to_eval;
1318             }
1319             }
1320             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'SEVAL') {
1321 34         101 $self->{rule}->{$rule_name}->{string_evaluation} = $sub_rule->[1];
1322 34         118 $self->{rule}->{$rule_name}->{matched_string} = $sub_rule->[2];
1323             }
1324             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'UNEVAL') {
1325 3 50       13 if ($self->{rule}->{$rule_name}->{parsing_unevaluation}) {
1326 0         0 croak ("Rule $rule_name has more than one unevaluation routine");
1327             }
1328 3   66     30 $self->{rule}->{$rule_name}->{parsing_unevaluation} = $sub_rule->[1]
1329             || $self->{rule}->{$rule_name}->{parsing_unevaluation};
1330 3         5 $self->{do_evaluation_in_parsing} = 1;
1331 3         8 $self->{any_unevaluation} = 1;
1332             }
1333             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'MATCH_MIN_FIRST') {
1334 13 50       39 if ($rule_type ne 'MULTIPLE') {
1335 0         0 croak ("Rule $rule_name: Only multiple rules can have MATCH_MIN_FIRST");
1336             }
1337 13         47 $self->{rule}->{$rule_name}->{minimize_children} = 1;
1338 13         37 $self->{any_minimize_children} = 1;
1339             }
1340             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'MATCH_ONCE') {
1341 18         59 $self->{rule}->{$rule_name}->{match_once} = 1;
1342 18         115 $self->{any_match_once} = 1;
1343             }
1344             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'RULE_INFO') {
1345 0 0       0 if ($self->{rule_info}->{$rule_name}) {
1346 0         0 croak ("Rule $rule_name has more than one rule_info");
1347             }
1348 0         0 $self->{rule_info}->{$rule_name} = $sub_rule->[1];
1349             }
1350             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'LEAF_DISPLAY') {
1351 733 50       2202 if ($self->{rule}->{$rule_name}->{leaf_display}) {
1352 0         0 croak ("Rule $rule_name has more than one leaf_display");
1353             }
1354 733 50       1513 if ($rule_type ne 'LEAF') {
1355 0         0 croak ("Only leaf rules can have LEAF_DISPLAY in rule $rule_name");
1356             }
1357 733         3494 $self->{rule}->{$rule_name}->{leaf_display} = $sub_rule->[1];
1358             }
1359             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'USE_STRING_MATCH') {
1360 8         34 $self->{rule}->{$rule_name}->{use_string_match} = 1;
1361             }
1362             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'PARSE_FORWARD') {
1363 49 100       191 if ($self->{rule}->{$rule_name}->{parse_forward}) {
1364 1         262 croak ("Rule $rule_name has more than one parse_forward");
1365             }
1366 48   33     194 $self->{rule}->{$rule_name}->{parse_forward} = $sub_rule->[1]
1367             || croak ("Rule $rule_name Illegal parse_forward routine");
1368 48         136 $self->{any_parse_forward} = 1;
1369             }
1370             elsif (ref $sub_rule eq 'ARRAY' && $sub_rule->[0] eq 'PARSE_BACKTRACK') {
1371 11 50       32 if ($rule_type eq 'LEAF') {
1372 11 50       42 if ($self->{rule}->{$rule_name}->{parse_backtrack}) {
1373 0         0 croak ("Rule $rule_name has more than one parse_backtrack");
1374             }
1375 11   33     44 $self->{rule}->{$rule_name}->{parse_backtrack} = $sub_rule->[1]
1376             || croak ("Rule $rule_name Illegal parse_backtrack routine");
1377 11         35 $self->{any_parse_backtrack} = 1;
1378             }
1379             else {
1380 0         0 croak ("Parse backtrack in rule $rule_name of $rule_type (not leaf)");
1381             }
1382             }
1383             elsif (!defined $sub_rule) {
1384 0         0 croak "undefined sub_rule in rule $rule_name";
1385             }
1386             else {
1387 4642         8715 push @copy_of_rule, $sub_rule;
1388             }
1389             }
1390 1623         2521 shift @copy_of_rule; #Remove rule type
1391 1623         3931 $self->{rule}->{$rule_name}->{leaf_rule} = 0;
1392 1623         3038 $self->{rule}->{$rule_name}->{or_rule} = 0;
1393 1623         2919 $self->{rule}->{$rule_name}->{and_rule} = 0;
1394 1623         3530 $self->{rule}->{$rule_name}->{multiple_rule} = 0;
1395 1623 100       3893 if ($rule_type eq 'LEAF') {
1396 789         1091 my $leaf_info = shift @copy_of_rule;
1397 789 100       1789 if (ref $leaf_info eq 'Regexp') {
    100          
1398 732         1738 $self->{rule}->{$rule_name}->{regex_match} = $leaf_info;
1399 732 100       3738 if ('' =~ $leaf_info) {
1400 79         242 $self->{rule}->{$rule_name}->{zero} = 1;
1401             }
1402             }
1403             elsif (defined $leaf_info) {
1404 10 50       24 if (defined $self->{rule_info}->{$rule_name}) {
1405 0         0 croak ("Duplicate info on $rule_name, leaf info is put into rule_info");
1406             }
1407 10         18 $self->{rule_info}->{$rule_name} = $leaf_info;
1408             }
1409 789   100     5125 $self->{rule}->{$rule_name}->{parse_forward} =
1410             $self->{rule}->{$rule_name}->{parse_forward} ||
1411             $self->{leaf_parse_forward};
1412 789   100     3843 $self->{rule}->{$rule_name}->{parse_backtrack} =
1413             $self->{rule}->{$rule_name}->{parse_backtrack} ||
1414             $self->{leaf_parse_backtrack};
1415 789         1518 $self->{rule}->{$rule_name}->{use_parse_match} = 1;
1416 789         2981 $self->{rule}->{$rule_name}->{leaf_rule} = 1;
1417             }
1418             else {
1419 834 100       2289 if ($rule_type eq 'AND') {
    100          
    50          
1420 514         1037 $self->{rule}->{$rule_name}->{and_rule} = 1;
1421             }
1422             elsif ($rule_type eq 'OR') {
1423 113         250 $self->{rule}->{$rule_name}->{or_rule} = 1;
1424             }
1425             elsif ($rule_type eq 'MULTIPLE') {
1426 207         414 $self->{rule}->{$rule_name}->{multiple_rule} = 1;
1427 207         642 my $min =
1428             $self->{rule}->{$rule_name}->{minimum_child} = shift @copy_of_rule;
1429 207         555 my $max =
1430             $self->{rule}->{$rule_name}->{maximum_child} = shift @copy_of_rule;
1431 207 50 66     2504 if (($max && ($min > $max)) || ($min < 0) || $min != int($min)
      33        
      33        
      33        
1432             || $max != int($max)) {
1433 0         0 croak("Illegal bound(s) $min and $max on $rule_name");
1434             }
1435 207 100       685 if ($self->{rule}->{$rule_name}->{maximum_child}) {
1436 70         121 $self->{any_maximum_child} = 1;
1437             }
1438 207 100       599 if ($self->{rule}->{$rule_name}->{minimum_child}) {
1439 22         45 $self->{any_minimum_child} = 1;
1440             }
1441 207         392 $self->{multiple_rule_mins} += $min;
1442             }
1443             else {
1444 0         0 croak "Bad rule type $rule_type on rule $rule_name";
1445             }
1446 834         1342 foreach my $current_rule (@copy_of_rule) {
1447 1861         2156 my ($alias, $name);
1448 1861 100       4051 if (ref $current_rule eq 'HASH') {
1449 121         189 my @hash_info = keys (%{$current_rule});
  121         465  
1450 121 50       381 if ($#hash_info != 0) {
1451 0         0 croak ("Too many keys in rule $rule_name");
1452             }
1453 121         186 $alias = $hash_info[0];
1454 121         263 $current_rule = $current_rule->{$alias};
1455             }
1456 1861 100       4758 if (ref $current_rule eq '') {
    100          
    50          
1457 1013 100       1938 if (!defined $alias) {
1458 977         1308 $alias = $current_rule;
1459             }
1460 1013         1224 $name = $current_rule;
1461             }
1462             elsif (ref $current_rule eq 'Regexp') {
1463 399 100       833 if (!defined $alias) {
1464 339         550 $alias = $default_alias;
1465             }
1466 399         1289 $name = $base_rule.$separator.
1467             ++$self->{unique_name_counter}->{$base_rule};
1468 399         925 $self->add_rule({
1469             rule_name => $name, rule_definition => LEAF($current_rule),
1470             generated_name => $base_rule});
1471             }
1472             elsif (ref $current_rule eq 'ARRAY') {
1473 449         1476 $name = $base_rule.$separator.
1474             ++$self->{unique_name_counter}->{$base_rule};
1475 449         3111 $self->add_rule({
1476             rule_name => $name, rule_definition => $current_rule,
1477             generated_name => $base_rule});
1478 449 100       1481 if (!defined $alias) {
1479 424 100 100     2610 if (defined $self->{rule}->{$name}->{parsing_evaluation} ||
1480             $self->{rule}->{$name}->{rule_type} eq 'LEAF') {
1481 81         146 $alias = $default_alias;
1482             }
1483             }
1484             }
1485 1861         3173 push @{$self->{rule}->{$rule_name}->{subrule_list}},
  1861         19704  
1486             {alias => $alias, name => $name};
1487             }
1488 834         2655 $self->{rule}->{$rule_name}->{subrule_list_count} =
1489 834         1239 scalar(@{$self->{rule}->{$rule_name}->{subrule_list}});
1490 834         1145 foreach my $subrule (@{$self->{rule}->{$rule_name}->{subrule_list}}) {
  834         2009  
1491 1861 100       3511 if (defined $subrule->{alias}) {
1492 1518         4403 update_count($rule_type,
1493             $self->{rule}->{$rule_name},$subrule->{alias}, 1);
1494             }
1495             else {
1496 343         412 foreach my $sub_alias (keys
  343         1358  
1497             %{$self->{rule}->{$subrule->{name}}->{rule_count}}) {
1498 650         2268 update_count($rule_type,
1499             $self->{rule}->{$rule_name}, $sub_alias,
1500             $self->{rule}->{$subrule->{name}}->{rule_count}->{$sub_alias});
1501             }
1502             }
1503             }
1504 834 100       2892 if (defined $self->{rule}->{$rule_name}->{string_evaluation}) {
1505 28 50       88 if ($self->{rule}->{$rule_name}->{parsing_evaluation}) {
1506 0         0 croak ("Rule $rule_name has multiple evaluation routines");
1507             }
1508 28         68 my $params = which_parameters_are_arrays($self, $rule_name);
1509 28         106 my @params = keys %$params;
1510 28         49 my $sub = "sub {\n";
1511 28 100       81 if ($self->{rule}->{$rule_name}->{use_string_match}) {
1512 2         5 $sub .= "\$_ = \$_[0];\n";
1513             }
1514             else {
1515 26         42 foreach my $param (@params) {
1516 52 100 66     371 if ($param =~ /\w+/ && ($param ne '_')) {
    50          
1517 43         119 $sub .= "my \$$param = \$_[0]->{$param};\n";
1518             }
1519             elsif ($param eq '') {
1520 9         30 $sub .= "\$_ = \$_[0]->{''};\n";
1521             }
1522             else {
1523 0         0 croak "String Evaluation of rule $rule_name cannot handle ".
1524             "parameter with name $param";
1525             }
1526             }
1527 26 50       104 if (my $ms = $self->{rule}->{$rule_name}->{matched_string}) {
1528 26         59 $sub .= "my \$".$ms." = MATCHED_STRING(\$_[1]);\n";
1529             }
1530             }
1531 28         77 $sub .= $self->{rule}->{$rule_name}->{string_evaluation}."}";
1532 28         4923 $self->{rule}->{$rule_name}->{parsing_evaluation} = eval $sub;
1533 28 50       144 if ($@) {croak "Rule $rule_name error on subroutine evaluation $@"};
  0         0  
1534             }
1535 834         2617 $self->{rule}->{$rule_name}->{sub_rule_name} =
1536             $self->{rule}->{$rule_name}->{subrule_list}->[0]->{name};
1537 834         4648 $self->{rule}->{$rule_name}->{sub_alias} =
1538             $self->{rule}->{$rule_name}->{subrule_list}->[0]->{alias};
1539             }
1540             }
1541              
1542             sub make_sure_all_rules_reachable {
1543 152     152 0 259 my $self = shift;
1544 152         215 my $parameters = shift;
1545 152         298 my $start_rule = $parameters->{start_rule};
1546 152         389 my @rules_to_check = ($start_rule);
1547 152         225 my %rules_checked;
1548 152         311 $rules_checked{$start_rule} = 1;
1549 152         545 while (my $rule_to_check = shift @rules_to_check) {
1550 1621 100       4612 if ($self->{rule}->{$rule_to_check}->{subrule_list}) {
1551 1407         2460 foreach my $rule_name_alias
  1407         4291  
1552             (@{$self->{rule}->{$rule_to_check}->{subrule_list}}) {
1553 1853         2590 my $rule_name = $rule_name_alias->{name};
1554 1853 100       5752 if (!($rules_checked{$rule_name}++)) {
1555 1469         4186 push @rules_to_check, $rule_name;
1556             }
1557             }
1558             }
1559             }
1560 152         469 my @unreachable;
1561 152         357 foreach my $rule (keys %{$self->{rule}}) {
  152         705  
1562 1642 100       3765 if (!$rules_checked{$rule}) {
1563 21         67 push @unreachable, "No path to rule $rule start rule $start_rule";
1564             }
1565             }
1566 152         909 return @unreachable;
1567             }
1568              
1569             sub make_sure_all_names_covered {
1570 153     153 0 375 my $self = shift;
1571 153         251 my $parameters = shift;
1572 153         290 my $return_list = $parameters->{return_list};
1573 153         334 my @list;
1574 153         266 foreach my $rule (keys %{$self->{rule}}) {
  153         685  
1575 1643 100       4284 if ($self->{rule}->{$rule}->{subrule_list}) {
1576 1428         1493 foreach my $rule_name_alias (@{$self->{rule}->{$rule}->{subrule_list}}) {
  1428         3215  
1577 1876         2633 my $rule_name = $rule_name_alias->{name};
1578 1876 100       5957 if (!$self->{rule}->{$rule_name}) {
1579 1 50       4 if ($return_list) {
1580 1         7 push @list, "Rule $rule missing subrule: $rule_name";
1581             }
1582             else {
1583 0         0 croak ("Rule $rule has undefined subrule of $rule_name");
1584             }
1585             }
1586             }
1587             }
1588             }
1589 153         613 return @list;
1590             }
1591              
1592             sub which_parameters_are_arrays {
1593 32     32 0 9642 my $self = shift;
1594 32         52 my $rule_name = shift;
1595 32         68 my $rules_details = $self->{rule};
1596 32         44 my %to_return;
1597 32         121 foreach my $child_rule_name (sort keys
  32         229  
1598             %{$rules_details->{$rule_name}->{rule_count}}) {
1599 60 100       169 if ($rules_details->{$rule_name}->{rule_count}->{$child_rule_name} > 1) {
1600 7         322 $to_return{$child_rule_name} = 1;
1601             }
1602             else {
1603 53         125 $to_return{$child_rule_name} = 0;
1604             }
1605             }
1606 32         107 return \%to_return;
1607             }
1608              
1609             sub set_up_full_rule_set {
1610 158     158 0 268 my $self = shift;
1611 158         319 my $rules_to_set_up_hash = shift;
1612 158         239 my $parameters = shift;
1613 158         372 my $start_rule = $parameters->{start_rule};
1614              
1615 158 100       8961 if (scalar keys %$rules_to_set_up_hash) {
1616 157         1132 foreach my $hash_rule_name (sort keys %$rules_to_set_up_hash) {
1617 778         3628 $self->add_rule({rule_name => $hash_rule_name,
1618             rule_definition => $rules_to_set_up_hash->{$hash_rule_name}});
1619             }
1620             }
1621              
1622 155 100       578 if (!defined $start_rule) {
1623 98         263 my %covered_rule;
1624 98         177 foreach my $rule_name (keys %{$self->{rule}}) {
  98         1092  
1625 1192         1349 foreach my $subrule
  1192         3444  
1626             (@{$self->{rule}->{$rule_name}->{subrule_list}}) {
1627 1367 100       3702 if ($subrule->{name} ne $self->{rule}->{$rule_name}->{base_rule}) {
1628 1355         4556 $covered_rule{$subrule->{name}}++;
1629             }
1630             }
1631             }
1632 98         273 START: foreach my $rule_name (keys %{$self->{rule}}) {
  98         720  
1633 672 100       1353 if (!$covered_rule{$rule_name}) {
1634 96         154 $start_rule = $rule_name;
1635 96         340 last START;
1636             }
1637             }
1638 98 100       517 if (!defined $start_rule) {croak "No valid start rule"};
  2         401  
1639             }
1640              
1641 153         986 my @missing_rules = $self->make_sure_all_names_covered({return_list=>1});
1642 153 100       619 if ($#missing_rules > -1) {
1643 1         232 croak "Missing rules: ".join("\n",@missing_rules)."\n";
1644             }
1645              
1646 152 50       540 if (!$self->{unreachable_rules_allowed}) {
1647 152         777 my @unreachable_rules = $self->make_sure_all_rules_reachable({
1648             start_rule=>$start_rule});
1649 152 100       667 if ($#unreachable_rules > -1) {
1650 2         498 croak "Unreachable rules: ".join("\n",@unreachable_rules)."\n";
1651             }
1652             }
1653              
1654 150         803 $self->look_for_left_recursion;
1655 147         697 $self->{start_rule} = $start_rule;
1656              
1657             }
1658              
1659             sub look_for_left_recursion {
1660 150     150 0 263 my $self = shift;
1661 150         305 my %checked_rules;
1662 150         246 foreach my $rule (keys %{$self->{rule}}) {
  150         616  
1663 1616 50       3301 if ($checked_rules{$rule}) {next};
  0         0  
1664 1616         2421 my $current_rule = $rule;
1665 1616         1872 my $moving_down = 1;
1666 1616         1650 my %active_rules;
1667             my @active_rules;
1668 1616         1865 my $previous_allows_zero = 0;
1669 1616         8817 while (defined $current_rule) {
1670 10998 100       18254 if ($moving_down) {
1671 4970 100       11703 if ($active_rules{$current_rule}++) {
1672 3         546 croak "Left recursion in grammar: ".
1673             join(" leads to ", @active_rules, $current_rule);
1674             }
1675 4967         7052 push @active_rules, $current_rule;
1676 4967 100 66     24653 if ($checked_rules{$current_rule}
1677             || $self->{rule}->{$current_rule}->{leaf_rule}) {
1678 2678         5742 $moving_down = 0;
1679             }
1680             else {
1681 2289         3033 $active_rules{$current_rule} = 1;
1682 2289 100       5616 if ($self->{rule}->{$current_rule}->{multiple_rule}) {
1683 318         1026 $current_rule = $self->{rule}->{$current_rule}->{sub_rule_name};
1684             }
1685             else {
1686 1971         7069 $current_rule =
1687             $self->{rule}->{$current_rule}->{subrule_list}->[0]->{name};
1688             }
1689             }
1690             }
1691             else {
1692 6028 100       10951 if ($previous_allows_zero) {
1693 107 100 100     893 if ($self->{rule}->{$current_rule}->{multiple_rule} ||
    100 100        
1694             $self->{rule}->{$current_rule}->{or_rule}) {
1695 46         114 $self->{rule}->{$current_rule}->{zero} = 1;
1696             }
1697             elsif ($self->{rule}->{$current_rule}->{and_rule} &&
1698             ($active_rules{$current_rule} ==
1699             $self->{rule}->{$current_rule}->{subrule_list_count})) {
1700 10         31 $self->{rule}->{$current_rule}->{zero} = 1;
1701             }
1702             else {
1703 51         78 $previous_allows_zero = 0;
1704             }
1705             }
1706 6028 100 100     49707 if ($self->{rule}->{$current_rule}->{multiple_rule} ||
    100 66        
    100          
1707             $self->{rule}->{$current_rule}->{leaf_rule} ||
1708             $checked_rules{$current_rule}) {
1709 2996         4601 delete $active_rules{$current_rule};
1710 2996   100     11515 $previous_allows_zero = $self->{rule}->{$current_rule}->{zero} || 0;
1711 2996         3487 pop @active_rules;
1712 2996         9319 $current_rule = $active_rules[-1];
1713             }
1714             elsif ($active_rules{$current_rule} ==
1715             $self->{rule}->{$current_rule}->{subrule_list_count}) {
1716 584   100     2318 $previous_allows_zero = $self->{rule}->{$current_rule}->{zero} || 0;
1717 584         1915 delete $active_rules{$current_rule};
1718 584         679 pop @active_rules;
1719 584         1673 $current_rule = $active_rules[-1];
1720             }
1721             elsif ($self->{rule}->{$current_rule}->{and_rule}) {
1722 1473         3969 my $previous_rule =
1723             $self->{rule}->{$current_rule}->{subrule_list}->
1724             [$active_rules{$current_rule}-1]->{name};
1725 1473 100 66     10186 if ((defined $self->{rule}->{$previous_rule}->{zero} &&
      100        
      66        
1726             $self->{rule}->{$previous_rule}->{zero}) ||
1727             ($self->{rule}->{$previous_rule}->{multiple_rule} &&
1728             $self->{rule}->{$previous_rule}->{minimum_child} == 0)) {
1729 90         259 $current_rule =
1730             $self->{rule}->{$current_rule}->{subrule_list}->
1731             [$active_rules{$current_rule}++]->{name};
1732 90         236 $moving_down = 1;
1733             }
1734             else {
1735 1383   50     5735 $previous_allows_zero = $self->{rule}->{$current_rule}->{zero} || 0;
1736 1383         2061 delete $active_rules{$current_rule};
1737 1383         2157 pop @active_rules;
1738 1383         4290 $current_rule = $active_rules[-1];
1739             }
1740             }
1741             else {
1742 975         2862 $current_rule =
1743             $self->{rule}->{$current_rule}->{subrule_list}->
1744             [$active_rules{$current_rule}++]->{name};
1745 975         2185 $moving_down = 1;
1746             }
1747             }
1748             }
1749             }
1750             }
1751              
1752             sub new_unevaluate_tree_node {
1753 461     461 0 531 my $self = shift;
1754 461         520 my $parameters = shift;
1755 461         677 my $node = $parameters->{node};
1756 461         597 my $rules_details = $self->{rule};
1757 461         561 my $rule_name = $node->{name};
1758 461         701 my $rule = $rules_details->{$rule_name};
1759 461         618 my $subroutine_to_run = $rule->{parsing_unevaluation};
1760 461         708 my $params_to_eval = $node->{__parameters};
1761              
1762 461 100       1089 if ($rule->{use_parse_match}) {
1763 187         325 $params_to_eval = $node->{parse_match};
1764             }
1765              
1766 461 100       868 if (defined $subroutine_to_run) {
1767 3         4 my $parse_hash = $parameters->{parse_hash};
1768 3         6 delete $parse_hash->{current_position};
1769 3         7 delete $parse_hash->{rule_name};
1770 3         6 $parse_hash->{current_node} = $node;
1771 3         8 &$subroutine_to_run($params_to_eval, $parse_hash);
1772 3         11 delete $parse_hash->{current_node};
1773             }
1774              
1775 461         449 my $parent;
1776 461 50       1131 if ($parent = $node->{parent}) {
1777              
1778 461         506 foreach my $param (keys %{$node->{passed_params}}) {
  461         1436  
1779 484 100       1106 if (my $count = $node->{passed_params}->{$param}) {
1780 246 50       310 if ($count > scalar(@{$parent->{__parameters}->{$param}})) {
  246         733  
1781 0         0 croak("Unevaluation parameter miscount; rule $rule_name p: $param");
1782             }
1783 246         324 splice(@{$parent->{__parameters}->{$param}}, - $count);
  246         865  
1784             }
1785             else {
1786 238         784 delete $parent->{__parameters}->{$param};
1787             }
1788             }
1789 461         1682 delete $node->{passed_params};
1790             }
1791             }
1792              
1793             sub MATCHED_STRING {
1794 64     64 1 157 my $parse_hash = shift;
1795 64         91 my $node = $parse_hash->{current_node};
1796 64         65 return substr(${$parse_hash->{parse_this_ref}},
  64         1575  
1797             $node->{position_when_entered},
1798             $node->{position_when_completed} - $node->{position_when_entered});
1799             }
1800              
1801             sub new_evaluate_tree_node {
1802 1531     1531 0 2191 my $self = shift;
1803 1531         1964 my $parameters = shift;
1804 1531         2415 my $nodes = $parameters->{nodes};
1805 1531         2605 my $rules_details = $self->{rule};
1806 1531         1728 my @results;
1807              
1808 1531         2072 my $parse_hash = $parameters->{parse_hash};
1809 1531         13219 foreach my $node (@$nodes) {
1810 8157         13417 my $rule_name = $node->{name};
1811 8157         11071 my $params_to_eval = $node->{__parameters};
1812 8157         11933 my $rule = $rules_details->{$rule_name};
1813 8157         10488 my $subroutine_to_run = $rule->{parsing_evaluation};
1814              
1815 8157 100       20059 if ($rule->{use_parse_match}) {
    100          
1816 3529         14512 $params_to_eval = $node->{parse_match};
1817             }
1818             elsif ($rule->{use_string_match}) {
1819 9         12 $params_to_eval = substr(${$parse_hash->{parse_this_ref}},
  9         72  
1820             $node->{position_when_entered},
1821             $node->{position_when_completed} - $node->{position_when_entered});
1822             }
1823 8157         12147 my $alias = $node->{alias};
1824              
1825 8157         8139 my $cv;
1826 8157 100       12627 if ($subroutine_to_run) {
1827 1556         3009 $parse_hash->{rule_name} = $rule_name;
1828 1556         7941 $parse_hash->{current_node} = $node;
1829 1556         6581 @results = &$subroutine_to_run($params_to_eval, $parse_hash);
1830 1555         10828 $cv = $results[0];
1831             }
1832             else {
1833 6601 100 100     31941 if ($rule->{generated} || $self->{do_not_compress_eval}) {
    100 100        
1834 4410         6188 $cv = $params_to_eval;
1835             }
1836             elsif ((ref $params_to_eval eq 'HASH') && (keys %$params_to_eval == 1)) {
1837 1256         2755 ($cv) = values %$params_to_eval;
1838             }
1839             else {
1840 935         1338 $cv = $params_to_eval;
1841             }
1842             }
1843 8156         17016 $node->{computed_value} = $cv;
1844              
1845 8156         7916 my $parent;
1846 8156 100       19583 if ($parent = $node->{parent}) {
1847 7804         11287 my $parent_name = $parent->{name};
1848              
1849 7804 100       12472 if (defined $alias) {
1850 5855 100       17171 if ($rules_details->{$parent_name}->{rule_count}->{$alias} > 1) {
1851 2311         2380 push @{$parent->{__parameters}->{$alias}}, $cv;
  2311         9766  
1852 2311         9705 $node->{passed_params}->{$alias} = 1;
1853             }
1854             else {
1855 3544         9766 $parent->{__parameters}->{$alias} = $cv;
1856 3544         30148 $node->{passed_params}->{$alias} = 0;
1857             }
1858             }
1859             else { # !defined alias
1860 1949         6254 foreach my $key (keys %$cv) {
1861 2429 100       9628 if ($rules_details->{$rule_name}->{rule_count}->{$key} > 1) {
    100          
1862 579 100       743 if (scalar(@{$cv->{$key}})) {
  579         1545  
1863 553         671 push @{$parent->{__parameters}->{$key}}, @{$cv->{$key}};
  553         1424  
  553         1432  
1864 553         1030 $node->{passed_params}->{$key} = scalar(@{$cv->{$key}});
  553         2545  
1865             }
1866             }
1867             elsif ($rules_details->{$parent_name}->{rule_count}->{$key} > 1) {
1868 1312         1284 push @{$parent->{__parameters}->{$key}}, $cv->{$key};
  1312         3728  
1869 1312         11265 $node->{passed_params}->{$key} = 1;
1870             }
1871             else {
1872 538         1304 $parent->{__parameters}->{$key} = $cv->{$key};
1873 538         2069 $node->{passed_params}->{$key} = 0;
1874             }
1875             }
1876             }
1877             }
1878             }
1879 1530         3894 delete $parse_hash->{current_node};
1880              
1881 1530         5105 return $results[1];
1882             }
1883              
1884             sub LOCATION {
1885 5     5 1 27 my ($text_ref, $value) = @_;
1886 5 50       19 if (ref $text_ref ne 'SCALAR') {
1887 0         0 croak "First arg to LOCATION must be string ref";
1888             }
1889 5         16 my $substring = substr($$text_ref,0,$value+1);
1890 5         17 my $line_number = 1 + ($substring =~ tr/\n//);
1891 5         340 $substring =~ /([^\n]*)$/;
1892 5         12 my $line_position = length($1);
1893 5         24 return ($line_number, $line_position);
1894             }
1895              
1896             sub parse_forward {
1897 0     0 0   my $parse_hash = shift;
1898            
1899             }
1900              
1901             1;
1902              
1903             __END__