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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d79363afacc07dac12ab5c1a861123e099626591104079c962e02f3df74a24f3
|
4
|
+
data.tar.gz: d8ddf78087e27510ab9da808301505a10ec0151ef55d1df3a59cc80ffde81b53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acc15bb56862ea03c6b195253ba881786acf498719f930b8a8435a60f86b44d4383778cc215e7497971833c4be596a9c41a6c5134f77703a9f5cd0a6b5714ad2
|
7
|
+
data.tar.gz: d45b2ec3a22ce2e29beb6a5ec0f4d7b142cebca3b6ca76786fa19b841c257d3841d5a7a43d7d564459b8f9c5b05faa7229bd9b2e2178592ec3988b64f77b535c
|
data/.github/workflows/test.yaml
CHANGED
@@ -22,6 +22,29 @@ jobs:
|
|
22
22
|
bundler-cache: true
|
23
23
|
- run: bundle install
|
24
24
|
- run: bundle exec rspec
|
25
|
+
test-windows:
|
26
|
+
runs-on: windows-2022
|
27
|
+
strategy:
|
28
|
+
fail-fast: false
|
29
|
+
matrix:
|
30
|
+
ruby: ['head']
|
31
|
+
steps:
|
32
|
+
- uses: actions/checkout@v3
|
33
|
+
- uses: ruby/setup-ruby@v1
|
34
|
+
with:
|
35
|
+
ruby-version: ${{ matrix.ruby }}
|
36
|
+
bundler-cache: true
|
37
|
+
- run: bundle install
|
38
|
+
- run: bundle exec rspec
|
39
|
+
check-misc:
|
40
|
+
runs-on: ubuntu-20.04
|
41
|
+
steps:
|
42
|
+
- uses: actions/checkout@v3
|
43
|
+
# Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
|
44
|
+
- name: Check for trailing spaces
|
45
|
+
run: |
|
46
|
+
git grep -I -n '[ ]$' -- '*.rb' '*.[chy]' '*.rs' && exit 1 || :
|
47
|
+
git grep -n '^[ ][ ]*$' -- '*.md' && exit 1 || :
|
25
48
|
steep-check:
|
26
49
|
runs-on: ubuntu-20.04
|
27
50
|
strategy:
|
@@ -58,7 +81,7 @@ jobs:
|
|
58
81
|
- run: mkdir -p tool/lrama
|
59
82
|
working-directory: ../ruby
|
60
83
|
- name: Copy Lrama to ruby/tool
|
61
|
-
run: cp -r exe lib template ../ruby/tool/lrama
|
84
|
+
run: cp -r LEGAL.md MIT exe lib template ../ruby/tool/lrama
|
62
85
|
working-directory:
|
63
86
|
- run: tree tool/lrama
|
64
87
|
working-directory: ../ruby
|
data/Gemfile
CHANGED
@@ -4,8 +4,9 @@ gemspec
|
|
4
4
|
|
5
5
|
gem "rspec"
|
6
6
|
gem "pry"
|
7
|
-
|
7
|
+
# stackprof doesn't support Windows
|
8
|
+
gem "stackprof", platforms: [:ruby]
|
8
9
|
gem "rake"
|
9
10
|
gem "rbs", require: false
|
10
11
|
gem "steep", require: false
|
11
|
-
gem "simplecov", require: false
|
12
|
+
gem "simplecov", require: false
|
data/README.md
CHANGED
@@ -49,10 +49,20 @@ Enter the formula:
|
|
49
49
|
|
50
50
|
## Versions and Branches
|
51
51
|
|
52
|
+
### v0_5 (`master` branch)
|
53
|
+
|
54
|
+
This branch is for Ruby 3.3. `lrama_0_5` branch is created from this branch, once Ruby 3.3 is released.
|
55
|
+
|
52
56
|
### v0_4 (`lrama_0_4` branch)
|
53
57
|
|
54
58
|
This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3.2. The first version migrated to ruby is ["0.4.0"](https://github.com/ruby/ruby/pull/7798) therefore keep this branch for Bison compatible branch.
|
55
59
|
|
60
|
+
## Supported Ruby version
|
61
|
+
|
62
|
+
Lrama is executed with BASERUBY when building ruby from source code. Therefore Lrama needs to support BASERUBY, currently 2.5, or later version.
|
63
|
+
|
64
|
+
This also requires Lrama to be able to run with only default gems and bundled gems.
|
65
|
+
|
56
66
|
## Build Ruby
|
57
67
|
|
58
68
|
1. Install Lrama
|
@@ -62,7 +72,7 @@ This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3
|
|
62
72
|
|
63
73
|
1. Update `Lrama::VERSION`
|
64
74
|
2. Release as a gem by `rake release`
|
65
|
-
3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib ruby/tool/lrama`
|
75
|
+
3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib template ruby/tool/lrama`
|
66
76
|
4. Create new release on [GitHub](https://github.com/ruby/lrama/releases)
|
67
77
|
|
68
78
|
## License
|
data/doc/TODO.md
CHANGED
@@ -44,10 +44,14 @@
|
|
44
44
|
* Reporting
|
45
45
|
* [ ] Bison style
|
46
46
|
* [ ] Wrap not selected reduce with "[]". See basic.output file generated by Bison.
|
47
|
+
* Counterexamples
|
48
|
+
* [x] Nonunifying Counterexamples
|
49
|
+
* [ ] Unifying Counterexamples
|
50
|
+
* [ ] Performance improvement using reverse_transitions and reverse_productions
|
47
51
|
* Error Tolerance
|
48
52
|
* [x] Corchuelo et al. algorithm with N = 1 (this means the next token when error is raised)
|
49
53
|
* [x] Add new decl for error token semantic value initialization (%error-token)
|
50
|
-
* [
|
54
|
+
* [x] Use YYMALLOC & YYFREE
|
51
55
|
* Lex state
|
52
56
|
* CI
|
53
57
|
* [x] Setup CI
|
data/exe/lrama
CHANGED
data/lib/lrama/command.rb
CHANGED
@@ -5,7 +5,6 @@ module Lrama
|
|
5
5
|
def initialize(argv)
|
6
6
|
@argv = argv
|
7
7
|
|
8
|
-
@version = nil
|
9
8
|
@skeleton = "bison/yacc.c"
|
10
9
|
@header = false
|
11
10
|
@header_file = nil
|
@@ -23,15 +22,11 @@ module Lrama
|
|
23
22
|
def run
|
24
23
|
parse_option
|
25
24
|
|
26
|
-
if @version
|
27
|
-
puts Lrama::VERSION
|
28
|
-
exit 0
|
29
|
-
end
|
30
|
-
|
31
25
|
Report::Duration.enable if @trace_opts[:time]
|
32
26
|
|
33
27
|
warning = Lrama::Warning.new
|
34
28
|
grammar = Lrama::Parser.new(@y.read).parse
|
29
|
+
@y.close if @y != STDIN
|
35
30
|
states = Lrama::States.new(grammar, warning, trace_state: (@trace_opts[:automaton] || @trace_opts[:closure]))
|
36
31
|
states.compute
|
37
32
|
context = Lrama::Context.new(states)
|
@@ -67,7 +62,7 @@ module Lrama
|
|
67
62
|
bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
|
68
63
|
others = %w[verbose]
|
69
64
|
list = bison_list + others
|
70
|
-
not_supported = %w[
|
65
|
+
not_supported = %w[cex none]
|
71
66
|
h = { grammar: true }
|
72
67
|
|
73
68
|
report.each do |r|
|
@@ -112,7 +107,7 @@ module Lrama
|
|
112
107
|
opt = OptionParser.new
|
113
108
|
|
114
109
|
# opt.on('-h') {|v| p v }
|
115
|
-
opt.on('-V', '--version') {|v|
|
110
|
+
opt.on('-V', '--version') {|v| puts "lrama #{Lrama::VERSION}"; exit 0 }
|
116
111
|
|
117
112
|
# Tuning the Parser
|
118
113
|
opt.on('-S', '--skeleton=FILE') {|v| @skeleton = v }
|
@@ -121,13 +116,13 @@ module Lrama
|
|
121
116
|
# Output Files:
|
122
117
|
opt.on('-h', '--header=[FILE]') {|v| @header = true; @header_file = v }
|
123
118
|
opt.on('-d') { @header = true }
|
124
|
-
opt.on('-r', '--report=THINGS') {|v| @report = v
|
119
|
+
opt.on('-r', '--report=THINGS', Array) {|v| @report = v }
|
125
120
|
opt.on('--report-file=FILE') {|v| @report_file = v }
|
126
121
|
opt.on('-v') { } # Do nothing
|
127
122
|
opt.on('-o', '--output=FILE') {|v| @outfile = v }
|
128
123
|
|
129
124
|
# Hidden
|
130
|
-
opt.on('--trace=THINGS') {|v| @trace = v
|
125
|
+
opt.on('--trace=THINGS', Array) {|v| @trace = v }
|
131
126
|
|
132
127
|
# Error Recovery
|
133
128
|
opt.on('-e') {|v| @error_recovery = true }
|
data/lib/lrama/context.rb
CHANGED
@@ -401,7 +401,6 @@ module Lrama
|
|
401
401
|
end
|
402
402
|
print sprintf("]\n\n")
|
403
403
|
|
404
|
-
|
405
404
|
print sprintf("width [\n")
|
406
405
|
vectors_count.times do |i|
|
407
406
|
print sprintf("%d, ", ary[i] ? ary[i][3] : 0)
|
@@ -409,7 +408,6 @@ module Lrama
|
|
409
408
|
end
|
410
409
|
print sprintf("]\n\n")
|
411
410
|
|
412
|
-
|
413
411
|
print sprintf("tally [\n")
|
414
412
|
vectors_count.times do |i|
|
415
413
|
print sprintf("%d, ", ary[i] ? ary[i][2] : 0)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Lrama
|
2
|
+
class Counterexamples
|
3
|
+
class Derivation
|
4
|
+
attr_reader :item, :left, :right
|
5
|
+
attr_writer :right
|
6
|
+
|
7
|
+
def initialize(item, left, right = nil)
|
8
|
+
@item = item
|
9
|
+
@left = left
|
10
|
+
@right = right
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"#<Derivation(#{item.display_name})>"
|
15
|
+
end
|
16
|
+
alias :inspect :to_s
|
17
|
+
|
18
|
+
def render_strings_for_report
|
19
|
+
result = []
|
20
|
+
_render_for_report(self, 0, result, 0)
|
21
|
+
result.map(&:rstrip)
|
22
|
+
end
|
23
|
+
|
24
|
+
def render_for_report
|
25
|
+
render_strings_for_report.join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def _render_for_report(derivation, offset, strings, index)
|
31
|
+
item = derivation.item
|
32
|
+
if strings[index]
|
33
|
+
strings[index] << " " * (offset - strings[index].length)
|
34
|
+
else
|
35
|
+
strings[index] = " " * offset
|
36
|
+
end
|
37
|
+
str = strings[index]
|
38
|
+
str << "#{item.rule_id}: #{item.symbols_before_dot.map(&:display_name).join(" ")} "
|
39
|
+
|
40
|
+
if derivation.left
|
41
|
+
len = str.length
|
42
|
+
str << "#{item.next_sym.display_name}"
|
43
|
+
length = _render_for_report(derivation.left, len, strings, index + 1)
|
44
|
+
# I want String#ljust!
|
45
|
+
str << " " * (length - str.length)
|
46
|
+
else
|
47
|
+
str << " • #{item.symbols_after_dot.map(&:display_name).join(" ")} "
|
48
|
+
return str.length
|
49
|
+
end
|
50
|
+
|
51
|
+
if derivation.right&.left
|
52
|
+
length = _render_for_report(derivation.right.left, str.length, strings, index + 1)
|
53
|
+
str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
|
54
|
+
str << " " * (length - str.length) if length > str.length
|
55
|
+
elsif item.next_next_sym
|
56
|
+
str << "#{item.symbols_after_dot[1..-1].map(&:display_name).join(" ")} "
|
57
|
+
end
|
58
|
+
|
59
|
+
return str.length
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Lrama
|
2
|
+
class Counterexamples
|
3
|
+
class Example
|
4
|
+
attr_reader :path1, :path2, :conflict, :conflict_symbol
|
5
|
+
|
6
|
+
# path1 is shift conflict when S/R conflict
|
7
|
+
# path2 is always reduce conflict
|
8
|
+
def initialize(path1, path2, conflict, conflict_symbol, counterexamples)
|
9
|
+
@path1 = path1
|
10
|
+
@path2 = path2
|
11
|
+
@conflict = conflict
|
12
|
+
@conflict_symbol = conflict_symbol
|
13
|
+
@counterexamples = counterexamples
|
14
|
+
end
|
15
|
+
|
16
|
+
def type
|
17
|
+
@conflict.type
|
18
|
+
end
|
19
|
+
|
20
|
+
def path1_item
|
21
|
+
@path1.last.to.item
|
22
|
+
end
|
23
|
+
|
24
|
+
def path2_item
|
25
|
+
@path2.last.to.item
|
26
|
+
end
|
27
|
+
|
28
|
+
def derivations1
|
29
|
+
@derivations1 ||= _derivations(path1)
|
30
|
+
end
|
31
|
+
|
32
|
+
def derivations2
|
33
|
+
@derivations2 ||= _derivations(path2)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def _derivations(paths)
|
39
|
+
derivation = nil
|
40
|
+
current = :production
|
41
|
+
lookahead_sym = paths.last.to.item.end_of_rule? ? @conflict_symbol : nil
|
42
|
+
|
43
|
+
paths.reverse.each do |path|
|
44
|
+
item = path.to.item
|
45
|
+
|
46
|
+
case current
|
47
|
+
when :production
|
48
|
+
case path
|
49
|
+
when StartPath
|
50
|
+
derivation = Derivation.new(item, derivation)
|
51
|
+
current = :start
|
52
|
+
when TransitionPath
|
53
|
+
derivation = Derivation.new(item, derivation)
|
54
|
+
current = :transition
|
55
|
+
when ProductionPath
|
56
|
+
derivation = Derivation.new(item, derivation)
|
57
|
+
current = :production
|
58
|
+
end
|
59
|
+
|
60
|
+
if lookahead_sym && item.next_next_sym && item.next_next_sym.first_set.include?(lookahead_sym)
|
61
|
+
state_item = @counterexamples.transitions[[path.to, item.next_sym]]
|
62
|
+
derivation2 = find_derivation_for_symbol(state_item, lookahead_sym)
|
63
|
+
derivation.right = derivation2
|
64
|
+
lookahead_sym = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
when :transition
|
68
|
+
case path
|
69
|
+
when StartPath
|
70
|
+
derivation = Derivation.new(item, derivation)
|
71
|
+
current = :start
|
72
|
+
when TransitionPath
|
73
|
+
# ignore
|
74
|
+
current = :transition
|
75
|
+
when ProductionPath
|
76
|
+
# ignore
|
77
|
+
current = :production
|
78
|
+
end
|
79
|
+
else
|
80
|
+
raise "BUG: Unknown #{current}"
|
81
|
+
end
|
82
|
+
|
83
|
+
break if current == :start
|
84
|
+
end
|
85
|
+
|
86
|
+
derivation
|
87
|
+
end
|
88
|
+
|
89
|
+
def find_derivation_for_symbol(state_item, sym)
|
90
|
+
queue = []
|
91
|
+
queue << [state_item]
|
92
|
+
|
93
|
+
while (sis = queue.shift)
|
94
|
+
si = sis.last
|
95
|
+
next_sym = si.item.next_sym
|
96
|
+
|
97
|
+
if next_sym == sym
|
98
|
+
derivation = nil
|
99
|
+
|
100
|
+
sis.reverse.each do |si|
|
101
|
+
derivation = Derivation.new(si.item, derivation)
|
102
|
+
end
|
103
|
+
|
104
|
+
return derivation
|
105
|
+
end
|
106
|
+
|
107
|
+
if next_sym.nterm? && next_sym.first_set.include?(sym)
|
108
|
+
@counterexamples.productions[si].each do |next_item|
|
109
|
+
next if next_item.empty_rule?
|
110
|
+
next_si = StateItem.new(si.state, next_item)
|
111
|
+
next if sis.include?(next_si)
|
112
|
+
queue << (sis + [next_si])
|
113
|
+
end
|
114
|
+
|
115
|
+
if next_sym.nullable
|
116
|
+
next_si = @counterexamples.transitions[[si, next_sym]]
|
117
|
+
queue << (sis + [next_si])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Lrama
|
2
|
+
class Counterexamples
|
3
|
+
class Path
|
4
|
+
def initialize(from_state_item, to_state_item)
|
5
|
+
@from_state_item = from_state_item
|
6
|
+
@to_state_item = to_state_item
|
7
|
+
end
|
8
|
+
|
9
|
+
def from
|
10
|
+
@from_state_item
|
11
|
+
end
|
12
|
+
|
13
|
+
def to
|
14
|
+
@to_state_item
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"#<Path(#{type})>"
|
19
|
+
end
|
20
|
+
alias :inspect :to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
class StartPath < Path
|
24
|
+
def initialize(to_state_item)
|
25
|
+
super nil, to_state_item
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
:start
|
30
|
+
end
|
31
|
+
|
32
|
+
def transition?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def production?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class TransitionPath < Path
|
42
|
+
def type
|
43
|
+
:transition
|
44
|
+
end
|
45
|
+
|
46
|
+
def transition?
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
def production?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ProductionPath < Path
|
56
|
+
def type
|
57
|
+
:production
|
58
|
+
end
|
59
|
+
|
60
|
+
def transition?
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
def production?
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Lrama
|
2
|
+
class Counterexamples
|
3
|
+
# s: state
|
4
|
+
# itm: item within s
|
5
|
+
# l: precise lookahead set
|
6
|
+
class Triple < Struct.new(:s, :itm, :l)
|
7
|
+
alias :state :s
|
8
|
+
alias :item :itm
|
9
|
+
alias :precise_lookahead_set :l
|
10
|
+
|
11
|
+
def state_item
|
12
|
+
StateItem.new(state, item)
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"#{state.inspect}. #{item.display_name}. #{l.map(&:id).map(&:s_value)}"
|
17
|
+
end
|
18
|
+
alias :to_s :inspect
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|