lrama 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a8a1b04a3e761af04029af3e3b74aaaf4fe9a9e2741205f430264ee3399f66c
4
- data.tar.gz: a97ec2c2b2007f3bad6cbe5d1b37baa87d520cc3025e82403a9d8a70cddccc8a
3
+ metadata.gz: 26bcef726eebf61de01200b02250b2aef91ca957df43db5d72e99ae30e320f4e
4
+ data.tar.gz: 751b62d184806c0cff319bffc4990ad0de9dd143accafdf6bdf1652eb02512b7
5
5
  SHA512:
6
- metadata.gz: 820bce06aefc235c02995cc957f9e0d9b2e8d588ce7748225896f0d63c319135068da39977be860815276c360a66e3dd6c2132802aa30e3292d706bc6ae7ef9d
7
- data.tar.gz: d5c4ec405196bca888c78bf8a16cc9aef47da0f9943d7eee2bf9033c104f9a07fcb07c4cb6aabb3bb49f0e3665bf37932e2206cd9acad925702c30c7124210fb
6
+ metadata.gz: 02001b5b137d023c4f5ce48c1d9284ce90c5aad2ec269d7ef7a17e6ffa65be9e553e213400fc63d8256c0209908fc4b314de261993442af4a25772449453fbeb
7
+ data.tar.gz: 76a9f6bac19c0dcbdc6f9e2834d3c437f9fc5eb999d1b45d20362d52a94c9dc74bca3411b681993e28f388374df7f9b8ea7d0f534e53399efb8cc24112f75ea4
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -22,6 +22,21 @@ 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 rbs collection install
39
+ - run: bundle exec steep check
25
40
  test-ruby:
26
41
  runs-on: ubuntu-20.04
27
42
  strategy:
@@ -43,9 +58,7 @@ jobs:
43
58
  - run: mkdir -p tool/lrama
44
59
  working-directory: ../ruby
45
60
  - name: Copy Lrama to ruby/tool
46
- run: cp -r exe lib ../ruby/tool/lrama
47
- # TODO: Consider how to manage changes on ruby/ruby master and ruby/lrama
48
- # run: cp -r exe lib template ../ruby/tool/lrama
61
+ run: cp -r exe lib template ../ruby/tool/lrama
49
62
  working-directory:
50
63
  - run: tree tool/lrama
51
64
  working-directory: ../ruby
@@ -70,5 +83,5 @@ jobs:
70
83
  - run: sudo apt-get --purge remove bison
71
84
  - run: ../autogen.sh
72
85
  - run: ../configure -C --disable-install-doc
73
- - run: make YACC=$(readlink -f $(pwd)/../tool/lrama/exe/lrama)
86
+ - run: make
74
87
  - run: make test-all
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ /.gem_rbs_collection/
1
2
  /tmp
2
3
  .irbrc
3
4
  /Gemfile.lock
data/Gemfile CHANGED
@@ -6,3 +6,5 @@ gem "rspec"
6
6
  gem "pry"
7
7
  gem "stackprof"
8
8
  gem "rake"
9
+ gem "rbs", require: false
10
+ gem "steep", require: false
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.1.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 LEGAL.md MIT 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
@@ -0,0 +1,9 @@
1
+ # D = Steep::Diagnostic
2
+ #
3
+ target :lib do
4
+ signature "sig"
5
+
6
+ check "lib/lrama/bitmap.rb"
7
+ check "lib/lrama/report.rb"
8
+ check "lib/lrama/warning.rb"
9
+ end
data/lib/lrama/grammar.rb CHANGED
@@ -155,18 +155,18 @@ module Lrama
155
155
  last_column = ref.last_column
156
156
 
157
157
  case
158
- when ref.number == "$" && ref.type == :dollar # $$
158
+ when ref.value == "$" && ref.type == :dollar # $$
159
159
  # Omit "<>"
160
160
  member = tag.s_value[1..-2]
161
161
  str = "((*yyvaluep).#{member})"
162
- when ref.number == "$" && ref.type == :at # @$
162
+ when ref.value == "$" && ref.type == :at # @$
163
163
  str = "(*yylocationp)"
164
164
  when ref.type == :dollar # $n
165
- raise "$#{ref.number} can not be used in %printer."
165
+ raise "$#{ref.value} can not be used in %printer."
166
166
  when ref.type == :at # @n
167
- raise "@#{ref.number} can not be used in %printer."
167
+ raise "@#{ref.value} can not be used in %printer."
168
168
  else
169
- raise "Unexpected. #{code}, #{ref}"
169
+ raise "Unexpected. #{self}, #{ref}"
170
170
  end
171
171
 
172
172
  t_code[first_column..last_column] = str
@@ -190,22 +190,22 @@ module Lrama
190
190
  last_column = ref.last_column
191
191
 
192
192
  case
193
- when ref.number == "$" && ref.type == :dollar # $$
193
+ when ref.value == "$" && ref.type == :dollar # $$
194
194
  # Omit "<>"
195
195
  member = ref.tag.s_value[1..-2]
196
196
  str = "(yyval.#{member})"
197
- when ref.number == "$" && ref.type == :at # @$
197
+ when ref.value == "$" && ref.type == :at # @$
198
198
  str = "(yyloc)"
199
199
  when ref.type == :dollar # $n
200
- i = -ref.position_in_rhs + ref.number
200
+ i = -ref.position_in_rhs + ref.value
201
201
  # Omit "<>"
202
202
  member = ref.tag.s_value[1..-2]
203
203
  str = "(yyvsp[#{i}].#{member})"
204
204
  when ref.type == :at # @n
205
- i = -ref.position_in_rhs + ref.number
205
+ i = -ref.position_in_rhs + ref.value
206
206
  str = "(yylsp[#{i}])"
207
207
  else
208
- raise "Unexpected. #{code}, #{ref}"
208
+ raise "Unexpected. #{self}, #{ref}"
209
209
  end
210
210
 
211
211
  t_code[first_column..last_column] = str
@@ -226,16 +226,16 @@ module Lrama
226
226
  last_column = ref.last_column
227
227
 
228
228
  case
229
- when ref.number == "$" && ref.type == :dollar # $$
229
+ when ref.value == "$" && ref.type == :dollar # $$
230
230
  str = "yylval"
231
- when ref.number == "$" && ref.type == :at # @$
231
+ when ref.value == "$" && ref.type == :at # @$
232
232
  str = "yylloc"
233
233
  when ref.type == :dollar # $n
234
- raise "$#{ref.number} can not be used in initial_action."
234
+ raise "$#{ref.value} can not be used in initial_action."
235
235
  when ref.type == :at # @n
236
- raise "@#{ref.number} can not be used in initial_action."
236
+ raise "@#{ref.value} can not be used in initial_action."
237
237
  else
238
- raise "Unexpected. #{code}, #{ref}"
238
+ raise "Unexpected. #{self}, #{ref}"
239
239
  end
240
240
 
241
241
  t_code[first_column..last_column] = str
@@ -247,7 +247,7 @@ module Lrama
247
247
 
248
248
  # type: :dollar or :at
249
249
  # ex_tag: "$<tag>1" (Optional)
250
- Reference = Struct.new(:type, :number, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true) do
250
+ Reference = Struct.new(:type, :value, :ex_tag, :first_column, :last_column, :referring_symbol, :position_in_rhs, keyword_init: true) do
251
251
  def tag
252
252
  if ex_tag
253
253
  ex_tag
@@ -382,8 +382,8 @@ module Lrama
382
382
  end
383
383
 
384
384
  def build_references(token_code)
385
- token_code.references.map! do |type, number, tag, first_column, last_column|
386
- Reference.new(type: type, number: number, ex_tag: tag, first_column: first_column, last_column: last_column)
385
+ token_code.references.map! do |type, value, tag, first_column, last_column|
386
+ Reference.new(type: type, value: value, ex_tag: tag, first_column: first_column, last_column: last_column)
387
387
  end
388
388
 
389
389
  token_code
@@ -627,15 +627,23 @@ module Lrama
627
627
  ref.position_in_rhs = i - 1
628
628
  next if ref.type == :at
629
629
  # $$, $n, @$, @n can be used in any actions
630
- number = ref.number
631
630
 
632
- if number == "$"
631
+ if ref.value == "$"
633
632
  # TODO: Should be postponed after middle actions are extracted?
634
633
  ref.referring_symbol = lhs
635
- else
636
- raise "Can not refer following component. #{number} >= #{i}. #{token}" if number >= i
637
- rhs1[number - 1].referred = true
638
- ref.referring_symbol = rhs1[number - 1]
634
+ elsif ref.value.is_a?(Integer)
635
+ raise "Can not refer following component. #{ref.value} >= #{i}. #{token}" if ref.value >= i
636
+ rhs1[ref.value - 1].referred = true
637
+ ref.referring_symbol = rhs1[ref.value - 1]
638
+ elsif ref.value.is_a?(String)
639
+ target_tokens = ([lhs] + rhs1 + [code]).compact.first(i)
640
+ referring_symbol_candidate = target_tokens.filter {|token| token.referred_by?(ref.value) }
641
+ raise "Referring symbol `#{ref.value}` is duplicated. #{token}" if referring_symbol_candidate.size >= 2
642
+ raise "Referring symbol `#{ref.value}` is not found. #{token}" if referring_symbol_candidate.count == 0
643
+
644
+ referring_symbol = referring_symbol_candidate.first
645
+ referring_symbol.referred = true
646
+ ref.referring_symbol = referring_symbol
639
647
  end
640
648
  end
641
649
  end
@@ -716,7 +724,7 @@ module Lrama
716
724
  # If id is Token::Char, it uses ASCII code
717
725
  if sym.term? && sym.token_id.nil?
718
726
  if sym.id.type == Token::Char
719
- # Igonre ' on the both sides
727
+ # Ignore ' on the both sides
720
728
  case sym.id.s_value[1..-2]
721
729
  when "\\b"
722
730
  sym.token_id = 8
@@ -844,7 +852,7 @@ module Lrama
844
852
 
845
853
  return if invalid.empty?
846
854
 
847
- raise "Symbol number is dupulicated. #{invalid}"
855
+ raise "Symbol number is duplicated. #{invalid}"
848
856
  end
849
857
  end
850
858
  end
data/lib/lrama/lexer.rb CHANGED
@@ -7,7 +7,7 @@ module Lrama
7
7
  include Lrama::Report::Duration
8
8
 
9
9
  # s_value is semantic value
10
- Token = Struct.new(:type, :s_value, keyword_init: true) do
10
+ Token = Struct.new(:type, :s_value, :alias, keyword_init: true) do
11
11
  Type = Struct.new(:id, :name, keyword_init: true)
12
12
 
13
13
  attr_accessor :line, :column, :referred
@@ -18,6 +18,31 @@ module Lrama
18
18
  "#{super} line: #{line}, column: #{column}"
19
19
  end
20
20
 
21
+ def referred_by?(string)
22
+ [self.s_value, self.alias].include?(string)
23
+ end
24
+
25
+ def ==(other)
26
+ self.class == other.class && self.type == other.type && self.s_value == other.s_value
27
+ end
28
+
29
+ def numberize_references(lhs, rhs)
30
+ self.references.map! {|ref|
31
+ ref_name = ref[1]
32
+ if ref_name.is_a?(String) && ref_name != '$'
33
+ value =
34
+ if lhs.referred_by?(ref_name)
35
+ '$'
36
+ else
37
+ rhs.find_index {|token| token.referred_by?(ref_name) } + 1
38
+ end
39
+ [ref[0], value, ref[2], ref[3], ref[4]]
40
+ else
41
+ ref
42
+ end
43
+ }
44
+ end
45
+
21
46
  @i = 0
22
47
  @types = []
23
48
 
@@ -47,6 +72,7 @@ module Lrama
47
72
  define_type(:Number) # 0
48
73
  define_type(:Ident_Colon) # k_if:, k_if : (spaces can be there)
49
74
  define_type(:Ident) # api.pure, tNUMBER
75
+ define_type(:Named_Ref) # [foo]
50
76
  define_type(:Semicolon) # ;
51
77
  define_type(:Bar) # |
52
78
  define_type(:String) # "str"
@@ -166,10 +192,15 @@ module Lrama
166
192
  tokens << create_token(Token::Number, Integer(ss[0]), line, ss.pos - column)
167
193
  when ss.scan(/(<[a-zA-Z0-9_]+>)/)
168
194
  tokens << create_token(Token::Tag, ss[0], line, ss.pos - column)
195
+ when ss.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]\s*:/)
196
+ tokens << create_token(Token::Ident_Colon, ss[1], line, ss.pos - column)
197
+ tokens << create_token(Token::Named_Ref, ss[2], line, ss.pos - column)
169
198
  when ss.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)\s*:/)
170
199
  tokens << create_token(Token::Ident_Colon, ss[1], line, ss.pos - column)
171
200
  when ss.scan(/([a-zA-Z_.][-a-zA-Z0-9_.]*)/)
172
201
  tokens << create_token(Token::Ident, ss[0], line, ss.pos - column)
202
+ when ss.scan(/\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/)
203
+ tokens << create_token(Token::Named_Ref, ss[1], line, ss.pos - column)
173
204
  when ss.scan(/%expect/)
174
205
  tokens << create_token(Token::P_expect, ss[0], line, ss.pos - column)
175
206
  when ss.scan(/%define/)
@@ -206,6 +237,8 @@ module Lrama
206
237
  when ss.scan(/\/\*/)
207
238
  # TODO: Need to keep comment?
208
239
  line = lex_comment(ss, line, lines, "")
240
+ when ss.scan(/\/\//)
241
+ line = lex_line_comment(ss, line, "")
209
242
  when ss.scan(/'(.)'/)
210
243
  tokens << create_token(Token::Char, ss[0], line, ss.pos - column)
211
244
  when ss.scan(/'\\(.)'/) # '\\', '\t'
@@ -218,7 +251,7 @@ module Lrama
218
251
  l = line - lines.first[1]
219
252
  split = ss.string.split("\n")
220
253
  col = ss.pos - split[0...l].join("\n").length
221
- raise "Parse error (unknow token): #{split[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{col})"
254
+ raise "Parse error (unknown token): #{split[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{col})"
222
255
  end
223
256
  end
224
257
  end
@@ -255,6 +288,9 @@ module Lrama
255
288
  when ss.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $<long>1
256
289
  tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
257
290
  references << [:dollar, Integer(ss[2]), tag, str.length, str.length + ss[0].length - 1]
291
+ when ss.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_.][-a-zA-Z0-9_.]*)/) # $foo, $expr, $<long>program
292
+ tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
293
+ references << [:dollar, ss[2], tag, str.length, str.length + ss[0].length - 1]
258
294
  when ss.scan(/@\$/) # @$
259
295
  references << [:at, "$", nil, str.length, str.length + ss[0].length - 1]
260
296
  when ss.scan(/@(\d)+/) # @1
@@ -276,6 +312,9 @@ module Lrama
276
312
  when ss.scan(/\/\*/)
277
313
  str << ss[0]
278
314
  line = lex_comment(ss, line, lines, str)
315
+ when ss.scan(/\/\//)
316
+ str << ss[0]
317
+ line = lex_line_comment(ss, line, str)
279
318
  else
280
319
  # noop, just consume char
281
320
  str << ss.getch
@@ -314,8 +353,6 @@ module Lrama
314
353
  raise "Parse error (quote mismatch): #{ss.string.split("\n")[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{ss.pos})"
315
354
  end
316
355
 
317
- # TODO: Need to handle // style comment
318
- #
319
356
  # /* */ style comment
320
357
  def lex_comment(ss, line, lines, str)
321
358
  while !ss.eos? do
@@ -337,6 +374,23 @@ module Lrama
337
374
  raise "Parse error (comment mismatch): #{ss.string.split("\n")[l]} \"#{ss.string[ss.pos]}\" (#{line}: #{ss.pos})"
338
375
  end
339
376
 
377
+ # // style comment
378
+ def lex_line_comment(ss, line, str)
379
+ while !ss.eos? do
380
+ case
381
+ when ss.scan(/\n/)
382
+ return line + 1
383
+ else
384
+ str << ss.getch
385
+ next
386
+ end
387
+
388
+ str << ss[0]
389
+ end
390
+
391
+ line # Reach to end of input
392
+ end
393
+
340
394
  def lex_grammar_rules_tokens
341
395
  lex_common(@grammar_rules, @grammar_rules_tokens)
342
396
  end
@@ -0,0 +1,59 @@
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 previous_token
18
+ @tokens[@index - 1]
19
+ end
20
+
21
+ def next
22
+ token = current_token
23
+ @index += 1
24
+ return token
25
+ end
26
+
27
+ def consume(*token_types)
28
+ if token_types.include?(current_type)
29
+ token = current_token
30
+ self.next
31
+ return token
32
+ end
33
+
34
+ return nil
35
+ end
36
+
37
+ def consume!(*token_types)
38
+ consume(*token_types) || (raise "#{token_types} is expected but #{current_type}. #{current_token}")
39
+ end
40
+
41
+ def consume_multi(*token_types)
42
+ a = []
43
+
44
+ while token_types.include?(current_type)
45
+ a << current_token
46
+ self.next
47
+ end
48
+
49
+ raise "No token is consumed. #{token_types}" if a.empty?
50
+
51
+ return a
52
+ end
53
+
54
+ def eots?
55
+ current_token.nil?
56
+ end
57
+ end
58
+ end
59
+ 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
@@ -226,8 +175,11 @@ module Lrama
226
175
  # LHS
227
176
  lhs = ts.consume!(T::Ident_Colon) # class:
228
177
  lhs.type = T::Ident
178
+ if named_ref = ts.consume(T::Named_Ref)
179
+ lhs.alias = named_ref.s_value
180
+ end
229
181
 
230
- rhs = parse_grammar_rule_rhs(ts, grammar)
182
+ rhs = parse_grammar_rule_rhs(ts, grammar, lhs)
231
183
 
232
184
  grammar.add_rule(lhs: lhs, rhs: rhs, lineno: rhs.first ? rhs.first.line : lhs.line)
233
185
 
@@ -237,7 +189,7 @@ module Lrama
237
189
  # |
238
190
  bar_lineno = ts.current_token.line
239
191
  ts.next
240
- rhs = parse_grammar_rule_rhs(ts, grammar)
192
+ rhs = parse_grammar_rule_rhs(ts, grammar, lhs)
241
193
  grammar.add_rule(lhs: lhs, rhs: rhs, lineno: rhs.first ? rhs.first.line : bar_lineno)
242
194
  when T::Semicolon
243
195
  # ;
@@ -256,13 +208,13 @@ module Lrama
256
208
  end
257
209
  end
258
210
 
259
- def parse_grammar_rule_rhs(ts, grammar)
211
+ def parse_grammar_rule_rhs(ts, grammar, lhs)
260
212
  a = []
261
213
  prec_seen = false
262
214
  code_after_prec = false
263
215
 
264
216
  while true do
265
- # TODO: Srting can be here
217
+ # TODO: String can be here
266
218
  case ts.current_type
267
219
  when T::Ident
268
220
  # keyword_class
@@ -295,9 +247,13 @@ module Lrama
295
247
  end
296
248
 
297
249
  code = ts.current_token
250
+ code.numberize_references(lhs, a)
298
251
  grammar.build_references(code)
299
252
  a << code
300
253
  ts.next
254
+ when T::Named_Ref
255
+ ts.previous_token.alias = ts.current_token.s_value
256
+ ts.next
301
257
  when T::Bar
302
258
  # |
303
259
  break
@@ -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
@@ -0,0 +1,13 @@
1
+ module Lrama
2
+ class State
3
+ class Shift
4
+ attr_reader :next_sym, :next_items
5
+ attr_accessor :not_selected
6
+
7
+ def initialize(next_sym, next_items)
8
+ @next_sym = next_sym
9
+ @next_items = next_items
10
+ end
11
+ end
12
+ end
13
+ end