lrama 0.5.3 → 0.5.5
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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yaml +24 -1
- data/Gemfile +3 -2
- data/README.md +11 -1
- data/doc/TODO.md +5 -1
- data/exe/lrama +0 -1
- data/lib/lrama/command.rb +5 -10
- data/lib/lrama/context.rb +0 -2
- data/lib/lrama/counterexamples/derivation.rb +63 -0
- data/lib/lrama/counterexamples/example.rb +124 -0
- data/lib/lrama/counterexamples/path.rb +69 -0
- data/lib/lrama/counterexamples/state_item.rb +6 -0
- data/lib/lrama/counterexamples/triple.rb +21 -0
- data/lib/lrama/counterexamples.rb +283 -0
- data/lib/lrama/digraph.rb +2 -3
- data/lib/lrama/grammar/auxiliary.rb +7 -0
- data/lib/lrama/grammar/code.rb +0 -1
- data/lib/lrama/grammar/rule.rb +6 -0
- data/lib/lrama/grammar/symbol.rb +4 -11
- data/lib/lrama/grammar.rb +44 -8
- data/lib/lrama/lexer/token/type.rb +8 -0
- data/lib/lrama/lexer/token.rb +4 -2
- data/lib/lrama/lexer.rb +3 -4
- data/lib/lrama/output.rb +1 -1
- data/lib/lrama/parser/token_scanner.rb +3 -6
- data/lib/lrama/parser.rb +9 -0
- data/lib/lrama/state/reduce_reduce_conflict.rb +9 -0
- data/lib/lrama/state/shift_reduce_conflict.rb +9 -0
- data/lib/lrama/state.rb +11 -4
- data/lib/lrama/states/item.rb +38 -2
- data/lib/lrama/states.rb +28 -34
- data/lib/lrama/states_reporter.rb +29 -16
- data/lib/lrama/type.rb +4 -0
- data/lib/lrama/version.rb +1 -1
- data/lib/lrama.rb +2 -0
- data/template/bison/yacc.c +103 -95
- metadata +13 -2
data/lib/lrama/states/item.rb
CHANGED
@@ -12,20 +12,56 @@ module Lrama
|
|
12
12
|
rule.id
|
13
13
|
end
|
14
14
|
|
15
|
+
def empty_rule?
|
16
|
+
rule.empty_rule?
|
17
|
+
end
|
18
|
+
|
19
|
+
def number_of_rest_symbols
|
20
|
+
rule.rhs.count - position
|
21
|
+
end
|
22
|
+
|
23
|
+
def lhs
|
24
|
+
rule.lhs
|
25
|
+
end
|
26
|
+
|
15
27
|
def next_sym
|
16
28
|
rule.rhs[position]
|
17
29
|
end
|
18
30
|
|
31
|
+
def next_next_sym
|
32
|
+
rule.rhs[position + 1]
|
33
|
+
end
|
34
|
+
|
35
|
+
def previous_sym
|
36
|
+
rule.rhs[position - 1]
|
37
|
+
end
|
38
|
+
|
19
39
|
def end_of_rule?
|
20
40
|
rule.rhs.count == position
|
21
41
|
end
|
22
42
|
|
43
|
+
def beginning_of_rule?
|
44
|
+
position == 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_item?
|
48
|
+
rule.id == 0 && position == 0
|
49
|
+
end
|
50
|
+
|
23
51
|
def new_by_next_position
|
24
52
|
Item.new(rule: rule, position: position + 1)
|
25
53
|
end
|
26
54
|
|
27
|
-
def
|
28
|
-
rule.rhs[position
|
55
|
+
def symbols_before_dot
|
56
|
+
rule.rhs[0...position]
|
57
|
+
end
|
58
|
+
|
59
|
+
def symbols_after_dot
|
60
|
+
rule.rhs[position..-1]
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
"#{lhs.id.s_value}: #{display_name}"
|
29
65
|
end
|
30
66
|
|
31
67
|
def display_name
|
data/lib/lrama/states.rb
CHANGED
@@ -102,43 +102,27 @@ module Lrama
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def direct_read_sets
|
105
|
-
|
106
|
-
|
107
|
-
@direct_read_sets.each do |k, v|
|
108
|
-
h[k] = bitmap_to_terms(v)
|
105
|
+
@direct_read_sets.transform_values do |v|
|
106
|
+
bitmap_to_terms(v)
|
109
107
|
end
|
110
|
-
|
111
|
-
return h
|
112
108
|
end
|
113
109
|
|
114
110
|
def read_sets
|
115
|
-
|
116
|
-
|
117
|
-
@read_sets.each do |k, v|
|
118
|
-
h[k] = bitmap_to_terms(v)
|
111
|
+
@read_sets.transform_values do |v|
|
112
|
+
bitmap_to_terms(v)
|
119
113
|
end
|
120
|
-
|
121
|
-
return h
|
122
114
|
end
|
123
115
|
|
124
116
|
def follow_sets
|
125
|
-
|
126
|
-
|
127
|
-
@follow_sets.each do |k, v|
|
128
|
-
h[k] = bitmap_to_terms(v)
|
117
|
+
@follow_sets.transform_values do |v|
|
118
|
+
bitmap_to_terms(v)
|
129
119
|
end
|
130
|
-
|
131
|
-
return h
|
132
120
|
end
|
133
121
|
|
134
122
|
def la
|
135
|
-
|
136
|
-
|
137
|
-
@la.each do |k, v|
|
138
|
-
h[k] = bitmap_to_terms(v)
|
123
|
+
@la.transform_values do |v|
|
124
|
+
bitmap_to_terms(v)
|
139
125
|
end
|
140
|
-
|
141
|
-
return h
|
142
126
|
end
|
143
127
|
|
144
128
|
private
|
@@ -452,7 +436,7 @@ module Lrama
|
|
452
436
|
|
453
437
|
# Can resolve only when both have prec
|
454
438
|
unless shift_prec && reduce_prec
|
455
|
-
state.conflicts << State::
|
439
|
+
state.conflicts << State::ShiftReduceConflict.new(symbols: [sym], shift: shift, reduce: reduce)
|
456
440
|
next
|
457
441
|
end
|
458
442
|
|
@@ -471,6 +455,11 @@ module Lrama
|
|
471
455
|
|
472
456
|
# shift_prec == reduce_prec, then check associativity
|
473
457
|
case sym.precedence.type
|
458
|
+
when :precedence
|
459
|
+
# %precedence only specifies precedence and not specify associativity
|
460
|
+
# then a conflict is unresolved if precedence is same.
|
461
|
+
state.conflicts << State::ShiftReduceConflict.new(symbols: [sym], shift: shift, reduce: reduce)
|
462
|
+
next
|
474
463
|
when :right
|
475
464
|
# Shift is selected
|
476
465
|
state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :shift, same_prec: true)
|
@@ -501,16 +490,21 @@ module Lrama
|
|
501
490
|
|
502
491
|
def compute_reduce_reduce_conflicts
|
503
492
|
states.each do |state|
|
504
|
-
|
493
|
+
count = state.reduces.count
|
505
494
|
|
506
|
-
|
507
|
-
|
495
|
+
for i in 0...count do
|
496
|
+
reduce1 = state.reduces[i]
|
497
|
+
next if reduce1.look_ahead.nil?
|
508
498
|
|
509
|
-
|
510
|
-
|
499
|
+
for j in (i+1)...count do
|
500
|
+
reduce2 = state.reduces[j]
|
501
|
+
next if reduce2.look_ahead.nil?
|
511
502
|
|
512
|
-
|
513
|
-
|
503
|
+
intersection = reduce1.look_ahead & reduce2.look_ahead
|
504
|
+
|
505
|
+
if !intersection.empty?
|
506
|
+
state.conflicts << State::ReduceReduceConflict.new(symbols: intersection, reduce1: reduce1, reduce2: reduce2)
|
507
|
+
end
|
514
508
|
end
|
515
509
|
end
|
516
510
|
end
|
@@ -526,9 +520,9 @@ module Lrama
|
|
526
520
|
|
527
521
|
state.default_reduction_rule = state.reduces.map do |r|
|
528
522
|
[r.rule, r.rule.id, (r.look_ahead || []).count]
|
529
|
-
end.
|
523
|
+
end.min_by do |rule, rule_id, count|
|
530
524
|
[-count, rule_id]
|
531
|
-
end.first
|
525
|
+
end.first
|
532
526
|
end
|
533
527
|
end
|
534
528
|
|
@@ -14,13 +14,13 @@ module Lrama
|
|
14
14
|
|
15
15
|
private
|
16
16
|
|
17
|
-
def _report(io, grammar: false, states: false, itemsets: false, lookaheads: false, solved: false, verbose: false)
|
17
|
+
def _report(io, grammar: false, states: false, itemsets: false, lookaheads: false, solved: false, counterexamples: false, verbose: false)
|
18
18
|
# TODO: Unused terms
|
19
19
|
# TODO: Unused rules
|
20
20
|
|
21
21
|
report_conflicts(io)
|
22
22
|
report_grammar(io) if grammar
|
23
|
-
report_states(io, itemsets, lookaheads, solved, verbose)
|
23
|
+
report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
|
24
24
|
end
|
25
25
|
|
26
26
|
def report_conflicts(io)
|
@@ -71,7 +71,11 @@ module Lrama
|
|
71
71
|
io << "\n\n"
|
72
72
|
end
|
73
73
|
|
74
|
-
def report_states(io, itemsets, lookaheads, solved, verbose)
|
74
|
+
def report_states(io, itemsets, lookaheads, solved, counterexamples, verbose)
|
75
|
+
if counterexamples
|
76
|
+
cex = Counterexamples.new(@states)
|
77
|
+
end
|
78
|
+
|
75
79
|
@states.states.each do |state|
|
76
80
|
# Report State
|
77
81
|
io << "State #{state.id}\n\n"
|
@@ -106,7 +110,6 @@ module Lrama
|
|
106
110
|
end
|
107
111
|
io << "\n"
|
108
112
|
|
109
|
-
|
110
113
|
# Report shifts
|
111
114
|
tmp = state.term_transitions.select do |shift, _|
|
112
115
|
!shift.not_selected
|
@@ -119,7 +122,6 @@ module Lrama
|
|
119
122
|
end
|
120
123
|
io << "\n" if !tmp.empty?
|
121
124
|
|
122
|
-
|
123
125
|
# Report error caused by %nonassoc
|
124
126
|
nl = false
|
125
127
|
tmp = state.resolved_conflicts.select do |resolved|
|
@@ -134,7 +136,6 @@ module Lrama
|
|
134
136
|
end
|
135
137
|
io << "\n" if !tmp.empty?
|
136
138
|
|
137
|
-
|
138
139
|
# Report reduces
|
139
140
|
nl = false
|
140
141
|
max_len = state.non_default_reduces.flat_map(&:look_ahead).compact.map(&:display_name).map(&:length).max || 0
|
@@ -167,7 +168,6 @@ module Lrama
|
|
167
168
|
end
|
168
169
|
io << "\n" if nl
|
169
170
|
|
170
|
-
|
171
171
|
# Report nonterminal transitions
|
172
172
|
tmp = []
|
173
173
|
max_len = 0
|
@@ -185,7 +185,6 @@ module Lrama
|
|
185
185
|
end
|
186
186
|
io << "\n" if !tmp.empty?
|
187
187
|
|
188
|
-
|
189
188
|
if solved
|
190
189
|
# Report conflict resolutions
|
191
190
|
state.resolved_conflicts.each do |resolved|
|
@@ -194,6 +193,27 @@ module Lrama
|
|
194
193
|
io << "\n" if !state.resolved_conflicts.empty?
|
195
194
|
end
|
196
195
|
|
196
|
+
if counterexamples && state.has_conflicts?
|
197
|
+
# Report counterexamples
|
198
|
+
examples = cex.compute(state)
|
199
|
+
examples.each do |example|
|
200
|
+
label0 = example.type == :shift_reduce ? "shift/reduce" : "reduce/reduce"
|
201
|
+
label1 = example.type == :shift_reduce ? "Shift derivation" : "First Reduce derivation"
|
202
|
+
label2 = example.type == :shift_reduce ? "Reduce derivation" : "Second Reduce derivation"
|
203
|
+
|
204
|
+
io << " #{label0} conflict on token #{example.conflict_symbol.id.s_value}:\n"
|
205
|
+
io << " #{example.path1_item}\n"
|
206
|
+
io << " #{example.path2_item}\n"
|
207
|
+
io << " #{label1}\n"
|
208
|
+
example.derivations1.render_strings_for_report.each do |str|
|
209
|
+
io << " #{str}\n"
|
210
|
+
end
|
211
|
+
io << " #{label2}\n"
|
212
|
+
example.derivations2.render_strings_for_report.each do |str|
|
213
|
+
io << " #{str}\n"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
197
217
|
|
198
218
|
if verbose
|
199
219
|
# Report direct_read_sets
|
@@ -209,7 +229,6 @@ module Lrama
|
|
209
229
|
end
|
210
230
|
io << "\n"
|
211
231
|
|
212
|
-
|
213
232
|
# Report reads_relation
|
214
233
|
io << " [Reads Relation]\n"
|
215
234
|
@states.nterms.each do |nterm|
|
@@ -223,7 +242,6 @@ module Lrama
|
|
223
242
|
end
|
224
243
|
io << "\n"
|
225
244
|
|
226
|
-
|
227
245
|
# Report read_sets
|
228
246
|
io << " [Read sets]\n"
|
229
247
|
read_sets = @states.read_sets
|
@@ -238,7 +256,6 @@ module Lrama
|
|
238
256
|
end
|
239
257
|
io << "\n"
|
240
258
|
|
241
|
-
|
242
259
|
# Report includes_relation
|
243
260
|
io << " [Includes Relation]\n"
|
244
261
|
@states.nterms.each do |nterm|
|
@@ -252,7 +269,6 @@ module Lrama
|
|
252
269
|
end
|
253
270
|
io << "\n"
|
254
271
|
|
255
|
-
|
256
272
|
# Report lookback_relation
|
257
273
|
io << " [Lookback Relation]\n"
|
258
274
|
@states.rules.each do |rule|
|
@@ -261,12 +277,11 @@ module Lrama
|
|
261
277
|
|
262
278
|
a.each do |state_id2, nterm_id2|
|
263
279
|
n = @states.nterms.find {|n| n.token_id == nterm_id2 }
|
264
|
-
io << " (Rule: #{rule
|
280
|
+
io << " (Rule: #{rule}) -> (State #{state_id2}, #{n.id.s_value})\n"
|
265
281
|
end
|
266
282
|
end
|
267
283
|
io << "\n"
|
268
284
|
|
269
|
-
|
270
285
|
# Report follow_sets
|
271
286
|
io << " [Follow sets]\n"
|
272
287
|
follow_sets = @states.follow_sets
|
@@ -281,7 +296,6 @@ module Lrama
|
|
281
296
|
end
|
282
297
|
io << "\n"
|
283
298
|
|
284
|
-
|
285
299
|
# Report LA
|
286
300
|
io << " [Look-Ahead Sets]\n"
|
287
301
|
tmp = []
|
@@ -301,7 +315,6 @@ module Lrama
|
|
301
315
|
io << "\n" if !tmp.empty?
|
302
316
|
end
|
303
317
|
|
304
|
-
|
305
318
|
# End of Report State
|
306
319
|
io << "\n"
|
307
320
|
end
|
data/lib/lrama/type.rb
ADDED
data/lib/lrama/version.rb
CHANGED
data/lib/lrama.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "lrama/bitmap"
|
2
2
|
require "lrama/command"
|
3
3
|
require "lrama/context"
|
4
|
+
require "lrama/counterexamples"
|
4
5
|
require "lrama/digraph"
|
5
6
|
require "lrama/grammar"
|
6
7
|
require "lrama/lexer"
|
@@ -10,5 +11,6 @@ require "lrama/report"
|
|
10
11
|
require "lrama/state"
|
11
12
|
require "lrama/states"
|
12
13
|
require "lrama/states_reporter"
|
14
|
+
require "lrama/type"
|
13
15
|
require "lrama/version"
|
14
16
|
require "lrama/warning"
|