lrama 0.5.3 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|