lrama 0.1.0 → 0.2.0
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/README.md +13 -2
- data/doc/TODO.md +4 -0
- data/lib/lrama/bitmap.rb +29 -0
- data/lib/lrama/command.rb +19 -4
- data/lib/lrama/context.rb +7 -6
- data/lib/lrama/digraph.rb +53 -0
- data/lib/lrama/output.rb +95 -4
- data/lib/lrama/report.rb +12 -0
- data/lib/lrama/states.rb +99 -391
- data/lib/lrama/states_reporter.rb +310 -0
- data/lib/lrama/version.rb +1 -1
- data/lib/lrama/warning.rb +25 -0
- data/lib/lrama.rb +4 -0
- data/sample/parse.y +58 -0
- data/template/bison/yacc.c +11 -18
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ba620aa365e3ce11d757da653bd6677ca8bec28ca1b6a5df745d37da6784f59
|
4
|
+
data.tar.gz: 2ab03daa03cbb925826f2ca8053dcb04d9648c5c31bd85b1e6fbfe6f9b4cec70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05c3e37259997144afe3191d573416c25746c80a7ef0ebc12411f1c126cedf7a8cb8113981c64f1c48e421f517790aa31a14f7ec35ded0f4a7fd4ad83a065e23
|
7
|
+
data.tar.gz: 6493c2a94e4681f65f76428c4327dc26be9c14643aadc371400db7def3eb1566f7b4bec091ca719a88c6949d3f46bec0fad87ec73298c69da4906a3c40b28079
|
data/README.md
CHANGED
@@ -14,6 +14,12 @@ Lrama is LALR (1) parser generator written by Ruby. The first goal of this proje
|
|
14
14
|
|
15
15
|
## Installation
|
16
16
|
|
17
|
+
```shell
|
18
|
+
$ gem install lrama
|
19
|
+
```
|
20
|
+
|
21
|
+
From source codes,
|
22
|
+
|
17
23
|
```shell
|
18
24
|
$ bundle exec rake install
|
19
25
|
$ lrama --version
|
@@ -23,10 +29,15 @@ $ lrama --version
|
|
23
29
|
## Usage
|
24
30
|
|
25
31
|
```shell
|
26
|
-
# "y.tab.c"
|
27
|
-
$ lrama parse.y
|
32
|
+
# "y.tab.c" and "y.tab.h" are generated
|
33
|
+
$ lrama -d sample/parse.y
|
28
34
|
```
|
29
35
|
|
36
|
+
## Build Ruby
|
37
|
+
|
38
|
+
1. Install Lrama
|
39
|
+
2. Run `make YACC=lrama`
|
40
|
+
|
30
41
|
## License
|
31
42
|
|
32
43
|
See LEGAL.md file.
|
data/doc/TODO.md
CHANGED
@@ -20,6 +20,9 @@
|
|
20
20
|
* [x] Precedence support
|
21
21
|
* [x] Conflict check
|
22
22
|
* [x] Algorithm Digraph
|
23
|
+
* [ ] Conflict resolution
|
24
|
+
* [x] Do not generate default action if states have conflicts
|
25
|
+
* [ ] Fix number of s/r conflicts of basic.y. See basic.output file generated by Bison.
|
23
26
|
* Rendering
|
24
27
|
* [x] Table compaction
|
25
28
|
* [x] -d option
|
@@ -41,6 +44,7 @@
|
|
41
44
|
* [x] Write down something about licenses
|
42
45
|
* Reporting
|
43
46
|
* [ ] Bison style
|
47
|
+
* [ ] Wrap not selected reduce with "[]". See basic.output file generated by Bison.
|
44
48
|
* Error Tolerance
|
45
49
|
* [x] Subset of Corchuelo et al.
|
46
50
|
* Lex state
|
data/lib/lrama/bitmap.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Lrama
|
2
|
+
module Bitmap
|
3
|
+
def self.from_array(ary)
|
4
|
+
bit = 0
|
5
|
+
|
6
|
+
ary.each do |int|
|
7
|
+
bit |= (1 << int)
|
8
|
+
end
|
9
|
+
|
10
|
+
bit
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.to_array(int)
|
14
|
+
a = []
|
15
|
+
i = 0
|
16
|
+
|
17
|
+
while int > 0 do
|
18
|
+
if int & 1 == 1
|
19
|
+
a << i
|
20
|
+
end
|
21
|
+
|
22
|
+
i += 1
|
23
|
+
int >>= 1
|
24
|
+
end
|
25
|
+
|
26
|
+
a
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/lrama/command.rb
CHANGED
@@ -63,9 +63,10 @@ module Lrama
|
|
63
63
|
|
64
64
|
Report::Duration.enable if trace_opts[:time]
|
65
65
|
|
66
|
+
warning = Lrama::Warning.new
|
66
67
|
y = File.read(grammar_file)
|
67
68
|
grammar = Lrama::Parser.new(y).parse
|
68
|
-
states = Lrama::States.new(grammar, trace_state: (trace_opts[:automaton] || trace_opts[:closure]))
|
69
|
+
states = Lrama::States.new(grammar, warning, trace_state: (trace_opts[:automaton] || trace_opts[:closure]))
|
69
70
|
states.compute
|
70
71
|
context = Lrama::Context.new(states)
|
71
72
|
|
@@ -87,14 +88,20 @@ module Lrama
|
|
87
88
|
grammar: grammar,
|
88
89
|
).render
|
89
90
|
end
|
91
|
+
|
92
|
+
if warning.has_error?
|
93
|
+
exit 1
|
94
|
+
end
|
90
95
|
end
|
91
96
|
|
92
97
|
private
|
93
98
|
|
94
99
|
def validate_report(report)
|
95
|
-
|
96
|
-
|
97
|
-
|
100
|
+
bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
|
101
|
+
others = %w[verbose]
|
102
|
+
list = bison_list + others
|
103
|
+
not_supported = %w[counterexamples cex none]
|
104
|
+
h = { grammar: true }
|
98
105
|
|
99
106
|
report.each do |r|
|
100
107
|
if list.include?(r) && !not_supported.include?(r)
|
@@ -104,6 +111,14 @@ module Lrama
|
|
104
111
|
end
|
105
112
|
end
|
106
113
|
|
114
|
+
if h[:all]
|
115
|
+
(bison_list - not_supported).each do |r|
|
116
|
+
h[r.to_sym] = true
|
117
|
+
end
|
118
|
+
|
119
|
+
h.delete(:all)
|
120
|
+
end
|
121
|
+
|
107
122
|
return h
|
108
123
|
end
|
109
124
|
|
data/lib/lrama/context.rb
CHANGED
@@ -18,7 +18,7 @@ module Lrama
|
|
18
18
|
# Array of array
|
19
19
|
@_actions = []
|
20
20
|
|
21
|
-
|
21
|
+
compute_tables
|
22
22
|
end
|
23
23
|
|
24
24
|
# enum yytokentype
|
@@ -187,11 +187,11 @@ module Lrama
|
|
187
187
|
# * yypact_ninf
|
188
188
|
# * yytable_ninf
|
189
189
|
def compute_tables
|
190
|
-
compute_yydefact
|
191
|
-
compute_yydefgoto
|
192
|
-
sort_actions
|
190
|
+
report_duration(:compute_yydefact) { compute_yydefact }
|
191
|
+
report_duration(:compute_yydefgoto) { compute_yydefgoto }
|
192
|
+
report_duration(:sort_actions) { sort_actions }
|
193
193
|
# debug_sorted_actions
|
194
|
-
compute_packed_table
|
194
|
+
report_duration(:compute_packed_table) { compute_packed_table }
|
195
195
|
end
|
196
196
|
|
197
197
|
def vectors_count
|
@@ -438,10 +438,11 @@ module Lrama
|
|
438
438
|
if @table[loc]
|
439
439
|
# If the cell of table is set, can not use the cell.
|
440
440
|
ok = false
|
441
|
+
break
|
441
442
|
end
|
442
443
|
end
|
443
444
|
|
444
|
-
if userd_res[res]
|
445
|
+
if ok && userd_res[res]
|
445
446
|
ok = false
|
446
447
|
end
|
447
448
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Lrama
|
2
|
+
# Algorithm Digraph of https://dl.acm.org/doi/pdf/10.1145/69622.357187 (P. 625)
|
3
|
+
class Digraph
|
4
|
+
def initialize(sets, relation, base_function)
|
5
|
+
# X in the paper
|
6
|
+
@sets = sets
|
7
|
+
# R in the paper
|
8
|
+
@relation = relation
|
9
|
+
# F' in the paper
|
10
|
+
@base_function = base_function
|
11
|
+
# S in the paper
|
12
|
+
@stack = []
|
13
|
+
# N in the paper
|
14
|
+
@h = Hash.new(0)
|
15
|
+
# F in the paper
|
16
|
+
@result = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def compute
|
20
|
+
@sets.each do |x|
|
21
|
+
next if @h[x] != 0
|
22
|
+
traverse(x)
|
23
|
+
end
|
24
|
+
|
25
|
+
return @result
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def traverse(x)
|
31
|
+
@stack.push(x)
|
32
|
+
d = @stack.count
|
33
|
+
@h[x] = d
|
34
|
+
@result[x] = @base_function[x] # F x = F' x
|
35
|
+
|
36
|
+
@relation[x] && @relation[x].each do |y|
|
37
|
+
traverse(y) if @h[y] == 0
|
38
|
+
@h[x] = [@h[x], @h[y]].min
|
39
|
+
@result[x] |= @result[y] # F x = F x + F y
|
40
|
+
end
|
41
|
+
|
42
|
+
if @h[x] == d
|
43
|
+
while true do
|
44
|
+
z = @stack.pop
|
45
|
+
@h[z] = Float::INFINITY
|
46
|
+
@result[z] = @result[x] # F (Top of S) = F x
|
47
|
+
|
48
|
+
break if z == x
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/lrama/output.rb
CHANGED
@@ -27,14 +27,14 @@ module Lrama
|
|
27
27
|
|
28
28
|
def render
|
29
29
|
report_duration(:render) do
|
30
|
-
erb = ERB.new(File.read(template_file),
|
30
|
+
erb = ERB.new(File.read(template_file), trim_mode: '-')
|
31
31
|
erb.filename = template_file
|
32
32
|
tmp = erb.result_with_hash(context: @context, output: self)
|
33
33
|
tmp = replace_special_variables(tmp, @output_file_path)
|
34
34
|
@out << tmp
|
35
35
|
|
36
36
|
if @header_file_path
|
37
|
-
erb = ERB.new(File.read(header_template_file),
|
37
|
+
erb = ERB.new(File.read(header_template_file), trim_mode: '-')
|
38
38
|
erb.filename = header_template_file
|
39
39
|
tmp = erb.result_with_hash(context: @context, output: self)
|
40
40
|
tmp = replace_special_variables(tmp, @header_file_path)
|
@@ -135,6 +135,17 @@ module Lrama
|
|
135
135
|
str
|
136
136
|
end
|
137
137
|
|
138
|
+
# b4_user_initial_action
|
139
|
+
def user_initial_action(comment = "")
|
140
|
+
return "" unless @grammar.initial_action
|
141
|
+
|
142
|
+
<<-STR
|
143
|
+
#{comment}
|
144
|
+
#line #{@grammar.initial_action.line} "#{@grammar_file_path}"
|
145
|
+
#{@grammar.initial_action.translated_code}
|
146
|
+
STR
|
147
|
+
end
|
148
|
+
|
138
149
|
# b4_user_actions
|
139
150
|
def user_actions
|
140
151
|
str = ""
|
@@ -164,10 +175,25 @@ module Lrama
|
|
164
175
|
str
|
165
176
|
end
|
166
177
|
|
178
|
+
def omit_braces_and_blanks(param)
|
179
|
+
param[1..-2].strip
|
180
|
+
end
|
181
|
+
|
167
182
|
# b4_parse_param
|
168
183
|
def parse_param
|
169
|
-
|
170
|
-
|
184
|
+
if @grammar.parse_param
|
185
|
+
omit_braces_and_blanks(@grammar.parse_param)
|
186
|
+
else
|
187
|
+
""
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def lex_param
|
192
|
+
if @grammar.lex_param
|
193
|
+
omit_braces_and_blanks(@grammar.lex_param)
|
194
|
+
else
|
195
|
+
""
|
196
|
+
end
|
171
197
|
end
|
172
198
|
|
173
199
|
# b4_user_formals
|
@@ -179,6 +205,60 @@ module Lrama
|
|
179
205
|
end
|
180
206
|
end
|
181
207
|
|
208
|
+
# b4_user_args
|
209
|
+
def user_args
|
210
|
+
if @grammar.parse_param
|
211
|
+
", #{parse_param_name}"
|
212
|
+
else
|
213
|
+
""
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def extract_param_name(param)
|
218
|
+
/\A(.)+([a-zA-Z0-9_]+)\z/.match(param)[2]
|
219
|
+
end
|
220
|
+
|
221
|
+
def parse_param_name
|
222
|
+
if @grammar.parse_param
|
223
|
+
extract_param_name(parse_param)
|
224
|
+
else
|
225
|
+
""
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def lex_param_name
|
230
|
+
if @grammar.lex_param
|
231
|
+
extract_param_name(lex_param)
|
232
|
+
else
|
233
|
+
""
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# b4_parse_param_use
|
238
|
+
def parse_param_use(val, loc)
|
239
|
+
str = <<-STR
|
240
|
+
YY_USE (#{val});
|
241
|
+
YY_USE (#{loc});
|
242
|
+
STR
|
243
|
+
|
244
|
+
if @grammar.parse_param
|
245
|
+
str << " YY_USE (#{parse_param_name});"
|
246
|
+
end
|
247
|
+
|
248
|
+
str
|
249
|
+
end
|
250
|
+
|
251
|
+
# b4_yylex_formals
|
252
|
+
def yylex_formals
|
253
|
+
ary = ["&yylval", "&yylloc"]
|
254
|
+
|
255
|
+
if @grammar.lex_param
|
256
|
+
ary << lex_param_name
|
257
|
+
end
|
258
|
+
|
259
|
+
"(#{ary.join(', ')})"
|
260
|
+
end
|
261
|
+
|
182
262
|
# b4_table_value_equals
|
183
263
|
def table_value_equals(table, value, literal, symbol)
|
184
264
|
if literal < table.min || table.max < literal
|
@@ -188,6 +268,17 @@ module Lrama
|
|
188
268
|
end
|
189
269
|
end
|
190
270
|
|
271
|
+
# b4_yyerror_args
|
272
|
+
def yyerror_args
|
273
|
+
ary = ["&yylloc"]
|
274
|
+
|
275
|
+
if @grammar.parse_param
|
276
|
+
ary << parse_param_name
|
277
|
+
end
|
278
|
+
|
279
|
+
"#{ary.join(', ')}"
|
280
|
+
end
|
281
|
+
|
191
282
|
def template_basename
|
192
283
|
File.basename(template_file)
|
193
284
|
end
|
data/lib/lrama/report.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
module Lrama
|
2
2
|
class Report
|
3
3
|
module Profile
|
4
|
+
# 1. Wrap target method with Profile.report_profile like below:
|
5
|
+
#
|
6
|
+
# Lrama::Report::Profile.report_profile { method }
|
7
|
+
#
|
8
|
+
# 2. Run lrama command, for example
|
9
|
+
#
|
10
|
+
# $ ./exe/lrama --trace=time spec/fixtures/integration/ruby_3_2_0/parse.tmp.y
|
11
|
+
#
|
12
|
+
# 3. Generate html file
|
13
|
+
#
|
14
|
+
# $ stackprof --d3-flamegraph tmp/stackprof-cpu-myapp.dump > tmp/flamegraph.html
|
15
|
+
#
|
4
16
|
def self.report_profile
|
5
17
|
require "stackprof"
|
6
18
|
|