lrama 0.5.5 → 0.5.6
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 +5 -5
- data/exe/lrama +1 -1
- data/lib/lrama/command.rb +15 -137
- data/lib/lrama/lexer/token.rb +7 -1
- data/lib/lrama/lexer.rb +15 -1
- data/lib/lrama/option_parser.rb +124 -0
- data/lib/lrama/options.rb +23 -0
- data/lib/lrama/version.rb +1 -1
- data/lib/lrama.rb +2 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e54c51af6f1d3632293cbd7f68762bf7cff63758d3ce633113805a629b92072b
|
4
|
+
data.tar.gz: 5d053543f0e00c9fb20c40f5ca8236e499292f35fa8cf6fb8e85cac33b930814
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87bafe9650720b154855e055e53d700cfba67d31489dbc855c716bc150dff35e92d0fc974c14cb81a07ae68febbd69118c1720a628e2819fec1ebfa304acad55
|
7
|
+
data.tar.gz: 19b0c51748cef053d205bbf13e8ff238bda2fdbb101d304f6bfe9633b4f88fe2c4a1f452627528fd2c9e78bc97955a2a5f7543212aa581c3a9f7ae96dd3d70f8
|
data/.github/workflows/test.yaml
CHANGED
@@ -15,7 +15,7 @@ jobs:
|
|
15
15
|
matrix:
|
16
16
|
ruby: ['head', '3.2', '3.1', '3.0', '2.7', '2.6', '2.5']
|
17
17
|
steps:
|
18
|
-
- uses: actions/checkout@
|
18
|
+
- uses: actions/checkout@v4
|
19
19
|
- uses: ruby/setup-ruby@v1
|
20
20
|
with:
|
21
21
|
ruby-version: ${{ matrix.ruby }}
|
@@ -29,7 +29,7 @@ jobs:
|
|
29
29
|
matrix:
|
30
30
|
ruby: ['head']
|
31
31
|
steps:
|
32
|
-
- uses: actions/checkout@
|
32
|
+
- uses: actions/checkout@v4
|
33
33
|
- uses: ruby/setup-ruby@v1
|
34
34
|
with:
|
35
35
|
ruby-version: ${{ matrix.ruby }}
|
@@ -39,7 +39,7 @@ jobs:
|
|
39
39
|
check-misc:
|
40
40
|
runs-on: ubuntu-20.04
|
41
41
|
steps:
|
42
|
-
- uses: actions/checkout@
|
42
|
+
- uses: actions/checkout@v4
|
43
43
|
# Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
|
44
44
|
- name: Check for trailing spaces
|
45
45
|
run: |
|
@@ -52,7 +52,7 @@ jobs:
|
|
52
52
|
matrix:
|
53
53
|
ruby: ['head']
|
54
54
|
steps:
|
55
|
-
- uses: actions/checkout@
|
55
|
+
- uses: actions/checkout@v4
|
56
56
|
- uses: ruby/setup-ruby@v1
|
57
57
|
with:
|
58
58
|
ruby-version: ${{ matrix.ruby }}
|
@@ -71,7 +71,7 @@ jobs:
|
|
71
71
|
run:
|
72
72
|
working-directory: ../ruby/build
|
73
73
|
steps:
|
74
|
-
- uses: actions/checkout@
|
74
|
+
- uses: actions/checkout@v4
|
75
75
|
- uses: ruby/setup-ruby@v1
|
76
76
|
with:
|
77
77
|
ruby-version: ${{ matrix.baseruby }}
|
data/exe/lrama
CHANGED
data/lib/lrama/command.rb
CHANGED
@@ -1,53 +1,34 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
|
3
1
|
module Lrama
|
4
2
|
class Command
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
@skeleton = "bison/yacc.c"
|
9
|
-
@header = false
|
10
|
-
@header_file = nil
|
11
|
-
@report = []
|
12
|
-
@report_file = nil
|
13
|
-
@outfile = "y.tab.c"
|
14
|
-
@trace = []
|
15
|
-
@error_recovery = false
|
16
|
-
@grammar_file = nil
|
17
|
-
@report_file = nil
|
18
|
-
@trace_opts = nil
|
19
|
-
@report_opts = nil
|
20
|
-
end
|
3
|
+
def run(argv)
|
4
|
+
options = OptionParser.new.parse(argv)
|
21
5
|
|
22
|
-
|
23
|
-
parse_option
|
24
|
-
|
25
|
-
Report::Duration.enable if @trace_opts[:time]
|
6
|
+
Report::Duration.enable if options.trace_opts[:time]
|
26
7
|
|
27
8
|
warning = Lrama::Warning.new
|
28
|
-
grammar = Lrama::Parser.new(
|
29
|
-
|
30
|
-
states = Lrama::States.new(grammar, warning, trace_state: (
|
9
|
+
grammar = Lrama::Parser.new(options.y.read).parse
|
10
|
+
options.y.close if options.y != STDIN
|
11
|
+
states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
|
31
12
|
states.compute
|
32
13
|
context = Lrama::Context.new(states)
|
33
14
|
|
34
|
-
if
|
15
|
+
if options.report_file
|
35
16
|
reporter = Lrama::StatesReporter.new(states)
|
36
|
-
File.open(
|
37
|
-
reporter.report(f,
|
17
|
+
File.open(options.report_file, "w+") do |f|
|
18
|
+
reporter.report(f, **options.report_opts)
|
38
19
|
end
|
39
20
|
end
|
40
21
|
|
41
|
-
File.open(
|
22
|
+
File.open(options.outfile, "w+") do |f|
|
42
23
|
Lrama::Output.new(
|
43
24
|
out: f,
|
44
|
-
output_file_path:
|
45
|
-
template_name:
|
46
|
-
grammar_file_path:
|
47
|
-
header_file_path:
|
25
|
+
output_file_path: options.outfile,
|
26
|
+
template_name: options.skeleton,
|
27
|
+
grammar_file_path: options.grammar_file,
|
28
|
+
header_file_path: options.header_file,
|
48
29
|
context: context,
|
49
30
|
grammar: grammar,
|
50
|
-
error_recovery:
|
31
|
+
error_recovery: options.error_recovery,
|
51
32
|
).render
|
52
33
|
end
|
53
34
|
|
@@ -55,108 +36,5 @@ module Lrama
|
|
55
36
|
exit 1
|
56
37
|
end
|
57
38
|
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def validate_report(report)
|
62
|
-
bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
|
63
|
-
others = %w[verbose]
|
64
|
-
list = bison_list + others
|
65
|
-
not_supported = %w[cex none]
|
66
|
-
h = { grammar: true }
|
67
|
-
|
68
|
-
report.each do |r|
|
69
|
-
if list.include?(r) && !not_supported.include?(r)
|
70
|
-
h[r.to_sym] = true
|
71
|
-
else
|
72
|
-
raise "Invalid report option \"#{r}\"."
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
if h[:all]
|
77
|
-
(bison_list - not_supported).each do |r|
|
78
|
-
h[r.to_sym] = true
|
79
|
-
end
|
80
|
-
|
81
|
-
h.delete(:all)
|
82
|
-
end
|
83
|
-
|
84
|
-
return h
|
85
|
-
end
|
86
|
-
|
87
|
-
def validate_trace(trace)
|
88
|
-
list = %w[
|
89
|
-
none locations scan parse automaton bitsets
|
90
|
-
closure grammar resource sets muscles tools
|
91
|
-
m4-early m4 skeleton time ielr cex all
|
92
|
-
]
|
93
|
-
h = {}
|
94
|
-
|
95
|
-
trace.each do |t|
|
96
|
-
if list.include?(t)
|
97
|
-
h[t.to_sym] = true
|
98
|
-
else
|
99
|
-
raise "Invalid trace option \"#{t}\"."
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
return h
|
104
|
-
end
|
105
|
-
|
106
|
-
def parse_option
|
107
|
-
opt = OptionParser.new
|
108
|
-
|
109
|
-
# opt.on('-h') {|v| p v }
|
110
|
-
opt.on('-V', '--version') {|v| puts "lrama #{Lrama::VERSION}"; exit 0 }
|
111
|
-
|
112
|
-
# Tuning the Parser
|
113
|
-
opt.on('-S', '--skeleton=FILE') {|v| @skeleton = v }
|
114
|
-
opt.on('-t') { } # Do nothing
|
115
|
-
|
116
|
-
# Output Files:
|
117
|
-
opt.on('-h', '--header=[FILE]') {|v| @header = true; @header_file = v }
|
118
|
-
opt.on('-d') { @header = true }
|
119
|
-
opt.on('-r', '--report=THINGS', Array) {|v| @report = v }
|
120
|
-
opt.on('--report-file=FILE') {|v| @report_file = v }
|
121
|
-
opt.on('-v') { } # Do nothing
|
122
|
-
opt.on('-o', '--output=FILE') {|v| @outfile = v }
|
123
|
-
|
124
|
-
# Hidden
|
125
|
-
opt.on('--trace=THINGS', Array) {|v| @trace = v }
|
126
|
-
|
127
|
-
# Error Recovery
|
128
|
-
opt.on('-e') {|v| @error_recovery = true }
|
129
|
-
|
130
|
-
opt.parse!(@argv)
|
131
|
-
|
132
|
-
@trace_opts = validate_trace(@trace)
|
133
|
-
@report_opts = validate_report(@report)
|
134
|
-
|
135
|
-
@grammar_file = @argv.shift
|
136
|
-
|
137
|
-
if !@grammar_file
|
138
|
-
abort "File should be specified\n"
|
139
|
-
end
|
140
|
-
|
141
|
-
if @grammar_file == '-'
|
142
|
-
@grammar_file = @argv.shift or abort "File name for STDIN should be specified\n"
|
143
|
-
@y = STDIN
|
144
|
-
else
|
145
|
-
@y = File.open(@grammar_file, 'r')
|
146
|
-
end
|
147
|
-
|
148
|
-
if !@report.empty? && @report_file.nil? && @grammar_file
|
149
|
-
@report_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".output"
|
150
|
-
end
|
151
|
-
|
152
|
-
if !@header_file && @header
|
153
|
-
case
|
154
|
-
when @outfile
|
155
|
-
@header_file = File.dirname(@outfile) + "/" + File.basename(@outfile, ".*") + ".h"
|
156
|
-
when @grammar_file
|
157
|
-
@header_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".h"
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
39
|
end
|
162
40
|
end
|
data/lib/lrama/lexer/token.rb
CHANGED
@@ -28,7 +28,13 @@ module Lrama
|
|
28
28
|
if lhs.referred_by?(ref_name)
|
29
29
|
'$'
|
30
30
|
else
|
31
|
-
rhs.find_index {|token| token.referred_by?(ref_name) }
|
31
|
+
index = rhs.find_index {|token| token.referred_by?(ref_name) }
|
32
|
+
|
33
|
+
if index
|
34
|
+
index + 1
|
35
|
+
else
|
36
|
+
raise "'#{ref_name}' is invalid name."
|
37
|
+
end
|
32
38
|
end
|
33
39
|
[ref[0], value, ref[2], ref[3], ref[4]]
|
34
40
|
else
|
data/lib/lrama/lexer.rb
CHANGED
@@ -213,19 +213,33 @@ module Lrama
|
|
213
213
|
string, line = lex_string(ss, "'", line, lines)
|
214
214
|
str << string
|
215
215
|
next
|
216
|
+
|
217
|
+
# $ references
|
218
|
+
# It need to wrap an identifier with brackets to use ".-" for identifiers
|
216
219
|
when ss.scan(/\$(<[a-zA-Z0-9_]+>)?\$/) # $$, $<long>$
|
217
220
|
tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
|
218
221
|
references << [:dollar, "$", tag, str.length, str.length + ss[0].length - 1]
|
219
222
|
when ss.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $<long>1
|
220
223
|
tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
|
221
224
|
references << [:dollar, Integer(ss[2]), tag, str.length, str.length + ss[0].length - 1]
|
222
|
-
when ss.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_
|
225
|
+
when ss.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_][a-zA-Z0-9_]*)/) # $foo, $expr, $<long>program (named reference without brackets)
|
226
|
+
tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
|
227
|
+
references << [:dollar, ss[2], tag, str.length, str.length + ss[0].length - 1]
|
228
|
+
when ss.scan(/\$(<[a-zA-Z0-9_]+>)?\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # $expr.right, $expr-right, $<long>program (named reference with brackets)
|
223
229
|
tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
|
224
230
|
references << [:dollar, ss[2], tag, str.length, str.length + ss[0].length - 1]
|
231
|
+
|
232
|
+
# @ references
|
233
|
+
# It need to wrap an identifier with brackets to use ".-" for identifiers
|
225
234
|
when ss.scan(/@\$/) # @$
|
226
235
|
references << [:at, "$", nil, str.length, str.length + ss[0].length - 1]
|
227
236
|
when ss.scan(/@(\d+)/) # @1
|
228
237
|
references << [:at, Integer(ss[1]), nil, str.length, str.length + ss[0].length - 1]
|
238
|
+
when ss.scan(/@([a-zA-Z][a-zA-Z0-9_]*)/) # @foo, @expr (named reference without brackets)
|
239
|
+
references << [:at, ss[1], nil, str.length, str.length + ss[0].length - 1]
|
240
|
+
when ss.scan(/@\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # @expr.right, @expr-right (named reference with brackets)
|
241
|
+
references << [:at, ss[1], nil, str.length, str.length + ss[0].length - 1]
|
242
|
+
|
229
243
|
when ss.scan(/{/)
|
230
244
|
brace_count += 1
|
231
245
|
when ss.scan(/}/)
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Lrama
|
4
|
+
# Handle option parsing for the command line interface.
|
5
|
+
class OptionParser
|
6
|
+
def initialize
|
7
|
+
@options = Options.new
|
8
|
+
@trace = []
|
9
|
+
@report = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse(argv)
|
13
|
+
parse_by_option_parser(argv)
|
14
|
+
|
15
|
+
@options.trace_opts = validate_trace(@trace)
|
16
|
+
@options.report_opts = validate_report(@report)
|
17
|
+
@options.grammar_file = argv.shift
|
18
|
+
|
19
|
+
if !@options.grammar_file
|
20
|
+
abort "File should be specified\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
if @options.grammar_file == '-'
|
24
|
+
@options.grammar_file = argv.shift or abort "File name for STDIN should be specified\n"
|
25
|
+
else
|
26
|
+
@options.y = File.open(@options.grammar_file, 'r')
|
27
|
+
end
|
28
|
+
|
29
|
+
if !@report.empty? && @options.report_file.nil? && @options.grammar_file
|
30
|
+
@options.report_file = File.dirname(@options.grammar_file) + "/" + File.basename(@options.grammar_file, ".*") + ".output"
|
31
|
+
end
|
32
|
+
|
33
|
+
if !@options.header_file && @options.header
|
34
|
+
case
|
35
|
+
when @options.outfile
|
36
|
+
@options.header_file = File.dirname(@options.outfile) + "/" + File.basename(@options.outfile, ".*") + ".h"
|
37
|
+
when @options.grammar_file
|
38
|
+
@options.header_file = File.dirname(@options.grammar_file) + "/" + File.basename(@options.grammar_file, ".*") + ".h"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@options
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def parse_by_option_parser(argv)
|
48
|
+
::OptionParser.new do |o|
|
49
|
+
o.banner = <<~BANNER
|
50
|
+
Lrama is LALR (1) parser generator written by Ruby.
|
51
|
+
|
52
|
+
Usage: lrama [options] FILE
|
53
|
+
BANNER
|
54
|
+
o.separator ''
|
55
|
+
o.separator 'Tuning the Parser:'
|
56
|
+
o.on('-S', '--skeleton=FILE', 'specify the skeleton to use') {|v| @options.skeleton = v }
|
57
|
+
o.on('-t', 'reserved, do nothing') { }
|
58
|
+
o.separator ''
|
59
|
+
o.separator 'Output:'
|
60
|
+
o.on('-h', '--header=[FILE]', 'also produce a header file named FILE') {|v| @options.header = true; @options.header_file = v }
|
61
|
+
o.on('-d', 'also produce a header file') { @options.header = true }
|
62
|
+
o.on('-r', '--report=THINGS', Array, 'also produce details on the automaton') {|v| @report = v }
|
63
|
+
o.on('--report-file=FILE', 'also produce details on the automaton output to a file named FILE') {|v| @options.report_file = v }
|
64
|
+
o.on('-o', '--output=FILE', 'leave output to FILE') {|v| @options.outfile = v }
|
65
|
+
o.on('--trace=THINGS', Array, 'also output trace logs at runtime') {|v| @trace = v }
|
66
|
+
o.on('-v', 'reserved, do nothing') { }
|
67
|
+
o.separator ''
|
68
|
+
o.separator 'Error Recovery:'
|
69
|
+
o.on('-e', 'enable error recovery') {|v| @options.error_recovery = true }
|
70
|
+
o.separator ''
|
71
|
+
o.separator 'Other options:'
|
72
|
+
o.on('-V', '--version', "output version information and exit") {|v| puts "lrama #{Lrama::VERSION}"; exit 0 }
|
73
|
+
o.on('--help', "display this help and exit") {|v| puts o; exit 0 }
|
74
|
+
o.separator ''
|
75
|
+
o.parse!(argv)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def validate_report(report)
|
80
|
+
bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
|
81
|
+
others = %w[verbose]
|
82
|
+
list = bison_list + others
|
83
|
+
not_supported = %w[cex none]
|
84
|
+
h = { grammar: true }
|
85
|
+
|
86
|
+
report.each do |r|
|
87
|
+
if list.include?(r) && !not_supported.include?(r)
|
88
|
+
h[r.to_sym] = true
|
89
|
+
else
|
90
|
+
raise "Invalid report option \"#{r}\"."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
if h[:all]
|
95
|
+
(bison_list - not_supported).each do |r|
|
96
|
+
h[r.to_sym] = true
|
97
|
+
end
|
98
|
+
|
99
|
+
h.delete(:all)
|
100
|
+
end
|
101
|
+
|
102
|
+
return h
|
103
|
+
end
|
104
|
+
|
105
|
+
def validate_trace(trace)
|
106
|
+
list = %w[
|
107
|
+
none locations scan parse automaton bitsets
|
108
|
+
closure grammar resource sets muscles tools
|
109
|
+
m4-early m4 skeleton time ielr cex all
|
110
|
+
]
|
111
|
+
h = {}
|
112
|
+
|
113
|
+
trace.each do |t|
|
114
|
+
if list.include?(t)
|
115
|
+
h[t.to_sym] = true
|
116
|
+
else
|
117
|
+
raise "Invalid trace option \"#{t}\"."
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
return h
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Lrama
|
2
|
+
# Command line options.
|
3
|
+
class Options
|
4
|
+
attr_accessor :skeleton, :header, :header_file,
|
5
|
+
:report_file, :outfile,
|
6
|
+
:error_recovery, :grammar_file,
|
7
|
+
:report_file, :trace_opts, :report_opts, :y
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@skeleton = "bison/yacc.c"
|
11
|
+
@header = false
|
12
|
+
@header_file = nil
|
13
|
+
@report_file = nil
|
14
|
+
@outfile = "y.tab.c"
|
15
|
+
@error_recovery = false
|
16
|
+
@grammar_file = nil
|
17
|
+
@report_file = nil
|
18
|
+
@trace_opts = nil
|
19
|
+
@report_opts = nil
|
20
|
+
@y = STDIN
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/lrama/version.rb
CHANGED
data/lib/lrama.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lrama
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuichiro Kaneko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: LALR (1) parser generator written by Ruby
|
14
14
|
email:
|
@@ -54,6 +54,8 @@ files:
|
|
54
54
|
- lib/lrama/lexer.rb
|
55
55
|
- lib/lrama/lexer/token.rb
|
56
56
|
- lib/lrama/lexer/token/type.rb
|
57
|
+
- lib/lrama/option_parser.rb
|
58
|
+
- lib/lrama/options.rb
|
57
59
|
- lib/lrama/output.rb
|
58
60
|
- lib/lrama/parser.rb
|
59
61
|
- lib/lrama/parser/token_scanner.rb
|
@@ -103,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
105
|
- !ruby/object:Gem::Version
|
104
106
|
version: '0'
|
105
107
|
requirements: []
|
106
|
-
rubygems_version: 3.
|
108
|
+
rubygems_version: 3.5.0.dev
|
107
109
|
signing_key:
|
108
110
|
specification_version: 4
|
109
111
|
summary: LALR (1) parser generator written by Ruby
|