line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# |
2
|
|
|
|
|
|
|
# Module Parse::Yapp::Lalr |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Copyright © 1998, 1999, 2000, 2001, Francois Desarmenien. |
5
|
|
|
|
|
|
|
# Copyright © 2017 William N. Braswell, Jr. |
6
|
|
|
|
|
|
|
# (see the pod text in Parse::Yapp module for use and distribution rights) |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
package Parse::Yapp::Lalr; |
9
|
|
|
|
|
|
|
@ISA=qw( Parse::Yapp::Grammar ); |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
require 5.004; |
12
|
|
|
|
|
|
|
|
13
|
3
|
|
|
3
|
|
1197
|
use Parse::Yapp::Grammar; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
95
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=for nobody |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Parse::Yapp::Compile Object Structure: |
18
|
|
|
|
|
|
|
-------------------------------------- |
19
|
|
|
|
|
|
|
{ |
20
|
|
|
|
|
|
|
GRAMMAR => Parse::Yapp::Grammar, |
21
|
|
|
|
|
|
|
STATES => [ { CORE => [ items... ], |
22
|
|
|
|
|
|
|
ACTIONS => { term => action } |
23
|
|
|
|
|
|
|
GOTOS => { nterm => stateno } |
24
|
|
|
|
|
|
|
}... ] |
25
|
|
|
|
|
|
|
CONFLICTS=>{ SOLVED => { stateno => [ ruleno, token, solved ] }, |
26
|
|
|
|
|
|
|
FORCED => { TOTAL => [ nbsr, nbrr ], |
27
|
|
|
|
|
|
|
DETAIL => { stateno => { TOTAL => [ nbsr, nbrr ] } |
28
|
|
|
|
|
|
|
LIST => [ ruleno, token ] |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
'items' are of form: [ ruleno, dotpos ] |
35
|
|
|
|
|
|
|
'term' in ACTIONS is '' means default action |
36
|
|
|
|
|
|
|
'action' may be: |
37
|
|
|
|
|
|
|
undef: explicit error (nonassociativity) |
38
|
|
|
|
|
|
|
0 : accept |
39
|
|
|
|
|
|
|
>0 : shift and go to state 'action' |
40
|
|
|
|
|
|
|
<0 : reduce using rule -'action' |
41
|
|
|
|
|
|
|
'solved' may have values of: |
42
|
|
|
|
|
|
|
'shift' if solved as Shift |
43
|
|
|
|
|
|
|
'reduce' if solved as Reduce |
44
|
|
|
|
|
|
|
'error' if solved by discarding both Shift and Reduce (nonassoc) |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
SOLVED is a set of states containing Solved conflicts |
47
|
|
|
|
|
|
|
FORCED are forced conflict resolutions |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
nbsr and nbrr are number of shift/reduce and reduce/reduce conflicts |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
TOTAL is the total number of SR/RR conflicts for the parser |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
DETAIL is the detail of conflicts for each state |
54
|
|
|
|
|
|
|
TOTAL is the total number of SR/RR conflicts for a state |
55
|
|
|
|
|
|
|
LIST is the list of discarded reductions (for display purpose only) |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=cut |
59
|
|
|
|
|
|
|
|
60
|
3
|
|
|
3
|
|
16
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
50
|
|
61
|
|
|
|
|
|
|
|
62
|
3
|
|
|
3
|
|
14
|
use Carp; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
10409
|
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
############### |
65
|
|
|
|
|
|
|
# Constructor # |
66
|
|
|
|
|
|
|
############### |
67
|
|
|
|
|
|
|
sub new { |
68
|
10
|
|
|
10
|
0
|
1858
|
my($class)=shift; |
69
|
|
|
|
|
|
|
|
70
|
10
|
50
|
|
|
|
32
|
ref($class) |
71
|
|
|
|
|
|
|
and $class=ref($class); |
72
|
|
|
|
|
|
|
|
73
|
10
|
|
|
|
|
60
|
my($self)=$class->SUPER::new(@_); |
74
|
10
|
|
|
|
|
65
|
$self->_Compile(); |
75
|
10
|
|
|
|
|
44
|
bless($self,$class); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
########### |
78
|
|
|
|
|
|
|
# Methods # |
79
|
|
|
|
|
|
|
########### |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
########################### |
82
|
|
|
|
|
|
|
# Method To View Warnings # |
83
|
|
|
|
|
|
|
########################### |
84
|
|
|
|
|
|
|
sub Warnings { |
85
|
0
|
|
|
0
|
0
|
0
|
my($self)=shift; |
86
|
0
|
|
|
|
|
0
|
my($text); |
87
|
0
|
|
|
|
|
0
|
my($nbsr,$nbrr)=@{$$self{CONFLICTS}{FORCED}{TOTAL}}; |
|
0
|
|
|
|
|
0
|
|
88
|
|
|
|
|
|
|
|
89
|
0
|
|
|
|
|
0
|
$text=$self->SUPER::Warnings(); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
$nbsr != $$self{GRAMMAR}{EXPECT} |
92
|
0
|
0
|
|
|
|
0
|
and $text.="$nbsr shift/reduce conflict".($nbsr > 1 ? "s" : ""); |
|
|
0
|
|
|
|
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
$nbrr |
95
|
0
|
0
|
|
|
|
0
|
and do { |
96
|
0
|
0
|
|
|
|
0
|
$nbsr |
97
|
|
|
|
|
|
|
and $text.=" and "; |
98
|
0
|
0
|
|
|
|
0
|
$text.="$nbrr reduce/reduce conflict".($nbrr > 1 ? "s" : ""); |
99
|
|
|
|
|
|
|
}; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
( $nbsr != $$self{GRAMMAR}{EXPECT} |
102
|
0
|
0
|
0
|
|
|
0
|
or $nbrr) |
103
|
|
|
|
|
|
|
and $text.="\n"; |
104
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
0
|
$text; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
############################# |
108
|
|
|
|
|
|
|
# Method To View DFA States # |
109
|
|
|
|
|
|
|
############################# |
110
|
|
|
|
|
|
|
sub ShowDfa { |
111
|
0
|
|
|
0
|
0
|
0
|
my($self)=shift; |
112
|
0
|
|
|
|
|
0
|
my($text); |
113
|
0
|
|
|
|
|
0
|
my($grammar,$states)=($$self{GRAMMAR}, $$self{STATES}); |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
0
|
for my $stateno (0..$#$states) { |
116
|
0
|
|
|
|
|
0
|
my(@shifts,@reduces,@errors,$default); |
117
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
0
|
$text.="State $stateno:\n\n"; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
#Dump Kernel Items |
121
|
0
|
0
|
|
|
|
0
|
for (sort { $$a[0] <=> $$b[0] |
|
0
|
|
|
|
|
0
|
|
122
|
0
|
|
|
|
|
0
|
or $$a[1] <=> $$b[1] } @{$$states[$stateno]{'CORE'}}) { |
123
|
0
|
|
|
|
|
0
|
my($ruleno,$pos)=@$_; |
124
|
0
|
|
|
|
|
0
|
my($lhs,$rhs)=@{$$grammar{RULES}[$ruleno]}[0,1]; |
|
0
|
|
|
|
|
0
|
|
125
|
0
|
|
|
|
|
0
|
my(@rhscopy)=@$rhs; |
126
|
|
|
|
|
|
|
|
127
|
0
|
0
|
|
|
|
0
|
$ruleno |
128
|
|
|
|
|
|
|
or $rhscopy[-1] = '$end'; |
129
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
0
|
splice(@rhscopy,$pos,0,'.'); |
131
|
0
|
|
|
|
|
0
|
$text.= "\t$lhs -> ".join(' ',@rhscopy)."\t(Rule $ruleno)\n"; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
#Prepare Actions |
135
|
0
|
|
|
|
|
0
|
for (keys(%{$$states[$stateno]{ACTIONS}})) { |
|
0
|
|
|
|
|
0
|
|
136
|
0
|
|
|
|
|
0
|
my($term,$action)=($_,$$states[$stateno]{ACTIONS}{$_}); |
137
|
|
|
|
|
|
|
|
138
|
0
|
0
|
|
|
|
0
|
$term eq chr(0) |
139
|
|
|
|
|
|
|
and $term = '$end'; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
not defined($action) |
142
|
0
|
0
|
|
|
|
0
|
and do { |
143
|
0
|
|
|
|
|
0
|
push(@errors,$term); |
144
|
0
|
|
|
|
|
0
|
next; |
145
|
|
|
|
|
|
|
}; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
$action > 0 |
148
|
0
|
0
|
|
|
|
0
|
and do { |
149
|
0
|
|
|
|
|
0
|
push(@shifts,[ $term, $action ]); |
150
|
0
|
|
|
|
|
0
|
next; |
151
|
|
|
|
|
|
|
}; |
152
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
0
|
$action = -$action; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
$term |
156
|
0
|
0
|
|
|
|
0
|
or do { |
157
|
0
|
|
|
|
|
0
|
$default= [ '$default', $action ]; |
158
|
0
|
|
|
|
|
0
|
next; |
159
|
|
|
|
|
|
|
}; |
160
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
0
|
push(@reduces,[ $term, $action ]); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
#Dump shifts |
165
|
|
|
|
|
|
|
@shifts |
166
|
0
|
0
|
|
|
|
0
|
and do { |
167
|
0
|
|
|
|
|
0
|
$text.="\n"; |
168
|
0
|
|
|
|
|
0
|
for (sort { $$a[0] cmp $$b[0] } @shifts) { |
|
0
|
|
|
|
|
0
|
|
169
|
0
|
|
|
|
|
0
|
my($term,$shift)=@$_; |
170
|
|
|
|
|
|
|
|
171
|
0
|
|
|
|
|
0
|
$text.="\t$term\tshift, and go to state $shift\n"; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
}; |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
#Dump errors |
176
|
|
|
|
|
|
|
@errors |
177
|
0
|
0
|
|
|
|
0
|
and do { |
178
|
0
|
|
|
|
|
0
|
$text.="\n"; |
179
|
0
|
|
|
|
|
0
|
for my $term (sort { $a cmp $b } @errors) { |
|
0
|
|
|
|
|
0
|
|
180
|
0
|
|
|
|
|
0
|
$text.="\t$term\terror (nonassociative)\n"; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
}; |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
#Prepare reduces |
185
|
|
|
|
|
|
|
exists($$self{CONFLICTS}{FORCED}{DETAIL}{$stateno}) |
186
|
0
|
0
|
|
|
|
0
|
and push(@reduces,@{$$self{CONFLICTS}{FORCED}{DETAIL}{$stateno}{LIST}}); |
|
0
|
|
|
|
|
0
|
|
187
|
|
|
|
|
|
|
|
188
|
0
|
0
|
|
|
|
0
|
@reduces=sort { $$a[0] cmp $$b[0] or $$a[1] <=> $$b[1] } @reduces; |
|
0
|
|
|
|
|
0
|
|
189
|
|
|
|
|
|
|
|
190
|
0
|
0
|
|
|
|
0
|
defined($default) |
191
|
|
|
|
|
|
|
and push(@reduces,$default); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
#Dump reduces |
194
|
|
|
|
|
|
|
@reduces |
195
|
0
|
0
|
|
|
|
0
|
and do { |
196
|
0
|
|
|
|
|
0
|
$text.="\n"; |
197
|
0
|
|
|
|
|
0
|
for (@reduces) { |
198
|
0
|
|
|
|
|
0
|
my($term,$ruleno)=@$_; |
199
|
0
|
|
|
|
|
0
|
my($discard); |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
$ruleno < 0 |
202
|
0
|
0
|
|
|
|
0
|
and do { |
203
|
0
|
|
|
|
|
0
|
++$discard; |
204
|
0
|
|
|
|
|
0
|
$ruleno = -$ruleno; |
205
|
|
|
|
|
|
|
}; |
206
|
|
|
|
|
|
|
|
207
|
0
|
0
|
|
|
|
0
|
$text.= "\t$term\t".($discard ? "[" : ""); |
208
|
0
|
0
|
|
|
|
0
|
if($ruleno) { |
209
|
0
|
|
|
|
|
0
|
$text.= "reduce using rule $ruleno ". |
210
|
|
|
|
|
|
|
"($$grammar{RULES}[$ruleno][0])"; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
else { |
213
|
0
|
|
|
|
|
0
|
$text.='accept'; |
214
|
|
|
|
|
|
|
} |
215
|
0
|
0
|
|
|
|
0
|
$text.=($discard ? "]" : "")."\n"; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
}; |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
#Dump gotos |
220
|
|
|
|
|
|
|
exists($$states[$stateno]{GOTOS}) |
221
|
0
|
0
|
|
|
|
0
|
and do { |
222
|
0
|
|
|
|
|
0
|
$text.= "\n"; |
223
|
0
|
|
|
|
|
0
|
for (keys(%{$$states[$stateno]{GOTOS}})) { |
|
0
|
|
|
|
|
0
|
|
224
|
0
|
|
|
|
|
0
|
$text.= "\t$_\tgo to state $$states[$stateno]{GOTOS}{$_}\n"; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
}; |
227
|
|
|
|
|
|
|
|
228
|
0
|
|
|
|
|
0
|
$text.="\n"; |
229
|
|
|
|
|
|
|
} |
230
|
0
|
|
|
|
|
0
|
$text; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
###################################### |
234
|
|
|
|
|
|
|
# Method to get summary about parser # |
235
|
|
|
|
|
|
|
###################################### |
236
|
|
|
|
|
|
|
sub Summary { |
237
|
0
|
|
|
0
|
0
|
0
|
my($self)=shift; |
238
|
0
|
|
|
|
|
0
|
my($text); |
239
|
|
|
|
|
|
|
|
240
|
0
|
|
|
|
|
0
|
$text=$self->SUPER::Summary(); |
241
|
|
|
|
|
|
|
$text.="Number of states : ". |
242
|
0
|
|
|
|
|
0
|
scalar(@{$$self{STATES}})."\n"; |
|
0
|
|
|
|
|
0
|
|
243
|
0
|
|
|
|
|
0
|
$text; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
####################################### |
247
|
|
|
|
|
|
|
# Method To Get Infos about conflicts # |
248
|
|
|
|
|
|
|
####################################### |
249
|
|
|
|
|
|
|
sub Conflicts { |
250
|
0
|
|
|
0
|
0
|
0
|
my($self)=shift; |
251
|
0
|
|
|
|
|
0
|
my($states)=$$self{STATES}; |
252
|
0
|
|
|
|
|
0
|
my($conflicts)=$$self{CONFLICTS}; |
253
|
0
|
|
|
|
|
0
|
my($text); |
254
|
|
|
|
|
|
|
|
255
|
0
|
|
|
|
|
0
|
for my $stateno ( sort { $a <=> $b } keys(%{$$conflicts{SOLVED}})) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
256
|
|
|
|
|
|
|
|
257
|
0
|
|
|
|
|
0
|
for (@{$$conflicts{SOLVED}{$stateno}}) { |
|
0
|
|
|
|
|
0
|
|
258
|
0
|
|
|
|
|
0
|
my($ruleno,$token,$how)=@$_; |
259
|
|
|
|
|
|
|
|
260
|
0
|
0
|
|
|
|
0
|
$token eq chr(0) |
261
|
|
|
|
|
|
|
and $token = '$end'; |
262
|
|
|
|
|
|
|
|
263
|
0
|
|
|
|
|
0
|
$text.="Conflict in state $stateno between rule ". |
264
|
|
|
|
|
|
|
"$ruleno and token $token resolved as $how.\n"; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
}; |
267
|
|
|
|
|
|
|
|
268
|
0
|
|
|
|
|
0
|
for my $stateno ( sort { $a <=> $b } keys(%{$$conflicts{FORCED}{DETAIL}})) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
269
|
0
|
|
|
|
|
0
|
my($nbsr,$nbrr)=@{$$conflicts{FORCED}{DETAIL}{$stateno}{TOTAL}}; |
|
0
|
|
|
|
|
0
|
|
270
|
|
|
|
|
|
|
|
271
|
0
|
|
|
|
|
0
|
$text.="State $stateno contains "; |
272
|
|
|
|
|
|
|
|
273
|
0
|
0
|
|
|
|
0
|
$nbsr |
|
|
0
|
|
|
|
|
|
274
|
|
|
|
|
|
|
and $text.="$nbsr shift/reduce conflict". |
275
|
|
|
|
|
|
|
($nbsr > 1 ? "s" : ""); |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
$nbrr |
278
|
0
|
0
|
|
|
|
0
|
and do { |
279
|
0
|
0
|
|
|
|
0
|
$nbsr |
280
|
|
|
|
|
|
|
and $text.=" and "; |
281
|
|
|
|
|
|
|
|
282
|
0
|
0
|
|
|
|
0
|
$text.="$nbrr reduce/reduce conflict". |
283
|
|
|
|
|
|
|
($nbrr > 1 ? "s" : ""); |
284
|
|
|
|
|
|
|
}; |
285
|
0
|
|
|
|
|
0
|
$text.="\n"; |
286
|
|
|
|
|
|
|
}; |
287
|
|
|
|
|
|
|
|
288
|
0
|
|
|
|
|
0
|
$text; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
################################# |
292
|
|
|
|
|
|
|
# Method to dump parsing tables # |
293
|
|
|
|
|
|
|
################################# |
294
|
|
|
|
|
|
|
sub DfaTable { |
295
|
9
|
|
|
9
|
0
|
18
|
my($self)=shift; |
296
|
9
|
|
|
|
|
17
|
my($states)=$$self{STATES}; |
297
|
9
|
|
|
|
|
16
|
my($stateno); |
298
|
|
|
|
|
|
|
my($text); |
299
|
|
|
|
|
|
|
|
300
|
9
|
|
|
|
|
17
|
$text="[\n\t{"; |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
$text.=join("\n\t},\n\t{", |
303
|
|
|
|
|
|
|
map { |
304
|
9
|
|
|
|
|
16
|
my($state)=$_; |
|
107
|
|
|
|
|
147
|
|
305
|
107
|
|
|
|
|
144
|
my($text); |
306
|
|
|
|
|
|
|
|
307
|
107
|
|
|
|
|
175
|
$text="#State ".$stateno++."\n\t\t"; |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
( not exists($$state{ACTIONS}{''}) |
310
|
63
|
|
|
|
|
219
|
or keys(%{$$state{ACTIONS}}) > 1) |
311
|
107
|
100
|
100
|
|
|
250
|
and do { |
312
|
|
|
|
|
|
|
|
313
|
57
|
|
|
|
|
85
|
$text.="ACTIONS => {\n\t\t\t"; |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
$text.=join(",\n\t\t\t", |
316
|
|
|
|
|
|
|
map { |
317
|
126
|
|
|
|
|
227
|
my($term,$action)=($_,$$state{ACTIONS}{$_}); |
318
|
126
|
|
|
|
|
152
|
my($text); |
319
|
|
|
|
|
|
|
|
320
|
126
|
100
|
|
|
|
245
|
if(substr($term,0,1) eq "'") { |
321
|
96
|
|
|
|
|
155
|
$term=~s/([\@\$\"])/\\$1/g; |
322
|
96
|
|
|
|
|
271
|
$term=~s/^'|'$/"/g; |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
else { |
325
|
30
|
100
|
|
|
|
65
|
$term= $term eq chr(0) |
326
|
|
|
|
|
|
|
? "''" |
327
|
|
|
|
|
|
|
: "'$term'"; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
126
|
100
|
|
|
|
227
|
if(defined($action)) { |
331
|
125
|
|
|
|
|
168
|
$action=int($action); |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
else { |
334
|
1
|
|
|
|
|
3
|
$action='undef'; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
126
|
|
|
|
|
282
|
"$term => $action"; |
338
|
|
|
|
|
|
|
|
339
|
57
|
|
|
|
|
75
|
} grep { $_ } keys(%{$$state{ACTIONS}})); |
|
139
|
|
|
|
|
248
|
|
|
57
|
|
|
|
|
115
|
|
340
|
|
|
|
|
|
|
|
341
|
57
|
|
|
|
|
102
|
$text.="\n\t\t}"; |
342
|
|
|
|
|
|
|
}; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
exists($$state{ACTIONS}{''}) |
345
|
107
|
100
|
|
|
|
225
|
and do { |
346
|
63
|
100
|
|
|
|
75
|
keys(%{$$state{ACTIONS}}) > 1 |
|
63
|
|
|
|
|
143
|
|
347
|
|
|
|
|
|
|
and $text.=",\n\t\t"; |
348
|
|
|
|
|
|
|
|
349
|
63
|
|
|
|
|
118
|
$text.="DEFAULT => $$state{ACTIONS}{''}"; |
350
|
|
|
|
|
|
|
}; |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
exists($$state{GOTOS}) |
353
|
107
|
100
|
|
|
|
213
|
and do { |
354
|
29
|
|
|
|
|
47
|
$text.=",\n\t\tGOTOS => {\n\t\t\t"; |
355
|
|
|
|
|
|
|
$text.=join(",\n\t\t\t", |
356
|
|
|
|
|
|
|
map { |
357
|
43
|
|
|
|
|
73
|
my($nterm,$stateno)=($_,$$state{GOTOS}{$_}); |
358
|
43
|
|
|
|
|
56
|
my($text); |
359
|
|
|
|
|
|
|
|
360
|
43
|
|
|
|
|
104
|
"'$nterm' => $stateno"; |
361
|
|
|
|
|
|
|
|
362
|
29
|
|
|
|
|
46
|
} keys(%{$$state{GOTOS}})); |
|
29
|
|
|
|
|
59
|
|
363
|
29
|
|
|
|
|
48
|
$text.="\n\t\t}"; |
364
|
|
|
|
|
|
|
}; |
365
|
|
|
|
|
|
|
|
366
|
107
|
|
|
|
|
202
|
$text; |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
}@$states); |
369
|
|
|
|
|
|
|
|
370
|
9
|
|
|
|
|
33
|
$text.="\n\t}\n]"; |
371
|
|
|
|
|
|
|
|
372
|
9
|
|
|
|
|
27
|
$text; |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
#################################### |
378
|
|
|
|
|
|
|
# Method to build Dfa from Grammar # |
379
|
|
|
|
|
|
|
#################################### |
380
|
|
|
|
|
|
|
sub _Compile { |
381
|
10
|
|
|
10
|
|
20
|
my($self)=shift; |
382
|
10
|
|
|
|
|
20
|
my($grammar,$states); |
383
|
|
|
|
|
|
|
|
384
|
10
|
|
|
|
|
24
|
$grammar=$self->{GRAMMAR}; |
385
|
|
|
|
|
|
|
|
386
|
10
|
|
|
|
|
33
|
$states = _LR0($grammar); |
387
|
|
|
|
|
|
|
|
388
|
10
|
|
|
|
|
36
|
$self->{CONFLICTS} = _LALR($grammar,$states); |
389
|
|
|
|
|
|
|
|
390
|
10
|
|
|
|
|
25
|
$self->{STATES}=$states; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
######################### |
394
|
|
|
|
|
|
|
# LR0 States Generation # |
395
|
|
|
|
|
|
|
######################### |
396
|
|
|
|
|
|
|
# |
397
|
|
|
|
|
|
|
########################### |
398
|
|
|
|
|
|
|
# General digraph routine # |
399
|
|
|
|
|
|
|
########################### |
400
|
|
|
|
|
|
|
sub _Digraph { |
401
|
30
|
|
|
30
|
|
56
|
my($rel,$F)=@_; |
402
|
30
|
|
|
|
|
50
|
my(%N,@S); |
403
|
30
|
|
|
|
|
48
|
my($infinity)=(~(1<<31)); |
404
|
30
|
|
|
|
|
52
|
my($Traverse); |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
$Traverse = sub { |
407
|
10659
|
|
|
10659
|
|
16523
|
my($x,$d)=@_; |
408
|
10659
|
|
|
|
|
13595
|
my($y); |
409
|
|
|
|
|
|
|
|
410
|
10659
|
|
|
|
|
14578
|
push(@S,$x); |
411
|
10659
|
|
|
|
|
18232
|
$N{$x}=$d; |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
exists($$rel{$x}) |
414
|
10659
|
100
|
|
|
|
22908
|
and do { |
415
|
9183
|
|
|
|
|
11934
|
for $y (keys(%{$$rel{$x}})) { |
|
9183
|
|
|
|
|
30201
|
|
416
|
42992
|
100
|
|
|
|
91941
|
exists($N{$y}) |
417
|
|
|
|
|
|
|
or &$Traverse($y,$d+1); |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
$N{$y} < $N{$x} |
420
|
42992
|
100
|
|
|
|
82489
|
and $N{$x} = $N{$y}; |
421
|
|
|
|
|
|
|
|
422
|
42992
|
|
|
|
|
79575
|
$$F{$x}|=$$F{$y}; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
}; |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
$N{$x} == $d |
427
|
10659
|
100
|
|
|
|
22869
|
and do { |
428
|
10322
|
|
|
|
|
13171
|
for(;;) { |
429
|
10659
|
|
|
|
|
14525
|
$y=pop(@S); |
430
|
10659
|
|
|
|
|
14975
|
$N{$y}=$infinity; |
431
|
10659
|
100
|
|
|
|
23137
|
$y eq $x |
432
|
|
|
|
|
|
|
and last; |
433
|
337
|
|
|
|
|
484
|
$$F{$y}=$$F{$x}; |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
}; |
436
|
30
|
|
|
|
|
128
|
}; |
437
|
|
|
|
|
|
|
|
438
|
30
|
|
|
|
|
3316
|
for (keys(%$rel)) { |
439
|
9183
|
100
|
|
|
|
20707
|
exists($N{$_}) |
440
|
|
|
|
|
|
|
or &$Traverse($_,1); |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
####################### |
444
|
|
|
|
|
|
|
# Generate LR0 states # |
445
|
|
|
|
|
|
|
####################### |
446
|
|
|
|
|
|
|
=for nobody |
447
|
|
|
|
|
|
|
Formula used for closures: |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
CLOSE(A) = DCLOSE(A) u U (CLOSE(B) | A close B) |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
where: |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
DCLOSE(A) = { [ A -> alpha ] in P } |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
A close B iff [ A -> B gamma ] in P |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=cut |
458
|
|
|
|
|
|
|
sub _SetClosures { |
459
|
10
|
|
|
10
|
|
21
|
my($grammar)=@_; |
460
|
10
|
|
|
|
|
19
|
my($rel,$closures); |
461
|
|
|
|
|
|
|
|
462
|
10
|
|
|
|
|
18
|
for my $symbol (keys(%{$$grammar{NTERM}})) { |
|
10
|
|
|
|
|
68
|
|
463
|
270
|
|
|
|
|
381
|
$closures->{$symbol}=pack('b'.@{$$grammar{RULES}}); |
|
270
|
|
|
|
|
644
|
|
464
|
|
|
|
|
|
|
|
465
|
270
|
|
|
|
|
408
|
for my $ruleno (@{$$grammar{NTERM}{$symbol}}) { |
|
270
|
|
|
|
|
465
|
|
466
|
888
|
|
|
|
|
1311
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
467
|
|
|
|
|
|
|
|
468
|
888
|
|
|
|
|
1622
|
vec($closures->{$symbol},$ruleno,1)=1; |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
@$rhs > 0 |
471
|
|
|
|
|
|
|
and exists($$grammar{NTERM}{$$rhs[0]}) |
472
|
888
|
100
|
100
|
|
|
3842
|
and ++$rel->{$symbol}{$$rhs[0]}; |
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
} |
475
|
10
|
|
|
|
|
44
|
_Digraph($rel,$closures); |
476
|
|
|
|
|
|
|
|
477
|
10
|
|
|
|
|
27
|
$closures |
478
|
|
|
|
|
|
|
} |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
sub _Closures { |
481
|
1718
|
|
|
1718
|
|
2868
|
my($grammar,$core,$closures)=@_; |
482
|
1718
|
|
|
|
|
2574
|
my($ruleset)=pack('b'.@{$$grammar{RULES}}); |
|
1718
|
|
|
|
|
5475
|
|
483
|
|
|
|
|
|
|
|
484
|
1718
|
|
|
|
|
3673
|
for (@$core) { |
485
|
3895
|
|
|
|
|
8716
|
my($ruleno,$pos)=@$_; |
486
|
3895
|
|
|
|
|
6903
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
$pos < @$rhs |
489
|
|
|
|
|
|
|
and exists($closures->{$$rhs[$pos]}) |
490
|
3895
|
100
|
100
|
|
|
17548
|
and $ruleset|=$closures->{$$rhs[$pos]}; |
491
|
|
|
|
|
|
|
} |
492
|
56069
|
|
|
|
|
101941
|
[ @$core, map { [ $_, 0 ] } |
493
|
1330007
|
|
|
|
|
1749211
|
grep { vec($ruleset,$_,1) } |
494
|
1718
|
|
|
|
|
2945
|
0..$#{$$grammar{RULES}} ]; |
|
1718
|
|
|
|
|
18370
|
|
495
|
|
|
|
|
|
|
} |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
sub _Transitions { |
498
|
1718
|
|
|
1718
|
|
3148
|
my($grammar,$cores,$closures,$states,$stateno)=@_; |
499
|
1718
|
|
|
|
|
3787
|
my($core)=$$states[$stateno]{'CORE'}; |
500
|
1718
|
|
|
|
|
2440
|
my(%transitions); |
501
|
|
|
|
|
|
|
|
502
|
1718
|
|
|
|
|
2638
|
for (@{_Closures($grammar,$core,$closures)}) { |
|
1718
|
|
|
|
|
3150
|
|
503
|
59964
|
|
|
|
|
96646
|
my($ruleno,$pos)=@$_; |
504
|
59964
|
|
|
|
|
93574
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
$pos == @$rhs |
507
|
59964
|
100
|
|
|
|
113417
|
and do { |
508
|
1187
|
|
|
|
|
1705
|
push(@{$$states[$stateno]{ACTIONS}{''}},$ruleno); |
|
1187
|
|
|
|
|
4278
|
|
509
|
1187
|
|
|
|
|
2509
|
next; |
510
|
|
|
|
|
|
|
}; |
511
|
58777
|
|
|
|
|
75151
|
push(@{$transitions{$$rhs[$pos]}},[ $ruleno, $pos+1 ]); |
|
58777
|
|
|
|
|
145947
|
|
512
|
|
|
|
|
|
|
} |
513
|
|
|
|
|
|
|
|
514
|
1718
|
|
|
|
|
12581
|
for (keys(%transitions)) { |
515
|
23159
|
|
|
|
|
38149
|
my($symbol,$core)=($_,$transitions{$_}); |
516
|
58777
|
|
|
|
|
126264
|
my($corekey)=join(',',map { join('.',@$_) } |
517
|
23159
|
50
|
|
|
|
40792
|
sort { $$a[0] <=> $$b[0] |
|
51997
|
|
|
|
|
103737
|
|
518
|
|
|
|
|
|
|
or $$a[1] <=> $$b[1] } |
519
|
|
|
|
|
|
|
@$core); |
520
|
23159
|
|
|
|
|
36416
|
my($tostateno); |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
exists($cores->{$corekey}) |
523
|
23159
|
100
|
|
|
|
53023
|
or do { |
524
|
1708
|
|
|
|
|
3933
|
push(@$states,{ 'CORE' => $core }); |
525
|
1708
|
|
|
|
|
4104
|
$cores->{$corekey}=$#$states; |
526
|
|
|
|
|
|
|
}; |
527
|
|
|
|
|
|
|
|
528
|
23159
|
|
|
|
|
34308
|
$tostateno=$cores->{$corekey}; |
529
|
23159
|
|
|
|
|
30124
|
push(@{$$states[$tostateno]{FROM}},$stateno); |
|
23159
|
|
|
|
|
44481
|
|
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
exists($$grammar{TERM}{$_}) |
532
|
23159
|
100
|
|
|
|
48419
|
and do { |
533
|
11824
|
|
|
|
|
23507
|
$$states[$stateno]{ACTIONS}{$_} = [ $tostateno ]; |
534
|
11824
|
|
|
|
|
28575
|
next; |
535
|
|
|
|
|
|
|
}; |
536
|
11335
|
|
|
|
|
29618
|
$$states[$stateno]{GOTOS}{$_} = $tostateno; |
537
|
|
|
|
|
|
|
} |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
sub _LR0 { |
541
|
10
|
|
|
10
|
|
20
|
my($grammar)=@_; |
542
|
10
|
|
|
|
|
22
|
my($states) = []; |
543
|
10
|
|
|
|
|
20
|
my($stateno); |
544
|
|
|
|
|
|
|
my($closures); #$closures={ nterm => ruleset,... } |
545
|
10
|
|
|
|
|
19
|
my($cores)={}; # { "itemlist" => stateno, ... } |
546
|
|
|
|
|
|
|
# where "itemlist" has the form: |
547
|
|
|
|
|
|
|
# "ruleno.pos,ruleno.pos" ordered by ruleno,pos |
548
|
|
|
|
|
|
|
|
549
|
10
|
|
|
|
|
29
|
$closures = _SetClosures($grammar); |
550
|
10
|
|
|
|
|
42
|
push(@$states,{ 'CORE' => [ [ 0, 0 ] ] }); |
551
|
10
|
|
|
|
|
37
|
for($stateno=0;$stateno<@$states;++$stateno) { |
552
|
1718
|
|
|
|
|
4075
|
_Transitions($grammar,$cores,$closures,$states,$stateno); |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
|
555
|
10
|
|
|
|
|
691
|
$states |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
######################################################### |
559
|
|
|
|
|
|
|
# Add Lookahead tokens where needed to make LALR states # |
560
|
|
|
|
|
|
|
######################################################### |
561
|
|
|
|
|
|
|
=for nobody |
562
|
|
|
|
|
|
|
Compute First sets for non-terminal using the following formula: |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
FIRST(A) = { a in T u { epsilon } | A l a } |
565
|
|
|
|
|
|
|
u |
566
|
|
|
|
|
|
|
U { FIRST(B) | B in V and A l B } |
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
where: |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
A l x iff [ A -> X1 X2 .. Xn x alpha ] in P and Xi =>* epsilon, 1 <= i <= n |
571
|
|
|
|
|
|
|
=cut |
572
|
|
|
|
|
|
|
sub _SetFirst { |
573
|
10
|
|
|
10
|
|
24
|
my($grammar,$termlst,$terminx)=@_; |
574
|
10
|
|
|
|
|
22
|
my($rel,$first)=( {}, {} ); |
575
|
|
|
|
|
|
|
|
576
|
10
|
|
|
|
|
16
|
for my $symbol (keys(%{$$grammar{NTERM}})) { |
|
10
|
|
|
|
|
76
|
|
577
|
270
|
|
|
|
|
734
|
$first->{$symbol}=pack('b'.@$termlst); |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
RULE: |
580
|
270
|
|
|
|
|
371
|
for my $ruleno (@{$$grammar{NTERM}{$symbol}}) { |
|
270
|
|
|
|
|
535
|
|
581
|
888
|
|
|
|
|
1601
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
582
|
|
|
|
|
|
|
|
583
|
888
|
|
|
|
|
1422
|
for (@$rhs) { |
584
|
|
|
|
|
|
|
exists($terminx->{$_}) |
585
|
868
|
100
|
|
|
|
1778
|
and do { |
586
|
299
|
|
|
|
|
582
|
vec($first->{$symbol},$terminx->{$_},1)=1; |
587
|
299
|
|
|
|
|
616
|
next RULE; |
588
|
|
|
|
|
|
|
}; |
589
|
569
|
|
|
|
|
970
|
++$rel->{$symbol}{$_}; |
590
|
569
|
100
|
|
|
|
1334
|
exists($$grammar{NULLABLE}{$_}) |
591
|
|
|
|
|
|
|
or next RULE; |
592
|
|
|
|
|
|
|
} |
593
|
47
|
|
|
|
|
400
|
vec($first->{$symbol},0,1)=1; |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
} |
596
|
10
|
|
|
|
|
60
|
_Digraph($rel,$first); |
597
|
|
|
|
|
|
|
|
598
|
10
|
|
|
|
|
35
|
$first |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
sub _Preds { |
602
|
8974
|
|
|
8974
|
|
14364
|
my($states,$stateno,$len)=@_; |
603
|
8974
|
|
|
|
|
12152
|
my($queue, $preds); |
604
|
|
|
|
|
|
|
|
605
|
8974
|
100
|
|
|
|
26156
|
$len |
606
|
|
|
|
|
|
|
or return [ $stateno ]; |
607
|
|
|
|
|
|
|
|
608
|
1004
|
|
|
|
|
2349
|
$queue=[ [ $stateno, $len ] ]; |
609
|
1004
|
|
|
|
|
2429
|
while(@$queue) { |
610
|
3862
|
|
|
|
|
5800
|
my($pred) = shift(@$queue); |
611
|
3862
|
|
|
|
|
6059
|
my($stateno, $len) = @$pred; |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
$len == 1 |
614
|
3862
|
100
|
|
|
|
7604
|
and do { |
615
|
3169
|
|
|
|
|
4244
|
push(@$preds,@{$states->[$stateno]{FROM}}); |
|
3169
|
|
|
|
|
9709
|
|
616
|
3169
|
|
|
|
|
7234
|
next; |
617
|
|
|
|
|
|
|
}; |
618
|
|
|
|
|
|
|
|
619
|
2858
|
|
|
|
|
6173
|
push(@$queue, map { [ $_, $len - 1 ] } |
620
|
693
|
|
|
|
|
1023
|
@{$states->[$stateno]{FROM}}); |
|
693
|
|
|
|
|
1699
|
|
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
# Pass @$preds through a hash to ensure unicity |
624
|
1004
|
|
|
|
|
1456
|
[ keys( %{ +{ map { ($_,1) } @$preds } } ) ]; |
|
1004
|
|
|
|
|
1744
|
|
|
34302
|
|
|
|
|
73648
|
|
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
sub _FirstSfx { |
628
|
1235
|
|
|
1235
|
|
2301
|
my($grammar,$firstset,$termlst,$terminx,$ruleno,$pos,$key)=@_; |
629
|
1235
|
|
|
|
|
2703
|
my($first)=pack('b'.@$termlst); |
630
|
1235
|
|
|
|
|
2821
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
631
|
|
|
|
|
|
|
|
632
|
1235
|
|
|
|
|
3070
|
for (;$pos < @$rhs;++$pos) { |
633
|
|
|
|
|
|
|
exists($terminx->{$$rhs[$pos]}) |
634
|
817
|
100
|
|
|
|
2293
|
and do { |
635
|
395
|
|
|
|
|
911
|
vec($first,$terminx->{$$rhs[$pos]},1)=1; |
636
|
395
|
|
|
|
|
1325
|
return($first); |
637
|
|
|
|
|
|
|
}; |
638
|
422
|
|
|
|
|
894
|
$first|=$firstset->{$$rhs[$pos]}; |
639
|
|
|
|
|
|
|
|
640
|
422
|
100
|
|
|
|
1084
|
vec($first,0,1) |
641
|
|
|
|
|
|
|
and vec($first,0,1)=0; |
642
|
|
|
|
|
|
|
|
643
|
422
|
100
|
|
|
|
1639
|
exists($$grammar{NULLABLE}{$$rhs[$pos]}) |
644
|
|
|
|
|
|
|
or return($first); |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
} |
647
|
597
|
|
|
|
|
1399
|
vec($first,0,1)=1; |
648
|
597
|
|
|
|
|
1923
|
$first; |
649
|
|
|
|
|
|
|
} |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=for noboby |
652
|
|
|
|
|
|
|
Compute Follow sets using following formula: |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
FOLLOW(p,A) = READ(p,A) |
655
|
|
|
|
|
|
|
u |
656
|
|
|
|
|
|
|
U { FOLLOW(q,B) | (p,A) include (q,B) |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
where: |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
READ(p,A) = U { FIRST(beta) | [ A -> alpha A . beta ] in KERNEL(GOTO(p,A)) |
661
|
|
|
|
|
|
|
} - { epsilon } |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
(p,a) include (q,B) iff [ B -> alpha A . beta ] in KERNEL(GOTO(p,A), |
664
|
|
|
|
|
|
|
epsilon in FIRST(beta) and |
665
|
|
|
|
|
|
|
q in PRED(p,alpha) |
666
|
|
|
|
|
|
|
=cut |
667
|
|
|
|
|
|
|
sub _ComputeFollows { |
668
|
10
|
|
|
10
|
|
21
|
my($grammar,$states,$termlst)=@_; |
669
|
10
|
|
|
|
|
19
|
my($firstset,$terminx); |
670
|
10
|
|
|
|
|
27
|
my($inconsistent, $rel, $follows, $sfx)= ( {}, {}, {}, {} ); |
671
|
|
|
|
|
|
|
|
672
|
10
|
|
|
|
|
36
|
%$terminx= map { ($termlst->[$_],$_) } 0..$#$termlst; |
|
174
|
|
|
|
|
294
|
|
673
|
|
|
|
|
|
|
|
674
|
10
|
|
|
|
|
42
|
$firstset=_SetFirst($grammar,$termlst,$terminx); |
675
|
|
|
|
|
|
|
|
676
|
10
|
|
|
|
|
32
|
for my $stateno (0..$#$states) { |
677
|
1718
|
|
|
|
|
3021
|
my($state)=$$states[$stateno]; |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
exists($$state{ACTIONS}{''}) |
680
|
|
|
|
|
|
|
and ( @{$$state{ACTIONS}{''}} > 1 |
681
|
|
|
|
|
|
|
or keys(%{$$state{ACTIONS}}) > 1 ) |
682
|
1718
|
100
|
100
|
|
|
5298
|
and do { |
|
|
|
100
|
|
|
|
|
683
|
397
|
|
|
|
|
1074
|
++$inconsistent->{$stateno}; |
684
|
|
|
|
|
|
|
|
685
|
397
|
|
|
|
|
589
|
for my $ruleno (@{$$state{ACTIONS}{''}}) { |
|
397
|
|
|
|
|
879
|
|
686
|
436
|
|
|
|
|
692
|
my($lhs,$rhs)=@{$$grammar{RULES}[$ruleno]}[0,1]; |
|
436
|
|
|
|
|
1347
|
|
687
|
|
|
|
|
|
|
|
688
|
436
|
|
|
|
|
810
|
for my $predno (@{_Preds($states,$stateno,scalar(@$rhs))}) { |
|
436
|
|
|
|
|
949
|
|
689
|
11975
|
|
|
|
|
24874
|
++$rel->{"$stateno.$ruleno"}{"$predno.$lhs"}; |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
}; |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
exists($$state{GOTOS}) |
695
|
1718
|
100
|
|
|
|
4213
|
or next; |
696
|
|
|
|
|
|
|
|
697
|
656
|
|
|
|
|
1000
|
for my $symbol (keys(%{$$state{GOTOS}})) { |
|
656
|
|
|
|
|
3620
|
|
698
|
11335
|
|
|
|
|
21133
|
my($tostate)=$$states[$$state{GOTOS}{$symbol}]; |
699
|
11335
|
|
|
|
|
19056
|
my($goto)="$stateno.$symbol"; |
700
|
|
|
|
|
|
|
|
701
|
11335
|
|
|
|
|
33627
|
$follows->{$goto}=pack('b'.@$termlst); |
702
|
|
|
|
|
|
|
|
703
|
11335
|
|
|
|
|
15947
|
for my $item (@{$$tostate{'CORE'}}) { |
|
11335
|
|
|
|
|
21723
|
|
704
|
39723
|
|
|
|
|
68808
|
my($ruleno,$pos)=@$item; |
705
|
39723
|
|
|
|
|
58492
|
my($key)="$ruleno.$pos"; |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
exists($sfx->{$key}) |
708
|
39723
|
100
|
|
|
|
82748
|
or $sfx->{$key} = _FirstSfx($grammar,$firstset, |
709
|
|
|
|
|
|
|
$termlst,$terminx, |
710
|
|
|
|
|
|
|
$ruleno,$pos,$key); |
711
|
|
|
|
|
|
|
|
712
|
39723
|
|
|
|
|
64487
|
$follows->{$goto}|=$sfx->{$key}; |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
vec($follows->{$goto},0,1) |
715
|
39723
|
100
|
|
|
|
86419
|
and do { |
716
|
8538
|
|
|
|
|
15527
|
my($lhs)=$$grammar{RULES}[$ruleno][0]; |
717
|
|
|
|
|
|
|
|
718
|
8538
|
|
|
|
|
17907
|
vec($follows->{$goto},0,1)=0; |
719
|
|
|
|
|
|
|
|
720
|
8538
|
|
|
|
|
14051
|
for my $predno (@{_Preds($states,$stateno,$pos-1)}) { |
|
8538
|
|
|
|
|
15834
|
|
721
|
30297
|
|
|
|
|
77522
|
++$rel->{$goto}{"$predno.$lhs"}; |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
}; |
724
|
|
|
|
|
|
|
} |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
} |
727
|
10
|
|
|
|
|
37
|
_Digraph($rel,$follows); |
728
|
|
|
|
|
|
|
|
729
|
10
|
|
|
|
|
1610
|
($follows,$inconsistent) |
730
|
|
|
|
|
|
|
} |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
sub _ComputeLA { |
733
|
10
|
|
|
10
|
|
21
|
my($grammar,$states)=@_; |
734
|
10
|
|
|
|
|
18
|
my($termlst)= [ '',keys(%{$$grammar{TERM}}) ]; |
|
10
|
|
|
|
|
155
|
|
735
|
|
|
|
|
|
|
|
736
|
10
|
|
|
|
|
42
|
my($follows,$inconsistent) = _ComputeFollows($grammar,$states,$termlst); |
737
|
|
|
|
|
|
|
|
738
|
10
|
|
|
|
|
150
|
for my $stateno ( keys(%$inconsistent ) ) { |
739
|
397
|
|
|
|
|
947
|
my($state)=$$states[$stateno]; |
740
|
397
|
|
|
|
|
523
|
my($conflict); |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
#NB the sort is VERY important for conflicts resolution order |
743
|
397
|
|
|
|
|
536
|
for my $ruleno (sort { $a <=> $b } |
|
41
|
|
|
|
|
107
|
|
744
|
397
|
|
|
|
|
1548
|
@{$$state{ACTIONS}{''}}) { |
745
|
436
|
|
|
|
|
1265
|
for my $term ( map { $termlst->[$_] } grep { |
|
7755
|
|
|
|
|
11269
|
|
746
|
46056
|
|
|
|
|
69315
|
vec($follows->{"$stateno.$ruleno"},$_,1) } |
747
|
|
|
|
|
|
|
0..$#$termlst) { |
748
|
7755
|
100
|
|
|
|
14686
|
exists($$state{ACTIONS}{$term}) |
749
|
|
|
|
|
|
|
and ++$conflict; |
750
|
7755
|
|
|
|
|
9754
|
push(@{$$state{ACTIONS}{$term}},-$ruleno); |
|
7755
|
|
|
|
|
19271
|
|
751
|
|
|
|
|
|
|
} |
752
|
|
|
|
|
|
|
} |
753
|
397
|
|
|
|
|
816
|
delete($$state{ACTIONS}{''}); |
754
|
|
|
|
|
|
|
$conflict |
755
|
397
|
100
|
|
|
|
1082
|
or delete($inconsistent->{$stateno}); |
756
|
|
|
|
|
|
|
} |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
$inconsistent |
759
|
10
|
|
|
|
|
196
|
} |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
############################# |
762
|
|
|
|
|
|
|
# Solve remaining conflicts # |
763
|
|
|
|
|
|
|
############################# |
764
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
sub _SolveConflicts { |
766
|
10
|
|
|
10
|
|
22
|
my($grammar,$states,$inconsistent)=@_; |
767
|
10
|
|
|
|
|
21
|
my(%rulesprec,$RulePrec); |
768
|
10
|
|
|
|
|
54
|
my($conflicts)={ SOLVED => {}, |
769
|
|
|
|
|
|
|
FORCED => { TOTAL => [ 0, 0 ], |
770
|
|
|
|
|
|
|
DETAIL => {} |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
}; |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
$RulePrec = sub { |
775
|
845
|
|
|
845
|
|
1250
|
my($ruleno)=@_; |
776
|
845
|
|
|
|
|
1070
|
my($rhs,$rprec)=@{$$grammar{RULES}[$ruleno]}[1,2]; |
|
845
|
|
|
|
|
1593
|
|
777
|
845
|
|
|
|
|
1134
|
my($lastterm); |
778
|
|
|
|
|
|
|
|
779
|
845
|
100
|
|
|
|
1717
|
defined($rprec) |
780
|
|
|
|
|
|
|
and return($rprec); |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
exists($rulesprec{$ruleno}) |
783
|
612
|
100
|
|
|
|
1483
|
and return($rulesprec{$ruleno}); |
784
|
|
|
|
|
|
|
|
785
|
67
|
|
|
|
|
134
|
$lastterm=(grep { exists($$grammar{TERM}{$_}) } @$rhs)[-1]; |
|
137
|
|
|
|
|
329
|
|
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
defined($lastterm) |
788
|
|
|
|
|
|
|
and ref($$grammar{TERM}{$lastterm}) |
789
|
67
|
100
|
66
|
|
|
263
|
and do { |
790
|
48
|
|
|
|
|
118
|
$rulesprec{$ruleno}=$$grammar{TERM}{$lastterm}[1]; |
791
|
48
|
|
|
|
|
99
|
return($rulesprec{$ruleno}); |
792
|
|
|
|
|
|
|
}; |
793
|
|
|
|
|
|
|
|
794
|
19
|
|
|
|
|
35
|
undef; |
795
|
10
|
|
|
|
|
58
|
}; |
796
|
|
|
|
|
|
|
|
797
|
10
|
|
|
|
|
67
|
for my $stateno (keys(%$inconsistent)) { |
798
|
155
|
|
|
|
|
372
|
my($state)=$$states[$stateno]; |
799
|
155
|
|
|
|
|
348
|
my($actions)=$$state{ACTIONS}; |
800
|
155
|
|
|
|
|
224
|
my($nbsr,$nbrr); |
801
|
|
|
|
|
|
|
|
802
|
155
|
|
|
|
|
1125
|
for my $term ( keys(%$actions) ) { |
803
|
5702
|
|
|
|
|
8180
|
my($act)=$$actions{$term}; |
804
|
|
|
|
|
|
|
|
805
|
5702
|
100
|
|
|
|
11125
|
@$act > 1 |
806
|
|
|
|
|
|
|
or next; |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
$$act[0] > 0 |
809
|
|
|
|
|
|
|
and ref($$grammar{TERM}{$term}) |
810
|
895
|
100
|
100
|
|
|
3508
|
and do { |
811
|
842
|
|
|
|
|
1120
|
my($assoc,$tprec)=@{$$grammar{TERM}{$term}}; |
|
842
|
|
|
|
|
1483
|
|
812
|
842
|
|
|
|
|
1188
|
my($k,$error); |
813
|
|
|
|
|
|
|
|
814
|
842
|
|
|
|
|
1746
|
for ($k=1;$k<@$act;++$k) { |
815
|
845
|
|
|
|
|
1244
|
my($ruleno)=-$$act[$k]; |
816
|
845
|
|
|
|
|
1396
|
my($rprec)=&$RulePrec($ruleno); |
817
|
|
|
|
|
|
|
|
818
|
845
|
100
|
|
|
|
1660
|
defined($rprec) |
819
|
|
|
|
|
|
|
or next; |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
( $tprec > $rprec |
822
|
|
|
|
|
|
|
or ( $tprec == $rprec and $assoc eq 'RIGHT')) |
823
|
826
|
100
|
100
|
|
|
2187
|
and do { |
|
|
|
100
|
|
|
|
|
824
|
542
|
|
|
|
|
691
|
push(@{$$conflicts{SOLVED}{$stateno}}, |
|
542
|
|
|
|
|
1644
|
|
825
|
|
|
|
|
|
|
[ $ruleno, $term, 'shift' ]); |
826
|
542
|
|
|
|
|
875
|
splice(@$act,$k--,1); |
827
|
542
|
|
|
|
|
1195
|
next; |
828
|
|
|
|
|
|
|
}; |
829
|
|
|
|
|
|
|
( $tprec < $rprec |
830
|
|
|
|
|
|
|
or $assoc eq 'LEFT') |
831
|
284
|
100
|
100
|
|
|
713
|
and do { |
832
|
283
|
|
|
|
|
377
|
push(@{$$conflicts{SOLVED}{$stateno}}, |
|
283
|
|
|
|
|
819
|
|
833
|
|
|
|
|
|
|
[ $ruleno, $term, 'reduce' ]); |
834
|
|
|
|
|
|
|
$$act[0] > 0 |
835
|
283
|
50
|
|
|
|
899
|
and do { |
836
|
283
|
|
|
|
|
408
|
splice(@$act,0,1); |
837
|
283
|
|
|
|
|
365
|
--$k; |
838
|
|
|
|
|
|
|
}; |
839
|
283
|
|
|
|
|
649
|
next; |
840
|
|
|
|
|
|
|
}; |
841
|
1
|
|
|
|
|
2
|
push(@{$$conflicts{SOLVED}{$stateno}}, |
|
1
|
|
|
|
|
4
|
|
842
|
|
|
|
|
|
|
[ $ruleno, $term, 'error' ]); |
843
|
1
|
|
|
|
|
4
|
splice(@$act,$k--,1); |
844
|
|
|
|
|
|
|
$$act[0] > 0 |
845
|
1
|
50
|
|
|
|
3
|
and do { |
846
|
1
|
|
|
|
|
2
|
splice(@$act,0,1); |
847
|
1
|
|
|
|
|
2
|
++$error; |
848
|
1
|
|
|
|
|
3
|
--$k; |
849
|
|
|
|
|
|
|
}; |
850
|
|
|
|
|
|
|
} |
851
|
842
|
100
|
|
|
|
1649
|
$error |
852
|
|
|
|
|
|
|
and unshift(@$act,undef); |
853
|
|
|
|
|
|
|
}; |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
@$act > 1 |
856
|
895
|
100
|
|
|
|
1856
|
and do { |
857
|
72
|
|
|
|
|
113
|
$nbrr += @$act - 2; |
858
|
72
|
100
|
|
|
|
126
|
($$act[0] > 0 ? $nbsr : $nbrr) += 1; |
859
|
72
|
|
|
|
|
222
|
push(@{$$conflicts{FORCED}{DETAIL}{$stateno}{LIST}}, |
860
|
72
|
|
|
|
|
102
|
map { [ $term, $_ ] } splice(@$act,1)); |
|
72
|
|
|
|
|
222
|
|
861
|
|
|
|
|
|
|
}; |
862
|
|
|
|
|
|
|
} |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
$nbsr |
865
|
155
|
100
|
|
|
|
495
|
and do { |
866
|
27
|
|
|
|
|
52
|
$$conflicts{FORCED}{TOTAL}[0]+=$nbsr; |
867
|
27
|
|
|
|
|
63
|
$$conflicts{FORCED}{DETAIL}{$stateno}{TOTAL}[0]+=$nbsr; |
868
|
|
|
|
|
|
|
}; |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
$nbrr |
871
|
155
|
100
|
|
|
|
355
|
and do { |
872
|
11
|
|
|
|
|
21
|
$$conflicts{FORCED}{TOTAL}[1]+=$nbrr; |
873
|
11
|
|
|
|
|
26
|
$$conflicts{FORCED}{DETAIL}{$stateno}{TOTAL}[1]+=$nbrr; |
874
|
|
|
|
|
|
|
}; |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
} |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
$conflicts |
879
|
10
|
|
|
|
|
115
|
} |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
############################### |
882
|
|
|
|
|
|
|
# Make default reduce actions # |
883
|
|
|
|
|
|
|
############################### |
884
|
|
|
|
|
|
|
sub _SetDefaults { |
885
|
10
|
|
|
10
|
|
20
|
my($states)=@_; |
886
|
|
|
|
|
|
|
|
887
|
10
|
|
|
|
|
25
|
for my $state (@$states) { |
888
|
1718
|
|
|
|
|
3030
|
my($actions)=$$state{ACTIONS}; |
889
|
1718
|
|
|
|
|
2301
|
my(%reduces,$default,$nodefault); |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
exists($$actions{''}) |
892
|
1718
|
100
|
|
|
|
3793
|
and do { |
893
|
751
|
|
|
|
|
1313
|
$$actions{''}[0] = -$$actions{''}[0]; |
894
|
751
|
|
|
|
|
1035
|
++$nodefault; |
895
|
|
|
|
|
|
|
}; |
896
|
|
|
|
|
|
|
|
897
|
|
|
|
|
|
|
#shift error token => no default |
898
|
|
|
|
|
|
|
exists($$actions{error}) |
899
|
1718
|
100
|
100
|
|
|
4119
|
and $$actions{error}[0] > 0 |
900
|
|
|
|
|
|
|
and ++$nodefault; |
901
|
|
|
|
|
|
|
|
902
|
1718
|
|
|
|
|
6710
|
for my $term (keys(%$actions)) { |
903
|
|
|
|
|
|
|
|
904
|
19432
|
|
|
|
|
31184
|
$$actions{$term}=$$actions{$term}[0]; |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
( not defined($$actions{$term}) |
907
|
19432
|
100
|
100
|
|
|
79688
|
or $$actions{$term} > 0 |
|
|
|
100
|
|
|
|
|
908
|
|
|
|
|
|
|
or $nodefault) |
909
|
|
|
|
|
|
|
and next; |
910
|
|
|
|
|
|
|
|
911
|
7059
|
|
|
|
|
9255
|
push(@{$reduces{$$actions{$term}}},$term); |
|
7059
|
|
|
|
|
13852
|
|
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
|
914
|
1718
|
100
|
|
|
|
4559
|
keys(%reduces) > 0 |
915
|
|
|
|
|
|
|
or next; |
916
|
|
|
|
|
|
|
|
917
|
416
|
|
|
|
|
792
|
$default=( map { $$_[0] } |
918
|
41
|
50
|
|
|
|
137
|
sort { $$b[1] <=> $$a[1] or $$b[0] <=> $$a[0] } |
919
|
377
|
|
|
|
|
731
|
map { [ $_, scalar(@{$reduces{$_}}) ] } |
|
416
|
|
|
|
|
546
|
|
|
416
|
|
|
|
|
1072
|
|
920
|
|
|
|
|
|
|
keys(%reduces))[0]; |
921
|
|
|
|
|
|
|
|
922
|
377
|
|
|
|
|
599
|
delete(@$actions{ @{$reduces{$default}} }); |
|
377
|
|
|
|
|
1303
|
|
923
|
377
|
|
|
|
|
1110
|
$$state{ACTIONS}{''}=$default; |
924
|
|
|
|
|
|
|
} |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
sub _LALR { |
928
|
10
|
|
|
10
|
|
20
|
my($grammar,$states) = @_; |
929
|
10
|
|
|
|
|
19
|
my($conflicts,$inconsistent); |
930
|
|
|
|
|
|
|
|
931
|
10
|
|
|
|
|
32
|
$inconsistent = _ComputeLA($grammar,$states); |
932
|
|
|
|
|
|
|
|
933
|
10
|
|
|
|
|
35
|
$conflicts = _SolveConflicts($grammar,$states,$inconsistent); |
934
|
10
|
|
|
|
|
42
|
_SetDefaults($states); |
935
|
|
|
|
|
|
|
|
936
|
10
|
|
|
|
|
79
|
$conflicts |
937
|
|
|
|
|
|
|
} |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
1; |