lrama 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -2
- data/doc/TODO.md +4 -0
- data/lib/lrama/bitmap.rb +29 -0
- data/lib/lrama/command.rb +19 -4
- data/lib/lrama/context.rb +7 -6
- data/lib/lrama/digraph.rb +53 -0
- data/lib/lrama/output.rb +95 -4
- data/lib/lrama/report.rb +12 -0
- data/lib/lrama/states.rb +99 -391
- data/lib/lrama/states_reporter.rb +310 -0
- data/lib/lrama/version.rb +1 -1
- data/lib/lrama/warning.rb +25 -0
- data/lib/lrama.rb +4 -0
- data/sample/parse.y +58 -0
- data/template/bison/yacc.c +11 -18
- metadata +7 -2
data/lib/lrama/states.rb
CHANGED
@@ -1,58 +1,7 @@
|
|
1
|
+
require "forwardable"
|
1
2
|
require "lrama/report"
|
2
3
|
|
3
4
|
module Lrama
|
4
|
-
# Algorithm Digraph of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625)
|
5
|
-
class Digraph
|
6
|
-
def initialize(sets, relation, base_function)
|
7
|
-
# X in the paper
|
8
|
-
@sets = sets
|
9
|
-
# R in the paper
|
10
|
-
@relation = relation
|
11
|
-
# F' in the paper
|
12
|
-
@base_function = base_function
|
13
|
-
# S in the paper
|
14
|
-
@stack = []
|
15
|
-
# N in the paper
|
16
|
-
@h = Hash.new(0)
|
17
|
-
# F in the paper
|
18
|
-
@result = {}
|
19
|
-
end
|
20
|
-
|
21
|
-
def compute
|
22
|
-
@sets.each do |x|
|
23
|
-
next if @h[x] != 0
|
24
|
-
traverse(x)
|
25
|
-
end
|
26
|
-
|
27
|
-
return @result
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def traverse(x)
|
33
|
-
@stack.push(x)
|
34
|
-
d = @stack.count
|
35
|
-
@h[x] = d
|
36
|
-
@result[x] = @base_function[x] # F x = F' x
|
37
|
-
|
38
|
-
@relation[x] && @relation[x].each do |y|
|
39
|
-
traverse(y) if @h[y] == 0
|
40
|
-
@h[x] = [@h[x], @h[y]].min
|
41
|
-
@result[x] |= @result[y] # F x = F x + F y
|
42
|
-
end
|
43
|
-
|
44
|
-
if @h[x] == d
|
45
|
-
while true do
|
46
|
-
z = @stack.pop
|
47
|
-
@h[z] = Float::INFINITY
|
48
|
-
@result[z] = @result[x] # F (Top of S) = F x
|
49
|
-
|
50
|
-
break if z == x
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
5
|
class State
|
57
6
|
class Reduce
|
58
7
|
# https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html
|
@@ -122,14 +71,17 @@ module Lrama
|
|
122
71
|
end
|
123
72
|
end
|
124
73
|
|
74
|
+
Conflict = Struct.new(:symbols, :reduce, :type, keyword_init: true)
|
75
|
+
|
125
76
|
attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
|
126
|
-
:default_reduction_rule
|
127
|
-
attr_accessor :
|
77
|
+
:default_reduction_rule, :closure, :items
|
78
|
+
attr_accessor :shifts, :reduces
|
128
79
|
|
129
80
|
def initialize(id, accessing_symbol, kernels)
|
130
81
|
@id = id
|
131
82
|
@accessing_symbol = accessing_symbol
|
132
83
|
@kernels = kernels.freeze
|
84
|
+
@items = @kernels
|
133
85
|
# Manage relationships between items to state
|
134
86
|
# to resolve next state
|
135
87
|
@items_to_state = {}
|
@@ -138,8 +90,9 @@ module Lrama
|
|
138
90
|
@default_reduction_rule = nil
|
139
91
|
end
|
140
92
|
|
141
|
-
def
|
142
|
-
@
|
93
|
+
def closure=(closure)
|
94
|
+
@closure = closure
|
95
|
+
@items = @kernels + @closure
|
143
96
|
end
|
144
97
|
|
145
98
|
def non_default_reduces
|
@@ -162,6 +115,7 @@ module Lrama
|
|
162
115
|
end
|
163
116
|
end
|
164
117
|
|
118
|
+
# It seems Bison 3.8.2 iterates transitions order by symbol number
|
165
119
|
shifts = _shifts.sort_by do |next_sym, new_items|
|
166
120
|
next_sym.number
|
167
121
|
end.map do |next_sym, new_items|
|
@@ -256,241 +210,16 @@ module Lrama
|
|
256
210
|
end
|
257
211
|
end
|
258
212
|
end
|
259
|
-
end
|
260
213
|
|
261
|
-
|
262
|
-
|
263
|
-
|
214
|
+
def sr_conflicts
|
215
|
+
@conflicts.select do |conflict|
|
216
|
+
conflict.type == :shift_reduce
|
217
|
+
end
|
264
218
|
end
|
265
219
|
|
266
|
-
def
|
267
|
-
@
|
268
|
-
|
269
|
-
io << "State #{state.id}\n\n"
|
270
|
-
|
271
|
-
# Report item
|
272
|
-
last_lhs = nil
|
273
|
-
list = itemsets ? state.items : state.kernels
|
274
|
-
list.sort_by {|i| [i.rule_id, i.position] }.each do |item|
|
275
|
-
rule = item.rule
|
276
|
-
position = item.position
|
277
|
-
if rule.rhs.empty?
|
278
|
-
r = "ε •"
|
279
|
-
else
|
280
|
-
r = rule.rhs.map(&:display_name).insert(position, "•").join(" ")
|
281
|
-
end
|
282
|
-
if rule.lhs == last_lhs
|
283
|
-
l = " " * rule.lhs.id.s_value.length + "|"
|
284
|
-
else
|
285
|
-
l = rule.lhs.id.s_value + ":"
|
286
|
-
end
|
287
|
-
la = ""
|
288
|
-
if lookaheads && item.end_of_rule?
|
289
|
-
reduce = state.find_reduce_by_item!(item)
|
290
|
-
look_ahead = reduce.selected_look_ahead
|
291
|
-
if !look_ahead.empty?
|
292
|
-
la = " [#{look_ahead.map(&:display_name).join(", ")}]"
|
293
|
-
end
|
294
|
-
end
|
295
|
-
last_lhs = rule.lhs
|
296
|
-
|
297
|
-
io << sprintf("%5i %s %s%s\n", rule.id, l, r, la)
|
298
|
-
end
|
299
|
-
io << "\n"
|
300
|
-
|
301
|
-
|
302
|
-
# Report shifts
|
303
|
-
tmp = state.term_transitions.select do |shift, _|
|
304
|
-
!shift.not_selected
|
305
|
-
end.map do |shift, next_state|
|
306
|
-
[shift.next_sym, next_state.id]
|
307
|
-
end
|
308
|
-
max_len = tmp.map(&:first).map(&:display_name).map(&:length).max
|
309
|
-
tmp.each do |term, state_id|
|
310
|
-
io << " #{term.display_name.ljust(max_len)} shift, and go to state #{state_id}\n"
|
311
|
-
end
|
312
|
-
io << "\n" if !tmp.empty?
|
313
|
-
|
314
|
-
|
315
|
-
# Report error caused by %nonassoc
|
316
|
-
nl = false
|
317
|
-
tmp = state.resolved_conflicts.select do |resolved|
|
318
|
-
resolved.which == :error
|
319
|
-
end.map do |error|
|
320
|
-
error.symbol.display_name
|
321
|
-
end
|
322
|
-
max_len = tmp.map(&:length).max
|
323
|
-
tmp.each do |name|
|
324
|
-
nl = true
|
325
|
-
io << " #{name.ljust(max_len)} error (nonassociative)\n"
|
326
|
-
end
|
327
|
-
io << "\n" if !tmp.empty?
|
328
|
-
|
329
|
-
|
330
|
-
# Report reduces
|
331
|
-
nl = false
|
332
|
-
max_len = state.non_default_reduces.flat_map(&:look_ahead).compact.map(&:display_name).map(&:length).max || 0
|
333
|
-
max_len = [max_len, "$default".length].max if state.default_reduction_rule
|
334
|
-
@states.terms.each do |term|
|
335
|
-
reduce = state.non_default_reduces.find do |r|
|
336
|
-
r.look_ahead.include?(term)
|
337
|
-
end
|
338
|
-
|
339
|
-
next unless reduce
|
340
|
-
|
341
|
-
rule = reduce.item.rule
|
342
|
-
io << " #{term.display_name.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.display_name})\n"
|
343
|
-
nl = true
|
344
|
-
end
|
345
|
-
if r = state.default_reduction_rule
|
346
|
-
nl = true
|
347
|
-
s = "$default".ljust(max_len)
|
348
|
-
|
349
|
-
if r.initial_rule?
|
350
|
-
io << " #{s} accept\n"
|
351
|
-
else
|
352
|
-
io << " #{s} reduce using rule #{r.id} (#{r.lhs.display_name})\n"
|
353
|
-
end
|
354
|
-
end
|
355
|
-
io << "\n" if nl
|
356
|
-
|
357
|
-
|
358
|
-
# Report nonterminal transitions
|
359
|
-
tmp = []
|
360
|
-
max_len = 0
|
361
|
-
state.nterm_transitions.each do |shift, next_state|
|
362
|
-
nterm = shift.next_sym
|
363
|
-
tmp << [nterm, next_state.id]
|
364
|
-
max_len = [max_len, nterm.id.s_value.length].max
|
365
|
-
end
|
366
|
-
tmp.uniq!
|
367
|
-
tmp.sort_by! do |nterm, state_id|
|
368
|
-
nterm.number
|
369
|
-
end
|
370
|
-
tmp.each do |nterm, state_id|
|
371
|
-
io << " #{nterm.id.s_value.ljust(max_len)} go to state #{state_id}\n"
|
372
|
-
end
|
373
|
-
io << "\n" if !tmp.empty?
|
374
|
-
|
375
|
-
|
376
|
-
if solved
|
377
|
-
# Report conflict resolutions
|
378
|
-
state.resolved_conflicts.each do |resolved|
|
379
|
-
io << " #{resolved.report_message}\n"
|
380
|
-
end
|
381
|
-
io << "\n" if !state.resolved_conflicts.empty?
|
382
|
-
end
|
383
|
-
|
384
|
-
|
385
|
-
if verbose
|
386
|
-
# Report direct_read_sets
|
387
|
-
io << " [Direct Read sets]\n"
|
388
|
-
direct_read_sets = @states.direct_read_sets
|
389
|
-
@states.nterms.each do |nterm|
|
390
|
-
terms = direct_read_sets[[state.id, nterm.token_id]]
|
391
|
-
next if !terms
|
392
|
-
next if terms.empty?
|
393
|
-
|
394
|
-
str = terms.map {|sym| sym.id.s_value }.join(", ")
|
395
|
-
io << " read #{nterm.id.s_value} shift #{str}\n"
|
396
|
-
end
|
397
|
-
io << "\n"
|
398
|
-
|
399
|
-
|
400
|
-
# Reprot reads_relation
|
401
|
-
io << " [Reads Relation]\n"
|
402
|
-
@states.nterms.each do |nterm|
|
403
|
-
a = @states.reads_relation[[state.id, nterm.token_id]]
|
404
|
-
next if !a
|
405
|
-
|
406
|
-
a.each do |state_id2, nterm_id2|
|
407
|
-
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
408
|
-
io << " (State #{state_id2}, #{n.id.s_value})\n"
|
409
|
-
end
|
410
|
-
end
|
411
|
-
io << "\n"
|
412
|
-
|
413
|
-
|
414
|
-
# Reprot read_sets
|
415
|
-
io << " [Read sets]\n"
|
416
|
-
read_sets = @states.read_sets
|
417
|
-
@states.nterms.each do |nterm|
|
418
|
-
terms = read_sets[[state.id, nterm.token_id]]
|
419
|
-
next if !terms
|
420
|
-
next if terms.empty?
|
421
|
-
|
422
|
-
terms.each do |sym|
|
423
|
-
io << " #{sym.id.s_value}\n"
|
424
|
-
end
|
425
|
-
end
|
426
|
-
io << "\n"
|
427
|
-
|
428
|
-
|
429
|
-
# Reprot includes_relation
|
430
|
-
io << " [Includes Relation]\n"
|
431
|
-
@states.nterms.each do |nterm|
|
432
|
-
a = @states.includes_relation[[state.id, nterm.token_id]]
|
433
|
-
next if !a
|
434
|
-
|
435
|
-
a.each do |state_id2, nterm_id2|
|
436
|
-
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
437
|
-
io << " (State #{state.id}, #{nterm.id.s_value}) -> (State #{state_id2}, #{n.id.s_value})\n"
|
438
|
-
end
|
439
|
-
end
|
440
|
-
io << "\n"
|
441
|
-
|
442
|
-
|
443
|
-
# Report lookback_relation
|
444
|
-
io << " [Lookback Relation]\n"
|
445
|
-
@states.rules.each do |rule|
|
446
|
-
a = @states.lookback_relation[[state.id, rule.id]]
|
447
|
-
next if !a
|
448
|
-
|
449
|
-
a.each do |state_id2, nterm_id2|
|
450
|
-
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
451
|
-
io << " (Rule: #{rule.to_s}) -> (State #{state_id2}, #{n.id.s_value})\n"
|
452
|
-
end
|
453
|
-
end
|
454
|
-
io << "\n"
|
455
|
-
|
456
|
-
|
457
|
-
# Reprot follow_sets
|
458
|
-
io << " [Follow sets]\n"
|
459
|
-
follow_sets = @states.follow_sets
|
460
|
-
@states.nterms.each do |nterm|
|
461
|
-
terms = follow_sets[[state.id, nterm.token_id]]
|
462
|
-
|
463
|
-
next if !terms
|
464
|
-
|
465
|
-
terms.each do |sym|
|
466
|
-
io << " #{nterm.id.s_value} -> #{sym.id.s_value}\n"
|
467
|
-
end
|
468
|
-
end
|
469
|
-
io << "\n"
|
470
|
-
|
471
|
-
|
472
|
-
# Report LA
|
473
|
-
io << " [Look-Ahead Sets]\n"
|
474
|
-
tmp = []
|
475
|
-
max_len = 0
|
476
|
-
@states.rules.each do |rule|
|
477
|
-
syms = @states.la[[state.id, rule.id]]
|
478
|
-
next if !syms
|
479
|
-
|
480
|
-
tmp << [rule, syms]
|
481
|
-
max_len = ([max_len] + syms.map {|s| s.id.s_value.length }).max
|
482
|
-
end
|
483
|
-
tmp.each do |rule, syms|
|
484
|
-
syms.each do |sym|
|
485
|
-
io << " #{sym.id.s_value.ljust(max_len)} reduce using rule #{rule.id} (#{rule.lhs.id.s_value})\n"
|
486
|
-
end
|
487
|
-
end
|
488
|
-
io << "\n" if !tmp.empty?
|
489
|
-
end
|
490
|
-
|
491
|
-
|
492
|
-
# End of Report State
|
493
|
-
io << "\n"
|
220
|
+
def rr_conflicts
|
221
|
+
@conflicts.select do |conflict|
|
222
|
+
conflict.type == :reduce_reduce
|
494
223
|
end
|
495
224
|
end
|
496
225
|
end
|
@@ -500,8 +229,12 @@ module Lrama
|
|
500
229
|
# "Efficient Computation of LALR(1) Look-Ahead Sets"
|
501
230
|
# https://dl.acm.org/doi/pdf/10.1145/69622.357187
|
502
231
|
class States
|
232
|
+
extend Forwardable
|
503
233
|
include Lrama::Report::Duration
|
504
234
|
|
235
|
+
def_delegators "@grammar", :symbols, :terms, :nterms, :rules,
|
236
|
+
:accept_symbol, :eof_symbol, :find_symbol_by_s_value!
|
237
|
+
|
505
238
|
# TODO: Validate position is not over rule rhs
|
506
239
|
Item = Struct.new(:rule, :position, keyword_init: true) do
|
507
240
|
# Optimization for States#setup_state
|
@@ -541,15 +274,14 @@ module Lrama
|
|
541
274
|
end
|
542
275
|
end
|
543
276
|
|
544
|
-
attr_reader :states, :
|
545
|
-
:reads_relation, :includes_relation, :lookback_relation
|
277
|
+
attr_reader :states, :reads_relation, :includes_relation, :lookback_relation
|
546
278
|
|
547
|
-
def initialize(grammar, trace_state: false)
|
279
|
+
def initialize(grammar, warning, trace_state: false)
|
548
280
|
@grammar = grammar
|
281
|
+
@warning = warning
|
549
282
|
@trace_state = trace_state
|
550
283
|
|
551
284
|
@states = []
|
552
|
-
@item_to_state = {}
|
553
285
|
|
554
286
|
# `DR(p, A) = {t ∈ T | p -(A)-> r -(t)-> }`
|
555
287
|
# where p is state, A is nterm, t is term.
|
@@ -568,8 +300,6 @@ module Lrama
|
|
568
300
|
# value is array of [state.id, nterm.token_id].
|
569
301
|
@reads_relation = {}
|
570
302
|
|
571
|
-
# `read_sets` is a hash whose key is [state.id, nterm.token_id]
|
572
|
-
#
|
573
303
|
# `@read_sets` is a hash whose
|
574
304
|
# key is [state.id, nterm.token_id],
|
575
305
|
# value is bitmap of term.
|
@@ -605,9 +335,6 @@ module Lrama
|
|
605
335
|
end
|
606
336
|
|
607
337
|
def compute
|
608
|
-
# TODO: Move report_grammar to other place
|
609
|
-
# report_grammar(@grammar)
|
610
|
-
|
611
338
|
# Look Ahead Sets
|
612
339
|
report_duration(:compute_lr0_states) { compute_lr0_states }
|
613
340
|
report_duration(:compute_direct_read_sets) { compute_direct_read_sets }
|
@@ -622,6 +349,8 @@ module Lrama
|
|
622
349
|
report_duration(:compute_conflicts) { compute_conflicts }
|
623
350
|
|
624
351
|
report_duration(:compute_default_reduction) { compute_default_reduction }
|
352
|
+
|
353
|
+
check_conflicts
|
625
354
|
end
|
626
355
|
|
627
356
|
def reporter
|
@@ -632,34 +361,6 @@ module Lrama
|
|
632
361
|
@states.count
|
633
362
|
end
|
634
363
|
|
635
|
-
def symbols
|
636
|
-
@grammar.symbols
|
637
|
-
end
|
638
|
-
|
639
|
-
def terms
|
640
|
-
@grammar.terms
|
641
|
-
end
|
642
|
-
|
643
|
-
def nterms
|
644
|
-
@grammar.nterms
|
645
|
-
end
|
646
|
-
|
647
|
-
def rules
|
648
|
-
@grammar.rules
|
649
|
-
end
|
650
|
-
|
651
|
-
def accept_symbol
|
652
|
-
@grammar.accept_symbol
|
653
|
-
end
|
654
|
-
|
655
|
-
def eof_symbol
|
656
|
-
@grammar.eof_symbol
|
657
|
-
end
|
658
|
-
|
659
|
-
def find_symbol_by_s_value!(s_value)
|
660
|
-
@grammar.find_symbol_by_s_value!(s_value)
|
661
|
-
end
|
662
|
-
|
663
364
|
def direct_read_sets
|
664
365
|
h = {}
|
665
366
|
|
@@ -702,32 +403,28 @@ module Lrama
|
|
702
403
|
|
703
404
|
private
|
704
405
|
|
705
|
-
def
|
706
|
-
|
707
|
-
|
406
|
+
def sr_conflicts
|
407
|
+
@states.flat_map(&:sr_conflicts)
|
408
|
+
end
|
708
409
|
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
else
|
713
|
-
r = rule.rhs.map(&:display_name).join(" ")
|
714
|
-
end
|
410
|
+
def rr_conflicts
|
411
|
+
@states.flat_map(&:rr_conflicts)
|
412
|
+
end
|
715
413
|
|
716
|
-
|
717
|
-
|
718
|
-
else
|
719
|
-
str << "\n"
|
720
|
-
str << sprintf("%5d %s: %s\n", rule.id, rule.lhs.display_name, r)
|
721
|
-
end
|
414
|
+
def initial_attrs
|
415
|
+
h = {}
|
722
416
|
|
723
|
-
|
417
|
+
attrs.each do |attr|
|
418
|
+
h[attr.id] = false
|
724
419
|
end
|
725
420
|
|
726
|
-
|
421
|
+
h
|
727
422
|
end
|
728
423
|
|
729
|
-
def trace_state
|
730
|
-
|
424
|
+
def trace_state
|
425
|
+
if @trace_state
|
426
|
+
yield STDERR
|
427
|
+
end
|
731
428
|
end
|
732
429
|
|
733
430
|
def create_state(accessing_symbol, kernels, states_creted)
|
@@ -804,32 +501,30 @@ module Lrama
|
|
804
501
|
state.closure = closure.sort_by {|i| i.rule.id }
|
805
502
|
|
806
503
|
# Trace
|
807
|
-
trace_state
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
504
|
+
trace_state do |out|
|
505
|
+
out << "Closure: input\n"
|
506
|
+
state.kernels.each do |item|
|
507
|
+
out << " #{item.display_rest}\n"
|
508
|
+
end
|
509
|
+
out << "\n\n"
|
510
|
+
out << "Closure: output\n"
|
511
|
+
state.items.each do |item|
|
512
|
+
out << " #{item.display_rest}\n"
|
513
|
+
end
|
514
|
+
out << "\n\n"
|
815
515
|
end
|
816
|
-
trace_state("\n\n")
|
817
516
|
|
818
517
|
# shift & reduce
|
819
518
|
state.compute_shifts_reduces
|
820
|
-
|
821
|
-
state.kernels.each do |item|
|
822
|
-
@item_to_state[item] = state
|
823
|
-
end
|
824
519
|
end
|
825
520
|
|
826
521
|
def enqueue_state(states, state)
|
827
522
|
# Trace
|
828
523
|
previous = state.kernels.first.previous_sym
|
829
|
-
trace_state
|
830
|
-
sprintf("state_list_append (state = %d, symbol = %d (%s))",
|
524
|
+
trace_state do |out|
|
525
|
+
out << sprintf("state_list_append (state = %d, symbol = %d (%s))",
|
831
526
|
@states.count, previous.number, previous.display_name)
|
832
|
-
|
527
|
+
end
|
833
528
|
|
834
529
|
states << state
|
835
530
|
end
|
@@ -848,14 +543,13 @@ module Lrama
|
|
848
543
|
# Bison 3.8.2 renders "(reached by "end-of-input")" for State 0 but
|
849
544
|
# I think it is not correct...
|
850
545
|
previous = state.kernels.first.previous_sym
|
851
|
-
trace_state
|
546
|
+
trace_state do |out|
|
547
|
+
out << "Processing state #{state.id} (reached by #{previous.display_name})\n"
|
548
|
+
end
|
852
549
|
|
853
550
|
setup_state(state)
|
854
551
|
|
855
|
-
|
856
|
-
state.shifts.sort_by do |shift|
|
857
|
-
shift.next_sym.number
|
858
|
-
end.each do |shift|
|
552
|
+
state.shifts.each do |shift|
|
859
553
|
new_state, created = create_state(shift.next_sym, shift.next_items, states_creted)
|
860
554
|
state.set_items_to_state(shift.next_items, new_state)
|
861
555
|
enqueue_state(states, new_state) if created
|
@@ -880,18 +574,13 @@ module Lrama
|
|
880
574
|
@states.each do |state|
|
881
575
|
state.nterm_transitions.each do |shift, next_state|
|
882
576
|
nterm = shift.next_sym
|
883
|
-
bit = 0
|
884
|
-
a = []
|
885
577
|
|
886
|
-
next_state.term_transitions.
|
887
|
-
|
888
|
-
# Encode terms into bitmap
|
889
|
-
bit |= (1 << sym.number)
|
890
|
-
a << sym
|
578
|
+
ary = next_state.term_transitions.map do |shift, _|
|
579
|
+
shift.next_sym.number
|
891
580
|
end
|
892
581
|
|
893
582
|
key = [state.id, nterm.token_id]
|
894
|
-
@direct_read_sets[key] =
|
583
|
+
@direct_read_sets[key] = Bitmap.from_array(ary)
|
895
584
|
end
|
896
585
|
end
|
897
586
|
end
|
@@ -941,7 +630,6 @@ module Lrama
|
|
941
630
|
sym = rule.rhs[i]
|
942
631
|
|
943
632
|
break if sym.term?
|
944
|
-
beta = []
|
945
633
|
state2 = transition(state, rule.rhs[0...i])
|
946
634
|
# p' = state, B = nterm, p = state2, A = sym
|
947
635
|
key = [state2.id, sym.token_id]
|
@@ -998,7 +686,7 @@ module Lrama
|
|
998
686
|
|
999
687
|
# No risk of conflict when
|
1000
688
|
# * the state only has single reduce
|
1001
|
-
# * the state only has
|
689
|
+
# * the state only has nterm_transitions (GOTO)
|
1002
690
|
next if state.reduces.count == 1 && state.term_transitions.count == 0
|
1003
691
|
|
1004
692
|
state.set_look_ahead(rule, bitmap_to_terms(look_ahead))
|
@@ -1008,24 +696,15 @@ module Lrama
|
|
1008
696
|
end
|
1009
697
|
|
1010
698
|
def bitmap_to_terms(bit)
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
while bit > 0 do
|
1015
|
-
if bit & 1 == 1
|
1016
|
-
a << @grammar.find_symbol_by_number!(i)
|
1017
|
-
end
|
1018
|
-
|
1019
|
-
i += 1
|
1020
|
-
bit >>= 1
|
699
|
+
ary = Bitmap.to_array(bit)
|
700
|
+
ary.map do |i|
|
701
|
+
@grammar.find_symbol_by_number!(i)
|
1021
702
|
end
|
1022
|
-
|
1023
|
-
return a
|
1024
703
|
end
|
1025
704
|
|
1026
705
|
def compute_conflicts
|
1027
706
|
compute_shift_reduce_conflicts
|
1028
|
-
|
707
|
+
compute_reduce_reduce_conflicts
|
1029
708
|
end
|
1030
709
|
|
1031
710
|
def compute_shift_reduce_conflicts
|
@@ -1043,7 +722,7 @@ module Lrama
|
|
1043
722
|
|
1044
723
|
# Can resolve only when both have prec
|
1045
724
|
unless shift_prec && reduce_prec
|
1046
|
-
state.conflicts << [sym, reduce, :
|
725
|
+
state.conflicts << State::Conflict.new(symbols: [sym], reduce: reduce, type: :shift_reduce)
|
1047
726
|
next
|
1048
727
|
end
|
1049
728
|
|
@@ -1090,7 +769,7 @@ module Lrama
|
|
1090
769
|
end
|
1091
770
|
end
|
1092
771
|
|
1093
|
-
def
|
772
|
+
def compute_reduce_reduce_conflicts
|
1094
773
|
states.each do |state|
|
1095
774
|
a = []
|
1096
775
|
|
@@ -1101,7 +780,7 @@ module Lrama
|
|
1101
780
|
a += reduce.look_ahead
|
1102
781
|
|
1103
782
|
if !intersection.empty?
|
1104
|
-
state.conflicts <<
|
783
|
+
state.conflicts << State::Conflict.new(symbols: intersection.dup, reduce: reduce, type: :reduce_reduce)
|
1105
784
|
end
|
1106
785
|
end
|
1107
786
|
end
|
@@ -1110,6 +789,8 @@ module Lrama
|
|
1110
789
|
def compute_default_reduction
|
1111
790
|
states.each do |state|
|
1112
791
|
next if state.reduces.empty?
|
792
|
+
# Do not set, if conflict exist
|
793
|
+
next if !state.conflicts.empty?
|
1113
794
|
# Do not set, if shift with `error` exists.
|
1114
795
|
next if state.shifts.map(&:next_sym).include?(@grammar.error_symbol)
|
1115
796
|
|
@@ -1120,5 +801,32 @@ module Lrama
|
|
1120
801
|
end.first.first
|
1121
802
|
end
|
1122
803
|
end
|
804
|
+
|
805
|
+
def check_conflicts
|
806
|
+
sr_count = sr_conflicts.count
|
807
|
+
rr_count = rr_conflicts.count
|
808
|
+
|
809
|
+
if @grammar.expect
|
810
|
+
|
811
|
+
expected_sr_conflicts = @grammar.expect
|
812
|
+
expected_rr_conflicts = 0
|
813
|
+
|
814
|
+
if expected_sr_conflicts != sr_count
|
815
|
+
@warning.error("shift/reduce conflicts: #{sr_count} found, #{expected_sr_conflicts} expected")
|
816
|
+
end
|
817
|
+
|
818
|
+
if expected_rr_conflicts != rr_count
|
819
|
+
@warning.error("reduce/reduce conflicts: #{rr_count} found, #{expected_rr_conflicts} expected")
|
820
|
+
end
|
821
|
+
else
|
822
|
+
if sr_count != 0
|
823
|
+
@warning.warn("shift/reduce conflicts: #{sr_count} found")
|
824
|
+
end
|
825
|
+
|
826
|
+
if rr_count != 0
|
827
|
+
@warning.warn("reduce/reduce conflicts: #{rr_count} found")
|
828
|
+
end
|
829
|
+
end
|
830
|
+
end
|
1123
831
|
end
|
1124
832
|
end
|