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__ |