lrama 0.5.1 → 0.5.3
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 +2 -3
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/LEGAL.md +1 -16
- data/README.md +1 -1
- data/Steepfile +3 -0
- data/doc/TODO.md +4 -3
- data/exe/lrama +1 -1
- data/lib/lrama/command.rb +90 -71
- data/lib/lrama/context.rb +11 -1
- data/lib/lrama/grammar/code.rb +123 -0
- data/lib/lrama/grammar/error_token.rb +9 -0
- data/lib/lrama/grammar/precedence.rb +11 -0
- data/lib/lrama/grammar/printer.rb +9 -0
- data/lib/lrama/grammar/reference.rb +22 -0
- data/lib/lrama/grammar/rule.rb +33 -0
- data/lib/lrama/grammar/symbol.rb +94 -0
- data/lib/lrama/grammar/union.rb +10 -0
- data/lib/lrama/grammar.rb +67 -285
- data/lib/lrama/lexer/token.rb +76 -0
- data/lib/lrama/lexer.rb +12 -48
- data/lib/lrama/output.rb +31 -3
- data/lib/lrama/parser/token_scanner.rb +4 -0
- data/lib/lrama/parser.rb +19 -5
- data/lib/lrama/report/duration.rb +25 -0
- data/lib/lrama/report/profile.rb +25 -0
- data/lib/lrama/report.rb +2 -47
- data/lib/lrama/state/resolved_conflict.rb +29 -0
- data/lib/lrama/state.rb +3 -28
- data/lib/lrama/states/item.rb +43 -0
- data/lib/lrama/states.rb +3 -41
- data/lib/lrama/version.rb +1 -1
- data/lrama.gemspec +2 -2
- data/rbs_collection.lock.yaml +26 -0
- data/rbs_collection.yaml +22 -0
- data/sig/lrama/report/duration.rbs +11 -0
- data/sig/lrama/report/profile.rbs +7 -0
- data/sig/lrama/warning.rbs +16 -0
- data/template/bison/yacc.c +397 -32
- metadata +23 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32eaf486545ca4143a227a34cee2bfdb94928e002a85fcb2e098dba3dedb71c7
|
4
|
+
data.tar.gz: b80a7402d9f6caf9f0e8b5396e4bd6b80d84487a35c8cd4b4d711e51ffb56601
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d118074af8984d85e27485a0c9fb2f8c7eab9a55b771ea3eff17e26d84fe56316404f6316ba5a9c83e61591c83ff9048c6625a904529aa686417f6f295499d9
|
7
|
+
data.tar.gz: e3591cc5f70e6fe8a04af5070a7b5d6ee60e98718c4c6dc6db1fbef2b3be9f5239155da91bb51ba10611b5017925f1bf71aa1259fd5550b5af6d0ba458e2ab96
|
data/.github/workflows/test.yaml
CHANGED
@@ -35,6 +35,7 @@ jobs:
|
|
35
35
|
ruby-version: ${{ matrix.ruby }}
|
36
36
|
bundler-cache: true
|
37
37
|
- run: bundle install
|
38
|
+
- run: bundle exec rbs collection install
|
38
39
|
- run: bundle exec steep check
|
39
40
|
test-ruby:
|
40
41
|
runs-on: ubuntu-20.04
|
@@ -57,9 +58,7 @@ jobs:
|
|
57
58
|
- run: mkdir -p tool/lrama
|
58
59
|
working-directory: ../ruby
|
59
60
|
- name: Copy Lrama to ruby/tool
|
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
|
61
|
+
run: cp -r exe lib template ../ruby/tool/lrama
|
63
62
|
working-directory:
|
64
63
|
- run: tree tool/lrama
|
65
64
|
working-directory: ../ruby
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/LEGAL.md
CHANGED
@@ -5,22 +5,7 @@ mentioned below.
|
|
5
5
|
|
6
6
|
## GNU General Public License version 3
|
7
7
|
|
8
|
-
These files are licensed under the GNU General Public License version 3. See these files for more information.
|
8
|
+
These files are licensed under the GNU General Public License version 3 or later. See these files for more information.
|
9
9
|
|
10
10
|
* template/bison/yacc.c
|
11
11
|
* template/bison/yacc.h
|
12
|
-
|
13
|
-
## Same with Ruby
|
14
|
-
|
15
|
-
These files are licensed same with Ruby. See https://github.com/ruby/ruby/blob/master/COPYING for more information.
|
16
|
-
|
17
|
-
* spec/fixtures/integration/ruby_3_0_5/parse.tmp.y
|
18
|
-
* spec/fixtures/integration/ruby_3_0_5/y.tab.c
|
19
|
-
* spec/fixtures/integration/ruby_3_0_5/y.tab.h
|
20
|
-
* spec/fixtures/integration/ruby_3_1_0/parse.tmp.y
|
21
|
-
* spec/fixtures/integration/ruby_3_1_0/y.tab.c
|
22
|
-
* spec/fixtures/integration/ruby_3_1_0/y.tab.h
|
23
|
-
* spec/fixtures/integration/ruby_3_2_0/parse.tmp.y
|
24
|
-
* spec/fixtures/integration/ruby_3_2_0/y.tab.c
|
25
|
-
* spec/fixtures/integration/ruby_3_2_0/y.tab.h
|
26
|
-
|
data/README.md
CHANGED
@@ -62,7 +62,7 @@ This branch generates "parse.c" compatible with Bison 3.8.2 for ruby 3.0, 3.1, 3
|
|
62
62
|
|
63
63
|
1. Update `Lrama::VERSION`
|
64
64
|
2. Release as a gem by `rake release`
|
65
|
-
3. Update Lrama in ruby/ruby by `cp -r exe lib ruby/tool/lrama`
|
65
|
+
3. Update Lrama in ruby/ruby by `cp -r LEGAL.md MIT exe lib ruby/tool/lrama`
|
66
66
|
4. Create new release on [GitHub](https://github.com/ruby/lrama/releases)
|
67
67
|
|
68
68
|
## License
|
data/Steepfile
CHANGED
data/doc/TODO.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# TODO
|
2
2
|
|
3
3
|
* command
|
4
|
-
* [ ] Add "--bison" option
|
5
4
|
* lexer
|
6
5
|
* [x] Basic functionalities
|
7
6
|
* parser
|
@@ -27,7 +26,7 @@
|
|
27
26
|
* [x] Table compaction
|
28
27
|
* [x] -d option
|
29
28
|
* yacc.c
|
30
|
-
* [
|
29
|
+
* [x] %lex-param
|
31
30
|
* [x] %parse-param
|
32
31
|
* [x] %printer
|
33
32
|
* [x] Replace $, @ in user codes
|
@@ -46,7 +45,9 @@
|
|
46
45
|
* [ ] Bison style
|
47
46
|
* [ ] Wrap not selected reduce with "[]". See basic.output file generated by Bison.
|
48
47
|
* Error Tolerance
|
49
|
-
* [x]
|
48
|
+
* [x] Corchuelo et al. algorithm with N = 1 (this means the next token when error is raised)
|
49
|
+
* [x] Add new decl for error token semantic value initialization (%error-token)
|
50
|
+
* [ ] Use YYMALLOC & YYFREE
|
50
51
|
* Lex state
|
51
52
|
* CI
|
52
53
|
* [x] Setup CI
|
data/exe/lrama
CHANGED
data/lib/lrama/command.rb
CHANGED
@@ -2,94 +2,57 @@ require 'optparse'
|
|
2
2
|
|
3
3
|
module Lrama
|
4
4
|
class Command
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
outfile = "y.tab.c"
|
23
|
-
|
24
|
-
opt.on('-h', '--header=[FILE]') {|v| header = true; header_file = v }
|
25
|
-
opt.on('-d') { header = true }
|
26
|
-
opt.on('-r', '--report=THINGS') {|v| report = v.split(',') }
|
27
|
-
opt.on('--report-file=FILE') {|v| report_file = v }
|
28
|
-
opt.on('-v') { } # Do nothing
|
29
|
-
opt.on('-o', '--output=FILE') {|v| outfile = v }
|
30
|
-
|
31
|
-
# Hidden
|
32
|
-
trace = []
|
33
|
-
opt.on('--trace=THINGS') {|v| trace = v.split(',') }
|
34
|
-
|
35
|
-
# Error Recovery
|
36
|
-
error_recovery = false
|
37
|
-
opt.on('-e') {|v| error_recovery = true }
|
38
|
-
|
39
|
-
opt.parse!(argv)
|
40
|
-
|
41
|
-
trace_opts = validate_trace(trace)
|
42
|
-
report_opts = validate_report(report)
|
43
|
-
|
44
|
-
grammar_file = argv.shift
|
45
|
-
|
46
|
-
if !report.empty? && report_file.nil? && grammar_file
|
47
|
-
report_file = File.dirname(grammar_file) + "/" + File.basename(grammar_file, ".*") + ".output"
|
48
|
-
end
|
5
|
+
def initialize(argv)
|
6
|
+
@argv = argv
|
7
|
+
|
8
|
+
@version = nil
|
9
|
+
@skeleton = "bison/yacc.c"
|
10
|
+
@header = false
|
11
|
+
@header_file = nil
|
12
|
+
@report = []
|
13
|
+
@report_file = nil
|
14
|
+
@outfile = "y.tab.c"
|
15
|
+
@trace = []
|
16
|
+
@error_recovery = false
|
17
|
+
@grammar_file = nil
|
18
|
+
@report_file = nil
|
19
|
+
@trace_opts = nil
|
20
|
+
@report_opts = nil
|
21
|
+
end
|
49
22
|
|
50
|
-
|
51
|
-
|
52
|
-
when outfile
|
53
|
-
header_file = File.dirname(outfile) + "/" + File.basename(outfile, ".*") + ".h"
|
54
|
-
when grammar_file
|
55
|
-
header_file = File.dirname(grammar_file) + "/" + File.basename(grammar_file, ".*") + ".h"
|
56
|
-
end
|
57
|
-
end
|
23
|
+
def run
|
24
|
+
parse_option
|
58
25
|
|
59
|
-
if
|
60
|
-
|
26
|
+
if @version
|
27
|
+
puts Lrama::VERSION
|
28
|
+
exit 0
|
61
29
|
end
|
62
30
|
|
63
|
-
Report::Duration.enable if trace_opts[:time]
|
31
|
+
Report::Duration.enable if @trace_opts[:time]
|
64
32
|
|
65
33
|
warning = Lrama::Warning.new
|
66
|
-
|
67
|
-
|
68
|
-
y = STDIN.read
|
69
|
-
else
|
70
|
-
y = File.read(grammar_file)
|
71
|
-
end
|
72
|
-
grammar = Lrama::Parser.new(y).parse
|
73
|
-
states = Lrama::States.new(grammar, warning, trace_state: (trace_opts[:automaton] || trace_opts[:closure]))
|
34
|
+
grammar = Lrama::Parser.new(@y.read).parse
|
35
|
+
states = Lrama::States.new(grammar, warning, trace_state: (@trace_opts[:automaton] || @trace_opts[:closure]))
|
74
36
|
states.compute
|
75
37
|
context = Lrama::Context.new(states)
|
76
38
|
|
77
|
-
if report_file
|
39
|
+
if @report_file
|
78
40
|
reporter = Lrama::StatesReporter.new(states)
|
79
|
-
File.open(report_file, "w+") do |f|
|
80
|
-
reporter.report(f,
|
41
|
+
File.open(@report_file, "w+") do |f|
|
42
|
+
reporter.report(f, **@report_opts)
|
81
43
|
end
|
82
44
|
end
|
83
45
|
|
84
|
-
File.open(outfile, "w+") do |f|
|
46
|
+
File.open(@outfile, "w+") do |f|
|
85
47
|
Lrama::Output.new(
|
86
48
|
out: f,
|
87
|
-
output_file_path: outfile,
|
88
|
-
template_name: skeleton,
|
89
|
-
grammar_file_path: grammar_file,
|
90
|
-
header_file_path: header_file,
|
49
|
+
output_file_path: @outfile,
|
50
|
+
template_name: @skeleton,
|
51
|
+
grammar_file_path: @grammar_file,
|
52
|
+
header_file_path: @header_file,
|
91
53
|
context: context,
|
92
54
|
grammar: grammar,
|
55
|
+
error_recovery: @error_recovery,
|
93
56
|
).render
|
94
57
|
end
|
95
58
|
|
@@ -144,5 +107,61 @@ module Lrama
|
|
144
107
|
|
145
108
|
return h
|
146
109
|
end
|
110
|
+
|
111
|
+
def parse_option
|
112
|
+
opt = OptionParser.new
|
113
|
+
|
114
|
+
# opt.on('-h') {|v| p v }
|
115
|
+
opt.on('-V', '--version') {|v| @version = true }
|
116
|
+
|
117
|
+
# Tuning the Parser
|
118
|
+
opt.on('-S', '--skeleton=FILE') {|v| @skeleton = v }
|
119
|
+
opt.on('-t') { } # Do nothing
|
120
|
+
|
121
|
+
# Output Files:
|
122
|
+
opt.on('-h', '--header=[FILE]') {|v| @header = true; @header_file = v }
|
123
|
+
opt.on('-d') { @header = true }
|
124
|
+
opt.on('-r', '--report=THINGS') {|v| @report = v.split(',') }
|
125
|
+
opt.on('--report-file=FILE') {|v| @report_file = v }
|
126
|
+
opt.on('-v') { } # Do nothing
|
127
|
+
opt.on('-o', '--output=FILE') {|v| @outfile = v }
|
128
|
+
|
129
|
+
# Hidden
|
130
|
+
opt.on('--trace=THINGS') {|v| @trace = v.split(',') }
|
131
|
+
|
132
|
+
# Error Recovery
|
133
|
+
opt.on('-e') {|v| @error_recovery = true }
|
134
|
+
|
135
|
+
opt.parse!(@argv)
|
136
|
+
|
137
|
+
@trace_opts = validate_trace(@trace)
|
138
|
+
@report_opts = validate_report(@report)
|
139
|
+
|
140
|
+
@grammar_file = @argv.shift
|
141
|
+
|
142
|
+
if !@grammar_file
|
143
|
+
abort "File should be specified\n"
|
144
|
+
end
|
145
|
+
|
146
|
+
if @grammar_file == '-'
|
147
|
+
@grammar_file = @argv.shift or abort "File name for STDIN should be specified\n"
|
148
|
+
@y = STDIN
|
149
|
+
else
|
150
|
+
@y = File.open(@grammar_file, 'r')
|
151
|
+
end
|
152
|
+
|
153
|
+
if !@report.empty? && @report_file.nil? && @grammar_file
|
154
|
+
@report_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".output"
|
155
|
+
end
|
156
|
+
|
157
|
+
if !@header_file && @header
|
158
|
+
case
|
159
|
+
when @outfile
|
160
|
+
@header_file = File.dirname(@outfile) + "/" + File.basename(@outfile, ".*") + ".h"
|
161
|
+
when @grammar_file
|
162
|
+
@header_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".h"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
147
166
|
end
|
148
167
|
end
|
data/lib/lrama/context.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require "lrama/report"
|
1
|
+
require "lrama/report/duration"
|
2
2
|
|
3
3
|
module Lrama
|
4
4
|
# This is passed to a template
|
@@ -89,6 +89,16 @@ module Lrama
|
|
89
89
|
return a
|
90
90
|
end
|
91
91
|
|
92
|
+
def yytranslate_inverted
|
93
|
+
a = Array.new(@states.symbols.count, @states.undef_symbol.token_id)
|
94
|
+
|
95
|
+
@states.terms.each do |term|
|
96
|
+
a[term.number] = term.token_id
|
97
|
+
end
|
98
|
+
|
99
|
+
return a
|
100
|
+
end
|
101
|
+
|
92
102
|
# Mapping from rule number to line number of the rule is defined.
|
93
103
|
# Dummy rule is appended as the first element whose value is 0
|
94
104
|
# because 0 means error in yydefact.
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module Lrama
|
4
|
+
class Grammar
|
5
|
+
class Code < Struct.new(:type, :token_code, keyword_init: true)
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators "token_code", :s_value, :line, :column, :references
|
9
|
+
|
10
|
+
# $$, $n, @$, @n is translated to C code
|
11
|
+
def translated_code
|
12
|
+
case type
|
13
|
+
when :user_code
|
14
|
+
translated_user_code
|
15
|
+
when :initial_action
|
16
|
+
translated_initial_action_code
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# * ($1) error
|
21
|
+
# * ($$) *yyvaluep
|
22
|
+
# * (@1) error
|
23
|
+
# * (@$) *yylocationp
|
24
|
+
def translated_printer_code(tag)
|
25
|
+
t_code = s_value.dup
|
26
|
+
|
27
|
+
references.reverse.each do |ref|
|
28
|
+
first_column = ref.first_column
|
29
|
+
last_column = ref.last_column
|
30
|
+
|
31
|
+
case
|
32
|
+
when ref.value == "$" && ref.type == :dollar # $$
|
33
|
+
# Omit "<>"
|
34
|
+
member = tag.s_value[1..-2]
|
35
|
+
str = "((*yyvaluep).#{member})"
|
36
|
+
when ref.value == "$" && ref.type == :at # @$
|
37
|
+
str = "(*yylocationp)"
|
38
|
+
when ref.type == :dollar # $n
|
39
|
+
raise "$#{ref.value} can not be used in %printer."
|
40
|
+
when ref.type == :at # @n
|
41
|
+
raise "@#{ref.value} can not be used in %printer."
|
42
|
+
else
|
43
|
+
raise "Unexpected. #{self}, #{ref}"
|
44
|
+
end
|
45
|
+
|
46
|
+
t_code[first_column..last_column] = str
|
47
|
+
end
|
48
|
+
|
49
|
+
return t_code
|
50
|
+
end
|
51
|
+
alias :translated_error_token_code :translated_printer_code
|
52
|
+
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# * ($1) yyvsp[i]
|
57
|
+
# * ($$) yyval
|
58
|
+
# * (@1) yylsp[i]
|
59
|
+
# * (@$) yyloc
|
60
|
+
def translated_user_code
|
61
|
+
t_code = s_value.dup
|
62
|
+
|
63
|
+
references.reverse.each do |ref|
|
64
|
+
first_column = ref.first_column
|
65
|
+
last_column = ref.last_column
|
66
|
+
|
67
|
+
case
|
68
|
+
when ref.value == "$" && ref.type == :dollar # $$
|
69
|
+
# Omit "<>"
|
70
|
+
member = ref.tag.s_value[1..-2]
|
71
|
+
str = "(yyval.#{member})"
|
72
|
+
when ref.value == "$" && ref.type == :at # @$
|
73
|
+
str = "(yyloc)"
|
74
|
+
when ref.type == :dollar # $n
|
75
|
+
i = -ref.position_in_rhs + ref.value
|
76
|
+
# Omit "<>"
|
77
|
+
member = ref.tag.s_value[1..-2]
|
78
|
+
str = "(yyvsp[#{i}].#{member})"
|
79
|
+
when ref.type == :at # @n
|
80
|
+
i = -ref.position_in_rhs + ref.value
|
81
|
+
str = "(yylsp[#{i}])"
|
82
|
+
else
|
83
|
+
raise "Unexpected. #{self}, #{ref}"
|
84
|
+
end
|
85
|
+
|
86
|
+
t_code[first_column..last_column] = str
|
87
|
+
end
|
88
|
+
|
89
|
+
return t_code
|
90
|
+
end
|
91
|
+
|
92
|
+
# * ($1) error
|
93
|
+
# * ($$) yylval
|
94
|
+
# * (@1) error
|
95
|
+
# * (@$) yylloc
|
96
|
+
def translated_initial_action_code
|
97
|
+
t_code = s_value.dup
|
98
|
+
|
99
|
+
references.reverse.each do |ref|
|
100
|
+
first_column = ref.first_column
|
101
|
+
last_column = ref.last_column
|
102
|
+
|
103
|
+
case
|
104
|
+
when ref.value == "$" && ref.type == :dollar # $$
|
105
|
+
str = "yylval"
|
106
|
+
when ref.value == "$" && ref.type == :at # @$
|
107
|
+
str = "yylloc"
|
108
|
+
when ref.type == :dollar # $n
|
109
|
+
raise "$#{ref.value} can not be used in initial_action."
|
110
|
+
when ref.type == :at # @n
|
111
|
+
raise "@#{ref.value} can not be used in initial_action."
|
112
|
+
else
|
113
|
+
raise "Unexpected. #{self}, #{ref}"
|
114
|
+
end
|
115
|
+
|
116
|
+
t_code[first_column..last_column] = str
|
117
|
+
end
|
118
|
+
|
119
|
+
return t_code
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# type: :dollar or :at
|
2
|
+
# ex_tag: "$<tag>1" (Optional)
|
3
|
+
|
4
|
+
module Lrama
|
5
|
+
class Grammar
|
6
|
+
class Reference < Struct.new(:type, :value, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true)
|
7
|
+
def tag
|
8
|
+
if ex_tag
|
9
|
+
ex_tag
|
10
|
+
else
|
11
|
+
# FIXME: Remove this class check
|
12
|
+
if referring_symbol.is_a?(Symbol)
|
13
|
+
referring_symbol.tag
|
14
|
+
else
|
15
|
+
# Lrama::Lexer::Token (User_code) case
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Lrama
|
2
|
+
class Grammar
|
3
|
+
class Rule < Struct.new(:id, :lhs, :rhs, :code, :nullable, :precedence_sym, :lineno, keyword_init: true)
|
4
|
+
# TODO: Change this to display_name
|
5
|
+
def to_s
|
6
|
+
l = lhs.id.s_value
|
7
|
+
r = rhs.empty? ? "ε" : rhs.map {|r| r.id.s_value }.join(", ")
|
8
|
+
|
9
|
+
"#{l} -> #{r}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Used by #user_actions
|
13
|
+
def as_comment
|
14
|
+
l = lhs.id.s_value
|
15
|
+
r = rhs.empty? ? "%empty" : rhs.map(&:display_name).join(" ")
|
16
|
+
|
17
|
+
"#{l}: #{r}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def precedence
|
21
|
+
precedence_sym&.precedence
|
22
|
+
end
|
23
|
+
|
24
|
+
def initial_rule?
|
25
|
+
id == 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def translated_code
|
29
|
+
code&.translated_code
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# Symbol is both of nterm and term
|
2
|
+
# `number` is both for nterm and term
|
3
|
+
# `token_id` is tokentype for term, internal sequence number for nterm
|
4
|
+
#
|
5
|
+
# TODO: Add validation for ASCII code range for Token::Char
|
6
|
+
|
7
|
+
module Lrama
|
8
|
+
class Grammar
|
9
|
+
class Symbol < Struct.new(:id, :alias_name, :number, :tag, :term, :token_id, :nullable, :precedence, :printer, :error_token, keyword_init: true)
|
10
|
+
attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol
|
11
|
+
|
12
|
+
def term?
|
13
|
+
term
|
14
|
+
end
|
15
|
+
|
16
|
+
def nterm?
|
17
|
+
!term
|
18
|
+
end
|
19
|
+
|
20
|
+
def eof_symbol?
|
21
|
+
!!@eof_symbol
|
22
|
+
end
|
23
|
+
|
24
|
+
def error_symbol?
|
25
|
+
!!@error_symbol
|
26
|
+
end
|
27
|
+
|
28
|
+
def undef_symbol?
|
29
|
+
!!@undef_symbol
|
30
|
+
end
|
31
|
+
|
32
|
+
def accept_symbol?
|
33
|
+
!!@accept_symbol
|
34
|
+
end
|
35
|
+
|
36
|
+
def display_name
|
37
|
+
if alias_name
|
38
|
+
alias_name
|
39
|
+
else
|
40
|
+
id.s_value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# name for yysymbol_kind_t
|
45
|
+
#
|
46
|
+
# See: b4_symbol_kind_base
|
47
|
+
def enum_name
|
48
|
+
case
|
49
|
+
when accept_symbol?
|
50
|
+
name = "YYACCEPT"
|
51
|
+
when eof_symbol?
|
52
|
+
name = "YYEOF"
|
53
|
+
when term? && id.type == Token::Char
|
54
|
+
if alias_name
|
55
|
+
name = number.to_s + alias_name
|
56
|
+
else
|
57
|
+
name = number.to_s + id.s_value
|
58
|
+
end
|
59
|
+
when term? && id.type == Token::Ident
|
60
|
+
name = id.s_value
|
61
|
+
when nterm? && (id.s_value.include?("$") || id.s_value.include?("@"))
|
62
|
+
name = number.to_s + id.s_value
|
63
|
+
when nterm?
|
64
|
+
name = id.s_value
|
65
|
+
else
|
66
|
+
raise "Unexpected #{self}"
|
67
|
+
end
|
68
|
+
|
69
|
+
"YYSYMBOL_" + name.gsub(/[^a-zA-Z_0-9]+/, "_")
|
70
|
+
end
|
71
|
+
|
72
|
+
# comment for yysymbol_kind_t
|
73
|
+
def comment
|
74
|
+
case
|
75
|
+
when accept_symbol?
|
76
|
+
# YYSYMBOL_YYACCEPT
|
77
|
+
id.s_value
|
78
|
+
when eof_symbol?
|
79
|
+
# YYEOF
|
80
|
+
alias_name
|
81
|
+
when (term? && 0 < token_id && token_id < 128)
|
82
|
+
# YYSYMBOL_3_backslash_, YYSYMBOL_14_
|
83
|
+
alias_name || id.s_value
|
84
|
+
when id.s_value.include?("$") || id.s_value.include?("@")
|
85
|
+
# YYSYMBOL_21_1
|
86
|
+
id.s_value
|
87
|
+
else
|
88
|
+
# YYSYMBOL_keyword_class, YYSYMBOL_strings_1
|
89
|
+
alias_name || id.s_value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|