File Coverage

blib/lib/FLAT/Legacy/FA/PRE.pm
Criterion Covered Total %
statement 249 305 81.6
branch 82 124 66.1
condition 5 6 83.3
subroutine 37 48 77.0
pod 0 42 0.0
total 373 525 71.0


line stmt bran cond sub pod time code
1             # $Revision: 1.5 $ $Date: 2006/03/02 21:00:28 $ $Author: estrabd $
2              
3             package FLAT::Legacy::FA::PRE;
4              
5 2     2   2645 use base 'FLAT::Legacy::FA';
  2         3  
  2         134  
6 2     2   8 use strict;
  2         14  
  2         33  
7 2     2   6 use Carp;
  2         3  
  2         116  
8              
9 2     2   9 use FLAT::Legacy::FA::PFA;
  2         3  
  2         40  
10 2     2   6 use Data::Dumper;
  2         3  
  2         4808  
11              
12             sub new {
13 3     3 0 14 my $class = shift;
14 3         54 bless {
15             _CAT_STATE => 0,
16             _CURRENT_STR => [],
17             _DONE => 0,
18             _EPSILON => 'epsilon',
19             _ERROR => 0,
20             _FOLLOW_POS => {},
21             _LOOKAHEAD => '',
22             _OR_STATE => 0,
23             _PARSE_TREE => undef,
24             _POS_COUNT => 0,
25             _PRE_END_SYMBOL => '#',
26             _PRE => '',
27             _SYMBOL_POS => [],
28             _TERMINALS => [qw(a b c d e f g h i j k l m n o p q r s t u v w x y z
29             A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
30             0 1 2 3 4 5 6 7 8 9 + - = ? [ ] { } . ~ ^ @ % $ :
31             ; < >)],
32             _TRACE => 0,
33             _SYMBOLS => [],
34             }, $class;
35             }
36              
37             sub set_epsilon {
38 0     0 0 0 my $self = shift;
39 0         0 my $e = shift;
40 0         0 chomp($e);
41 0         0 $self->{_EPSILON} = $e;
42 0         0 return;
43             }
44              
45             sub get_epsilon_symbol {
46 2     2 0 3 my $self = shift;
47 2         6 return $self->{_EPSILON};
48             }
49              
50             sub set_pre {
51 77     77 0 73960 my $self = shift;
52 77         104 my $pre = shift;
53 77         153 chomp($pre);
54             # reset stuff
55 77         194 $self->{_CAT_STATE} = 0;
56 77         170 $self->{_CURRENT_STR} = [];
57 77         376 $self->{_DONE} = 0;
58 77         191 $self->{_ERROR} = 0;
59 77         131 $self->{_FOLLOW_POS} = {};
60 77         179 $self->{_LOOKAHEAD} = '';
61 77         116 $self->{_OR_STATE} = 0;
62 77         172 $self->{_PARSE_TREE} = undef;
63 77         1267 $self->{_POS_COUNT} = 0;
64 77         145 $self->{_SYMBOL_POS} = [];
65 77         262 $self->{_TRACE} = 0;
66 77         118 $self->{_SYMBOLS} = [];
67 77         160 $self->{_PRE} = $pre;
68             # load up current string stack
69 77         232 $self->set_current($pre);
70 77         231 my @re = split(//,$pre);
71             # load up symbol position stack, and store unique terminal symbols encountered
72 77         175 foreach (@re) {
73 713 100       893 if ($self->is_terminal($_)) {
74 519         357 push(@{$self->{_SYMBOL_POS}},$_);
  519         650  
75 519 100       495 if (!$self->is_member($_,@{$self->{_SYMBOLS}})) {
  519         724  
76 152         125 push(@{$self->{_SYMBOLS}},$_);
  152         590  
77             }
78             }
79             }
80 77         99 push(@{$self->{_SYMBOL_POS}},$self->{_PRE_END_SYMBOL});
  77         134  
81 77         190 return;
82             }
83              
84             sub get_pre {
85 77     77 0 64 my $self = shift;
86 77         138 return $self->{_PRE};
87             }
88              
89             sub set_current {
90 77     77 0 92 my $self = shift;
91 77         91 my $pre = shift;
92 77         85 chomp($pre);
93 77         107 @{$self->{_CURRENT_STR}} = split(//,$pre);
  77         1700  
94 77         118 return;
95             }
96              
97             sub reset_current {
98 77     77 0 91 my $self = shift;
99 77         182 @{$self->{_CURRENT_STR}} = split(//,$self->get_pre());
  77         265  
100 77         107 return;
101             }
102              
103             sub get_current {
104 0     0 0 0 my $self = shift;
105 0         0 return $self->{_CURRENT_STR};
106             }
107              
108             sub to_pfa {
109 77     77 0 378 my $self = shift;
110             # parse re if _PARSE_TREE is not defined
111 77 50       278 if (!defined($self->{_PARSE_TREE})) {
112 77         218 $self->parse();
113             }
114             # sync PFA's epsilon symbol with RE's
115 77         166 my $PFA = $self->thompson($self->get_parse_tree());
116             # find and store tied nodes
117 77         231 $PFA->find_tied();
118 77         355 return $PFA;
119             }
120              
121             sub thompson {
122 1170     1170 0 1016 my $self = shift;
123 1170         891 my $tree = shift;
124 1170         817 my $PFA_l = undef;
125 1170         832 my $PFA_r = undef;
126 1170 100       1797 if ($tree->{symbol} ne $self->{_PRE_END_SYMBOL}) {
127             # dive into tree recursively_RE_END_SYMBOL
128             # go left
129 1093 100       1334 if (defined($tree->{left}) ) {
130 572         737 $PFA_l = $self->thompson($tree->{left});
131             }
132             # go right
133 1093 100       1636 if (defined($tree->{right})) {
134 521         960 $PFA_r = $self->thompson($tree->{right});
135             }
136             # kleene - terminal always returned from left
137 1093 100 100     3050 if (defined($PFA_l) && $tree->{symbol} eq '*') {
138 51         146 $PFA_l->kleene();
139             }
140             # Checks to see if current node is a leaf or not
141 1093 100 66     2862 if (defined($tree->{pos})) {
    100          
142             # create a minimal PFA with 1 symbol,
143 521         1255 $PFA_l = FLAT::Legacy::FA::PFA->jump_start($tree->{symbol});
144             } elsif(defined($PFA_l) && defined($PFA_r)) {
145             # ORs, Interleaves (ANDs) and CATs
146 444 100       1106 if ($tree->{symbol} eq '|') { # or
    100          
    50          
147 51         168 $PFA_l->or_pfa($PFA_r);
148             } elsif ($tree->{symbol} eq '&') { # interleave (and)
149 54         142 $PFA_l->interleave_pfa($PFA_r);
150             } elsif ($tree->{symbol} eq '.') { # cat
151 339         654 $PFA_l->append_pfa($PFA_r);
152             }
153             }
154             }
155 1170         2713 return $PFA_l;
156             }
157              
158             ################################################################
159             # Recursive Descent routines - parse tree is constructed here #
160             ################################################################
161              
162             sub parse {
163 77     77 0 107 my $self = shift;
164             # load up first lookahead char
165 77         258 $self->nexttoken();
166             # PARSE
167 77         161 $self->set_parse_tree($self->R());
168 77         194 $self->cat_endmarker();
169 77         187 $self->reset_current();
170 77         67 return;
171             }
172              
173             sub cat_endmarker {
174 77     77 0 95 my $self = shift;
175 77         192 $self->{_PARSE_TREE} = {symbol=>'.',left=>$self->{_PARSE_TREE},right=>{symbol=>$self->{_PRE_END_SYMBOL},pos=>$self->get_next_pos()}};
176 77         87 return;
177             }
178              
179             sub match {
180 713     713 0 480 my $self = shift;
181 713         482 my $match = shift;
182 713         549 chomp($match);
183 713 50       1300 if ($self->{_TRACE}) {print "match!: '$match'\n"};
  0         0  
184 713 50       707 if ($self->lookahead() eq $match) {
185 713         790 $self->nexttoken();
186             } else {
187 0         0 $self->set_error();
188 0         0 $self->set_done();
189             }
190             # returns the symbol passed to it.
191 713         561 return $match;
192             }
193              
194             sub lookahead {
195 3332     3332 0 2063 my $self = shift;
196 3332         3890 return $self->{_LOOKAHEAD};
197             }
198              
199             sub nexttoken {
200 790     790 0 531 my $self = shift;
201 790         673 $self->{_LOOKAHEAD} = '';
202 790 100       623 if (@{$self->{_CURRENT_STR}}) {
  790         1145  
203 713         441 $self->{_LOOKAHEAD} = shift(@{$self->{_CURRENT_STR}});
  713         812  
204             }
205 790         672 return;
206             }
207              
208             sub R {
209 96     96 0 95 my $self = shift;
210 96         91 my $tree = undef;
211 96 50       183 if ($self->{_TRACE}) {print ">R "};
  0         0  
212 96 50       240 if (!$self->done()) {
213 96         199 $tree = $self->P();
214             }
215 96 50       166 if ($self->{_TRACE}) {print "R> "};
  0         0  
216 96         193 return $tree;
217             }
218              
219             sub P {
220 96     96 0 110 my $self = shift;
221 96         94 my $tree = shift;
222 96 50       186 if ($self->{_TRACE}) {print ">P "};
  0         0  
223 96 50       113 if (!$self->done()) {
224 96         239 $tree = $self->O();
225 96         144 $tree = $self->P_prime($tree);
226             }
227 96 50       190 if ($self->{_TRACE}) {print "P> "};
  0         0  
228 96         134 return $tree;
229             }
230              
231             sub P_prime {
232 150     150 0 107 my $self = shift;
233 150         120 my $tree = shift;
234 150 50       225 if ($self->{_TRACE}) {print ">P' "};
  0         0  
235             # first rule that contains a terminal symbol
236 150         187 my $look = $self->lookahead();
237 150 50       224 if (!$self->done()) {
238 150 100       246 if ($look eq '&') {
239 54         91 $self->match('&');
240             # handles epsilon "and"
241 54 50       105 if (!defined($tree)) {
242 0         0 $tree = {symbol=>$self->get_epsilon_symbol(),pos=>-1};
243             }
244 54         110 my $O = $self->O();
245 54 50       101 if (defined($O)) {
246 54         126 $tree = {symbol=>'&',left=>$tree,right=>$O};
247             } else {
248 0         0 $tree = {symbol=>'&',left=>$tree,right=>{symbol=>$self->get_epsilon_symbol(),pos=>-1}};
249             }
250 54         120 $tree = $self->P_prime($tree);
251             }
252             }
253 150 50       258 if ($self->{_TRACE}) {print "P'> "};
  0         0  
254 150         174 return $tree;
255             }
256              
257             sub O {
258 150     150 0 130 my $self = shift;
259 150         106 my $tree = shift;
260 150 50       223 if ($self->{_TRACE}) {print ">O "};
  0         0  
261 150 50       212 if (!$self->done()) {
262 150         305 $tree = $self->C();
263 150         249 $tree = $self->O_prime($tree);
264             }
265 150 50       248 if ($self->{_TRACE}) {print "O> "};
  0         0  
266 150         142 return $tree;
267             }
268              
269             sub O_prime {
270 201     201 0 162 my $self = shift;
271 201         189 my $tree = shift;
272 201 50       293 if ($self->{_TRACE}) {print ">O' "};
  0         0  
273             # first rule that contains a terminal symbol
274 201         271 my $look = $self->lookahead();
275 201 50       268 if (!$self->done()) {
276 201 100       334 if ($look eq '|') {
277 51         96 $self->match('|');
278             # handles epsilon "or"
279 51 50       107 if (!defined($tree)) {
280 0         0 $tree = {symbol=>$self->get_epsilon_symbol(),pos=>-1};
281             }
282 51         95 my $C = $self->C();
283 51 50       90 if (defined($C)) {
284 51         149 $tree = {symbol=>'|',left=>$tree,right=>$C};
285             } else {
286 0         0 $tree = {symbol=>'|',left=>$tree,right=>{symbol=>$self->get_epsilon_symbol(),pos=>-1}};
287             }
288 51         122 $tree = $self->O_prime($tree);
289             }
290             }
291 201 50       350 if ($self->{_TRACE}) {print "O'> "};
  0         0  
292 201         187 return $tree;
293             }
294              
295             sub C {
296 201     201 0 184 my $self = shift;
297 201         169 my $tree = shift;
298 201 50       354 if ($self->{_TRACE}) {print ">C "};
  0         0  
299 201 50       268 if (!$self->done()) {
300 201         368 $tree = $self->S();
301 201         302 $tree = $self->C_prime($tree);
302             }
303 201 50       337 if ($self->{_TRACE}) {print "C> "};
  0         0  
304 201         197 return $tree;
305             }
306              
307             sub C_prime {
308 739     739 0 565 my $self = shift;
309 739         508 my $tree = shift;
310 739 50       895 if ($self->{_TRACE}) {print ">C' "};
  0         0  
311 739         827 my $look = $self->lookahead();
312 739 50       917 if (!$self->done()) {
313 739 100       730 if ($self->get_cat_state() == 1) {
314 538         571 $self->toggle_cat_state();
315 538         537 my $S = $self->S();
316 538 50       687 if (defined($tree)) {
317 538 100       710 if (defined($S)) {
318 339         616 $tree = {symbol=>'.',left=>$tree,right=>$S};
319             }
320             } else {
321 0 0       0 if (defined($S)) {
322 0         0 $tree = $S;
323             }
324             }
325 538         748 $tree = $self->C_prime($tree);
326             }
327             }
328 739 50       900 if ($self->{_TRACE}) {print "C'> "};
  0         0  
329 739         751 return $tree;
330             }
331              
332             sub S {
333 739     739 0 488 my $self = shift;
334 739         499 my $tree = shift;
335 739 50       985 if ($self->{_TRACE}) {print ">S "};
  0         0  
336 739 50       777 if (!$self->done()) {
337 739         1072 $tree = $self->L($tree);
338 739         936 $tree = $self->S_prime($tree);
339             }
340 739 50       980 if ($self->{_TRACE}) {print "S> "};
  0         0  
341 739         646 return $tree;
342             }
343              
344             sub S_prime {
345 790     790 0 609 my $self = shift;
346 790         574 my $tree = shift;
347 790 50       972 if ($self->{_TRACE}) {print ">S' "};
  0         0  
348 790         790 my $look = $self->lookahead();
349 790 50       798 if (!$self->done()) {
350 790 100       1053 if ($look eq '*') {
351 51         81 $self->match('*');
352 51         102 $tree = {symbol=>'*',left=>$self->S_prime($tree),right=>undef};
353             }
354             }
355 790 50       967 if ($self->{_TRACE}) {print "S'> "};
  0         0  
356 790         703 return $tree;
357             }
358              
359             sub L {
360 739     739 0 503 my $self = shift;
361 739         490 my $tree = shift;
362 739 50       986 if ($self->{_TRACE}) {print ">L "};
  0         0  
363 739         799 my $term = $self->lookahead();
364 739 50       810 if (!$self->done()) {
365 739 100       865 if ($term eq '(') {
366 19         28 $self->match('(');
367 19         34 $tree = $self->R();
368 19         30 $self->match(')');
369 19 100       41 if (!defined($tree)) {
370 2         8 $tree = {symbol=>$self->get_epsilon_symbol(),pos=>-1};
371             }
372 19         35 $self->toggle_cat_state();
373             } else {
374 720         812 foreach my $terminal ($self->get_terminals()) {
375 43828 100       47273 if ($term eq $terminal) {
376 519         642 $self->match($term);
377             #set position automatically
378 519         661 $tree = {symbol=>$term,pos=>$self->get_next_pos()};
379 519         645 $self->toggle_cat_state();
380 519         482 last;
381             }
382             }
383             }
384             }
385 739 50       2573 if ($self->{_TRACE}) {print "L> "};
  0         0  
386 739         616 return $tree;
387             }
388              
389             sub get_next_pos {
390 596     596 0 599 my $self = shift;
391 596         1181 return ++$self->{_POS_COUNT};
392             }
393              
394             sub get_curr_pos {
395 0     0 0 0 my $self = shift;
396 0         0 return $self->{_POS_COUNT};
397             }
398              
399             sub set_parse_tree {
400 77     77 0 70 my $self = shift;
401 77         98 $self->{_PARSE_TREE} = shift;
402 77         64 return;
403             }
404              
405             sub get_parse_tree {
406 77     77 0 96 my $self = shift;
407 77         169 return $self->{_PARSE_TREE};
408             }
409              
410             sub get_terminals {
411 1433     1433 0 956 my $self = shift;
412 1433         904 return @{$self->{_TERMINALS}};
  1433         9223  
413             }
414              
415             sub is_terminal {
416 713     713 0 540 my $self = shift;
417 713         834 return $self->is_member(shift,$self->get_terminals());
418             }
419              
420             sub is_member {
421 1232     1232 0 803 my $self = shift;
422 1232         1023 my $test = shift;
423 1232         762 my $ret = 0;
424 1232 50       1556 if (defined($test)) {
425             # This way to test if something is a member is significantly faster..thanks, PM!
426 1232 100       1089 if (grep {$_ eq $test} @_) {
  57782         45864  
427 886         584 $ret++;
428             }
429             # foreach (@_) {
430             # if (defined($_)) {
431             # if ($test eq $_) {
432             # $ret++;
433             # last;
434             # }
435             # }
436             # }
437             }
438 1232         3234 return $ret;
439             }
440              
441             sub get_symbols {
442 0     0 0 0 my $self = shift;
443 0         0 return @{$self->{_SYMBOLS}};
  0         0  
444             }
445              
446             sub trace_on {
447 0     0 0 0 my $self = shift;
448 0         0 $self->{_TRACE} = 1;
449 0         0 return;
450             }
451              
452             sub trace_off {
453 0     0 0 0 my $self = shift;
454 0         0 $self->{_TRACE} = 0;
455 0         0 return;
456             }
457              
458             sub trace {
459 0     0 0 0 my $self = shift;
460 0         0 return $self->{_TRACE};
461             }
462              
463             sub toggle_cat_state {
464 1076     1076 0 721 my $self = shift;
465 1076 100       1014 if ($self->get_cat_state == 0) {$self->{_CAT_STATE}++} else {$self->{_CAT_STATE} = 0};
  538         473  
  538         381  
466 1076         756 return;
467             }
468              
469             sub get_cat_state {
470 1815     1815 0 1212 my $self = shift;
471 1815         2238 return $self->{_CAT_STATE};
472             }
473              
474             sub set_error {
475 0     0 0 0 my $self = shift;
476 0         0 $self->{_ERROR}++;
477             }
478              
479             sub get_error {
480 0     0 0 0 my $self = shift;
481 0         0 return $self->{_ERROR};
482             }
483              
484             sub set_done {
485 0     0 0 0 my $self = shift;
486 0         0 $self->{_DONE}++;
487             }
488              
489             sub done {
490 3901     3901 0 2334 my $self = shift;
491 3901         5376 return $self->{_DONE};
492             }
493              
494             sub DESTROY {
495 0     0     return;
496             }
497              
498             1;
499              
500             __END__