racc 1.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitattributes +2 -0
- data/.gitignore +7 -0
- data/COPYING +515 -0
- data/ChangeLog +846 -0
- data/DEPENDS +4 -0
- data/README.en.rdoc +86 -0
- data/README.ja.rdoc +96 -0
- data/Rakefile +15 -0
- data/TODO +5 -0
- data/bin/racc +308 -0
- data/bin/racc2y +195 -0
- data/bin/y2racc +339 -0
- data/doc/en/NEWS.en.rdoc +282 -0
- data/doc/en/command.en.html +78 -0
- data/doc/en/debug.en.rdoc +20 -0
- data/doc/en/grammar.en.rdoc +230 -0
- data/doc/en/index.en.html +10 -0
- data/doc/en/parser.en.rdoc +74 -0
- data/doc/en/usage.en.html +92 -0
- data/doc/ja/NEWS.ja.rdoc +307 -0
- data/doc/ja/command.ja.html +94 -0
- data/doc/ja/debug.ja.rdoc +36 -0
- data/doc/ja/grammar.ja.rdoc +348 -0
- data/doc/ja/index.ja.html +10 -0
- data/doc/ja/parser.ja.rdoc +125 -0
- data/doc/ja/usage.ja.html +414 -0
- data/ext/racc/cparse/MANIFEST +4 -0
- data/ext/racc/cparse/cparse.c +824 -0
- data/ext/racc/cparse/depend +1 -0
- data/ext/racc/cparse/extconf.rb +7 -0
- data/fastcache/extconf.rb +2 -0
- data/fastcache/fastcache.c +185 -0
- data/lib/racc.rb +6 -0
- data/lib/racc/compat.rb +40 -0
- data/lib/racc/debugflags.rb +59 -0
- data/lib/racc/exception.rb +15 -0
- data/lib/racc/grammar.rb +1115 -0
- data/lib/racc/grammarfileparser.rb +559 -0
- data/lib/racc/info.rb +16 -0
- data/lib/racc/iset.rb +91 -0
- data/lib/racc/logfilegenerator.rb +214 -0
- data/lib/racc/parser.rb +439 -0
- data/lib/racc/parserfilegenerator.rb +511 -0
- data/lib/racc/pre-setup +13 -0
- data/lib/racc/sourcetext.rb +34 -0
- data/lib/racc/state.rb +971 -0
- data/lib/racc/statetransitiontable.rb +316 -0
- data/lib/racc/static.rb +5 -0
- data/misc/dist.sh +31 -0
- data/sample/array.y +67 -0
- data/sample/array2.y +59 -0
- data/sample/calc-ja.y +66 -0
- data/sample/calc.y +65 -0
- data/sample/conflict.y +15 -0
- data/sample/hash.y +60 -0
- data/sample/lalr.y +17 -0
- data/sample/lists.y +57 -0
- data/sample/syntax.y +46 -0
- data/sample/yyerr.y +46 -0
- data/setup.rb +1587 -0
- data/tasks/doc.rb +12 -0
- data/tasks/email.rb +55 -0
- data/tasks/file.rb +37 -0
- data/tasks/gem.rb +37 -0
- data/tasks/test.rb +16 -0
- data/test/assets/chk.y +126 -0
- data/test/assets/conf.y +16 -0
- data/test/assets/digraph.y +29 -0
- data/test/assets/echk.y +118 -0
- data/test/assets/err.y +60 -0
- data/test/assets/expect.y +7 -0
- data/test/assets/firstline.y +4 -0
- data/test/assets/ichk.y +102 -0
- data/test/assets/intp.y +546 -0
- data/test/assets/mailp.y +437 -0
- data/test/assets/newsyn.y +25 -0
- data/test/assets/noend.y +4 -0
- data/test/assets/nonass.y +41 -0
- data/test/assets/normal.y +27 -0
- data/test/assets/norule.y +4 -0
- data/test/assets/nullbug1.y +25 -0
- data/test/assets/nullbug2.y +15 -0
- data/test/assets/opt.y +123 -0
- data/test/assets/percent.y +35 -0
- data/test/assets/recv.y +97 -0
- data/test/assets/rrconf.y +14 -0
- data/test/assets/scan.y +72 -0
- data/test/assets/syntax.y +50 -0
- data/test/assets/unterm.y +5 -0
- data/test/assets/useless.y +12 -0
- data/test/assets/yyerr.y +46 -0
- data/test/bench.y +36 -0
- data/test/helper.rb +88 -0
- data/test/infini.y +8 -0
- data/test/scandata/brace +7 -0
- data/test/scandata/gvar +1 -0
- data/test/scandata/normal +4 -0
- data/test/scandata/percent +18 -0
- data/test/scandata/slash +10 -0
- data/test/src.intp +34 -0
- data/test/start.y +20 -0
- data/test/test_chk_y.rb +51 -0
- data/test/test_grammar_file_parser.rb +15 -0
- data/test/test_racc_command.rb +155 -0
- data/test/test_scan_y.rb +51 -0
- data/test/testscanner.rb +51 -0
- data/web/racc.en.rhtml +42 -0
- data/web/racc.ja.rhtml +51 -0
- metadata +166 -0
data/lib/racc/pre-setup
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
def generate_parser_text_rb(target)
|
2
|
+
return if File.exist?(srcfile(target))
|
3
|
+
$stderr.puts "generating #{target}..."
|
4
|
+
File.open(target, 'w') {|f|
|
5
|
+
f.puts "module Racc"
|
6
|
+
f.puts " PARSER_TEXT = <<'__end_of_file__'"
|
7
|
+
f.puts File.read(srcfile('parser.rb'))
|
8
|
+
f.puts "__end_of_file__"
|
9
|
+
f.puts "end"
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
generate_parser_text_rb 'parser-text.rb'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#
|
2
|
+
# $Id$
|
3
|
+
#
|
4
|
+
# Copyright (c) 1999-2006 Minero Aoki
|
5
|
+
#
|
6
|
+
# This program is free software.
|
7
|
+
# You can distribute/modify this program under the terms of
|
8
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
9
|
+
# For details of LGPL, see the file "COPYING".
|
10
|
+
#
|
11
|
+
|
12
|
+
module Racc
|
13
|
+
|
14
|
+
class SourceText
|
15
|
+
def initialize(text, filename, lineno)
|
16
|
+
@text = text
|
17
|
+
@filename = filename
|
18
|
+
@lineno = lineno
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :text
|
22
|
+
attr_reader :filename
|
23
|
+
attr_reader :lineno
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
"#<SourceText #{location()}>"
|
27
|
+
end
|
28
|
+
|
29
|
+
def location
|
30
|
+
"#{@filename}:#{@lineno}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/lib/racc/state.rb
ADDED
@@ -0,0 +1,971 @@
|
|
1
|
+
#
|
2
|
+
# $Id$
|
3
|
+
#
|
4
|
+
# Copyright (c) 1999-2006 Minero Aoki
|
5
|
+
#
|
6
|
+
# This program is free software.
|
7
|
+
# You can distribute/modify this program under the terms of
|
8
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
9
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'racc/iset'
|
13
|
+
require 'racc/statetransitiontable'
|
14
|
+
require 'racc/exception'
|
15
|
+
require 'forwardable'
|
16
|
+
|
17
|
+
module Racc
|
18
|
+
|
19
|
+
# A table of LALR states.
|
20
|
+
class States
|
21
|
+
|
22
|
+
include Enumerable
|
23
|
+
|
24
|
+
def initialize(grammar, debug_flags = DebugFlags.new)
|
25
|
+
@grammar = grammar
|
26
|
+
@symboltable = grammar.symboltable
|
27
|
+
@d_state = debug_flags.state
|
28
|
+
@d_la = debug_flags.la
|
29
|
+
@d_prec = debug_flags.prec
|
30
|
+
@states = []
|
31
|
+
@statecache = {}
|
32
|
+
@actions = ActionTable.new(@grammar, self)
|
33
|
+
@nfa_computed = false
|
34
|
+
@dfa_computed = false
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :grammar
|
38
|
+
attr_reader :actions
|
39
|
+
|
40
|
+
def size
|
41
|
+
@states.size
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
'#<state table>'
|
46
|
+
end
|
47
|
+
|
48
|
+
alias to_s inspect
|
49
|
+
|
50
|
+
def [](i)
|
51
|
+
@states[i]
|
52
|
+
end
|
53
|
+
|
54
|
+
def each_state(&block)
|
55
|
+
@states.each(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
alias each each_state
|
59
|
+
|
60
|
+
def each_index(&block)
|
61
|
+
@states.each_index(&block)
|
62
|
+
end
|
63
|
+
|
64
|
+
extend Forwardable
|
65
|
+
|
66
|
+
def_delegator "@actions", :shift_n
|
67
|
+
def_delegator "@actions", :reduce_n
|
68
|
+
def_delegator "@actions", :nt_base
|
69
|
+
|
70
|
+
def should_report_srconflict?
|
71
|
+
srconflict_exist? and
|
72
|
+
(n_srconflicts() != @grammar.n_expected_srconflicts)
|
73
|
+
end
|
74
|
+
|
75
|
+
def srconflict_exist?
|
76
|
+
n_srconflicts() != 0
|
77
|
+
end
|
78
|
+
|
79
|
+
def n_srconflicts
|
80
|
+
@n_srconflicts ||= inject(0) {|sum, st| sum + st.n_srconflicts }
|
81
|
+
end
|
82
|
+
|
83
|
+
def rrconflict_exist?
|
84
|
+
n_rrconflicts() != 0
|
85
|
+
end
|
86
|
+
|
87
|
+
def n_rrconflicts
|
88
|
+
@n_rrconflicts ||= inject(0) {|sum, st| sum + st.n_rrconflicts }
|
89
|
+
end
|
90
|
+
|
91
|
+
def state_transition_table
|
92
|
+
@state_transition_table ||= StateTransitionTable.generate(self.dfa)
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# NFA (Non-deterministic Finite Automaton) Computation
|
97
|
+
#
|
98
|
+
|
99
|
+
public
|
100
|
+
|
101
|
+
def nfa
|
102
|
+
return self if @nfa_computed
|
103
|
+
compute_nfa
|
104
|
+
@nfa_computed = true
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def compute_nfa
|
111
|
+
@grammar.init
|
112
|
+
# add state 0
|
113
|
+
core_to_state [ @grammar[0].ptrs[0] ]
|
114
|
+
# generate LALR states
|
115
|
+
cur = 0
|
116
|
+
@gotos = []
|
117
|
+
while cur < @states.size
|
118
|
+
generate_states @states[cur] # state is added here
|
119
|
+
cur += 1
|
120
|
+
end
|
121
|
+
@actions.init
|
122
|
+
end
|
123
|
+
|
124
|
+
def generate_states(state)
|
125
|
+
puts "dstate: #{state}" if @d_state
|
126
|
+
|
127
|
+
table = {}
|
128
|
+
state.closure.each do |ptr|
|
129
|
+
if sym = ptr.dereference
|
130
|
+
addsym table, sym, ptr.next
|
131
|
+
end
|
132
|
+
end
|
133
|
+
table.each do |sym, core|
|
134
|
+
puts "dstate: sym=#{sym} ncore=#{core}" if @d_state
|
135
|
+
|
136
|
+
dest = core_to_state(core.to_a)
|
137
|
+
state.goto_table[sym] = dest
|
138
|
+
id = sym.nonterminal?() ? @gotos.size : nil
|
139
|
+
g = Goto.new(id, sym, state, dest)
|
140
|
+
@gotos.push g if sym.nonterminal?
|
141
|
+
state.gotos[sym] = g
|
142
|
+
puts "dstate: #{state.ident} --#{sym}--> #{dest.ident}" if @d_state
|
143
|
+
|
144
|
+
# check infinite recursion
|
145
|
+
if state.ident == dest.ident and state.closure.size == 1
|
146
|
+
raise CompileError,
|
147
|
+
sprintf("Infinite recursion: state %d, with rule %d",
|
148
|
+
state.ident, state.ptrs[0].rule.ident)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def addsym(table, sym, ptr)
|
154
|
+
unless s = table[sym]
|
155
|
+
table[sym] = s = ISet.new
|
156
|
+
end
|
157
|
+
s.add ptr
|
158
|
+
end
|
159
|
+
|
160
|
+
def core_to_state(core)
|
161
|
+
#
|
162
|
+
# convert CORE to a State object.
|
163
|
+
# If matching state does not exist, create it and add to the table.
|
164
|
+
#
|
165
|
+
|
166
|
+
k = fingerprint(core)
|
167
|
+
unless dest = @statecache[k]
|
168
|
+
# not registered yet
|
169
|
+
dest = State.new(@states.size, core)
|
170
|
+
@states.push dest
|
171
|
+
|
172
|
+
@statecache[k] = dest
|
173
|
+
|
174
|
+
puts "core_to_state: create state ID #{dest.ident}" if @d_state
|
175
|
+
else
|
176
|
+
if @d_state
|
177
|
+
puts "core_to_state: dest is cached ID #{dest.ident}"
|
178
|
+
puts "core_to_state: dest core #{dest.core.join(' ')}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
dest
|
183
|
+
end
|
184
|
+
|
185
|
+
def fingerprint(arr)
|
186
|
+
arr.map {|i| i.ident }.pack('L*')
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# DFA (Deterministic Finite Automaton) Generation
|
191
|
+
#
|
192
|
+
|
193
|
+
public
|
194
|
+
|
195
|
+
def dfa
|
196
|
+
return self if @dfa_computed
|
197
|
+
nfa
|
198
|
+
compute_dfa
|
199
|
+
@dfa_computed = true
|
200
|
+
self
|
201
|
+
end
|
202
|
+
|
203
|
+
private
|
204
|
+
|
205
|
+
def compute_dfa
|
206
|
+
la = lookahead()
|
207
|
+
@states.each do |state|
|
208
|
+
state.la = la
|
209
|
+
resolve state
|
210
|
+
end
|
211
|
+
set_accept
|
212
|
+
@states.each do |state|
|
213
|
+
pack state
|
214
|
+
end
|
215
|
+
check_useless
|
216
|
+
end
|
217
|
+
|
218
|
+
def lookahead
|
219
|
+
#
|
220
|
+
# lookahead algorithm ver.3 -- from bison 1.26
|
221
|
+
#
|
222
|
+
|
223
|
+
gotos = @gotos
|
224
|
+
if @d_la
|
225
|
+
puts "\n--- goto ---"
|
226
|
+
gotos.each_with_index {|g, i| print i, ' '; p g }
|
227
|
+
end
|
228
|
+
|
229
|
+
### initialize_LA()
|
230
|
+
### set_goto_map()
|
231
|
+
la_rules = []
|
232
|
+
@states.each do |state|
|
233
|
+
state.check_la la_rules
|
234
|
+
end
|
235
|
+
|
236
|
+
### initialize_F()
|
237
|
+
f = create_tmap(gotos.size)
|
238
|
+
reads = []
|
239
|
+
edge = []
|
240
|
+
gotos.each do |goto|
|
241
|
+
goto.to_state.goto_table.each do |t, st|
|
242
|
+
if t.terminal?
|
243
|
+
f[goto.ident] |= (1 << t.ident)
|
244
|
+
elsif t.nullable?
|
245
|
+
edge.push goto.to_state.gotos[t].ident
|
246
|
+
end
|
247
|
+
end
|
248
|
+
if edge.empty?
|
249
|
+
reads.push nil
|
250
|
+
else
|
251
|
+
reads.push edge
|
252
|
+
edge = []
|
253
|
+
end
|
254
|
+
end
|
255
|
+
digraph f, reads
|
256
|
+
if @d_la
|
257
|
+
puts "\n--- F1 (reads) ---"
|
258
|
+
print_tab gotos, reads, f
|
259
|
+
end
|
260
|
+
|
261
|
+
### build_relations()
|
262
|
+
### compute_FOLLOWS
|
263
|
+
path = nil
|
264
|
+
edge = []
|
265
|
+
lookback = Array.new(la_rules.size, nil)
|
266
|
+
includes = []
|
267
|
+
gotos.each do |goto|
|
268
|
+
goto.symbol.heads.each do |ptr|
|
269
|
+
path = record_path(goto.from_state, ptr.rule)
|
270
|
+
lastgoto = path.last
|
271
|
+
st = lastgoto ? lastgoto.to_state : goto.from_state
|
272
|
+
if st.conflict?
|
273
|
+
addrel lookback, st.rruleid(ptr.rule), goto
|
274
|
+
end
|
275
|
+
path.reverse_each do |g|
|
276
|
+
break if g.symbol.terminal?
|
277
|
+
edge.push g.ident
|
278
|
+
break unless g.symbol.nullable?
|
279
|
+
end
|
280
|
+
end
|
281
|
+
if edge.empty?
|
282
|
+
includes.push nil
|
283
|
+
else
|
284
|
+
includes.push edge
|
285
|
+
edge = []
|
286
|
+
end
|
287
|
+
end
|
288
|
+
includes = transpose(includes)
|
289
|
+
digraph f, includes
|
290
|
+
if @d_la
|
291
|
+
puts "\n--- F2 (includes) ---"
|
292
|
+
print_tab gotos, includes, f
|
293
|
+
end
|
294
|
+
|
295
|
+
### compute_lookaheads
|
296
|
+
la = create_tmap(la_rules.size)
|
297
|
+
lookback.each_with_index do |arr, i|
|
298
|
+
if arr
|
299
|
+
arr.each do |g|
|
300
|
+
la[i] |= f[g.ident]
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
if @d_la
|
305
|
+
puts "\n--- LA (lookback) ---"
|
306
|
+
print_tab la_rules, lookback, la
|
307
|
+
end
|
308
|
+
|
309
|
+
la
|
310
|
+
end
|
311
|
+
|
312
|
+
def create_tmap(size)
|
313
|
+
Array.new(size, 0) # use Integer as bitmap
|
314
|
+
end
|
315
|
+
|
316
|
+
def addrel(tbl, i, item)
|
317
|
+
if a = tbl[i]
|
318
|
+
a.push item
|
319
|
+
else
|
320
|
+
tbl[i] = [item]
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def record_path(begst, rule)
|
325
|
+
st = begst
|
326
|
+
path = []
|
327
|
+
rule.symbols.each do |t|
|
328
|
+
goto = st.gotos[t]
|
329
|
+
path.push goto
|
330
|
+
st = goto.to_state
|
331
|
+
end
|
332
|
+
path
|
333
|
+
end
|
334
|
+
|
335
|
+
def transpose(rel)
|
336
|
+
new = Array.new(rel.size, nil)
|
337
|
+
rel.each_with_index do |arr, idx|
|
338
|
+
if arr
|
339
|
+
arr.each do |i|
|
340
|
+
addrel new, i, idx
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
new
|
345
|
+
end
|
346
|
+
|
347
|
+
def digraph(map, relation)
|
348
|
+
n = relation.size
|
349
|
+
index = Array.new(n, nil)
|
350
|
+
vertices = []
|
351
|
+
@infinity = n + 2
|
352
|
+
|
353
|
+
index.each_index do |i|
|
354
|
+
if not index[i] and relation[i]
|
355
|
+
traverse i, index, vertices, map, relation
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
def traverse(i, index, vertices, map, relation)
|
361
|
+
vertices.push i
|
362
|
+
index[i] = height = vertices.size
|
363
|
+
|
364
|
+
if rp = relation[i]
|
365
|
+
rp.each do |proci|
|
366
|
+
unless index[proci]
|
367
|
+
traverse proci, index, vertices, map, relation
|
368
|
+
end
|
369
|
+
if index[i] > index[proci]
|
370
|
+
# circulative recursion !!!
|
371
|
+
index[i] = index[proci]
|
372
|
+
end
|
373
|
+
map[i] |= map[proci]
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
if index[i] == height
|
378
|
+
while true
|
379
|
+
proci = vertices.pop
|
380
|
+
index[proci] = @infinity
|
381
|
+
break if i == proci
|
382
|
+
|
383
|
+
map[proci] |= map[i]
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# for debug
|
389
|
+
def print_atab(idx, tab)
|
390
|
+
tab.each_with_index do |i,ii|
|
391
|
+
printf '%-20s', idx[ii].inspect
|
392
|
+
p i
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def print_tab(idx, rel, tab)
|
397
|
+
tab.each_with_index do |bin,i|
|
398
|
+
print i, ' ', idx[i].inspect, ' << '; p rel[i]
|
399
|
+
print ' '
|
400
|
+
each_t(@symboltable, bin) {|t| print ' ', t }
|
401
|
+
puts
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# for debug
|
406
|
+
def print_tab_i(idx, rel, tab, i)
|
407
|
+
bin = tab[i]
|
408
|
+
print i, ' ', idx[i].inspect, ' << '; p rel[i]
|
409
|
+
print ' '
|
410
|
+
each_t(@symboltable, bin) {|t| print ' ', t }
|
411
|
+
end
|
412
|
+
|
413
|
+
# for debug
|
414
|
+
def printb(i)
|
415
|
+
each_t(@symboltable, i) do |t|
|
416
|
+
print t, ' '
|
417
|
+
end
|
418
|
+
puts
|
419
|
+
end
|
420
|
+
|
421
|
+
def each_t(tbl, set)
|
422
|
+
0.upto( set.size ) do |i|
|
423
|
+
(0..7).each do |ii|
|
424
|
+
if set[idx = i * 8 + ii] == 1
|
425
|
+
yield tbl[idx]
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
#
|
432
|
+
# resolve
|
433
|
+
#
|
434
|
+
|
435
|
+
def resolve(state)
|
436
|
+
if state.conflict?
|
437
|
+
resolve_rr state, state.ritems
|
438
|
+
resolve_sr state, state.stokens
|
439
|
+
else
|
440
|
+
if state.rrules.empty?
|
441
|
+
# shift
|
442
|
+
state.stokens.each do |t|
|
443
|
+
state.action[t] = @actions.shift(state.goto_table[t])
|
444
|
+
end
|
445
|
+
else
|
446
|
+
# reduce
|
447
|
+
state.defact = @actions.reduce(state.rrules[0])
|
448
|
+
end
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
def resolve_rr(state, r)
|
453
|
+
r.each do |item|
|
454
|
+
item.each_la(@symboltable) do |t|
|
455
|
+
act = state.action[t]
|
456
|
+
if act
|
457
|
+
unless act.kind_of?(Reduce)
|
458
|
+
raise "racc: fatal: #{act.class} in action table"
|
459
|
+
end
|
460
|
+
# Cannot resolve R/R conflict (on t).
|
461
|
+
# Reduce with upper rule as default.
|
462
|
+
state.rr_conflict act.rule, item.rule, t
|
463
|
+
else
|
464
|
+
# No conflict.
|
465
|
+
state.action[t] = @actions.reduce(item.rule)
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def resolve_sr(state, s)
|
472
|
+
s.each do |stok|
|
473
|
+
goto = state.goto_table[stok]
|
474
|
+
act = state.action[stok]
|
475
|
+
|
476
|
+
unless act
|
477
|
+
# no conflict
|
478
|
+
state.action[stok] = @actions.shift(goto)
|
479
|
+
else
|
480
|
+
unless act.kind_of?(Reduce)
|
481
|
+
puts 'DEBUG -------------------------------'
|
482
|
+
p stok
|
483
|
+
p act
|
484
|
+
state.action.each do |k,v|
|
485
|
+
print k.inspect, ' ', v.inspect, "\n"
|
486
|
+
end
|
487
|
+
raise "racc: fatal: #{act.class} in action table"
|
488
|
+
end
|
489
|
+
|
490
|
+
# conflict on stok
|
491
|
+
|
492
|
+
rtok = act.rule.precedence
|
493
|
+
case do_resolve_sr(stok, rtok)
|
494
|
+
when :Reduce
|
495
|
+
# action is already set
|
496
|
+
|
497
|
+
when :Shift
|
498
|
+
# overwrite
|
499
|
+
act.decref
|
500
|
+
state.action[stok] = @actions.shift(goto)
|
501
|
+
|
502
|
+
when :Error
|
503
|
+
act.decref
|
504
|
+
state.action[stok] = @actions.error
|
505
|
+
|
506
|
+
when :CantResolve
|
507
|
+
# shift as default
|
508
|
+
act.decref
|
509
|
+
state.action[stok] = @actions.shift(goto)
|
510
|
+
state.sr_conflict stok, act.rule
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
ASSOC = {
|
517
|
+
:Left => :Reduce,
|
518
|
+
:Right => :Shift,
|
519
|
+
:Nonassoc => :Error
|
520
|
+
}
|
521
|
+
|
522
|
+
def do_resolve_sr(stok, rtok)
|
523
|
+
puts "resolve_sr: s/r conflict: rtok=#{rtok}, stok=#{stok}" if @d_prec
|
524
|
+
|
525
|
+
unless rtok and rtok.precedence
|
526
|
+
puts "resolve_sr: no prec for #{rtok}(R)" if @d_prec
|
527
|
+
return :CantResolve
|
528
|
+
end
|
529
|
+
rprec = rtok.precedence
|
530
|
+
|
531
|
+
unless stok and stok.precedence
|
532
|
+
puts "resolve_sr: no prec for #{stok}(S)" if @d_prec
|
533
|
+
return :CantResolve
|
534
|
+
end
|
535
|
+
sprec = stok.precedence
|
536
|
+
|
537
|
+
ret = if rprec == sprec
|
538
|
+
ASSOC[rtok.assoc] or
|
539
|
+
raise "racc: fatal: #{rtok}.assoc is not Left/Right/Nonassoc"
|
540
|
+
else
|
541
|
+
(rprec > sprec) ? (:Reduce) : (:Shift)
|
542
|
+
end
|
543
|
+
|
544
|
+
puts "resolve_sr: resolved as #{ret.id2name}" if @d_prec
|
545
|
+
ret
|
546
|
+
end
|
547
|
+
|
548
|
+
#
|
549
|
+
# complete
|
550
|
+
#
|
551
|
+
|
552
|
+
def set_accept
|
553
|
+
anch = @symboltable.anchor
|
554
|
+
init_state = @states[0].goto_table[@grammar.start]
|
555
|
+
targ_state = init_state.action[anch].goto_state
|
556
|
+
acc_state = targ_state.action[anch].goto_state
|
557
|
+
|
558
|
+
acc_state.action.clear
|
559
|
+
acc_state.goto_table.clear
|
560
|
+
acc_state.defact = @actions.accept
|
561
|
+
end
|
562
|
+
|
563
|
+
def pack(state)
|
564
|
+
### find most frequently used reduce rule
|
565
|
+
act = state.action
|
566
|
+
arr = Array.new(@grammar.size, 0)
|
567
|
+
act.each do |t, a|
|
568
|
+
arr[a.ruleid] += 1 if a.kind_of?(Reduce)
|
569
|
+
end
|
570
|
+
i = arr.max
|
571
|
+
s = (i > 0) ? arr.index(i) : nil
|
572
|
+
|
573
|
+
### set & delete default action
|
574
|
+
if s
|
575
|
+
r = @actions.reduce(s)
|
576
|
+
if not state.defact or state.defact == r
|
577
|
+
act.delete_if {|t, a| a == r }
|
578
|
+
state.defact = r
|
579
|
+
end
|
580
|
+
else
|
581
|
+
state.defact ||= @actions.error
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
def check_useless
|
586
|
+
used = []
|
587
|
+
@actions.each_reduce do |act|
|
588
|
+
if not act or act.refn == 0
|
589
|
+
act.rule.useless = true
|
590
|
+
else
|
591
|
+
t = act.rule.target
|
592
|
+
used[t.ident] = t
|
593
|
+
end
|
594
|
+
end
|
595
|
+
@symboltable.nt_base.upto(@symboltable.nt_max - 1) do |n|
|
596
|
+
unless used[n]
|
597
|
+
@symboltable[n].useless = true
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
end # class StateTable
|
603
|
+
|
604
|
+
|
605
|
+
# A LALR state.
|
606
|
+
class State
|
607
|
+
|
608
|
+
def initialize(ident, core)
|
609
|
+
@ident = ident
|
610
|
+
@core = core
|
611
|
+
@goto_table = {}
|
612
|
+
@gotos = {}
|
613
|
+
@stokens = nil
|
614
|
+
@ritems = nil
|
615
|
+
@action = {}
|
616
|
+
@defact = nil
|
617
|
+
@rrconf = nil
|
618
|
+
@srconf = nil
|
619
|
+
|
620
|
+
@closure = make_closure(@core)
|
621
|
+
end
|
622
|
+
|
623
|
+
attr_reader :ident
|
624
|
+
alias stateid ident
|
625
|
+
alias hash ident
|
626
|
+
|
627
|
+
attr_reader :core
|
628
|
+
attr_reader :closure
|
629
|
+
|
630
|
+
attr_reader :goto_table
|
631
|
+
attr_reader :gotos
|
632
|
+
|
633
|
+
attr_reader :stokens
|
634
|
+
attr_reader :ritems
|
635
|
+
attr_reader :rrules
|
636
|
+
|
637
|
+
attr_reader :action
|
638
|
+
attr_accessor :defact # default action
|
639
|
+
|
640
|
+
attr_reader :rrconf
|
641
|
+
attr_reader :srconf
|
642
|
+
|
643
|
+
def inspect
|
644
|
+
"<state #{@ident}>"
|
645
|
+
end
|
646
|
+
|
647
|
+
alias to_s inspect
|
648
|
+
|
649
|
+
def ==(oth)
|
650
|
+
@ident == oth.ident
|
651
|
+
end
|
652
|
+
|
653
|
+
alias eql? ==
|
654
|
+
|
655
|
+
def make_closure(core)
|
656
|
+
set = ISet.new
|
657
|
+
core.each do |ptr|
|
658
|
+
set.add ptr
|
659
|
+
if t = ptr.dereference and t.nonterminal?
|
660
|
+
set.update_a t.expand
|
661
|
+
end
|
662
|
+
end
|
663
|
+
set.to_a
|
664
|
+
end
|
665
|
+
|
666
|
+
def check_la(la_rules)
|
667
|
+
@conflict = false
|
668
|
+
s = []
|
669
|
+
r = []
|
670
|
+
@closure.each do |ptr|
|
671
|
+
if t = ptr.dereference
|
672
|
+
if t.terminal?
|
673
|
+
s[t.ident] = t
|
674
|
+
if t.ident == 1 # $error
|
675
|
+
@conflict = true
|
676
|
+
end
|
677
|
+
end
|
678
|
+
else
|
679
|
+
r.push ptr.rule
|
680
|
+
end
|
681
|
+
end
|
682
|
+
unless r.empty?
|
683
|
+
if not s.empty? or r.size > 1
|
684
|
+
@conflict = true
|
685
|
+
end
|
686
|
+
end
|
687
|
+
s.compact!
|
688
|
+
@stokens = s
|
689
|
+
@rrules = r
|
690
|
+
|
691
|
+
if @conflict
|
692
|
+
@la_rules_i = la_rules.size
|
693
|
+
@la_rules = r.map {|i| i.ident }
|
694
|
+
la_rules.concat r
|
695
|
+
else
|
696
|
+
@la_rules_i = @la_rules = nil
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
def conflict?
|
701
|
+
@conflict
|
702
|
+
end
|
703
|
+
|
704
|
+
def rruleid(rule)
|
705
|
+
if i = @la_rules.index(rule.ident)
|
706
|
+
@la_rules_i + i
|
707
|
+
else
|
708
|
+
puts '/// rruleid'
|
709
|
+
p self
|
710
|
+
p rule
|
711
|
+
p @rrules
|
712
|
+
p @la_rules_i
|
713
|
+
raise 'racc: fatal: cannot get reduce rule id'
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
def la=(la)
|
718
|
+
return unless @conflict
|
719
|
+
i = @la_rules_i
|
720
|
+
@ritems = r = []
|
721
|
+
@rrules.each do |rule|
|
722
|
+
r.push Item.new(rule, la[i])
|
723
|
+
i += 1
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
def rr_conflict(high, low, ctok)
|
728
|
+
c = RRconflict.new(@ident, high, low, ctok)
|
729
|
+
|
730
|
+
@rrconf ||= {}
|
731
|
+
if a = @rrconf[ctok]
|
732
|
+
a.push c
|
733
|
+
else
|
734
|
+
@rrconf[ctok] = [c]
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
738
|
+
def sr_conflict(shift, reduce)
|
739
|
+
c = SRconflict.new(@ident, shift, reduce)
|
740
|
+
|
741
|
+
@srconf ||= {}
|
742
|
+
if a = @srconf[shift]
|
743
|
+
a.push c
|
744
|
+
else
|
745
|
+
@srconf[shift] = [c]
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
def n_srconflicts
|
750
|
+
@srconf ? @srconf.size : 0
|
751
|
+
end
|
752
|
+
|
753
|
+
def n_rrconflicts
|
754
|
+
@rrconf ? @rrconf.size : 0
|
755
|
+
end
|
756
|
+
|
757
|
+
end # class State
|
758
|
+
|
759
|
+
|
760
|
+
#
|
761
|
+
# Represents a transition on the grammar.
|
762
|
+
# "Real goto" means a transition by nonterminal,
|
763
|
+
# but this class treats also terminal's.
|
764
|
+
# If one is a terminal transition, .ident returns nil.
|
765
|
+
#
|
766
|
+
class Goto
|
767
|
+
def initialize(ident, sym, from, to)
|
768
|
+
@ident = ident
|
769
|
+
@symbol = sym
|
770
|
+
@from_state = from
|
771
|
+
@to_state = to
|
772
|
+
end
|
773
|
+
|
774
|
+
attr_reader :ident
|
775
|
+
attr_reader :symbol
|
776
|
+
attr_reader :from_state
|
777
|
+
attr_reader :to_state
|
778
|
+
|
779
|
+
def inspect
|
780
|
+
"(#{@from_state.ident}-#{@symbol}->#{@to_state.ident})"
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
|
785
|
+
# LALR item. A set of rule and its lookahead tokens.
|
786
|
+
class Item
|
787
|
+
def initialize(rule, la)
|
788
|
+
@rule = rule
|
789
|
+
@la = la
|
790
|
+
end
|
791
|
+
|
792
|
+
attr_reader :rule
|
793
|
+
attr_reader :la
|
794
|
+
|
795
|
+
def each_la(tbl)
|
796
|
+
la = @la
|
797
|
+
0.upto(la.size - 1) do |i|
|
798
|
+
(0..7).each do |ii|
|
799
|
+
if la[idx = i * 8 + ii] == 1
|
800
|
+
yield tbl[idx]
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
|
808
|
+
# The table of LALR actions. Actions are either of
|
809
|
+
# Shift, Reduce, Accept and Error.
|
810
|
+
class ActionTable
|
811
|
+
|
812
|
+
def initialize(rt, st)
|
813
|
+
@grammar = rt
|
814
|
+
@statetable = st
|
815
|
+
|
816
|
+
@reduce = []
|
817
|
+
@shift = []
|
818
|
+
@accept = nil
|
819
|
+
@error = nil
|
820
|
+
end
|
821
|
+
|
822
|
+
def init
|
823
|
+
@grammar.each do |rule|
|
824
|
+
@reduce.push Reduce.new(rule)
|
825
|
+
end
|
826
|
+
@statetable.each do |state|
|
827
|
+
@shift.push Shift.new(state)
|
828
|
+
end
|
829
|
+
@accept = Accept.new
|
830
|
+
@error = Error.new
|
831
|
+
end
|
832
|
+
|
833
|
+
def reduce_n
|
834
|
+
@reduce.size
|
835
|
+
end
|
836
|
+
|
837
|
+
def reduce(i)
|
838
|
+
case i
|
839
|
+
when Rule then i = i.ident
|
840
|
+
when Integer then ;
|
841
|
+
else
|
842
|
+
raise "racc: fatal: wrong class #{i.class} for reduce"
|
843
|
+
end
|
844
|
+
|
845
|
+
r = @reduce[i] or raise "racc: fatal: reduce action #{i.inspect} not exist"
|
846
|
+
r.incref
|
847
|
+
r
|
848
|
+
end
|
849
|
+
|
850
|
+
def each_reduce(&block)
|
851
|
+
@reduce.each(&block)
|
852
|
+
end
|
853
|
+
|
854
|
+
def shift_n
|
855
|
+
@shift.size
|
856
|
+
end
|
857
|
+
|
858
|
+
def shift(i)
|
859
|
+
case i
|
860
|
+
when State then i = i.ident
|
861
|
+
when Integer then ;
|
862
|
+
else
|
863
|
+
raise "racc: fatal: wrong class #{i.class} for shift"
|
864
|
+
end
|
865
|
+
|
866
|
+
@shift[i] or raise "racc: fatal: shift action #{i} does not exist"
|
867
|
+
end
|
868
|
+
|
869
|
+
def each_shift(&block)
|
870
|
+
@shift.each(&block)
|
871
|
+
end
|
872
|
+
|
873
|
+
attr_reader :accept
|
874
|
+
attr_reader :error
|
875
|
+
|
876
|
+
end
|
877
|
+
|
878
|
+
|
879
|
+
class Shift
|
880
|
+
def initialize(goto)
|
881
|
+
@goto_state = goto
|
882
|
+
end
|
883
|
+
|
884
|
+
attr_reader :goto_state
|
885
|
+
|
886
|
+
def goto_id
|
887
|
+
@goto_state.ident
|
888
|
+
end
|
889
|
+
|
890
|
+
def inspect
|
891
|
+
"<shift #{@goto_state.ident}>"
|
892
|
+
end
|
893
|
+
end
|
894
|
+
|
895
|
+
|
896
|
+
class Reduce
|
897
|
+
def initialize(rule)
|
898
|
+
@rule = rule
|
899
|
+
@refn = 0
|
900
|
+
end
|
901
|
+
|
902
|
+
attr_reader :rule
|
903
|
+
attr_reader :refn
|
904
|
+
|
905
|
+
def ruleid
|
906
|
+
@rule.ident
|
907
|
+
end
|
908
|
+
|
909
|
+
def inspect
|
910
|
+
"<reduce #{@rule.ident}>"
|
911
|
+
end
|
912
|
+
|
913
|
+
def incref
|
914
|
+
@refn += 1
|
915
|
+
end
|
916
|
+
|
917
|
+
def decref
|
918
|
+
@refn -= 1
|
919
|
+
raise 'racc: fatal: act.refn < 0' if @refn < 0
|
920
|
+
end
|
921
|
+
end
|
922
|
+
|
923
|
+
class Accept
|
924
|
+
def inspect
|
925
|
+
"<accept>"
|
926
|
+
end
|
927
|
+
end
|
928
|
+
|
929
|
+
class Error
|
930
|
+
def inspect
|
931
|
+
"<error>"
|
932
|
+
end
|
933
|
+
end
|
934
|
+
|
935
|
+
class SRconflict
|
936
|
+
def initialize(sid, shift, reduce)
|
937
|
+
@stateid = sid
|
938
|
+
@shift = shift
|
939
|
+
@reduce = reduce
|
940
|
+
end
|
941
|
+
|
942
|
+
attr_reader :stateid
|
943
|
+
attr_reader :shift
|
944
|
+
attr_reader :reduce
|
945
|
+
|
946
|
+
def to_s
|
947
|
+
sprintf('state %d: S/R conflict rule %d reduce and shift %s',
|
948
|
+
@stateid, @reduce.ruleid, @shift.to_s)
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
class RRconflict
|
953
|
+
def initialize(sid, high, low, tok)
|
954
|
+
@stateid = sid
|
955
|
+
@high_prec = high
|
956
|
+
@low_prec = low
|
957
|
+
@token = tok
|
958
|
+
end
|
959
|
+
|
960
|
+
attr_reader :stateid
|
961
|
+
attr_reader :high_prec
|
962
|
+
attr_reader :low_prec
|
963
|
+
attr_reader :token
|
964
|
+
|
965
|
+
def to_s
|
966
|
+
sprintf('state %d: R/R conflict with rule %d and %d on %s',
|
967
|
+
@stateid, @high_prec.ident, @low_prec.ident, @token.to_s)
|
968
|
+
end
|
969
|
+
end
|
970
|
+
|
971
|
+
end
|