line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Parse::Eyapp::Lalr; |
2
|
|
|
|
|
|
|
@ISA=qw( Parse::Eyapp::Grammar ); |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
require 5.004; |
5
|
|
|
|
|
|
|
|
6
|
61
|
|
|
61
|
|
21774
|
use Parse::Eyapp::Grammar; |
|
61
|
|
|
|
|
208
|
|
|
61
|
|
|
|
|
1935
|
|
7
|
61
|
|
|
61
|
|
343
|
use Data::Dumper; |
|
61
|
|
|
|
|
132
|
|
|
61
|
|
|
|
|
3256
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# Parse::Eyapp::Compile Object Structure: |
10
|
|
|
|
|
|
|
# -------------------------------------- |
11
|
|
|
|
|
|
|
# { |
12
|
|
|
|
|
|
|
# GRAMMAR => Parse::Eyapp::Grammar, |
13
|
|
|
|
|
|
|
# STATES => [ { CORE => [ items... ], |
14
|
|
|
|
|
|
|
# ACTIONS => { term => action } |
15
|
|
|
|
|
|
|
# GOTOS => { nterm => stateno } |
16
|
|
|
|
|
|
|
# }... ] |
17
|
|
|
|
|
|
|
# CONFLICTS=>{ SOLVED => { stateno => [ ruleno, token, solved ] }, |
18
|
|
|
|
|
|
|
# FORCED => { TOTAL => [ nbsr, nbrr ], |
19
|
|
|
|
|
|
|
# DETAIL => { stateno => { TOTAL => [ nbsr, nbrr ] } |
20
|
|
|
|
|
|
|
# LIST => [ ruleno, token ] |
21
|
|
|
|
|
|
|
# } |
22
|
|
|
|
|
|
|
# } |
23
|
|
|
|
|
|
|
# } |
24
|
|
|
|
|
|
|
# } |
25
|
|
|
|
|
|
|
# |
26
|
|
|
|
|
|
|
# 'items' are of form: [ ruleno, dotpos ] |
27
|
|
|
|
|
|
|
# 'term' in ACTIONS is '' means default action |
28
|
|
|
|
|
|
|
# 'action' may be: |
29
|
|
|
|
|
|
|
# undef: explicit error (nonassociativity) |
30
|
|
|
|
|
|
|
# 0 : accept |
31
|
|
|
|
|
|
|
# >0 : shift and go to state 'action' |
32
|
|
|
|
|
|
|
# <0 : reduce using rule -'action' |
33
|
|
|
|
|
|
|
# 'solved' may have values of: |
34
|
|
|
|
|
|
|
# 'shift' if solved as Shift |
35
|
|
|
|
|
|
|
# 'reduce' if solved as Reduce |
36
|
|
|
|
|
|
|
# 'error' if solved by discarding both Shift and Reduce (nonassoc) |
37
|
|
|
|
|
|
|
# |
38
|
|
|
|
|
|
|
# SOLVED is a set of states containing Solved conflicts |
39
|
|
|
|
|
|
|
# FORCED are forced conflict resolutions |
40
|
|
|
|
|
|
|
# |
41
|
|
|
|
|
|
|
# nbsr and nbrr are number of shift/reduce and reduce/reduce conflicts |
42
|
|
|
|
|
|
|
# |
43
|
|
|
|
|
|
|
# TOTAL is the total number of SR/RR conflicts for the parser |
44
|
|
|
|
|
|
|
# |
45
|
|
|
|
|
|
|
# DETAIL is the detail of conflicts for each state |
46
|
|
|
|
|
|
|
# TOTAL is the total number of SR/RR conflicts for a state |
47
|
|
|
|
|
|
|
# LIST is the list of discarded reductions (for display purpose only) |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
|
50
|
61
|
|
|
61
|
|
388
|
use strict; |
|
61
|
|
|
|
|
135
|
|
|
61
|
|
|
|
|
1209
|
|
51
|
|
|
|
|
|
|
|
52
|
61
|
|
|
61
|
|
284
|
use Carp; |
|
61
|
|
|
|
|
124
|
|
|
61
|
|
|
|
|
298593
|
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
############### |
55
|
|
|
|
|
|
|
# Constructor # |
56
|
|
|
|
|
|
|
############### |
57
|
|
|
|
|
|
|
sub new { |
58
|
54
|
|
|
54
|
0
|
182
|
my($class)=shift; |
59
|
|
|
|
|
|
|
|
60
|
54
|
50
|
|
|
|
205
|
ref($class) |
61
|
|
|
|
|
|
|
and $class=ref($class); |
62
|
|
|
|
|
|
|
|
63
|
54
|
|
|
|
|
533
|
my($self)=$class->SUPER::new(@_); |
64
|
54
|
|
|
|
|
651
|
$self->_Compile(); |
65
|
54
|
|
|
|
|
614
|
$self->_DynamicConflicts(); # call it only if dynamic conflict handlers |
66
|
|
|
|
|
|
|
|
67
|
54
|
50
|
|
|
|
396
|
if ($self->Option('prefix')) { |
68
|
|
|
|
|
|
|
# weak accept for nested parsing !!!!!!!!!!!! |
69
|
|
|
|
|
|
|
# substitute End Of Input by DEFAULT for each state |
70
|
0
|
|
|
|
|
0
|
for (@{$self->{STATES}}) { |
|
0
|
|
|
|
|
0
|
|
71
|
0
|
0
|
|
|
|
0
|
if (exists($_->{ACTIONS}{"\c@"})) { |
72
|
|
|
|
|
|
|
# what if DEFAULT action already exists ? |
73
|
|
|
|
|
|
|
# Shall I have to use an option in eyapp???? |
74
|
0
|
|
|
|
|
0
|
$_->{ACTIONS}{''} = $_->{ACTIONS}{"\c@"}; |
75
|
0
|
|
|
|
|
0
|
delete($_->{ACTIONS}{"\c@"}); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
54
|
|
|
|
|
418
|
bless($self,$class); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
########### |
83
|
|
|
|
|
|
|
# Methods # |
84
|
|
|
|
|
|
|
########### |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
########################### |
87
|
|
|
|
|
|
|
# Method To View Warnings # |
88
|
|
|
|
|
|
|
########################### |
89
|
|
|
|
|
|
|
sub Warnings { |
90
|
4
|
|
|
4
|
0
|
51
|
my($self)=shift; |
91
|
4
|
|
|
|
|
12
|
my($text) = ''; |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# $nbsr = number of shift-reduce conflicts |
94
|
|
|
|
|
|
|
# $nbrr = number of reduce-reduce conflicts |
95
|
4
|
|
|
|
|
8
|
my($nbsr,$nbrr)=@{$$self{CONFLICTS}{FORCED}{TOTAL}}; |
|
4
|
|
|
|
|
20
|
|
96
|
|
|
|
|
|
|
|
97
|
4
|
|
|
|
|
31
|
$text=$self->SUPER::Warnings(); |
98
|
|
|
|
|
|
|
|
99
|
4
|
|
|
|
|
12
|
my $expected = $$self{GRAMMAR}{EXPECT}; |
100
|
4
|
50
|
|
|
|
23
|
my ($sre, $rre) = ref($expected) ? @$expected : ($expected, 0); |
101
|
|
|
|
|
|
|
|
102
|
4
|
100
|
66
|
|
|
24
|
$nbsr != $sre and $nbsr > 0 and do { |
103
|
1
|
50
|
|
|
|
7
|
$text.="$nbsr shift/reduce conflict".($nbsr > 1 ? "s " : " "); |
104
|
|
|
|
|
|
|
}; # end of $nbsr != $sre There were shift-reduce conflicts |
105
|
|
|
|
|
|
|
|
106
|
4
|
50
|
33
|
|
|
19
|
$nbrr != $rre and $nbrr > 0 and do { |
107
|
0
|
0
|
|
|
|
0
|
$nbsr != $sre and $text.="and "; |
108
|
0
|
0
|
|
|
|
0
|
$text.="$nbrr reduce/reduce conflict".($nbrr > 1 ? "s" : ""); |
109
|
|
|
|
|
|
|
}; |
110
|
|
|
|
|
|
|
|
111
|
4
|
|
|
|
|
17
|
$text; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
############################# |
114
|
|
|
|
|
|
|
# Method To View DFA States # |
115
|
|
|
|
|
|
|
############################# |
116
|
|
|
|
|
|
|
sub ShowDfa { |
117
|
0
|
|
|
0
|
0
|
0
|
my($self)=shift; |
118
|
0
|
|
|
|
|
0
|
my($text) = ''; |
119
|
0
|
|
|
|
|
0
|
my($grammar,$states)=($$self{GRAMMAR}, $$self{STATES}); |
120
|
|
|
|
|
|
|
|
121
|
0
|
|
|
|
|
0
|
for my $stateno (0..$#$states) { |
122
|
0
|
|
|
|
|
0
|
my(@shifts,@reduces,@errors,$default); |
123
|
|
|
|
|
|
|
|
124
|
0
|
|
|
|
|
0
|
$text.="State $stateno:\n\n"; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
#Dump Kernel Items |
127
|
0
|
0
|
|
|
|
0
|
for (sort { $$a[0] <=> $$b[0] |
|
0
|
|
|
|
|
0
|
|
128
|
0
|
|
|
|
|
0
|
or $$a[1] <=> $$b[1] } @{$$states[$stateno]{'CORE'}}) { |
129
|
0
|
|
|
|
|
0
|
my($ruleno,$pos)=@$_; |
130
|
0
|
|
|
|
|
0
|
my($lhs,$rhs)=@{$$grammar{RULES}[$ruleno]}[0,1]; |
|
0
|
|
|
|
|
0
|
|
131
|
0
|
|
|
|
|
0
|
my(@rhscopy)=@$rhs; |
132
|
|
|
|
|
|
|
|
133
|
0
|
0
|
|
|
|
0
|
$ruleno |
134
|
|
|
|
|
|
|
or $rhscopy[-1] = '$end'; |
135
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
0
|
splice(@rhscopy,$pos,0,'.'); |
137
|
0
|
|
|
|
|
0
|
$text.= "\t$lhs -> ".join(' ',@rhscopy)."\t(Rule $ruleno)\n"; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
#Prepare Actions |
141
|
0
|
|
|
|
|
0
|
for (keys(%{$$states[$stateno]{ACTIONS}})) { |
|
0
|
|
|
|
|
0
|
|
142
|
0
|
|
|
|
|
0
|
my($term,$action)=($_,$$states[$stateno]{ACTIONS}{$_}); |
143
|
|
|
|
|
|
|
|
144
|
0
|
0
|
|
|
|
0
|
$term eq chr(0) |
145
|
|
|
|
|
|
|
and $term = '$end'; |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
not defined($action) |
148
|
0
|
0
|
|
|
|
0
|
and do { |
149
|
0
|
|
|
|
|
0
|
push(@errors,$term); |
150
|
0
|
|
|
|
|
0
|
next; |
151
|
|
|
|
|
|
|
}; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
$action > 0 |
154
|
0
|
0
|
|
|
|
0
|
and do { |
155
|
0
|
|
|
|
|
0
|
push(@shifts,[ $term, $action ]); |
156
|
0
|
|
|
|
|
0
|
next; |
157
|
|
|
|
|
|
|
}; |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
0
|
$action = -$action; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
$term |
162
|
0
|
0
|
|
|
|
0
|
or do { |
163
|
0
|
|
|
|
|
0
|
$default= [ '$default', $action ]; |
164
|
0
|
|
|
|
|
0
|
next; |
165
|
|
|
|
|
|
|
}; |
166
|
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
0
|
push(@reduces,[ $term, $action ]); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
#Dump shifts |
171
|
|
|
|
|
|
|
@shifts |
172
|
0
|
0
|
|
|
|
0
|
and do { |
173
|
0
|
|
|
|
|
0
|
$text.="\n"; |
174
|
0
|
|
|
|
|
0
|
for (sort { $$a[0] cmp $$b[0] } @shifts) { |
|
0
|
|
|
|
|
0
|
|
175
|
0
|
|
|
|
|
0
|
my($term,$shift)=@$_; |
176
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
0
|
$text.="\t$term\tshift, and go to state $shift\n"; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
}; |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
#Dump errors |
182
|
|
|
|
|
|
|
@errors |
183
|
0
|
0
|
|
|
|
0
|
and do { |
184
|
0
|
|
|
|
|
0
|
$text.="\n"; |
185
|
0
|
|
|
|
|
0
|
for my $term (sort { $a cmp $b } @errors) { |
|
0
|
|
|
|
|
0
|
|
186
|
0
|
|
|
|
|
0
|
$text.="\t$term\terror (nonassociative)\n"; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
}; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
#Prepare reduces |
191
|
|
|
|
|
|
|
exists($$self{CONFLICTS}{FORCED}{DETAIL}{$stateno}) |
192
|
0
|
0
|
|
|
|
0
|
and push(@reduces,@{$$self{CONFLICTS}{FORCED}{DETAIL}{$stateno}{LIST}}); |
|
0
|
|
|
|
|
0
|
|
193
|
|
|
|
|
|
|
|
194
|
0
|
0
|
|
|
|
0
|
@reduces=sort { $$a[0] cmp $$b[0] or $$a[1] <=> $$b[1] } @reduces; |
|
0
|
|
|
|
|
0
|
|
195
|
|
|
|
|
|
|
|
196
|
0
|
0
|
|
|
|
0
|
defined($default) |
197
|
|
|
|
|
|
|
and push(@reduces,$default); |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
#Dump reduces |
200
|
|
|
|
|
|
|
@reduces |
201
|
0
|
0
|
|
|
|
0
|
and do { |
202
|
0
|
|
|
|
|
0
|
$text.="\n"; |
203
|
0
|
|
|
|
|
0
|
for (@reduces) { |
204
|
0
|
|
|
|
|
0
|
my($term,$ruleno)=@$_; |
205
|
0
|
|
|
|
|
0
|
my($discard); |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
$ruleno < 0 |
208
|
0
|
0
|
|
|
|
0
|
and do { |
209
|
0
|
|
|
|
|
0
|
++$discard; |
210
|
0
|
|
|
|
|
0
|
$ruleno = -$ruleno; |
211
|
|
|
|
|
|
|
}; |
212
|
|
|
|
|
|
|
|
213
|
0
|
0
|
|
|
|
0
|
$term eq chr(0) |
214
|
|
|
|
|
|
|
and $term = '$end'; |
215
|
|
|
|
|
|
|
|
216
|
0
|
0
|
|
|
|
0
|
$text.= "\t$term\t".($discard ? "[" : ""); |
217
|
0
|
0
|
|
|
|
0
|
if($ruleno) { |
218
|
0
|
|
|
|
|
0
|
$text.= "reduce using rule $ruleno ". |
219
|
|
|
|
|
|
|
"($$grammar{RULES}[$ruleno][0])"; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
else { |
222
|
0
|
|
|
|
|
0
|
$text.='accept'; |
223
|
|
|
|
|
|
|
} |
224
|
0
|
0
|
|
|
|
0
|
$text.=($discard ? "]" : "")."\n"; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
}; |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
#Dump gotos |
229
|
|
|
|
|
|
|
exists($$states[$stateno]{GOTOS}) |
230
|
0
|
0
|
|
|
|
0
|
and do { |
231
|
0
|
|
|
|
|
0
|
$text.= "\n"; |
232
|
0
|
|
|
|
|
0
|
for (keys(%{$$states[$stateno]{GOTOS}})) { |
|
0
|
|
|
|
|
0
|
|
233
|
0
|
|
|
|
|
0
|
$text.= "\t$_\tgo to state $$states[$stateno]{GOTOS}{$_}\n"; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
}; |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
0
|
$text.="\n"; |
238
|
|
|
|
|
|
|
} |
239
|
0
|
|
|
|
|
0
|
$text; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
#################################################################### |
243
|
|
|
|
|
|
|
# Usage : $parser->outputtables($path, $base) |
244
|
|
|
|
|
|
|
# Purpose : Gives support to eyapp option -v |
245
|
|
|
|
|
|
|
# Parameters : The parser object plus the $path and $base names for the .output |
246
|
|
|
|
|
|
|
# file |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub outputtables { |
249
|
0
|
|
|
0
|
0
|
0
|
my ($parser, $path, $base) = @_; |
250
|
|
|
|
|
|
|
|
251
|
0
|
0
|
|
|
|
0
|
my($output)=$base?"$path$base.output":"STDOUT"; |
252
|
0
|
|
|
|
|
0
|
my($tmp); |
253
|
|
|
|
|
|
|
|
254
|
0
|
0
|
|
|
|
0
|
open(my $OUT,">$output") |
255
|
|
|
|
|
|
|
or die "Cannot create $base.output for writing.\n"; |
256
|
|
|
|
|
|
|
|
257
|
0
|
0
|
|
|
|
0
|
$tmp=$parser->Warnings() |
258
|
|
|
|
|
|
|
and print $OUT "Warnings:\n---------\n$tmp\n"; |
259
|
0
|
0
|
|
|
|
0
|
$tmp=$parser->Conflicts() |
260
|
|
|
|
|
|
|
and print $OUT "Conflicts:\n----------\n$tmp\n"; |
261
|
0
|
|
|
|
|
0
|
print $OUT "Rules:\n------\n"; |
262
|
0
|
|
|
|
|
0
|
print $OUT $parser->ShowRules()."\n"; |
263
|
0
|
|
|
|
|
0
|
print $OUT "States:\n-------\n"; |
264
|
0
|
|
|
|
|
0
|
print $OUT $parser->ShowDfa()."\n"; |
265
|
0
|
|
|
|
|
0
|
print $OUT "Summary:\n--------\n"; |
266
|
0
|
|
|
|
|
0
|
print $OUT $parser->Summary(); |
267
|
|
|
|
|
|
|
|
268
|
0
|
|
|
|
|
0
|
close($OUT); |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub outputDot { |
272
|
0
|
|
|
0
|
0
|
0
|
my ($parser, $path, $base, $labelWithCore) = @_; |
273
|
|
|
|
|
|
|
|
274
|
0
|
0
|
|
|
|
0
|
my ($output)=$base?"$path$base.dot":"STDOUT"; |
275
|
|
|
|
|
|
|
|
276
|
0
|
0
|
|
|
|
0
|
open(my $OUT,">$output") |
277
|
|
|
|
|
|
|
or die "Cannot create $base.dot for writing.\n"; |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
0
|
my $graph = ''; |
280
|
|
|
|
|
|
|
|
281
|
0
|
|
|
|
|
0
|
my $dfa = $parser->ShowDfa(); |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
#warn "$dfa\n"; |
284
|
|
|
|
|
|
|
|
285
|
0
|
|
|
|
|
0
|
my $grammar = $parser->ShowRules()."\n"; |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
#warn "$grammar\n"; |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# make an array from the grammar |
290
|
|
|
|
|
|
|
|
291
|
0
|
|
|
|
|
0
|
my %grammar = $grammar =~ m{(\d+):\s+(.*)}gx; |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# escape double quotes inside %grammar |
294
|
0
|
|
|
|
|
0
|
$graph .= qq{ "g0" [label="0: $grammar{0}", shape = doubleoctagon, fontcolor=blue, color=blue ]\n}; |
295
|
0
|
|
|
|
|
0
|
for (1 .. (keys %grammar)-1) { |
296
|
0
|
|
|
|
|
0
|
$grammar{$_} =~ s/\\/\\\\/g; # escape escapes |
297
|
0
|
|
|
|
|
0
|
$grammar{$_} =~ s/"/\\"/g; # escape double quotes |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
#warn "$_ => $grammar{$_}\n"; |
300
|
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
0
|
$graph .= qq{ "g$_" [label="$_: $grammar{$_}", shape = box, fontcolor=blue, color=blue ]\n}; |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
0
|
|
|
|
|
0
|
for (0 .. (keys %grammar)-2) { |
305
|
0
|
|
|
|
|
0
|
my $n = $_+1; |
306
|
0
|
|
|
|
|
0
|
$graph .= qq{ g$_ ->g$n [style=dotted];\n}; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
0
|
|
|
|
|
0
|
my $conflicts = $parser->Conflicts(); |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
#warn $conflicts; |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# State 13 contains 5 shift/reduce conflicts |
314
|
|
|
|
|
|
|
# State 23 contains 5 shift/reduce conflicts |
315
|
0
|
|
|
|
|
0
|
my @conflictstates = $conflicts =~ m{State\s+(\d+)\s+contains\s+\d+\s+(?:shift|reduce)/reduce\s+conflicts?\s*}gx; |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
#warn "(@conflictstates)\n"; |
318
|
|
|
|
|
|
|
|
319
|
0
|
|
|
|
|
0
|
$graph .= qq{$_ [shape = diamond, fontcolor=red, color=red]\n} for @conflictstates; |
320
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
0
|
my %states = ($dfa =~ m{State\s*(\d+)\s*:\n\s* |
322
|
|
|
|
|
|
|
( |
323
|
|
|
|
|
|
|
(?: |
324
|
|
|
|
|
|
|
.*->.* | # a production line |
325
|
|
|
|
|
|
|
.*go\s+to.* | # a shift or a goto line |
326
|
|
|
|
|
|
|
.*reduce.* | # a reduce line |
327
|
|
|
|
|
|
|
.*accept.* | # an accept line |
328
|
|
|
|
|
|
|
\s+ | # white lines |
329
|
|
|
|
|
|
|
)+ |
330
|
|
|
|
|
|
|
) |
331
|
|
|
|
|
|
|
}gx); |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
0
|
for (sort { $a <=> $b } keys %states) { |
|
0
|
|
|
|
|
0
|
|
334
|
0
|
|
|
|
|
0
|
my $desc = $states{$_}; |
335
|
0
|
|
|
|
|
0
|
my @LRitems = $desc =~ m{(\S.*->.*[^\s.])\s+\(Rule\s+\d+\)}g; # remove productions |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
# label states with core LR-0 items |
338
|
0
|
0
|
|
|
|
0
|
if ($labelWithCore) { # this is optional |
339
|
0
|
|
|
|
|
0
|
local $" = "\\n"; |
340
|
0
|
|
|
|
|
0
|
$graph .= qq{$_ [ label = "$_\\n@LRitems"}; #shape = plaintext, |
341
|
0
|
|
|
|
|
0
|
my $s = $_; |
342
|
0
|
0
|
|
|
|
0
|
$graph .= qq{, shape = plaintext} unless (grep { $_ eq $s} @conflictstates); |
|
0
|
|
|
|
|
0
|
|
343
|
0
|
|
|
|
|
0
|
$graph .= "]\n"; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
#warn "LRitems in $_:\n@LRitems\n"; |
347
|
|
|
|
|
|
|
|
348
|
0
|
|
|
|
|
0
|
$desc =~ s/\n\s*\n/\n/g; # remove white lines |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# build digraph |
351
|
|
|
|
|
|
|
# ID shift, and go to state 4 |
352
|
0
|
|
|
|
|
0
|
while ($desc =~ m{\t(.*)\s+shift,\s+and\s+go\s+to\s+state\s+(\d+)}gx) { |
353
|
0
|
|
|
|
|
0
|
my ($label, $state) = ($1, $2); |
354
|
0
|
|
|
|
|
0
|
$label =~ s/\\(?!")/\\\\/g; |
355
|
0
|
|
|
|
|
0
|
$graph .= qq{$_ -> $state [label = "$label"]\n}; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# decl go to state 1 |
359
|
0
|
|
|
|
|
0
|
while ($desc =~ m{\t(\S+)\s+go\s+to\s+state\s+(\d+)}gx) { |
360
|
0
|
|
|
|
|
0
|
$graph .= qq{$_ -> $2 [label = "$1", arrowhead = odot, color = "red", fontcolor = "red"]\n}; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# $default reduce using rule 1 (prog) |
364
|
|
|
|
|
|
|
# ID reduce using rule 15 (decORexp_explorer) |
365
|
0
|
|
|
|
|
0
|
while ($desc =~ m{\t(\S+)\s+reduce\s+using\s+rule\s+(\d+)}gx) { |
366
|
0
|
|
|
|
|
0
|
$graph .= qq{$_ -> "g$2" [label = "$1", arrowhead=dot, color = "blue", fontcolor = "blue"]\n}; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# shift-reduce conflicts |
370
|
|
|
|
|
|
|
# ';' [reduce using rule 4 (ds)] |
371
|
0
|
|
|
|
|
0
|
while ($desc =~ m{\t(\S+)\s+\[\s*reduce\s+using\s+rule\s+(\d+)}gx) { |
372
|
0
|
|
|
|
|
0
|
$graph .= |
373
|
|
|
|
|
|
|
qq{$_ -> "g$2" [label = "$1", arrowhead=dot, style=dotted, color = "red", fontcolor = "red"]\n}; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# $default accept |
377
|
0
|
0
|
|
|
|
0
|
if ($desc =~ m{\t\$default\s+accept\s*}gx) { |
378
|
0
|
|
|
|
|
0
|
$graph .= qq{$_ [shape = doublecircle]\n}; |
379
|
0
|
|
|
|
|
0
|
$graph .= qq{$_ -> "g0" [arrowhead = dot, color = blue]\n}; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
#warn "$_ => $desc\n"; |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
} |
385
|
0
|
|
|
|
|
0
|
print $OUT <<"EOGRAPH"; |
386
|
|
|
|
|
|
|
digraph G { |
387
|
|
|
|
|
|
|
#concentrate = true |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
$graph |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
EOGRAPH |
392
|
0
|
|
|
|
|
0
|
close $OUT; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub qtables { |
396
|
0
|
|
|
0
|
0
|
0
|
my ($parser) = @_; |
397
|
|
|
|
|
|
|
|
398
|
0
|
|
|
|
|
0
|
my($tmp); |
399
|
|
|
|
|
|
|
|
400
|
0
|
|
|
|
|
0
|
my $warnings = $parser->Warnings(); |
401
|
0
|
|
|
|
|
0
|
my $conflicts = $parser->Conflicts(); |
402
|
0
|
|
|
|
|
0
|
my $rules = $parser->ShowRules(); |
403
|
0
|
|
|
|
|
0
|
my $states = $parser->ShowDfa(); |
404
|
0
|
|
|
|
|
0
|
my $summary = $parser->Summary(); |
405
|
|
|
|
|
|
|
|
406
|
0
|
|
|
|
|
0
|
my $tables =<<"ENDOFLALAR" |
407
|
|
|
|
|
|
|
Warnings: |
408
|
|
|
|
|
|
|
--------- |
409
|
|
|
|
|
|
|
$warnings |
410
|
|
|
|
|
|
|
Conflicts: |
411
|
|
|
|
|
|
|
---------- |
412
|
|
|
|
|
|
|
$conflicts |
413
|
|
|
|
|
|
|
Rules: |
414
|
|
|
|
|
|
|
------ |
415
|
|
|
|
|
|
|
$rules |
416
|
|
|
|
|
|
|
States: |
417
|
|
|
|
|
|
|
------ |
418
|
|
|
|
|
|
|
$states |
419
|
|
|
|
|
|
|
$states |
420
|
|
|
|
|
|
|
Summary: |
421
|
|
|
|
|
|
|
-------- |
422
|
|
|
|
|
|
|
$summary |
423
|
|
|
|
|
|
|
ENDOFLALAR |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
###################################### |
427
|
|
|
|
|
|
|
# Method to get summary about parser # |
428
|
|
|
|
|
|
|
###################################### |
429
|
|
|
|
|
|
|
sub Summary { |
430
|
0
|
|
|
0
|
0
|
0
|
my($self)=shift; |
431
|
0
|
|
|
|
|
0
|
my($text) = ''; |
432
|
|
|
|
|
|
|
|
433
|
0
|
|
|
|
|
0
|
$text=$self->SUPER::Summary(); |
434
|
|
|
|
|
|
|
$text.="Number of states : ". |
435
|
0
|
|
|
|
|
0
|
scalar(@{$$self{STATES}})."\n"; |
|
0
|
|
|
|
|
0
|
|
436
|
0
|
|
|
|
|
0
|
$text; |
437
|
|
|
|
|
|
|
} |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
####################################### |
440
|
|
|
|
|
|
|
# Method To Get Infos about conflicts # |
441
|
|
|
|
|
|
|
####################################### |
442
|
|
|
|
|
|
|
sub Conflicts { |
443
|
0
|
|
|
0
|
0
|
0
|
my($self)=shift; |
444
|
0
|
|
|
|
|
0
|
my($states)=$$self{STATES}; |
445
|
0
|
|
|
|
|
0
|
my($conflicts)=$$self{CONFLICTS}; |
446
|
0
|
|
|
|
|
0
|
my($text) = ''; |
447
|
|
|
|
|
|
|
|
448
|
0
|
|
|
|
|
0
|
for my $stateno ( sort { $a <=> $b } keys(%{$$conflicts{SOLVED}})) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
449
|
|
|
|
|
|
|
|
450
|
0
|
|
|
|
|
0
|
for (@{$$conflicts{SOLVED}{$stateno}}) { |
|
0
|
|
|
|
|
0
|
|
451
|
0
|
|
|
|
|
0
|
my($ruleno,$token,$how)=@$_; |
452
|
|
|
|
|
|
|
|
453
|
0
|
0
|
|
|
|
0
|
$token eq chr(0) |
454
|
|
|
|
|
|
|
and $token = '$end'; |
455
|
|
|
|
|
|
|
|
456
|
0
|
|
|
|
|
0
|
$text.="Conflict in state $stateno between rule ". |
457
|
|
|
|
|
|
|
"$ruleno and token $token resolved as $how.\n"; |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
}; |
460
|
|
|
|
|
|
|
|
461
|
0
|
|
|
|
|
0
|
for my $stateno ( sort { $a <=> $b } keys(%{$$conflicts{FORCED}{DETAIL}})) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
462
|
0
|
|
|
|
|
0
|
my($nbsr,$nbrr)=@{$$conflicts{FORCED}{DETAIL}{$stateno}{TOTAL}}; |
|
0
|
|
|
|
|
0
|
|
463
|
|
|
|
|
|
|
|
464
|
0
|
|
|
|
|
0
|
$text.="State $stateno contains "; |
465
|
|
|
|
|
|
|
|
466
|
0
|
0
|
|
|
|
0
|
$nbsr |
|
|
0
|
|
|
|
|
|
467
|
|
|
|
|
|
|
and $text.="$nbsr shift/reduce conflict". |
468
|
|
|
|
|
|
|
($nbsr > 1 ? "s" : ""); |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
$nbrr |
471
|
0
|
0
|
|
|
|
0
|
and do { |
472
|
0
|
0
|
|
|
|
0
|
$nbsr |
473
|
|
|
|
|
|
|
and $text.=" and "; |
474
|
|
|
|
|
|
|
|
475
|
0
|
0
|
|
|
|
0
|
$text.="$nbrr reduce/reduce conflict". |
476
|
|
|
|
|
|
|
($nbrr > 1 ? "s" : ""); |
477
|
|
|
|
|
|
|
}; |
478
|
0
|
|
|
|
|
0
|
$text.="\n"; |
479
|
|
|
|
|
|
|
}; |
480
|
|
|
|
|
|
|
|
481
|
0
|
|
|
|
|
0
|
$text; |
482
|
|
|
|
|
|
|
} |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
################################# |
485
|
|
|
|
|
|
|
# Method to dump parsing tables # |
486
|
|
|
|
|
|
|
################################# |
487
|
|
|
|
|
|
|
sub DfaTable { |
488
|
54
|
|
|
54
|
0
|
183
|
my($self)=shift; |
489
|
54
|
|
|
|
|
159
|
my($states)=$$self{STATES}; |
490
|
54
|
|
|
|
|
208
|
my($stateno); |
491
|
|
|
|
|
|
|
my($text); |
492
|
|
|
|
|
|
|
|
493
|
54
|
|
|
|
|
156
|
$text="[\n\t{"; |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
$text.=join("\n\t},\n\t{", |
496
|
|
|
|
|
|
|
map { |
497
|
54
|
|
|
|
|
181
|
my($state)=$_; |
|
1289
|
|
|
|
|
1965
|
|
498
|
1289
|
|
|
|
|
1718
|
my($text); |
499
|
|
|
|
|
|
|
|
500
|
1289
|
|
|
|
|
2344
|
$text="#State ".$stateno++."\n\t\t"; |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
( not exists($$state{ACTIONS}{''}) |
503
|
694
|
|
|
|
|
2360
|
or keys(%{$$state{ACTIONS}}) > 1) |
504
|
1289
|
100
|
100
|
|
|
3547
|
and do { |
505
|
|
|
|
|
|
|
|
506
|
877
|
|
|
|
|
1503
|
$text.="ACTIONS => {\n\t\t\t"; |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
$text.=join(",\n\t\t\t", |
509
|
|
|
|
|
|
|
map { |
510
|
3101
|
|
|
|
|
5991
|
my($term,$action)=($_,$$state{ACTIONS}{$_}); |
511
|
3101
|
|
|
|
|
4117
|
my($text); |
512
|
|
|
|
|
|
|
|
513
|
3101
|
100
|
|
|
|
5964
|
if(substr($term,0,1) eq "'") { |
514
|
2247
|
|
|
|
|
4036
|
$term=~s/([\@\$\"])/\\$1/g; |
515
|
2247
|
|
|
|
|
6444
|
$term=~s/^'|'$/"/g; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
else { |
518
|
854
|
100
|
|
|
|
1929
|
$term= $term eq chr(0) |
519
|
|
|
|
|
|
|
? "''" |
520
|
|
|
|
|
|
|
: "'$term'"; |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
3101
|
50
|
|
|
|
6174
|
if(defined($action)) { |
524
|
3101
|
|
|
|
|
4246
|
$action=int($action); |
525
|
|
|
|
|
|
|
} |
526
|
|
|
|
|
|
|
else { |
527
|
0
|
|
|
|
|
0
|
$action='undef'; |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
|
530
|
3101
|
|
|
|
|
7361
|
"$term => $action"; |
531
|
|
|
|
|
|
|
|
532
|
877
|
|
|
|
|
1319
|
} grep { $_ } keys(%{$$state{ACTIONS}})); |
|
3383
|
|
|
|
|
5513
|
|
|
877
|
|
|
|
|
2032
|
|
533
|
|
|
|
|
|
|
|
534
|
877
|
|
|
|
|
1748
|
$text.="\n\t\t}"; |
535
|
|
|
|
|
|
|
}; |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
exists($$state{ACTIONS}{''}) |
538
|
1289
|
100
|
|
|
|
2997
|
and do { |
539
|
694
|
100
|
|
|
|
958
|
keys(%{$$state{ACTIONS}}) > 1 |
|
694
|
|
|
|
|
1727
|
|
540
|
|
|
|
|
|
|
and $text.=",\n\t\t"; |
541
|
|
|
|
|
|
|
|
542
|
694
|
|
|
|
|
1440
|
$text.="DEFAULT => $$state{ACTIONS}{''}"; |
543
|
|
|
|
|
|
|
}; |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
exists($$state{GOTOS}) |
546
|
1289
|
100
|
|
|
|
2734
|
and do { |
547
|
481
|
|
|
|
|
831
|
$text.=",\n\t\tGOTOS => {\n\t\t\t"; |
548
|
|
|
|
|
|
|
$text.=join(",\n\t\t\t", |
549
|
|
|
|
|
|
|
map { |
550
|
909
|
|
|
|
|
1776
|
my($nterm,$stateno)=($_,$$state{GOTOS}{$_}); |
551
|
909
|
|
|
|
|
1252
|
my($text); |
552
|
|
|
|
|
|
|
|
553
|
909
|
|
|
|
|
2177
|
"'$nterm' => $stateno"; |
554
|
|
|
|
|
|
|
|
555
|
481
|
|
|
|
|
701
|
} keys(%{$$state{GOTOS}})); |
|
481
|
|
|
|
|
1085
|
|
556
|
481
|
|
|
|
|
965
|
$text.="\n\t\t}"; |
557
|
|
|
|
|
|
|
}; |
558
|
|
|
|
|
|
|
|
559
|
1289
|
|
|
|
|
2903
|
$text; |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
}@$states); |
562
|
|
|
|
|
|
|
|
563
|
54
|
|
|
|
|
296
|
$text.="\n\t}\n]"; |
564
|
|
|
|
|
|
|
|
565
|
54
|
|
|
|
|
318
|
$text; |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
sub _DynamicConflicts { |
570
|
54
|
|
|
54
|
|
147
|
my $self = shift; |
571
|
54
|
|
|
|
|
170
|
my $ch = $self->{GRAMMAR}{CONFLICTHANDLERS}; |
572
|
|
|
|
|
|
|
|
573
|
54
|
50
|
|
|
|
233
|
return unless %$ch; |
574
|
|
|
|
|
|
|
|
575
|
0
|
|
|
|
|
0
|
my $co = $self->{CONFLICTS}{FORCED}{DETAIL}; |
576
|
|
|
|
|
|
|
|
577
|
0
|
|
|
|
|
0
|
my %C; # keys: |
578
|
|
|
|
|
|
|
# conflictive grammar productions. |
579
|
|
|
|
|
|
|
# Values: |
580
|
|
|
|
|
|
|
# tokens for which there is a conflict with this production |
581
|
0
|
|
|
|
|
0
|
for my $state (keys %$co) { |
582
|
0
|
|
|
|
|
0
|
my @conList = @{$co->{$state}{LIST}}; |
|
0
|
|
|
|
|
0
|
|
583
|
|
|
|
|
|
|
|
584
|
0
|
|
|
|
|
0
|
for my $c (@conList) { |
585
|
0
|
|
|
|
|
0
|
my ($token, $production) = @$c; |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
# the action chosen is in: $self->{STATES}[$state]{ACTIONS}{$token} |
588
|
0
|
|
|
|
|
0
|
push @{$C{($production)}{$state}}, $token; |
|
0
|
|
|
|
|
0
|
|
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
0
|
|
|
|
|
0
|
for my $c (keys %$ch) { # for each conflict handler |
593
|
0
|
|
|
|
|
0
|
my $d = $ch->{$c}{production}; # hash ref of productions managed by this handler |
594
|
0
|
|
|
|
|
0
|
for my $p (keys %$d) { # for each production |
595
|
|
|
|
|
|
|
# # if $p reduce or shift? |
596
|
|
|
|
|
|
|
# # find the conflictive states where $p appears |
597
|
|
|
|
|
|
|
# # if $p is reduce and appears in state $s as -$p it is a state of conflict (the other is in the action table) |
598
|
|
|
|
|
|
|
|
599
|
0
|
0
|
|
|
|
0
|
if ($C{$p}) { |
600
|
0
|
|
|
|
|
0
|
push @{$ch->{$c}{states}}, $C{$p} |
|
0
|
|
|
|
|
0
|
|
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
else { |
603
|
|
|
|
|
|
|
# check that it is a shift with this production. |
604
|
|
|
|
|
|
|
} |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
} |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
#################################### |
610
|
|
|
|
|
|
|
# Method to build Dfa from Grammar # |
611
|
|
|
|
|
|
|
#################################### |
612
|
|
|
|
|
|
|
sub _Compile { |
613
|
54
|
|
|
54
|
|
152
|
my($self)=shift; |
614
|
54
|
|
|
|
|
134
|
my($grammar,$states); |
615
|
|
|
|
|
|
|
|
616
|
54
|
|
|
|
|
146
|
$grammar=$self->{GRAMMAR}; |
617
|
|
|
|
|
|
|
|
618
|
54
|
|
|
|
|
272
|
$states = _LR0($grammar); |
619
|
|
|
|
|
|
|
|
620
|
54
|
|
|
|
|
333
|
$self->{CONFLICTS} = _LALR($grammar,$states); |
621
|
|
|
|
|
|
|
|
622
|
54
|
|
|
|
|
176
|
$self->{STATES}=$states; |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
######################### |
626
|
|
|
|
|
|
|
# LR0 States Generation # |
627
|
|
|
|
|
|
|
######################### |
628
|
|
|
|
|
|
|
# |
629
|
|
|
|
|
|
|
########################### |
630
|
|
|
|
|
|
|
# General digraph routine # |
631
|
|
|
|
|
|
|
########################### |
632
|
|
|
|
|
|
|
sub _Digraph { |
633
|
162
|
|
|
162
|
|
1240
|
my($rel,$F)=@_; |
634
|
162
|
|
|
|
|
322
|
my(%N,@S); |
635
|
162
|
|
|
|
|
309
|
my($infinity)=(~(1<<31)); |
636
|
162
|
|
|
|
|
279
|
my($Traverse); |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
$Traverse = sub { |
639
|
1747
|
|
|
1747
|
|
3081
|
my($x,$d)=@_; |
640
|
1747
|
|
|
|
|
2356
|
my($y); |
641
|
|
|
|
|
|
|
|
642
|
1747
|
|
|
|
|
2692
|
push(@S,$x); |
643
|
1747
|
|
|
|
|
2888
|
$N{$x}=$d; |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
exists($$rel{$x}) |
646
|
1747
|
100
|
|
|
|
3951
|
and do { |
647
|
1487
|
|
|
|
|
2116
|
for $y (keys(%{$$rel{$x}})) { |
|
1487
|
|
|
|
|
4465
|
|
648
|
7959
|
100
|
|
|
|
16987
|
exists($N{$y}) |
649
|
|
|
|
|
|
|
or &$Traverse($y,$d+1); |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
$N{$y} < $N{$x} |
652
|
7959
|
100
|
|
|
|
16241
|
and $N{$x} = $N{$y}; |
653
|
|
|
|
|
|
|
|
654
|
7959
|
|
|
|
|
13182
|
$$F{$x}|=$$F{$y}; |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
}; |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
$N{$x} == $d |
659
|
1747
|
100
|
|
|
|
4202
|
and do { |
660
|
1538
|
|
|
|
|
2144
|
for(;;) { |
661
|
1747
|
|
|
|
|
2701
|
$y=pop(@S); |
662
|
1747
|
|
|
|
|
3240
|
$N{$y}=$infinity; |
663
|
1747
|
100
|
|
|
|
4744
|
$y eq $x |
664
|
|
|
|
|
|
|
and last; |
665
|
209
|
|
|
|
|
388
|
$$F{$y}=$$F{$x}; |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
}; |
668
|
162
|
|
|
|
|
984
|
}; |
669
|
|
|
|
|
|
|
|
670
|
162
|
|
|
|
|
750
|
for (keys(%$rel)) { |
671
|
1487
|
100
|
|
|
|
3895
|
exists($N{$_}) |
672
|
|
|
|
|
|
|
or &$Traverse($_,1); |
673
|
|
|
|
|
|
|
} |
674
|
|
|
|
|
|
|
} |
675
|
|
|
|
|
|
|
####################### |
676
|
|
|
|
|
|
|
# Generate LR0 states # |
677
|
|
|
|
|
|
|
####################### |
678
|
|
|
|
|
|
|
# Formula used for closures: |
679
|
|
|
|
|
|
|
# |
680
|
|
|
|
|
|
|
# CLOSE(A) = DCLOSE(A) u U (CLOSE(B) | A close B) |
681
|
|
|
|
|
|
|
# |
682
|
|
|
|
|
|
|
# where: |
683
|
|
|
|
|
|
|
# |
684
|
|
|
|
|
|
|
# DCLOSE(A) = { [ A -> alpha ] in P } |
685
|
|
|
|
|
|
|
# |
686
|
|
|
|
|
|
|
# A close B iff [ A -> B gamma ] in P |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
sub _SetClosures { |
689
|
54
|
|
|
54
|
|
136
|
my($grammar)=@_; |
690
|
54
|
|
|
|
|
130
|
my($rel,$closures); |
691
|
|
|
|
|
|
|
|
692
|
54
|
|
|
|
|
141
|
for my $symbol (keys(%{$$grammar{NTERM}})) { |
|
54
|
|
|
|
|
345
|
|
693
|
277
|
|
|
|
|
462
|
$closures->{$symbol}=pack('b'.@{$$grammar{RULES}}); |
|
277
|
|
|
|
|
1016
|
|
694
|
|
|
|
|
|
|
|
695
|
277
|
|
|
|
|
484
|
for my $ruleno (@{$$grammar{NTERM}{$symbol}}) { |
|
277
|
|
|
|
|
643
|
|
696
|
691
|
|
|
|
|
1184
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
697
|
|
|
|
|
|
|
|
698
|
691
|
|
|
|
|
1409
|
vec($closures->{$symbol},$ruleno,1)=1; |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
@$rhs > 0 |
701
|
|
|
|
|
|
|
and exists($$grammar{NTERM}{$$rhs[0]}) |
702
|
691
|
100
|
100
|
|
|
3433
|
and ++$rel->{$symbol}{$$rhs[0]}; |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
} |
705
|
54
|
|
|
|
|
690
|
_Digraph($rel,$closures); |
706
|
|
|
|
|
|
|
|
707
|
54
|
|
|
|
|
136
|
$closures |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
sub _Closures { |
711
|
1289
|
|
|
1289
|
|
2127
|
my($grammar,$core,$closures)=@_; |
712
|
1289
|
|
|
|
|
1864
|
my($ruleset)=pack('b'.@{$$grammar{RULES}}); |
|
1289
|
|
|
|
|
3515
|
|
713
|
|
|
|
|
|
|
|
714
|
1289
|
|
|
|
|
2467
|
for (@$core) { |
715
|
3265
|
|
|
|
|
5951
|
my($ruleno,$pos)=@$_; |
716
|
3265
|
|
|
|
|
5208
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
$pos < @$rhs |
719
|
|
|
|
|
|
|
and exists($closures->{$$rhs[$pos]}) |
720
|
3265
|
100
|
100
|
|
|
13020
|
and $ruleset|=$closures->{$$rhs[$pos]}; |
721
|
|
|
|
|
|
|
} |
722
|
5201
|
|
|
|
|
10133
|
[ @$core, map { [ $_, 0 ] } |
723
|
34895
|
|
|
|
|
50720
|
grep { vec($ruleset,$_,1) } |
724
|
1289
|
|
|
|
|
2174
|
0..$#{$$grammar{RULES}} ]; |
|
1289
|
|
|
|
|
2944
|
|
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
sub _Transitions { |
728
|
1289
|
|
|
1289
|
|
2355
|
my($grammar,$cores,$closures,$states,$stateno)=@_; |
729
|
1289
|
|
|
|
|
2331
|
my($core)=$$states[$stateno]{'CORE'}; |
730
|
1289
|
|
|
|
|
1839
|
my(%transitions); |
731
|
|
|
|
|
|
|
|
732
|
1289
|
|
|
|
|
1820
|
for (@{_Closures($grammar,$core,$closures)}) { |
|
1289
|
|
|
|
|
2355
|
|
733
|
8466
|
|
|
|
|
15194
|
my($ruleno,$pos)=@$_; |
734
|
8466
|
|
|
|
|
13432
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
$pos == @$rhs |
737
|
8466
|
100
|
|
|
|
17235
|
and do { |
738
|
717
|
|
|
|
|
1087
|
push(@{$$states[$stateno]{ACTIONS}{''}},$ruleno); |
|
717
|
|
|
|
|
2068
|
|
739
|
717
|
|
|
|
|
1472
|
next; |
740
|
|
|
|
|
|
|
}; |
741
|
7749
|
|
|
|
|
10717
|
push(@{$transitions{$$rhs[$pos]}},[ $ruleno, $pos+1 ]); |
|
7749
|
|
|
|
|
20738
|
|
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
|
744
|
1289
|
|
|
|
|
4416
|
for (keys(%transitions)) { |
745
|
4777
|
|
|
|
|
8645
|
my($symbol,$core)=($_,$transitions{$_}); |
746
|
7749
|
|
|
|
|
20094
|
my($corekey)=join(',',map { join('.',@$_) } |
747
|
4777
|
50
|
|
|
|
10120
|
sort { $$a[0] <=> $$b[0] |
|
5988
|
|
|
|
|
13158
|
|
748
|
|
|
|
|
|
|
or $$a[1] <=> $$b[1] } |
749
|
|
|
|
|
|
|
@$core); |
750
|
4777
|
|
|
|
|
7826
|
my($tostateno); |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
exists($cores->{$corekey}) |
753
|
4777
|
100
|
|
|
|
10583
|
or do { |
754
|
1235
|
|
|
|
|
2933
|
push(@$states,{ 'CORE' => $core }); |
755
|
1235
|
|
|
|
|
2992
|
$cores->{$corekey}=$#$states; |
756
|
|
|
|
|
|
|
}; |
757
|
|
|
|
|
|
|
|
758
|
4777
|
|
|
|
|
7171
|
$tostateno=$cores->{$corekey}; |
759
|
4777
|
|
|
|
|
6518
|
push(@{$$states[$tostateno]{FROM}},$stateno); |
|
4777
|
|
|
|
|
9391
|
|
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
exists($$grammar{TERM}{$_}) |
762
|
4777
|
100
|
|
|
|
10696
|
and do { |
763
|
3868
|
|
|
|
|
7973
|
$$states[$stateno]{ACTIONS}{$_} = [ $tostateno ]; |
764
|
3868
|
|
|
|
|
9505
|
next; |
765
|
|
|
|
|
|
|
}; |
766
|
909
|
|
|
|
|
2925
|
$$states[$stateno]{GOTOS}{$_} = $tostateno; |
767
|
|
|
|
|
|
|
} |
768
|
|
|
|
|
|
|
} |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
sub _LR0 { |
771
|
54
|
|
|
54
|
|
157
|
my($grammar)=@_; |
772
|
54
|
|
|
|
|
153
|
my($states) = []; |
773
|
54
|
|
|
|
|
136
|
my($stateno); |
774
|
|
|
|
|
|
|
my($closures); #$closures={ nterm => ruleset,... } |
775
|
54
|
|
|
|
|
145
|
my($cores)={}; # { "itemlist" => stateno, ... } |
776
|
|
|
|
|
|
|
# where "itemlist" has the form: |
777
|
|
|
|
|
|
|
# "ruleno.pos,ruleno.pos" ordered by ruleno,pos |
778
|
|
|
|
|
|
|
|
779
|
54
|
|
|
|
|
225
|
$closures = _SetClosures($grammar); |
780
|
54
|
|
|
|
|
257
|
push(@$states,{ 'CORE' => [ [ 0, 0 ] ] }); |
781
|
54
|
|
|
|
|
252
|
for($stateno=0;$stateno<@$states;++$stateno) { |
782
|
1289
|
|
|
|
|
2880
|
_Transitions($grammar,$cores,$closures,$states,$stateno); |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
54
|
|
|
|
|
446
|
$states |
786
|
|
|
|
|
|
|
} |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
######################################################### |
789
|
|
|
|
|
|
|
# Add Lookahead tokens where needed to make LALR states # |
790
|
|
|
|
|
|
|
######################################################### |
791
|
|
|
|
|
|
|
# Compute First sets for non-terminal using the following formula: |
792
|
|
|
|
|
|
|
# |
793
|
|
|
|
|
|
|
# FIRST(A) = { a in T u { epsilon } | A l a } |
794
|
|
|
|
|
|
|
# u |
795
|
|
|
|
|
|
|
# U { FIRST(B) | B in V and A l B } |
796
|
|
|
|
|
|
|
# |
797
|
|
|
|
|
|
|
# where: |
798
|
|
|
|
|
|
|
# |
799
|
|
|
|
|
|
|
# A l x iff [ A -> X1 X2 .. Xn x alpha ] in P and Xi =>* epsilon, 1 <= i <= n |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub _SetFirst { |
802
|
54
|
|
|
54
|
|
155
|
my($grammar,$termlst,$terminx)=@_; |
803
|
54
|
|
|
|
|
164
|
my($rel,$first)=( {}, {} ); |
804
|
|
|
|
|
|
|
|
805
|
54
|
|
|
|
|
126
|
for my $symbol (keys(%{$$grammar{NTERM}})) { |
|
54
|
|
|
|
|
288
|
|
806
|
277
|
|
|
|
|
857
|
$first->{$symbol}=pack('b'.@$termlst); |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
RULE: |
809
|
277
|
|
|
|
|
442
|
for my $ruleno (@{$$grammar{NTERM}{$symbol}}) { |
|
277
|
|
|
|
|
605
|
|
810
|
691
|
|
|
|
|
1199
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
811
|
|
|
|
|
|
|
|
812
|
691
|
|
|
|
|
1120
|
for (@$rhs) { |
813
|
|
|
|
|
|
|
exists($terminx->{$_}) |
814
|
680
|
100
|
|
|
|
1580
|
and do { |
815
|
269
|
|
|
|
|
726
|
vec($first->{$symbol},$terminx->{$_},1)=1; |
816
|
269
|
|
|
|
|
606
|
next RULE; |
817
|
|
|
|
|
|
|
}; |
818
|
411
|
|
|
|
|
749
|
++$rel->{$symbol}{$_}; |
819
|
411
|
100
|
|
|
|
1124
|
exists($$grammar{NULLABLE}{$_}) |
820
|
|
|
|
|
|
|
or next RULE; |
821
|
|
|
|
|
|
|
} |
822
|
28
|
|
|
|
|
88
|
vec($first->{$symbol},0,1)=1; |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
} |
825
|
54
|
|
|
|
|
318
|
_Digraph($rel,$first); |
826
|
|
|
|
|
|
|
|
827
|
54
|
|
|
|
|
159
|
$first |
828
|
|
|
|
|
|
|
} |
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
sub _Preds { |
831
|
1073
|
|
|
1073
|
|
1906
|
my($states,$stateno,$len)=@_; |
832
|
1073
|
|
|
|
|
1520
|
my($queue, $preds); |
833
|
|
|
|
|
|
|
|
834
|
1073
|
100
|
|
|
|
2767
|
$len |
835
|
|
|
|
|
|
|
or return [ $stateno ]; |
836
|
|
|
|
|
|
|
|
837
|
696
|
|
|
|
|
1591
|
$queue=[ [ $stateno, $len ] ]; |
838
|
696
|
|
|
|
|
1891
|
while(@$queue) { |
839
|
4898
|
|
|
|
|
7500
|
my($pred) = shift(@$queue); |
840
|
4898
|
|
|
|
|
7709
|
my($stateno, $len) = @$pred; |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
$len == 1 |
843
|
4898
|
100
|
|
|
|
9497
|
and do { |
844
|
4136
|
|
|
|
|
5659
|
push(@$preds,@{$states->[$stateno]{FROM}}); |
|
4136
|
|
|
|
|
7305
|
|
845
|
4136
|
|
|
|
|
9353
|
next; |
846
|
|
|
|
|
|
|
}; |
847
|
|
|
|
|
|
|
|
848
|
4202
|
|
|
|
|
8927
|
push(@$queue, map { [ $_, $len - 1 ] } |
849
|
762
|
|
|
|
|
1125
|
@{$states->[$stateno]{FROM}}); |
|
762
|
|
|
|
|
1562
|
|
850
|
|
|
|
|
|
|
} |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
# Pass @$preds through a hash to ensure unicity |
853
|
696
|
|
|
|
|
1010
|
[ keys( %{ +{ map { ($_,1) } @$preds } } ) ]; |
|
696
|
|
|
|
|
1180
|
|
|
7052
|
|
|
|
|
17557
|
|
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
sub _FirstSfx { |
857
|
825
|
|
|
825
|
|
1646
|
my($grammar,$firstset,$termlst,$terminx,$ruleno,$pos,$key)=@_; |
858
|
825
|
|
|
|
|
1690
|
my($first)=pack('b'.@$termlst); |
859
|
825
|
|
|
|
|
1491
|
my($rhs)=$$grammar{RULES}[$ruleno][1]; |
860
|
|
|
|
|
|
|
|
861
|
825
|
|
|
|
|
1950
|
for (;$pos < @$rhs;++$pos) { |
862
|
|
|
|
|
|
|
exists($terminx->{$$rhs[$pos]}) |
863
|
414
|
100
|
|
|
|
1061
|
and do { |
864
|
344
|
|
|
|
|
882
|
vec($first,$terminx->{$$rhs[$pos]},1)=1; |
865
|
344
|
|
|
|
|
1131
|
return($first); |
866
|
|
|
|
|
|
|
}; |
867
|
70
|
|
|
|
|
145
|
$first|=$firstset->{$$rhs[$pos]}; |
868
|
|
|
|
|
|
|
|
869
|
70
|
100
|
|
|
|
265
|
vec($first,0,1) |
870
|
|
|
|
|
|
|
and vec($first,0,1)=0; |
871
|
|
|
|
|
|
|
|
872
|
70
|
100
|
|
|
|
291
|
exists($$grammar{NULLABLE}{$$rhs[$pos]}) |
873
|
|
|
|
|
|
|
or return($first); |
874
|
|
|
|
|
|
|
|
875
|
|
|
|
|
|
|
} |
876
|
417
|
|
|
|
|
1038
|
vec($first,0,1)=1; |
877
|
417
|
|
|
|
|
1298
|
$first; |
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
# Compute Follow sets using following formula: |
881
|
|
|
|
|
|
|
# |
882
|
|
|
|
|
|
|
# FOLLOW(p,A) = READ(p,A) |
883
|
|
|
|
|
|
|
# u |
884
|
|
|
|
|
|
|
# U { FOLLOW(q,B) | (p,A) include (q,B) |
885
|
|
|
|
|
|
|
# |
886
|
|
|
|
|
|
|
# where: |
887
|
|
|
|
|
|
|
# |
888
|
|
|
|
|
|
|
# READ(p,A) = U { FIRST(beta) | [ A -> alpha A . beta ] in KERNEL(GOTO(p,A)) |
889
|
|
|
|
|
|
|
# } - { epsilon } |
890
|
|
|
|
|
|
|
# |
891
|
|
|
|
|
|
|
# (p,a) include (q,B) iff [ B -> alpha A . beta ] in KERNEL(GOTO(p,A), |
892
|
|
|
|
|
|
|
# epsilon in FIRST(beta) and |
893
|
|
|
|
|
|
|
# q in PRED(p,alpha) |
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
# >> x $firstset |
896
|
|
|
|
|
|
|
# 0 HASH(0x1f7af60) |
897
|
|
|
|
|
|
|
# '$start' => "\cG" |
898
|
|
|
|
|
|
|
# 'a' => "\cB" |
899
|
|
|
|
|
|
|
# 'b' => "\cH" |
900
|
|
|
|
|
|
|
# 's' => "\cC" |
901
|
|
|
|
|
|
|
# >> x $firstset->{'a'} # firstset es una string compactada de 0 y 1 que es trratada como un conjunto |
902
|
|
|
|
|
|
|
# 0 "\cB" |
903
|
|
|
|
|
|
|
# >> x unpack ("b*", $firstset->{'a'}) |
904
|
|
|
|
|
|
|
# 0 01000000 |
905
|
|
|
|
|
|
|
# >> x unpack ("b*", $firstset->{'b'}) |
906
|
|
|
|
|
|
|
# 0 00010000 |
907
|
|
|
|
|
|
|
# >> x unpack ("b*", $firstset->{'s'}) |
908
|
|
|
|
|
|
|
# 0 11000000 |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
sub _ComputeFollows { |
911
|
54
|
|
|
54
|
|
159
|
my($grammar,$states,$termlst)=@_; |
912
|
54
|
|
|
|
|
228
|
my($firstset,$terminx); |
913
|
54
|
|
|
|
|
211
|
my($inconsistent, $rel, $follows, $sfx)= ( {}, {}, {}, {} ); |
914
|
|
|
|
|
|
|
|
915
|
54
|
|
|
|
|
198
|
%$terminx= map { ($termlst->[$_],$_) } 0..$#$termlst; |
|
624
|
|
|
|
|
1240
|
|
916
|
|
|
|
|
|
|
|
917
|
54
|
|
|
|
|
336
|
$firstset=_SetFirst($grammar,$termlst,$terminx); |
918
|
|
|
|
|
|
|
|
919
|
54
|
|
|
|
|
226
|
for my $stateno (0..$#$states) { |
920
|
1289
|
|
|
|
|
2334
|
my($state)=$$states[$stateno]; |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
exists($$state{ACTIONS}{''}) |
923
|
|
|
|
|
|
|
and ( @{$$state{ACTIONS}{''}} > 1 |
924
|
|
|
|
|
|
|
or keys(%{$$state{ACTIONS}}) > 1 ) |
925
|
1289
|
100
|
100
|
|
|
3200
|
and do { |
|
|
|
100
|
|
|
|
|
926
|
393
|
|
|
|
|
895
|
++$inconsistent->{$stateno}; |
927
|
|
|
|
|
|
|
|
928
|
393
|
|
|
|
|
579
|
for my $ruleno (@{$$state{ACTIONS}{''}}) { |
|
393
|
|
|
|
|
764
|
|
929
|
400
|
|
|
|
|
604
|
my($lhs,$rhs)=@{$$grammar{RULES}[$ruleno]}[0,1]; |
|
400
|
|
|
|
|
980
|
|
930
|
|
|
|
|
|
|
|
931
|
400
|
|
|
|
|
639
|
for my $predno (@{_Preds($states,$stateno,scalar(@$rhs))}) { |
|
400
|
|
|
|
|
871
|
|
932
|
3693
|
|
|
|
|
8104
|
++$rel->{"$stateno.$ruleno"}{"$predno.$lhs"}; |
933
|
|
|
|
|
|
|
} |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
}; |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
exists($$state{GOTOS}) |
938
|
1289
|
100
|
|
|
|
3233
|
or next; |
939
|
|
|
|
|
|
|
|
940
|
481
|
|
|
|
|
710
|
for my $symbol (keys(%{$$state{GOTOS}})) { |
|
481
|
|
|
|
|
1344
|
|
941
|
909
|
|
|
|
|
1839
|
my($tostate)=$$states[$$state{GOTOS}{$symbol}]; |
942
|
909
|
|
|
|
|
1756
|
my($goto)="$stateno.$symbol"; |
943
|
|
|
|
|
|
|
|
944
|
909
|
|
|
|
|
2635
|
$follows->{$goto}=pack('b'.@$termlst); |
945
|
|
|
|
|
|
|
|
946
|
909
|
|
|
|
|
1327
|
for my $item (@{$$tostate{'CORE'}}) { |
|
909
|
|
|
|
|
1744
|
|
947
|
3497
|
|
|
|
|
6625
|
my($ruleno,$pos)=@$item; |
948
|
3497
|
|
|
|
|
5809
|
my($key)="$ruleno.$pos"; |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
exists($sfx->{$key}) |
951
|
3497
|
100
|
|
|
|
7877
|
or $sfx->{$key} = _FirstSfx($grammar,$firstset, |
952
|
|
|
|
|
|
|
$termlst,$terminx, |
953
|
|
|
|
|
|
|
$ruleno,$pos,$key); |
954
|
|
|
|
|
|
|
|
955
|
3497
|
|
|
|
|
6035
|
$follows->{$goto}|=$sfx->{$key}; |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
vec($follows->{$goto},0,1) |
958
|
3497
|
100
|
|
|
|
8548
|
and do { |
959
|
673
|
|
|
|
|
1328
|
my($lhs)=$$grammar{RULES}[$ruleno][0]; |
960
|
|
|
|
|
|
|
|
961
|
673
|
|
|
|
|
1482
|
vec($follows->{$goto},0,1)=0; |
962
|
|
|
|
|
|
|
|
963
|
673
|
|
|
|
|
1171
|
for my $predno (@{_Preds($states,$stateno,$pos-1)}) { |
|
673
|
|
|
|
|
1551
|
|
964
|
3736
|
|
|
|
|
8675
|
++$rel->{$goto}{"$predno.$lhs"}; |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
}; |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
} |
969
|
|
|
|
|
|
|
} |
970
|
54
|
|
|
|
|
232
|
_Digraph($rel,$follows); |
971
|
|
|
|
|
|
|
|
972
|
54
|
|
|
|
|
520
|
($follows,$inconsistent) |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
sub _ComputeLA { |
976
|
54
|
|
|
54
|
|
679
|
my($grammar,$states)=@_; |
977
|
54
|
|
|
|
|
147
|
my($termlst)= [ '',keys(%{$$grammar{TERM}}) ]; |
|
54
|
|
|
|
|
438
|
|
978
|
|
|
|
|
|
|
|
979
|
54
|
|
|
|
|
307
|
my($follows,$inconsistent) = _ComputeFollows($grammar,$states,$termlst); |
980
|
|
|
|
|
|
|
|
981
|
54
|
|
|
|
|
248
|
for my $stateno ( keys(%$inconsistent ) ) { |
982
|
393
|
|
|
|
|
878
|
my($state)=$$states[$stateno]; |
983
|
393
|
|
|
|
|
623
|
my($conflict); |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
#NB the sort is VERY important for conflicts resolution order |
986
|
393
|
|
|
|
|
565
|
for my $ruleno (sort { $a <=> $b } |
|
7
|
|
|
|
|
22
|
|
987
|
393
|
|
|
|
|
977
|
@{$$state{ACTIONS}{''}}) { |
988
|
400
|
|
|
|
|
870
|
for my $term ( map { $termlst->[$_] } grep { |
|
2715
|
|
|
|
|
4491
|
|
989
|
7450
|
|
|
|
|
12909
|
vec($follows->{"$stateno.$ruleno"},$_,1) } |
990
|
|
|
|
|
|
|
0..$#$termlst) { |
991
|
2715
|
100
|
|
|
|
5859
|
exists($$state{ACTIONS}{$term}) |
992
|
|
|
|
|
|
|
and ++$conflict; |
993
|
2715
|
|
|
|
|
3673
|
push(@{$$state{ACTIONS}{$term}},-$ruleno); |
|
2715
|
|
|
|
|
6226
|
|
994
|
|
|
|
|
|
|
} |
995
|
|
|
|
|
|
|
} |
996
|
393
|
|
|
|
|
772
|
delete($$state{ACTIONS}{''}); |
997
|
|
|
|
|
|
|
$conflict |
998
|
393
|
100
|
|
|
|
1033
|
or delete($inconsistent->{$stateno}); |
999
|
|
|
|
|
|
|
} |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
$inconsistent |
1002
|
54
|
|
|
|
|
261
|
} |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
############################# |
1005
|
|
|
|
|
|
|
# Solve remaining conflicts # |
1006
|
|
|
|
|
|
|
############################# |
1007
|
|
|
|
|
|
|
|
1008
|
|
|
|
|
|
|
sub _SolveConflicts { |
1009
|
54
|
|
|
54
|
|
153
|
my($grammar,$states,$inconsistent)=@_; |
1010
|
54
|
|
|
|
|
128
|
my(%rulesprec,$RulePrec); |
1011
|
54
|
|
|
|
|
371
|
my($conflicts)={ SOLVED => {}, |
1012
|
|
|
|
|
|
|
FORCED => { TOTAL => [ 0, 0 ], |
1013
|
|
|
|
|
|
|
DETAIL => {} |
1014
|
|
|
|
|
|
|
} |
1015
|
|
|
|
|
|
|
}; |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
$RulePrec = sub { |
1018
|
1377
|
|
|
1377
|
|
2174
|
my($ruleno)=@_; |
1019
|
1377
|
|
|
|
|
1983
|
my($rhs,$rprec)=@{$$grammar{RULES}[$ruleno]}[1,2]; |
|
1377
|
|
|
|
|
2742
|
|
1020
|
1377
|
|
|
|
|
2018
|
my($lastterm); |
1021
|
|
|
|
|
|
|
|
1022
|
1377
|
100
|
|
|
|
2874
|
defined($rprec) |
1023
|
|
|
|
|
|
|
and return($rprec); |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
exists($rulesprec{$ruleno}) |
1026
|
1244
|
100
|
|
|
|
3189
|
and return($rulesprec{$ruleno}); |
1027
|
|
|
|
|
|
|
|
1028
|
210
|
|
|
|
|
438
|
$lastterm=(grep { exists($$grammar{TERM}{$_}) } @$rhs)[-1]; |
|
632
|
|
|
|
|
1437
|
|
1029
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
defined($lastterm) |
1031
|
|
|
|
|
|
|
and ref($$grammar{TERM}{$lastterm}) |
1032
|
210
|
100
|
66
|
|
|
1003
|
and do { |
1033
|
209
|
|
|
|
|
512
|
$rulesprec{$ruleno}=$$grammar{TERM}{$lastterm}[1]; |
1034
|
209
|
|
|
|
|
472
|
return($rulesprec{$ruleno}); |
1035
|
|
|
|
|
|
|
}; |
1036
|
|
|
|
|
|
|
|
1037
|
1
|
|
|
|
|
4
|
undef; |
1038
|
54
|
|
|
|
|
383
|
}; |
1039
|
|
|
|
|
|
|
|
1040
|
54
|
|
|
|
|
223
|
for my $stateno (keys(%$inconsistent)) { |
1041
|
263
|
|
|
|
|
586
|
my($state)=$$states[$stateno]; |
1042
|
263
|
|
|
|
|
483
|
my($actions)=$$state{ACTIONS}; |
1043
|
263
|
|
|
|
|
448
|
my($nbsr,$nbrr); |
1044
|
|
|
|
|
|
|
|
1045
|
263
|
|
|
|
|
745
|
for my $term ( keys(%$actions) ) { |
1046
|
2252
|
|
|
|
|
3570
|
my($act)=$$actions{$term}; |
1047
|
|
|
|
|
|
|
|
1048
|
2252
|
100
|
|
|
|
4646
|
@$act > 1 |
1049
|
|
|
|
|
|
|
or next; |
1050
|
|
|
|
|
|
|
|
1051
|
|
|
|
|
|
|
$$act[0] > 0 |
1052
|
|
|
|
|
|
|
and ref($$grammar{TERM}{$term}) |
1053
|
1393
|
100
|
66
|
|
|
5641
|
and do { |
1054
|
1377
|
|
|
|
|
2037
|
my($assoc,$tprec)=@{$$grammar{TERM}{$term}}; |
|
1377
|
|
|
|
|
2612
|
|
1055
|
1377
|
|
|
|
|
2156
|
my($k,$error); |
1056
|
|
|
|
|
|
|
|
1057
|
1377
|
|
|
|
|
2975
|
for ($k=1;$k<@$act;++$k) { |
1058
|
1377
|
|
|
|
|
2165
|
my($ruleno)=-$$act[$k]; |
1059
|
1377
|
|
|
|
|
2478
|
my($rprec)=&$RulePrec($ruleno); |
1060
|
|
|
|
|
|
|
|
1061
|
1377
|
100
|
|
|
|
3110
|
defined($rprec) |
1062
|
|
|
|
|
|
|
or next; |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
( $tprec > $rprec |
1065
|
|
|
|
|
|
|
or ( $tprec == $rprec and $assoc eq 'RIGHT')) |
1066
|
1376
|
100
|
100
|
|
|
4641
|
and do { |
|
|
|
100
|
|
|
|
|
1067
|
602
|
|
|
|
|
866
|
push(@{$$conflicts{SOLVED}{$stateno}}, |
|
602
|
|
|
|
|
1751
|
|
1068
|
|
|
|
|
|
|
[ $ruleno, $term, 'shift' ]); |
1069
|
602
|
|
|
|
|
1107
|
splice(@$act,$k--,1); |
1070
|
602
|
|
|
|
|
1437
|
next; |
1071
|
|
|
|
|
|
|
}; |
1072
|
|
|
|
|
|
|
( $tprec < $rprec |
1073
|
|
|
|
|
|
|
or $assoc eq 'LEFT') |
1074
|
774
|
50
|
66
|
|
|
2328
|
and do { |
1075
|
774
|
|
|
|
|
1107
|
push(@{$$conflicts{SOLVED}{$stateno}}, |
|
774
|
|
|
|
|
2024
|
|
1076
|
|
|
|
|
|
|
[ $ruleno, $term, 'reduce' ]); |
1077
|
|
|
|
|
|
|
$$act[0] > 0 |
1078
|
774
|
50
|
|
|
|
1749
|
and do { |
1079
|
774
|
|
|
|
|
1171
|
splice(@$act,0,1); |
1080
|
774
|
|
|
|
|
1115
|
--$k; |
1081
|
|
|
|
|
|
|
}; |
1082
|
774
|
|
|
|
|
1809
|
next; |
1083
|
|
|
|
|
|
|
}; |
1084
|
0
|
|
|
|
|
0
|
push(@{$$conflicts{SOLVED}{$stateno}}, |
|
0
|
|
|
|
|
0
|
|
1085
|
|
|
|
|
|
|
[ $ruleno, $term, 'error' ]); |
1086
|
0
|
|
|
|
|
0
|
splice(@$act,$k--,1); |
1087
|
|
|
|
|
|
|
$$act[0] > 0 |
1088
|
0
|
0
|
|
|
|
0
|
and do { |
1089
|
0
|
|
|
|
|
0
|
splice(@$act,0,1); |
1090
|
0
|
|
|
|
|
0
|
++$error; |
1091
|
0
|
|
|
|
|
0
|
--$k; |
1092
|
|
|
|
|
|
|
}; |
1093
|
|
|
|
|
|
|
} |
1094
|
1377
|
50
|
|
|
|
2806
|
$error |
1095
|
|
|
|
|
|
|
and unshift(@$act,undef); |
1096
|
|
|
|
|
|
|
}; |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
@$act > 1 |
1099
|
1393
|
100
|
|
|
|
3155
|
and do { |
1100
|
17
|
|
|
|
|
29
|
$nbrr += @$act - 2; |
1101
|
17
|
50
|
|
|
|
45
|
($$act[0] > 0 ? $nbsr : $nbrr) += 1; |
1102
|
17
|
|
|
|
|
62
|
push(@{$$conflicts{FORCED}{DETAIL}{$stateno}{LIST}}, |
1103
|
17
|
|
|
|
|
25
|
map { [ $term, $_ ] } splice(@$act,1)); |
|
17
|
|
|
|
|
52
|
|
1104
|
|
|
|
|
|
|
}; |
1105
|
|
|
|
|
|
|
} |
1106
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
$nbsr |
1108
|
263
|
100
|
|
|
|
709
|
and do { |
1109
|
17
|
|
|
|
|
35
|
$$conflicts{FORCED}{TOTAL}[0]+=$nbsr; |
1110
|
17
|
|
|
|
|
38
|
$$conflicts{FORCED}{DETAIL}{$stateno}{TOTAL}[0]+=$nbsr; |
1111
|
|
|
|
|
|
|
}; |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
$nbrr |
1114
|
263
|
50
|
|
|
|
688
|
and do { |
1115
|
0
|
|
|
|
|
0
|
$$conflicts{FORCED}{TOTAL}[1]+=$nbrr; |
1116
|
0
|
|
|
|
|
0
|
$$conflicts{FORCED}{DETAIL}{$stateno}{TOTAL}[1]+=$nbrr; |
1117
|
|
|
|
|
|
|
}; |
1118
|
|
|
|
|
|
|
|
1119
|
|
|
|
|
|
|
} |
1120
|
|
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
$conflicts |
1122
|
54
|
|
|
|
|
517
|
} |
1123
|
|
|
|
|
|
|
|
1124
|
|
|
|
|
|
|
############################### |
1125
|
|
|
|
|
|
|
# Make default reduce actions # |
1126
|
|
|
|
|
|
|
############################### |
1127
|
|
|
|
|
|
|
sub _SetDefaults { |
1128
|
54
|
|
|
54
|
|
152
|
my($states)=@_; |
1129
|
|
|
|
|
|
|
|
1130
|
54
|
|
|
|
|
171
|
for my $state (@$states) { |
1131
|
1289
|
|
|
|
|
2120
|
my($actions)=$$state{ACTIONS}; |
1132
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
# %reduces: - rule number => array of tokens to reduce |
1134
|
|
|
|
|
|
|
# $nodefault is true if no default can be derived |
1135
|
1289
|
|
|
|
|
1910
|
my(%reduces,$default,$nodefault); |
1136
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
#If action with ''=> no default |
1138
|
|
|
|
|
|
|
exists($$actions{''}) |
1139
|
1289
|
100
|
|
|
|
2731
|
and do { |
1140
|
317
|
|
|
|
|
581
|
$$actions{''}[0] = -$$actions{''}[0]; |
1141
|
317
|
|
|
|
|
496
|
++$nodefault; |
1142
|
|
|
|
|
|
|
}; |
1143
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
#shift error token => no default |
1145
|
|
|
|
|
|
|
exists($$actions{error}) |
1146
|
1289
|
100
|
66
|
|
|
2933
|
and $$actions{error}[0] > 0 |
1147
|
|
|
|
|
|
|
and ++$nodefault; |
1148
|
|
|
|
|
|
|
|
1149
|
1289
|
|
|
|
|
2909
|
for my $term (keys(%$actions)) { |
1150
|
|
|
|
|
|
|
|
1151
|
5507
|
|
|
|
|
8749
|
$$actions{$term}=$$actions{$term}[0]; |
1152
|
|
|
|
|
|
|
|
1153
|
5507
|
100
|
66
|
|
|
23986
|
(not defined($$actions{$term}) or $$actions{$term} > 0 or $nodefault) |
|
|
|
100
|
|
|
|
|
1154
|
|
|
|
|
|
|
and next; |
1155
|
|
|
|
|
|
|
|
1156
|
2096
|
|
|
|
|
2918
|
push(@{$reduces{$$actions{$term}}},$term); |
|
2096
|
|
|
|
|
4837
|
|
1157
|
|
|
|
|
|
|
} |
1158
|
|
|
|
|
|
|
|
1159
|
1289
|
100
|
|
|
|
3366
|
keys(%reduces) > 0 or next; |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
# Find the production rule with the largest reduce set, i.e. |
1162
|
|
|
|
|
|
|
# the largest number of tokens |
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
# OLD CODE: |
1165
|
|
|
|
|
|
|
# $default=( |
1166
|
|
|
|
|
|
|
# # take the largest ... |
1167
|
|
|
|
|
|
|
# map { $$_[0] } |
1168
|
|
|
|
|
|
|
# # sort them by cardinal (in reverse) |
1169
|
|
|
|
|
|
|
# sort { $$b[1] <=> $$a[1] or $$b[0] <=> $$a[0] } |
1170
|
|
|
|
|
|
|
# # list of [ - rule number, number of tokens for that rule ] |
1171
|
|
|
|
|
|
|
# map { [ $_, scalar(@{$reduces{$_}}) ] } |
1172
|
|
|
|
|
|
|
# keys(%reduces) # list of - rule numbers |
1173
|
|
|
|
|
|
|
# )[0]; |
1174
|
|
|
|
|
|
|
|
1175
|
377
|
|
|
|
|
593
|
my $max = 0; |
1176
|
377
|
|
|
|
|
816
|
for (keys(%reduces)) { |
1177
|
384
|
|
|
|
|
552
|
my $t = @{$reduces{$_}}; |
|
384
|
|
|
|
|
648
|
|
1178
|
384
|
100
|
|
|
|
1025
|
($max, $default) = ($t, $_) if $t > $max; |
1179
|
|
|
|
|
|
|
} |
1180
|
|
|
|
|
|
|
|
1181
|
377
|
|
|
|
|
588
|
delete(@$actions{ @{$reduces{$default}} }); |
|
377
|
|
|
|
|
924
|
|
1182
|
377
|
|
|
|
|
1081
|
$$state{ACTIONS}{''}=$default; |
1183
|
|
|
|
|
|
|
} |
1184
|
|
|
|
|
|
|
} |
1185
|
|
|
|
|
|
|
|
1186
|
|
|
|
|
|
|
sub _dereference { |
1187
|
0
|
|
|
0
|
|
0
|
my($states)=@_; |
1188
|
|
|
|
|
|
|
|
1189
|
0
|
|
|
|
|
0
|
for my $state (@$states) { |
1190
|
0
|
|
|
|
|
0
|
my($actions)=$$state{ACTIONS}; |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
exists($$actions{''}) |
1193
|
0
|
0
|
|
|
|
0
|
and do { |
1194
|
0
|
|
|
|
|
0
|
$$actions{''}[0] = -$$actions{''}[0]; |
1195
|
|
|
|
|
|
|
}; |
1196
|
|
|
|
|
|
|
|
1197
|
0
|
|
|
|
|
0
|
for my $term (keys(%$actions)) { |
1198
|
0
|
|
|
|
|
0
|
$$actions{$term}=$$actions{$term}[0]; |
1199
|
|
|
|
|
|
|
} |
1200
|
|
|
|
|
|
|
|
1201
|
|
|
|
|
|
|
} |
1202
|
|
|
|
|
|
|
} |
1203
|
|
|
|
|
|
|
|
1204
|
|
|
|
|
|
|
sub _LALR { |
1205
|
54
|
|
|
54
|
|
174
|
my($grammar,$states) = @_; |
1206
|
54
|
|
|
|
|
186
|
my($conflicts,$inconsistent); |
1207
|
|
|
|
|
|
|
|
1208
|
54
|
|
|
|
|
408
|
$inconsistent = _ComputeLA($grammar,$states); |
1209
|
|
|
|
|
|
|
|
1210
|
54
|
|
|
|
|
255
|
$conflicts = _SolveConflicts($grammar,$states,$inconsistent); |
1211
|
|
|
|
|
|
|
|
1212
|
54
|
50
|
|
|
|
265
|
if ($grammar->{NOCOMPACT}) { |
1213
|
0
|
|
|
|
|
0
|
_dereference($states); |
1214
|
|
|
|
|
|
|
} |
1215
|
|
|
|
|
|
|
else { |
1216
|
54
|
|
|
|
|
238
|
_SetDefaults($states); |
1217
|
|
|
|
|
|
|
} |
1218
|
|
|
|
|
|
|
|
1219
|
54
|
|
|
|
|
267
|
$conflicts |
1220
|
|
|
|
|
|
|
} |
1221
|
|
|
|
|
|
|
|
1222
|
|
|
|
|
|
|
|
1223
|
|
|
|
|
|
|
1; |
1224
|
|
|
|
|
|
|
|