lrama 0.4.0 → 0.5.1
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/dependabot.yml +6 -0
- data/.github/workflows/test.yaml +19 -3
- data/Gemfile +2 -0
- data/README.md +29 -2
- data/Steepfile +7 -0
- data/lib/lrama/command.rb +7 -3
- data/lib/lrama/grammar.rb +5 -5
- data/lib/lrama/lexer.rb +23 -3
- data/lib/lrama/output.rb +1 -3
- data/lib/lrama/parser/token_scanner.rb +55 -0
- data/lib/lrama/parser.rb +1 -52
- data/lib/lrama/state/reduce.rb +35 -0
- data/lib/lrama/state/shift.rb +13 -0
- data/lib/lrama/state.rb +184 -0
- data/lib/lrama/states.rb +6 -238
- data/lib/lrama/states_reporter.rb +4 -4
- data/lib/lrama/version.rb +1 -1
- data/lib/lrama.rb +1 -0
- data/sample/calc.output +263 -0
- data/sample/calc.y +98 -0
- data/sig/lrama/bitmap.rbs +7 -0
- data/template/bison/yacc.c +1 -1
- data/template/bison/yacc.h +1 -1
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20a0927bedeb14281abb8a5c59daf643fdfe556b5899cbe4872878b022804da2
|
4
|
+
data.tar.gz: 731fdd0201266db9724a2ebcc1162427a2cfaa9d0d94543e1298b3f2683eb14f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a6e7c0ef4e7266dae41dba15e3a5d7609cb7171b82e0dbd5b75595e8e3cf8a4a402c5b710cc0f714c54357ef9fc20fd0935e55b8c529c99cd3c09ea173efb87
|
7
|
+
data.tar.gz: fa867c9be43384c7f282bf22ecd2b0939cd0dca263a51914871dba42f409ddc01fb00c34d8696288c3668177fdc450ff1bc9fb5e90fdf053e2d56a5bf31bbe04
|
data/.github/workflows/test.yaml
CHANGED
@@ -22,6 +22,20 @@ jobs:
|
|
22
22
|
bundler-cache: true
|
23
23
|
- run: bundle install
|
24
24
|
- run: bundle exec rspec
|
25
|
+
steep-check:
|
26
|
+
runs-on: ubuntu-20.04
|
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 steep check
|
25
39
|
test-ruby:
|
26
40
|
runs-on: ubuntu-20.04
|
27
41
|
strategy:
|
@@ -40,10 +54,12 @@ jobs:
|
|
40
54
|
bundler-cache: true
|
41
55
|
- run: git clone --depth=1 https://github.com/ruby/ruby.git -b ${{ matrix.ruby_branch }} ../ruby
|
42
56
|
working-directory:
|
43
|
-
- run: mkdir tool/lrama
|
57
|
+
- run: mkdir -p tool/lrama
|
44
58
|
working-directory: ../ruby
|
45
59
|
- name: Copy Lrama to ruby/tool
|
46
|
-
run: cp -r exe lib
|
60
|
+
run: cp -r exe lib ../ruby/tool/lrama
|
61
|
+
# TODO: Consider how to manage changes on ruby/ruby master and ruby/lrama
|
62
|
+
# run: cp -r exe lib template ../ruby/tool/lrama
|
47
63
|
working-directory:
|
48
64
|
- run: tree tool/lrama
|
49
65
|
working-directory: ../ruby
|
@@ -68,5 +84,5 @@ jobs:
|
|
68
84
|
- run: sudo apt-get --purge remove bison
|
69
85
|
- run: ../autogen.sh
|
70
86
|
- run: ../configure -C --disable-install-doc
|
71
|
-
- run: make
|
87
|
+
- run: make
|
72
88
|
- run: make test-all
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -21,9 +21,11 @@ $ gem install lrama
|
|
21
21
|
From source codes,
|
22
22
|
|
23
23
|
```shell
|
24
|
+
$ cd "$(lrama root)"
|
25
|
+
$ bundle install
|
24
26
|
$ bundle exec rake install
|
25
|
-
$ lrama --version
|
26
|
-
0.
|
27
|
+
$ bundle exec lrama --version
|
28
|
+
0.5.0
|
27
29
|
```
|
28
30
|
|
29
31
|
## Usage
|
@@ -33,11 +35,36 @@ $ lrama --version
|
|
33
35
|
$ lrama -d sample/parse.y
|
34
36
|
```
|
35
37
|
|
38
|
+
```shell
|
39
|
+
# "calc", "calc.c", and "calc.h" are generated
|
40
|
+
$ lrama -d sample/calc.y -o calc.c && gcc -Wall calc.c -o calc && ./calc
|
41
|
+
Enter the formula:
|
42
|
+
1
|
43
|
+
=> 1
|
44
|
+
1+2*3
|
45
|
+
=> 7
|
46
|
+
(1+2)*3
|
47
|
+
=> 9
|
48
|
+
```
|
49
|
+
|
50
|
+
## Versions and Branches
|
51
|
+
|
52
|
+
### v0_4 (`lrama_0_4` branch)
|
53
|
+
|
54
|
+
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
|
+
|
36
56
|
## Build Ruby
|
37
57
|
|
38
58
|
1. Install Lrama
|
39
59
|
2. Run `make YACC=lrama`
|
40
60
|
|
61
|
+
## Release flow
|
62
|
+
|
63
|
+
1. Update `Lrama::VERSION`
|
64
|
+
2. Release as a gem by `rake release`
|
65
|
+
3. Update Lrama in ruby/ruby by `cp -r exe lib ruby/tool/lrama`
|
66
|
+
4. Create new release on [GitHub](https://github.com/ruby/lrama/releases)
|
67
|
+
|
41
68
|
## License
|
42
69
|
|
43
70
|
See LEGAL.md file.
|
data/Steepfile
ADDED
data/lib/lrama/command.rb
CHANGED
@@ -57,14 +57,18 @@ module Lrama
|
|
57
57
|
end
|
58
58
|
|
59
59
|
if !grammar_file
|
60
|
-
|
61
|
-
exit 1
|
60
|
+
abort "File should be specified\n"
|
62
61
|
end
|
63
62
|
|
64
63
|
Report::Duration.enable if trace_opts[:time]
|
65
64
|
|
66
65
|
warning = Lrama::Warning.new
|
67
|
-
|
66
|
+
if grammar_file == '-'
|
67
|
+
grammar_file = argv.shift or abort "File name for STDIN should be specified\n"
|
68
|
+
y = STDIN.read
|
69
|
+
else
|
70
|
+
y = File.read(grammar_file)
|
71
|
+
end
|
68
72
|
grammar = Lrama::Parser.new(y).parse
|
69
73
|
states = Lrama::States.new(grammar, warning, trace_state: (trace_opts[:automaton] || trace_opts[:closure]))
|
70
74
|
states.compute
|
data/lib/lrama/grammar.rb
CHANGED
@@ -166,7 +166,7 @@ module Lrama
|
|
166
166
|
when ref.type == :at # @n
|
167
167
|
raise "@#{ref.number} can not be used in %printer."
|
168
168
|
else
|
169
|
-
raise "Unexpected. #{
|
169
|
+
raise "Unexpected. #{self}, #{ref}"
|
170
170
|
end
|
171
171
|
|
172
172
|
t_code[first_column..last_column] = str
|
@@ -205,7 +205,7 @@ module Lrama
|
|
205
205
|
i = -ref.position_in_rhs + ref.number
|
206
206
|
str = "(yylsp[#{i}])"
|
207
207
|
else
|
208
|
-
raise "Unexpected. #{
|
208
|
+
raise "Unexpected. #{self}, #{ref}"
|
209
209
|
end
|
210
210
|
|
211
211
|
t_code[first_column..last_column] = str
|
@@ -235,7 +235,7 @@ module Lrama
|
|
235
235
|
when ref.type == :at # @n
|
236
236
|
raise "@#{ref.number} can not be used in initial_action."
|
237
237
|
else
|
238
|
-
raise "Unexpected. #{
|
238
|
+
raise "Unexpected. #{self}, #{ref}"
|
239
239
|
end
|
240
240
|
|
241
241
|
t_code[first_column..last_column] = str
|
@@ -716,7 +716,7 @@ module Lrama
|
|
716
716
|
# If id is Token::Char, it uses ASCII code
|
717
717
|
if sym.term? && sym.token_id.nil?
|
718
718
|
if sym.id.type == Token::Char
|
719
|
-
#
|
719
|
+
# Ignore ' on the both sides
|
720
720
|
case sym.id.s_value[1..-2]
|
721
721
|
when "\\b"
|
722
722
|
sym.token_id = 8
|
@@ -844,7 +844,7 @@ module Lrama
|
|
844
844
|
|
845
845
|
return if invalid.empty?
|
846
846
|
|
847
|
-
raise "Symbol number is
|
847
|
+
raise "Symbol number is duplicated. #{invalid}"
|
848
848
|
end
|
849
849
|
end
|
850
850
|
end
|
data/lib/lrama/lexer.rb
CHANGED
@@ -206,6 +206,8 @@ module Lrama
|
|
206
206
|
when ss.scan(/\/\*/)
|
207
207
|
# TODO: Need to keep comment?
|
208
208
|
line = lex_comment(ss, line, lines, "")
|
209
|
+
when ss.scan(/\/\//)
|
210
|
+
line = lex_line_comment(ss, line, "")
|
209
211
|
when ss.scan(/'(.)'/)
|
210
212
|
tokens << create_token(Token::Char, ss[0], line, ss.pos - column)
|
211
213
|
when ss.scan(/'\\(.)'/) # '\\', '\t'
|
@@ -218,7 +220,7 @@ module Lrama
|
|
218
220
|
l = line - lines.first[1]
|
219
221
|
split = ss.string.split("\n")
|
220
222
|
col = ss.pos - split[0...l].join("\n").length
|
221
|
-
raise "Parse error (
|
223
|
+
raise "Parse error (unknown token): #{split[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{col})"
|
222
224
|
end
|
223
225
|
end
|
224
226
|
end
|
@@ -276,6 +278,9 @@ module Lrama
|
|
276
278
|
when ss.scan(/\/\*/)
|
277
279
|
str << ss[0]
|
278
280
|
line = lex_comment(ss, line, lines, str)
|
281
|
+
when ss.scan(/\/\//)
|
282
|
+
str << ss[0]
|
283
|
+
line = lex_line_comment(ss, line, str)
|
279
284
|
else
|
280
285
|
# noop, just consume char
|
281
286
|
str << ss.getch
|
@@ -314,8 +319,6 @@ module Lrama
|
|
314
319
|
raise "Parse error (quote mismatch): #{ss.string.split("\n")[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{ss.pos})"
|
315
320
|
end
|
316
321
|
|
317
|
-
# TODO: Need to handle // style comment
|
318
|
-
#
|
319
322
|
# /* */ style comment
|
320
323
|
def lex_comment(ss, line, lines, str)
|
321
324
|
while !ss.eos? do
|
@@ -337,6 +340,23 @@ module Lrama
|
|
337
340
|
raise "Parse error (comment mismatch): #{ss.string.split("\n")[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{ss.pos})"
|
338
341
|
end
|
339
342
|
|
343
|
+
# // style comment
|
344
|
+
def lex_line_comment(ss, line, str)
|
345
|
+
while !ss.eos? do
|
346
|
+
case
|
347
|
+
when ss.scan(/\n/)
|
348
|
+
return line + 1
|
349
|
+
else
|
350
|
+
str << ss.getch
|
351
|
+
next
|
352
|
+
end
|
353
|
+
|
354
|
+
str << ss[0]
|
355
|
+
end
|
356
|
+
|
357
|
+
line # Reach to end of input
|
358
|
+
end
|
359
|
+
|
340
360
|
def lex_grammar_rules_tokens
|
341
361
|
lex_common(@grammar_rules, @grammar_rules_tokens)
|
342
362
|
end
|
data/lib/lrama/output.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Lrama
|
2
|
+
class Parser
|
3
|
+
class TokenScanner
|
4
|
+
def initialize(tokens)
|
5
|
+
@tokens = tokens
|
6
|
+
@index = 0
|
7
|
+
end
|
8
|
+
|
9
|
+
def current_token
|
10
|
+
@tokens[@index]
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_type
|
14
|
+
current_token && current_token.type
|
15
|
+
end
|
16
|
+
|
17
|
+
def next
|
18
|
+
token = current_token
|
19
|
+
@index += 1
|
20
|
+
return token
|
21
|
+
end
|
22
|
+
|
23
|
+
def consume(*token_types)
|
24
|
+
if token_types.include?(current_type)
|
25
|
+
token = current_token
|
26
|
+
self.next
|
27
|
+
return token
|
28
|
+
end
|
29
|
+
|
30
|
+
return nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def consume!(*token_types)
|
34
|
+
consume(*token_types) || (raise "#{token_types} is expected but #{current_type}. #{current_token}")
|
35
|
+
end
|
36
|
+
|
37
|
+
def consume_multi(*token_types)
|
38
|
+
a = []
|
39
|
+
|
40
|
+
while token_types.include?(current_type)
|
41
|
+
a << current_token
|
42
|
+
self.next
|
43
|
+
end
|
44
|
+
|
45
|
+
raise "No token is consumed. #{token_types}" if a.empty?
|
46
|
+
|
47
|
+
return a
|
48
|
+
end
|
49
|
+
|
50
|
+
def eots?
|
51
|
+
current_token.nil?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/lrama/parser.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "lrama/report"
|
2
|
+
require "lrama/parser/token_scanner"
|
2
3
|
|
3
4
|
module Lrama
|
4
5
|
# Parser for parse.y, generates a grammar
|
@@ -7,58 +8,6 @@ module Lrama
|
|
7
8
|
|
8
9
|
T = Lrama::Lexer::Token
|
9
10
|
|
10
|
-
class TokenScanner
|
11
|
-
def initialize(tokens)
|
12
|
-
@tokens = tokens
|
13
|
-
@index = 0
|
14
|
-
end
|
15
|
-
|
16
|
-
def current_token
|
17
|
-
@tokens[@index]
|
18
|
-
end
|
19
|
-
|
20
|
-
def current_type
|
21
|
-
current_token && current_token.type
|
22
|
-
end
|
23
|
-
|
24
|
-
def next
|
25
|
-
token = current_token
|
26
|
-
@index += 1
|
27
|
-
return token
|
28
|
-
end
|
29
|
-
|
30
|
-
def consume(*token_types)
|
31
|
-
if token_types.include?(current_type)
|
32
|
-
token = current_token
|
33
|
-
self.next
|
34
|
-
return token
|
35
|
-
end
|
36
|
-
|
37
|
-
return nil
|
38
|
-
end
|
39
|
-
|
40
|
-
def consume!(*token_types)
|
41
|
-
consume(*token_types) || (raise "#{token_types} is expected but #{current_type}. #{current_token}")
|
42
|
-
end
|
43
|
-
|
44
|
-
def consume_multi(*token_types)
|
45
|
-
a = []
|
46
|
-
|
47
|
-
while token_types.include?(current_type)
|
48
|
-
a << current_token
|
49
|
-
self.next
|
50
|
-
end
|
51
|
-
|
52
|
-
raise "No token is consumed. #{token_types}" if a.empty?
|
53
|
-
|
54
|
-
return a
|
55
|
-
end
|
56
|
-
|
57
|
-
def eots?
|
58
|
-
current_token.nil?
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
11
|
def initialize(text)
|
63
12
|
@text = text
|
64
13
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Lrama
|
2
|
+
class State
|
3
|
+
class Reduce
|
4
|
+
# https://www.gnu.org/software/bison/manual/html_node/Default-Reductions.html
|
5
|
+
attr_reader :item, :look_ahead, :not_selected_symbols
|
6
|
+
attr_accessor :default_reduction
|
7
|
+
|
8
|
+
def initialize(item)
|
9
|
+
@item = item
|
10
|
+
@look_ahead = nil
|
11
|
+
@not_selected_symbols = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def rule
|
15
|
+
@item.rule
|
16
|
+
end
|
17
|
+
|
18
|
+
def look_ahead=(look_ahead)
|
19
|
+
@look_ahead = look_ahead.freeze
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_not_selected_symbol(sym)
|
23
|
+
@not_selected_symbols << sym
|
24
|
+
end
|
25
|
+
|
26
|
+
def selected_look_ahead
|
27
|
+
if @look_ahead
|
28
|
+
@look_ahead - @not_selected_symbols
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/lrama/state.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
require "lrama/state/reduce"
|
2
|
+
require "lrama/state/shift"
|
3
|
+
|
4
|
+
module Lrama
|
5
|
+
class State
|
6
|
+
# * symbol: A symbol under discussion
|
7
|
+
# * reduce: A reduce under discussion
|
8
|
+
# * which: For which a conflict is resolved. :shift, :reduce or :error (for nonassociative)
|
9
|
+
ResolvedConflict = Struct.new(:symbol, :reduce, :which, :same_prec, keyword_init: true) do
|
10
|
+
def report_message
|
11
|
+
s = symbol.display_name
|
12
|
+
r = reduce.rule.precedence_sym.display_name
|
13
|
+
case
|
14
|
+
when which == :shift && same_prec
|
15
|
+
msg = "resolved as #{which} (%right #{s})"
|
16
|
+
when which == :shift
|
17
|
+
msg = "resolved as #{which} (#{r} < #{s})"
|
18
|
+
when which == :reduce && same_prec
|
19
|
+
msg = "resolved as #{which} (%left #{s})"
|
20
|
+
when which == :reduce
|
21
|
+
msg = "resolved as #{which} (#{s} < #{r})"
|
22
|
+
when which == :error
|
23
|
+
msg = "resolved as an #{which} (%nonassoc #{s})"
|
24
|
+
else
|
25
|
+
raise "Unknown direction. #{self}"
|
26
|
+
end
|
27
|
+
|
28
|
+
"Conflict between rule #{reduce.rule.id} and token #{s} #{msg}."
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Conflict = Struct.new(:symbols, :reduce, :type, keyword_init: true)
|
33
|
+
|
34
|
+
attr_reader :id, :accessing_symbol, :kernels, :conflicts, :resolved_conflicts,
|
35
|
+
:default_reduction_rule, :closure, :items
|
36
|
+
attr_accessor :shifts, :reduces
|
37
|
+
|
38
|
+
def initialize(id, accessing_symbol, kernels)
|
39
|
+
@id = id
|
40
|
+
@accessing_symbol = accessing_symbol
|
41
|
+
@kernels = kernels.freeze
|
42
|
+
@items = @kernels
|
43
|
+
# Manage relationships between items to state
|
44
|
+
# to resolve next state
|
45
|
+
@items_to_state = {}
|
46
|
+
@conflicts = []
|
47
|
+
@resolved_conflicts = []
|
48
|
+
@default_reduction_rule = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def closure=(closure)
|
52
|
+
@closure = closure
|
53
|
+
@items = @kernels + @closure
|
54
|
+
end
|
55
|
+
|
56
|
+
def non_default_reduces
|
57
|
+
reduces.select do |reduce|
|
58
|
+
reduce.rule != @default_reduction_rule
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def compute_shifts_reduces
|
63
|
+
_shifts = {}
|
64
|
+
reduces = []
|
65
|
+
items.each do |item|
|
66
|
+
# TODO: Consider what should be pushed
|
67
|
+
if item.end_of_rule?
|
68
|
+
reduces << Reduce.new(item)
|
69
|
+
else
|
70
|
+
key = item.next_sym
|
71
|
+
_shifts[key] ||= []
|
72
|
+
_shifts[key] << item.new_by_next_position
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# It seems Bison 3.8.2 iterates transitions order by symbol number
|
77
|
+
shifts = _shifts.sort_by do |next_sym, new_items|
|
78
|
+
next_sym.number
|
79
|
+
end.map do |next_sym, new_items|
|
80
|
+
Shift.new(next_sym, new_items.flatten)
|
81
|
+
end
|
82
|
+
self.shifts = shifts.freeze
|
83
|
+
self.reduces = reduces.freeze
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_items_to_state(items, next_state)
|
87
|
+
@items_to_state[items] = next_state
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
def set_look_ahead(rule, look_ahead)
|
92
|
+
reduce = reduces.find do |r|
|
93
|
+
r.rule == rule
|
94
|
+
end
|
95
|
+
|
96
|
+
reduce.look_ahead = look_ahead
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns array of [nterm, next_state]
|
100
|
+
def nterm_transitions
|
101
|
+
return @nterm_transitions if @nterm_transitions
|
102
|
+
|
103
|
+
@nterm_transitions = []
|
104
|
+
|
105
|
+
shifts.each do |shift|
|
106
|
+
next if shift.next_sym.term?
|
107
|
+
|
108
|
+
@nterm_transitions << [shift, @items_to_state[shift.next_items]]
|
109
|
+
end
|
110
|
+
|
111
|
+
@nterm_transitions
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns array of [term, next_state]
|
115
|
+
def term_transitions
|
116
|
+
return @term_transitions if @term_transitions
|
117
|
+
|
118
|
+
@term_transitions = []
|
119
|
+
|
120
|
+
shifts.each do |shift|
|
121
|
+
next if shift.next_sym.nterm?
|
122
|
+
|
123
|
+
@term_transitions << [shift, @items_to_state[shift.next_items]]
|
124
|
+
end
|
125
|
+
|
126
|
+
@term_transitions
|
127
|
+
end
|
128
|
+
|
129
|
+
def selected_term_transitions
|
130
|
+
term_transitions.select do |shift, next_state|
|
131
|
+
!shift.not_selected
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Move to next state by sym
|
136
|
+
def transition(sym)
|
137
|
+
result = nil
|
138
|
+
|
139
|
+
if sym.term?
|
140
|
+
term_transitions.each do |shift, next_state|
|
141
|
+
term = shift.next_sym
|
142
|
+
result = next_state if term == sym
|
143
|
+
end
|
144
|
+
else
|
145
|
+
nterm_transitions.each do |shift, next_state|
|
146
|
+
nterm = shift.next_sym
|
147
|
+
result = next_state if nterm == sym
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
raise "Can not transit by #{sym} #{self}" if result.nil?
|
152
|
+
|
153
|
+
result
|
154
|
+
end
|
155
|
+
|
156
|
+
def find_reduce_by_item!(item)
|
157
|
+
reduces.find do |r|
|
158
|
+
r.item == item
|
159
|
+
end || (raise "reduce is not found. #{item}")
|
160
|
+
end
|
161
|
+
|
162
|
+
def default_reduction_rule=(default_reduction_rule)
|
163
|
+
@default_reduction_rule = default_reduction_rule
|
164
|
+
|
165
|
+
reduces.each do |r|
|
166
|
+
if r.rule == default_reduction_rule
|
167
|
+
r.default_reduction = true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def sr_conflicts
|
173
|
+
@conflicts.select do |conflict|
|
174
|
+
conflict.type == :shift_reduce
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def rr_conflicts
|
179
|
+
@conflicts.select do |conflict|
|
180
|
+
conflict.type == :reduce_reduce
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|