File Coverage

blib/lib/FLAT/Legacy/FA/RE.pm
Criterion Covered Total %
statement 228 430 53.0
branch 70 170 41.1
condition 5 27 18.5
subroutine 36 56 64.2
pod 0 49 0.0
total 339 732 46.3


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::RE;
4              
5 3     3   14 use base 'FLAT::Legacy::FA';
  3         925  
  3         902  
6 3     3   15 use strict;
  3         3  
  3         62  
7 3     3   10 use Carp;
  3         4  
  3         158  
8              
9 3     3   13 use FLAT::Legacy::FA::NFA;
  3         4  
  3         48  
10 3     3   10 use FLAT::Legacy::FA::DFA;
  3         4  
  3         49  
11 3     3   10 use Data::Dumper;
  3         2  
  3         10339  
12              
13             sub new {
14 2     2 0 12 my $class = shift;
15 2         44 bless {
16             _CAT_STATE => 0,
17             _CURRENT_STR => [],
18             _DONE => 0,
19             _EPSILON => 'epsilon',
20             _ERROR => 0,
21             _FOLLOW_POS => {},
22             _LOOKAHEAD => '',
23             _OR_STATE => 0,
24             _PARSE_TREE => undef,
25             _POS_COUNT => 0,
26             _RE_END_SYMBOL => '#',
27             _RE => '',
28             _SYMBOL_POS => [],
29             _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
30             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
31             0 1 2 3 4 5 6 7 8 9 + - = ? & [ ] { } . ~ ^ @ % $
32             : ; < >)],
33             _TRACE => 0,
34             _SYMBOLS => [],
35             }, $class;
36             }
37              
38             sub set_epsilon {
39 0     0 0 0 my $self = shift;
40 0         0 my $e = shift;
41 0         0 chomp($e);
42 0         0 $self->{_EPSILON} = $e;
43 0         0 return;
44             }
45              
46             sub get_epsilon_symbol {
47 1     1 0 2 my $self = shift;
48 1         5 return $self->{_EPSILON};
49             }
50              
51             sub set_re {
52 43     43 0 41447 my $self = shift;
53 43         83 my $re = shift;
54 43         92 chomp($re);
55             # reset stuff
56 43         106 $self->{_CAT_STATE} = 0;
57 43         106 $self->{_CURRENT_STR} = [];
58 43         405 $self->{_DONE} = 0;
59 43         81 $self->{_ERROR} = 0;
60 43         79 $self->{_FOLLOW_POS} = {};
61 43         96 $self->{_LOOKAHEAD} = '';
62 43         72 $self->{_OR_STATE} = 0;
63 43         63 $self->{_PARSE_TREE} = undef;
64 43         1670 $self->{_POS_COUNT} = 0;
65 43         109 $self->{_SYMBOL_POS} = [];
66 43         233 $self->{_TRACE} = 0;
67 43         61 $self->{_SYMBOLS} = [];
68 43         94 $self->{_RE} = $re;
69             # load up current string stack
70 43         150 $self->set_current($re);
71 43         249 my @re = split(//,$re);
72             # load up symbol position stack, and store unique terminal symbols encountered
73 43         99 foreach (@re) {
74 1504 100       1725 if ($self->is_terminal($_)) {
75 1176         824 push(@{$self->{_SYMBOL_POS}},$_);
  1176         1668  
76 1176 100       852 if (!$self->is_member($_,@{$self->{_SYMBOLS}})) {
  1176         1559  
77 84         73 push(@{$self->{_SYMBOLS}},$_);
  84         352  
78             }
79             }
80             }
81 43         42 push(@{$self->{_SYMBOL_POS}},$self->{_RE_END_SYMBOL});
  43         73  
82 43         295 return;
83             }
84              
85             sub get_re {
86 43     43 0 75 my $self = shift;
87 43         65 return $self->{_RE};
88             }
89              
90             sub set_current {
91 43     43 0 61 my $self = shift;
92 43         59 my $re = shift;
93 43         48 chomp($re);
94 43         56 @{$self->{_CURRENT_STR}} = split(//,$re);
  43         988  
95 43         59 return;
96             }
97              
98             sub reset_current {
99 43     43 0 45 my $self = shift;
100 43         97 @{$self->{_CURRENT_STR}} = split(//,$self->get_re());
  43         323  
101 43         57 return;
102             }
103              
104             sub get_current {
105 0     0 0 0 my $self = shift;
106 0         0 return $self->{_CURRENT_STR};
107             }
108              
109             sub minimize {
110 0     0 0 0 my $self = shift;
111 0         0 return;
112             }
113              
114             sub shrink {
115 0     0 0 0 my $self = shift;
116              
117 0         0 return;
118             }
119              
120             sub to_nfa {
121 43     43 0 215 my $self = shift;
122             # parse re if _PARSE_TREE is not defined
123 43 50       109 if (!defined($self->{_PARSE_TREE})) {
124 43         118 $self->parse();
125             }
126             # sync NFA's epsilon symbol with RE's
127 43         99 my $NFA = $self->thompson($self->get_parse_tree());
128 43         205 return $NFA;
129             }
130              
131             sub thompson {
132 2529     2529 0 2037 my $self = shift;
133 2529         1947 my $tree = shift;
134 2529         1782 my $NFA_l = undef;
135 2529         1919 my $NFA_r = undef;
136 2529 100       4939 if ($tree->{symbol} ne $self->{_RE_END_SYMBOL}) {
137             # dive into tree recursively_RE_END_SYMBOL
138             # go left
139 2486 100       3526 if (defined($tree->{left}) ) {
140 1309         1983 $NFA_l = $self->thompson($tree->{left});
141             }
142             # go right
143 2486 100       4145 if (defined($tree->{right})) {
144 1177         2330 $NFA_r = $self->thompson($tree->{right});
145             }
146             # kleene - terminal always returned from left
147 2486 100 100     7114 if (defined($NFA_l) && $tree->{symbol} eq '*') {
148 132         381 $NFA_l->kleene();
149             }
150             # Checks to see if current node is a leaf or not
151 2486 100 66     6725 if (defined($tree->{pos})) {
    100          
152             # create a minimal NFA with 1 symbol,
153 1177         2840 $NFA_l = FLAT::Legacy::FA::NFA->jump_start($tree->{symbol});
154             } elsif(defined($NFA_l) && defined($NFA_r)) {
155             # ORs and CATs
156 1134 100       2542 if ($tree->{symbol} eq '|') { # or
    50          
157 112         368 $NFA_l->or_nfa($NFA_r);
158             } elsif ($tree->{symbol} eq '.') { # cat
159 1022         2041 $NFA_l->append_nfa($NFA_r);
160             }
161             }
162             }
163 2529         7955 return $NFA_l;
164             }
165              
166             #Currently BREAKS on a*(b|cd)m!!!!!!!!!!!!!!
167             sub to_dfa_BROKEN {
168 0     0 0 0 my $self = shift;
169             # parse re if _PARSE_TREE is not defined
170 0 0       0 if (!defined($self->{_PARSE_TREE})) {
171 0         0 $self->parse();
172             }
173             # calculate firstpos and lastpos, add to _PARSE_TREE`
174 0         0 my $pt = $self->lastpos($self->firstpos($self->get_parse_tree()));
175             # calculate follow positions
176 0         0 $self->followpos($pt);
177             #print Dumper($self->{_FOLLOW_POS});
178             # BEGIN SUBSET CONSTRUCTION - based on what is in NFA.pm
179 0         0 my @Dstates = (); # stack of new states to find transitions for
180             # New DFA object reference
181 0         0 my $DFA = FLAT::Legacy::FA::DFA->new();
182             # Initialize DFA start state by performing e-closure on the NFA start state
183 0         0 my @Start = @{$pt->{firstpos}};
  0         0  
184             # Add this state to Dstates - subsets stored as anonymous arrays (no faking here!)
185 0         0 push(@Dstates,[sort(@Start)]);
186             # Serialize subset into new state name - i.e, generate string-ified name
187 0         0 my $ns = join('_',@Start);
188             # Add start state to DFA (placeholder Dtran not used)
189 0         0 $DFA->set_start($ns);
190             # Add new state (serialized name) to DFA state array
191 0         0 $DFA->add_state($ns);
192             # Check if start state is also final state (i.e., contains state accepting '#'), if so add
193 0         0 foreach my $s (@Start) {
194 0 0 0     0 if ($s == ($#{$self->{_SYMBOL_POS}}+1) && !$DFA->is_final($ns)) {
  0         0  
195 0         0 $DFA->add_final($ns);
196             }
197             }
198             # Loop until Dstate stack is exhausted
199 0         0 while (@Dstates) {
200             # pop next state off to check
201 0         0 my @T = @{pop @Dstates};
  0         0  
202             # Serialize subset into a string name
203 0         0 my $CURR_STATE = join('_',@T);
204             # loop over each input symbol
205 0         0 foreach my $symbol ($self->get_symbols()) {
206             # Obviously do not add the epsilon symbol to the dfa
207             # Add symbol - add_symbol ensures set of symbols is unique
208 0         0 $DFA->add_symbol($symbol);
209             # Get new subset of transition states
210 0         0 my @new = $self->move($symbol,(@T));
211             # Serialize name of new state
212 0         0 $ns = join('_',@new);
213             # Add transition as long as $ns is not empty string
214 0 0       0 if ($ns !~ m/^$/) {
215 0         0 $DFA->add_transition($CURR_STATE,$symbol,$ns);
216             # Do only if this is a new state and it is not an empty string
217 0 0       0 if (!$DFA->is_state($ns)) {
218             # add subset to @Dstates as an anonymous array
219 0         0 push(@Dstates,[@new]);
220 0         0 $DFA->add_state($ns);
221             # check to see if any NFA final states are in
222             # the new DFA states
223 0         0 foreach my $s (@new) {
224 0 0 0     0 if ($s == ($#{$self->{_SYMBOL_POS}}+1) && !$DFA->is_final($ns)) {
  0         0  
225 0         0 $DFA->add_final($ns);
226             }
227             }
228             }
229             }
230             }
231             }
232 0         0 return $DFA;
233             }
234              
235             sub get_transition_on {
236 0     0 0 0 my $self = shift;
237 0         0 my $state = shift;
238 0         0 my $symbol = shift;
239 0         0 my @ret = undef;
240 0 0       0 if (@{$self->{_SYMBOL_POS}}[$state-1] eq $symbol) {
  0         0  
241 0         0 @ret = @{$self->{_FOLLOW_POS}->{$state}};
  0         0  
242             }
243 0         0 return @ret;
244             }
245              
246             sub move {
247 0     0 0 0 my $self = shift;
248 0         0 my $symbol = shift;
249 0         0 my @subset = @_; # could be one state, could be a sub set of states...
250 0         0 my @T = ();
251             # Loop over subset until exhausted
252 0         0 while (@subset) {
253             # get a state from the subset
254 0         0 my $state = pop @subset;
255             # get all transitions for $t, and put the in @u
256 0         0 my @u = $self->get_transition_on($state,$symbol);
257 0         0 foreach (@u) {
258 0 0       0 if (defined($_)) {
259             # Add to new subset if not there already
260 0 0       0 if (!$self->is_member($_,@T)) {
261 0         0 push(@T,$_);
262             }
263             }
264             }
265             }
266             # Returns ref to sorted subset array instead of list to preserve subset
267 0         0 return sort(@T);
268             }
269              
270             sub firstpos {
271 0     0 0 0 my $self = shift;
272 0         0 my $tree = shift;
273             # dive into tree recursively
274 0 0       0 if (defined($tree->{left}) ) {$self->firstpos($tree->{left});}
  0         0  
275 0 0       0 if (defined($tree->{right})) {$self->firstpos($tree->{right});}
  0         0  
276             # Denotes leaves - fp_nullable is false by definition
277 0 0       0 if (defined($tree->{pos})) {
278 0 0       0 if ($tree->{symbol} eq $self->get_epsilon_symbol()) {
279 0         0 $tree->{firstpos} = []; # empty anonymous array
280 0         0 $tree->{fp_nullable} = 1; # true by definition
281             } else {
282 0         0 $tree->{firstpos} = [$tree->{pos}]; # anonymous array
283 0         0 $tree->{fp_nullable} = 0; # false by definition
284             }
285             } else {
286             # All other nodes
287 0 0       0 if ($tree->{symbol} eq '|') { # or
    0          
    0          
288             # firstpos(left) UNION firstpos(right) - always
289 0         0 push(@{$tree->{firstpos}},@{$tree->{left}->{firstpos}},@{$tree->{right}->{firstpos}});
  0         0  
  0         0  
  0         0  
290             # determine fp_nullable-ness of this node
291 0         0 $tree->{fp_nullable} = 0;
292 0 0 0     0 if ($tree->{left}->{fp_nullable} == 1 || $tree->{right}->{fp_nullable} == 1) {
293             # set fp_nullable if either left or right trees are fp_nullable
294 0         0 $tree->{fp_nullable}++;
295             }
296             } elsif ($tree->{symbol} eq '.') { # cat
297             # determine firstpos
298 0 0       0 if ($tree->{left}->{fp_nullable} == 1) {
299 0         0 push(@{$tree->{firstpos}},@{$tree->{left}->{firstpos}},@{$tree->{right}->{firstpos}});
  0         0  
  0         0  
  0         0  
300             } else {
301 0         0 push(@{$tree->{firstpos}},@{$tree->{left}->{firstpos}});
  0         0  
  0         0  
302             }
303             # determine fp_nullable-ness of this node
304 0         0 $tree->{fp_nullable} = 0;
305 0 0 0     0 if ($tree->{left}->{fp_nullable} == 1 && $tree->{right}->{fp_nullable} == 1) {
306 0         0 $tree->{fp_nullable} = 1;
307             }
308             } elsif ($tree->{symbol} eq '*') { # kleene star (closure)
309 0         0 $tree->{fp_nullable} = 1;
310 0         0 push(@{$tree->{firstpos}},@{$tree->{left}->{firstpos}});
  0         0  
  0         0  
311             }
312             }
313 0         0 return $tree;
314             }
315              
316             sub lastpos {
317 0     0 0 0 my $self = shift;
318 0         0 my $tree = shift;
319             # dive into tree recursively
320 0 0       0 if (defined($tree->{left}) ) {$self->lastpos($tree->{left});}
  0         0  
321 0 0       0 if (defined($tree->{right})) {$self->lastpos($tree->{right});}
  0         0  
322             # Denotes leaves - lp_nullable is false by definition
323 0 0       0 if (defined($tree->{pos})) {
324 0 0       0 if ($tree->{symbol} eq $self->get_epsilon_symbol()) {
325 0         0 $tree->{lastpos} = []; # empty anonymous array
326 0         0 $tree->{lp_nullable} = 1; # true by definition
327             } else {
328 0         0 $tree->{lastpos} = [$tree->{pos}]; # anonymous array
329 0         0 $tree->{lp_nullable} = 0; # false by definition
330             }
331             } else {
332             # All other nodes
333 0 0       0 if ($tree->{symbol} eq '|') { # or
    0          
    0          
334             # lastpos(left) UNION lastpos(right) - always
335 0         0 push(@{$tree->{lastpos}},@{$tree->{left}->{lastpos}},@{$tree->{right}->{lastpos}});
  0         0  
  0         0  
  0         0  
336             # determine lp_nullable-ness of this node
337 0         0 $tree->{lp_nullable} = 0;
338 0 0 0     0 if ($tree->{left}->{lp_nullable} == 1 || $tree->{right}->{lp_nullable} == 1) {
339             # set lp_nullable if either left or right trees are lp_nullable
340 0         0 $tree->{lp_nullable} = 1;
341             }
342             } elsif ($tree->{symbol} eq '.') { # cat
343             # determine lastpos
344 0 0       0 if ($tree->{right}->{lp_nullable} == 1) {
345 0         0 push(@{$tree->{lastpos}},@{$tree->{left}->{lastpos}},@{$tree->{right}->{lastpos}});
  0         0  
  0         0  
  0         0  
346             } else {
347 0         0 push(@{$tree->{lastpos}},@{$tree->{right}->{lastpos}});
  0         0  
  0         0  
348             }
349             # determine lp_nullable-ness of this node
350 0         0 $tree->{lp_nullable} = 0;
351 0 0 0     0 if ($tree->{left}->{lp_nullable} == 1 && $tree->{right}->{lp_nullable} == 1) {
352 0         0 $tree->{lp_nullable}++;
353             }
354             } elsif ($tree->{symbol} eq '*') { # kleene star (closure)
355 0         0 $tree->{lp_nullable} = 1;
356 0         0 push(@{$tree->{lastpos}},@{$tree->{left}->{lastpos}});
  0         0  
  0         0  
357             }
358             }
359 0         0 return $tree;
360             }
361              
362             sub followpos {
363 0     0 0 0 my $self = shift;
364 0         0 my $tree = shift;
365 0 0       0 if (defined($tree->{left})) {
366 0         0 $self->followpos($tree->{left});
367             }
368 0 0       0 if (defined($tree->{right})) {
369 0         0 $self->followpos($tree->{right});
370             }
371             # Works on one, depth first traversal
372 0 0 0     0 if (!defined($tree->{pos}) && $tree->{symbol} ne '|') {
373 0 0       0 if ($tree->{symbol} eq '.') {
    0          
374 0         0 foreach (@{$tree->{left}->{lastpos}}) {
  0         0  
375 0         0 push(@{$self->{_FOLLOW_POS}{$_}},@{$tree->{right}->{lastpos}});
  0         0  
  0         0  
376             }
377             } elsif ($tree->{symbol} eq '*') {
378 0         0 foreach (@{$tree->{lastpos}}) {
  0         0  
379 0         0 push(@{$self->{_FOLLOW_POS}{$_}},@{$tree->{firstpos}});
  0         0  
  0         0  
380             }
381             }
382             }
383             }
384              
385             sub get_followpos {
386 0     0 0 0 my $self = shift;
387 0         0 return $self->{_FOLLOW_POS};
388             }
389              
390             ################################################################
391             # Recursive Descent routines - parse tree is constructed here #
392             ################################################################
393              
394             sub parse {
395 43     43 0 63 my $self = shift;
396             # load up first lookahead char
397 43         127 $self->nexttoken();
398             # PARSE
399 43         97 $self->set_parse_tree($self->R());
400 43         102 $self->cat_endmarker();
401 43         117 $self->reset_current();
402 43         53 return;
403             }
404              
405             sub cat_endmarker {
406 43     43 0 45 my $self = shift;
407 43         117 $self->{_PARSE_TREE} = {symbol=>'.',left=>$self->{_PARSE_TREE},right=>{symbol=>$self->{_RE_END_SYMBOL},pos=>$self->get_next_pos()}};
408 43         54 return;
409             }
410              
411             sub match {
412 1504     1504 0 1093 my $self = shift;
413 1504         1179 my $match = shift;
414 1504         1230 chomp($match);
415 1504 50       2021 if ($self->{_TRACE}) {print "match!: '$match'\n"};
  0         0  
416 1504 50       1666 if ($self->lookahead() eq $match) {
417 1504         1793 $self->nexttoken();
418             } else {
419 0         0 $self->set_error();
420 0         0 $self->set_done();
421             }
422             # returns the symbol passed to it.
423 1504         1192 return $match;
424             }
425              
426             sub lookahead {
427 6078     6078 0 4045 my $self = shift;
428 6078         7936 return $self->{_LOOKAHEAD};
429             }
430              
431             sub nexttoken {
432 1547     1547 0 1152 my $self = shift;
433 1547         1254 $self->{_LOOKAHEAD} = '';
434 1547 100       1020 if (@{$self->{_CURRENT_STR}}) {
  1547         2216  
435 1504         969 $self->{_LOOKAHEAD} = shift(@{$self->{_CURRENT_STR}});
  1504         1897  
436             }
437 1547         1687 return;
438             }
439              
440             sub R {
441 85     85 0 83 my $self = shift;
442 85         83 my $tree = undef;
443 85 50       160 if ($self->{_TRACE}) {print ">R "};
  0         0  
444 85 50       191 if (!$self->done()) {
445 85         183 $tree = $self->O();
446             }
447 85 50       445 if ($self->{_TRACE}) {print "R> "};
  0         0  
448 85         166 return $tree;
449             }
450              
451             sub O {
452 85     85 0 99 my $self = shift;
453 85         90 my $tree = shift;
454 85 50       179 if ($self->{_TRACE}) {print ">O "};
  0         0  
455 85 50       144 if (!$self->done()) {
456 85         187 $tree = $self->C();
457 85         173 $tree = $self->O_prime($tree);
458             }
459 85 50       142 if ($self->{_TRACE}) {print "O> "};
  0         0  
460 85         99 return $tree;
461             }
462              
463             sub O_prime {
464 197     197 0 207 my $self = shift;
465 197         172 my $tree = shift;
466 197 50       362 if ($self->{_TRACE}) {print ">O' "};
  0         0  
467             # first rule that contains a terminal symbol
468 197         237 my $look = $self->lookahead();
469 197 50       247 if (!$self->done()) {
470 197 100       332 if ($look eq '|') {
471 112         182 $self->match('|');
472             # handles epsilon "or"
473 112 50       205 if (!defined($tree)) {
474 0         0 $tree = {symbol=>$self->get_epsilon_symbol(),pos=>-1};
475             }
476 112         171 my $C = $self->C();
477 112 100       182 if (defined($C)) {
478 111         285 $tree = {symbol=>'|',left=>$tree,right=>$C};
479             } else {
480 1         5 $tree = {symbol=>'|',left=>$tree,right=>{symbol=>$self->get_epsilon_symbol(),pos=>-1}};
481             }
482 112         220 $tree = $self->O_prime($tree);
483             }
484             }
485 197 50       305 if ($self->{_TRACE}) {print "O'> "};
  0         0  
486 197         186 return $tree;
487             }
488              
489             sub C {
490 197     197 0 163 my $self = shift;
491 197         148 my $tree = shift;
492 197 50       319 if ($self->{_TRACE}) {print ">C "};
  0         0  
493 197 50       238 if (!$self->done()) {
494 197         375 $tree = $self->S();
495 197         285 $tree = $self->C_prime($tree);
496             }
497 197 50       319 if ($self->{_TRACE}) {print "C> "};
  0         0  
498 197         212 return $tree;
499             }
500              
501             sub C_prime {
502 1415     1415 0 1050 my $self = shift;
503 1415         965 my $tree = shift;
504 1415 50       1874 if ($self->{_TRACE}) {print ">C' "};
  0         0  
505 1415         1407 my $look = $self->lookahead();
506 1415 50       1413 if (!$self->done()) {
507 1415 100       1441 if ($self->get_cat_state() == 1) {
508 1218         1227 $self->toggle_cat_state();
509 1218         1250 my $S = $self->S();
510 1218 50       1895 if (defined($tree)) {
511 1218 100       1535 if (defined($S)) {
512 1022         2085 $tree = {symbol=>'.',left=>$tree,right=>$S};
513             }
514             } else {
515 0 0       0 if (defined($S)) {
516 0         0 $tree = $S;
517             }
518             }
519 1218         1784 $tree = $self->C_prime($tree);
520             }
521             }
522 1415 50       1806 if ($self->{_TRACE}) {print "C'> "};
  0         0  
523 1415         1279 return $tree;
524             }
525              
526             sub S {
527 1415     1415 0 1054 my $self = shift;
528 1415         1017 my $tree = shift;
529 1415 50       1834 if ($self->{_TRACE}) {print ">S "};
  0         0  
530 1415 50       1413 if (!$self->done()) {
531 1415         1642 $tree = $self->L($tree);
532 1415         1968 $tree = $self->S_prime($tree);
533             }
534 1415 50       1827 if ($self->{_TRACE}) {print "S> "};
  0         0  
535 1415         1352 return $tree;
536             }
537              
538             sub S_prime {
539 1547     1547 0 994 my $self = shift;
540 1547         987 my $tree = shift;
541 1547 50       1957 if ($self->{_TRACE}) {print ">S' "};
  0         0  
542 1547         1557 my $look = $self->lookahead();
543 1547 50       1854 if (!$self->done()) {
544 1547 100       2103 if ($look eq '*') {
545 132         168 $self->match('*');
546 132         185 $tree = {symbol=>'*',left=>$self->S_prime($tree),right=>undef};
547             }
548             }
549 1547 50       2207 if ($self->{_TRACE}) {print "S'> "};
  0         0  
550 1547         1519 return $tree;
551             }
552              
553             sub L {
554 1415     1415 0 976 my $self = shift;
555 1415         872 my $tree = shift;
556 1415 50       1824 if ($self->{_TRACE}) {print ">L "};
  0         0  
557 1415         1497 my $term = $self->lookahead();
558 1415 50       1435 if (!$self->done()) {
559 1415 100       1560 if ($term eq '(') {
560 42         67 $self->match('(');
561 42         85 $tree = $self->R();
562 42         79 $self->match(')');
563 42 50       94 if (!defined($tree)) {
564 0         0 $tree = {symbol=>$self->get_epsilon_symbol(),pos=>-1};
565             }
566 42         81 $self->toggle_cat_state();
567             } else {
568 1373         1460 foreach my $terminal ($self->get_terminals()) {
569 78877 100       89657 if ($term eq $terminal) {
570 1176         1583 $self->match($term);
571             #set position automatically
572 1176         1391 $tree = {symbol=>$term,pos=>$self->get_next_pos()};
573 1176         1357 $self->toggle_cat_state();
574 1176         1094 last;
575             }
576             }
577             }
578             }
579 1415 50       5334 if ($self->{_TRACE}) {print "L> "};
  0         0  
580 1415         1325 return $tree;
581             }
582              
583             sub get_next_pos {
584 1219     1219 0 921 my $self = shift;
585 1219         2606 return ++$self->{_POS_COUNT};
586             }
587              
588             sub get_curr_pos {
589 0     0 0 0 my $self = shift;
590 0         0 return $self->{_POS_COUNT};
591             }
592              
593             sub set_parse_tree {
594 43     43 0 38 my $self = shift;
595 43         49 $self->{_PARSE_TREE} = shift;
596 43         31 return;
597             }
598              
599             sub get_parse_tree {
600 43     43 0 42 my $self = shift;
601 43         97 return $self->{_PARSE_TREE};
602             }
603              
604             sub get_terminals {
605 2877     2877 0 2091 my $self = shift;
606 2877         1827 return @{$self->{_TERMINALS}};
  2877         19596  
607             }
608              
609             sub is_terminal {
610 1504     1504 0 997 my $self = shift;
611 1504         1629 return $self->is_member(shift,$self->get_terminals());
612             }
613              
614             sub is_member {
615 2680     2680 0 1825 my $self = shift;
616 2680         1799 my $test = shift;
617 2680         1720 my $ret = 0;
618 2680 50       3270 if (defined($test)) {
619             # This way to test if something is a member is significantly faster..thanks, PM!
620 2680 100       2511 if (grep {$_ eq $test} @_) {
  124016         104895  
621 2268         1464 $ret++;
622             }
623             }
624 2680         7850 return $ret;
625             }
626              
627             sub get_symbols {
628 0     0 0 0 my $self = shift;
629 0         0 return @{$self->{_SYMBOLS}};
  0         0  
630             }
631              
632             sub trace_on {
633 0     0 0 0 my $self = shift;
634 0         0 $self->{_TRACE} = 1;
635 0         0 return;
636             }
637              
638             sub trace_off {
639 0     0 0 0 my $self = shift;
640 0         0 $self->{_TRACE} = 0;
641 0         0 return;
642             }
643              
644             sub trace {
645 0     0 0 0 my $self = shift;
646 0         0 return $self->{_TRACE};
647             }
648              
649             sub toggle_cat_state {
650 2436     2436 0 1579 my $self = shift;
651 2436 100       2283 if ($self->get_cat_state == 0) {$self->{_CAT_STATE}++} else {$self->{_CAT_STATE} = 0};
  1218         839  
  1218         909  
652 2436         1734 return;
653             }
654              
655             sub get_cat_state {
656 3851     3851 0 2442 my $self = shift;
657 3851         5110 return $self->{_CAT_STATE};
658             }
659              
660             sub set_error {
661 0     0 0 0 my $self = shift;
662 0         0 $self->{_ERROR}++;
663             }
664              
665             sub get_error {
666 0     0 0 0 my $self = shift;
667 0         0 return $self->{_ERROR};
668             }
669              
670             sub set_done {
671 0     0 0 0 my $self = shift;
672 0         0 $self->{_DONE}++;
673             }
674              
675             sub done {
676 6356     6356 0 4150 my $self = shift;
677 6356         9281 return $self->{_DONE};
678             }
679              
680             sub DESTROY {
681 0     0     return;
682             }
683              
684             1;
685              
686             __END__