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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d7cf0f612d3e1ac4aea0b45db6c0533beadd6412f10a85dd17aceefcfb104a9
4
- data.tar.gz: 9e60878988696b8d300700a442cb93bb7d7919be94be80a4bd96cbfe689dad1a
3
+ metadata.gz: 2ba620aa365e3ce11d757da653bd6677ca8bec28ca1b6a5df745d37da6784f59
4
+ data.tar.gz: 2ab03daa03cbb925826f2ca8053dcb04d9648c5c31bd85b1e6fbfe6f9b4cec70
5
5
  SHA512:
6
- metadata.gz: 0fa702fd65a2b84c3d426c45ea6d09a5129391409408604d50767c71f8f2d059db45bbde0b8fd96f093caf3741479add35e8cb1434bdd763c38761f70a994d93
7
- data.tar.gz: d2d5ed81585710107200595b38316120ccc5e01718247c08b6c7de7708ae619de1ec7e37d4ce987b6c21c31d81d5f5c812ecb385d7a6d2838be26e4cf52621f1
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" is generated
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
@@ -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
- list = %w[states itemsets lookaheads solved counterexamples cex all none]
96
- not_supported = %w[counterexamples cex all none]
97
- h = {}
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
- report_duration(:compute_tables) { compute_tables }
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), nil, '-')
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), nil, '-')
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
- # Omit "{}"
170
- @grammar.parse_param[1..-2]
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