lrama 0.5.4 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2e675399217ba6b1c8cc57aaa36bbf863ed8b22dc3e22777c88d0d0aaf1cb26
4
- data.tar.gz: 940b0da60c6b25edb1c10ed80539b17617e033d7ccc3a5c9c6036959c356ae37
3
+ metadata.gz: e54c51af6f1d3632293cbd7f68762bf7cff63758d3ce633113805a629b92072b
4
+ data.tar.gz: 5d053543f0e00c9fb20c40f5ca8236e499292f35fa8cf6fb8e85cac33b930814
5
5
  SHA512:
6
- metadata.gz: 26eb48911cf5ba12b3087390bb7f7053165ff092a8919f7969e31b3e784a0085e876140d419cf4b463426cbfc4ae5f3625504a6c1433f9f9842ee9c32490082f
7
- data.tar.gz: 8bce42121ffb5d45076dc3a1664e61209fec0f1a06a08d50d3a4279eb5158911b35165e21f8de0ac87c19e7cab1d2b7b0cac16bcaba0606ec61ea3b1c6195e0b
6
+ metadata.gz: 87bafe9650720b154855e055e53d700cfba67d31489dbc855c716bc150dff35e92d0fc974c14cb81a07ae68febbd69118c1720a628e2819fec1ebfa304acad55
7
+ data.tar.gz: 19b0c51748cef053d205bbf13e8ff238bda2fdbb101d304f6bfe9633b4f88fe2c4a1f452627528fd2c9e78bc97955a2a5f7543212aa581c3a9f7ae96dd3d70f8
@@ -15,7 +15,21 @@ 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@v3
18
+ - uses: actions/checkout@v4
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ bundler-cache: true
23
+ - run: bundle install
24
+ - run: bundle exec rspec
25
+ test-windows:
26
+ runs-on: windows-2022
27
+ strategy:
28
+ fail-fast: false
29
+ matrix:
30
+ ruby: ['head']
31
+ steps:
32
+ - uses: actions/checkout@v4
19
33
  - uses: ruby/setup-ruby@v1
20
34
  with:
21
35
  ruby-version: ${{ matrix.ruby }}
@@ -25,7 +39,7 @@ jobs:
25
39
  check-misc:
26
40
  runs-on: ubuntu-20.04
27
41
  steps:
28
- - uses: actions/checkout@v3
42
+ - uses: actions/checkout@v4
29
43
  # Copy from https://github.com/ruby/ruby/blob/089227e94823542acfdafa68541d330eee42ffea/.github/workflows/check_misc.yml#L27
30
44
  - name: Check for trailing spaces
31
45
  run: |
@@ -38,7 +52,7 @@ jobs:
38
52
  matrix:
39
53
  ruby: ['head']
40
54
  steps:
41
- - uses: actions/checkout@v3
55
+ - uses: actions/checkout@v4
42
56
  - uses: ruby/setup-ruby@v1
43
57
  with:
44
58
  ruby-version: ${{ matrix.ruby }}
@@ -57,7 +71,7 @@ jobs:
57
71
  run:
58
72
  working-directory: ../ruby/build
59
73
  steps:
60
- - uses: actions/checkout@v3
74
+ - uses: actions/checkout@v4
61
75
  - uses: ruby/setup-ruby@v1
62
76
  with:
63
77
  ruby-version: ${{ matrix.baseruby }}
data/Gemfile CHANGED
@@ -4,8 +4,9 @@ gemspec
4
4
 
5
5
  gem "rspec"
6
6
  gem "pry"
7
- gem "stackprof"
7
+ # stackprof doesn't support Windows
8
+ gem "stackprof", platforms: [:ruby]
8
9
  gem "rake"
9
10
  gem "rbs", require: false
10
11
  gem "steep", require: false
11
- gem "simplecov", require: false
12
+ gem "simplecov", require: false
data/exe/lrama CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
-
4
3
  $LOAD_PATH << File.join(__dir__, "../lib")
5
4
  require "lrama"
6
5
 
7
- Lrama::Command.new(ARGV.dup).run
6
+ Lrama::Command.new.run(ARGV.dup)
data/lib/lrama/command.rb CHANGED
@@ -1,58 +1,34 @@
1
- require 'optparse'
2
-
3
1
  module Lrama
4
2
  class Command
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
22
-
23
- def run
24
- parse_option
25
-
26
- if @version
27
- puts Lrama::VERSION
28
- exit 0
29
- end
3
+ def run(argv)
4
+ options = OptionParser.new.parse(argv)
30
5
 
31
- Report::Duration.enable if @trace_opts[:time]
6
+ Report::Duration.enable if options.trace_opts[:time]
32
7
 
33
8
  warning = Lrama::Warning.new
34
- grammar = Lrama::Parser.new(@y.read).parse
35
- states = Lrama::States.new(grammar, warning, trace_state: (@trace_opts[:automaton] || @trace_opts[:closure]))
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]))
36
12
  states.compute
37
13
  context = Lrama::Context.new(states)
38
14
 
39
- if @report_file
15
+ if options.report_file
40
16
  reporter = Lrama::StatesReporter.new(states)
41
- File.open(@report_file, "w+") do |f|
42
- reporter.report(f, **@report_opts)
17
+ File.open(options.report_file, "w+") do |f|
18
+ reporter.report(f, **options.report_opts)
43
19
  end
44
20
  end
45
21
 
46
- File.open(@outfile, "w+") do |f|
22
+ File.open(options.outfile, "w+") do |f|
47
23
  Lrama::Output.new(
48
24
  out: f,
49
- output_file_path: @outfile,
50
- template_name: @skeleton,
51
- grammar_file_path: @grammar_file,
52
- header_file_path: @header_file,
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,
53
29
  context: context,
54
30
  grammar: grammar,
55
- error_recovery: @error_recovery,
31
+ error_recovery: options.error_recovery,
56
32
  ).render
57
33
  end
58
34
 
@@ -60,108 +36,5 @@ module Lrama
60
36
  exit 1
61
37
  end
62
38
  end
63
-
64
- private
65
-
66
- def validate_report(report)
67
- bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
68
- others = %w[verbose]
69
- list = bison_list + others
70
- not_supported = %w[cex none]
71
- h = { grammar: true }
72
-
73
- report.each do |r|
74
- if list.include?(r) && !not_supported.include?(r)
75
- h[r.to_sym] = true
76
- else
77
- raise "Invalid report option \"#{r}\"."
78
- end
79
- end
80
-
81
- if h[:all]
82
- (bison_list - not_supported).each do |r|
83
- h[r.to_sym] = true
84
- end
85
-
86
- h.delete(:all)
87
- end
88
-
89
- return h
90
- end
91
-
92
- def validate_trace(trace)
93
- list = %w[
94
- none locations scan parse automaton bitsets
95
- closure grammar resource sets muscles tools
96
- m4-early m4 skeleton time ielr cex all
97
- ]
98
- h = {}
99
-
100
- trace.each do |t|
101
- if list.include?(t)
102
- h[t.to_sym] = true
103
- else
104
- raise "Invalid trace option \"#{t}\"."
105
- end
106
- end
107
-
108
- return h
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', Array) {|v| @report = v }
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', Array) {|v| @trace = v }
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
166
39
  end
167
40
  end
data/lib/lrama/context.rb CHANGED
@@ -401,7 +401,6 @@ module Lrama
401
401
  end
402
402
  print sprintf("]\n\n")
403
403
 
404
-
405
404
  print sprintf("width [\n")
406
405
  vectors_count.times do |i|
407
406
  print sprintf("%d, ", ary[i] ? ary[i][3] : 0)
@@ -409,7 +408,6 @@ module Lrama
409
408
  end
410
409
  print sprintf("]\n\n")
411
410
 
412
-
413
411
  print sprintf("tally [\n")
414
412
  vectors_count.times do |i|
415
413
  print sprintf("%d, ", ary[i] ? ary[i][2] : 0)
@@ -205,7 +205,7 @@ module Lrama
205
205
  end
206
206
 
207
207
  def build_paths_from_state_items(state_items)
208
- paths = state_items.zip([nil] + state_items).map do |si, prev_si|
208
+ state_items.zip([nil] + state_items).map do |si, prev_si|
209
209
  case
210
210
  when prev_si.nil?
211
211
  StartPath.new(si)
@@ -215,8 +215,6 @@ module Lrama
215
215
  TransitionPath.new(prev_si, si)
216
216
  end
217
217
  end
218
-
219
- paths
220
218
  end
221
219
 
222
220
  def shortest_path(conflict_state, conflict_reduce_item, conflict_term)
@@ -50,7 +50,6 @@ module Lrama
50
50
  end
51
51
  alias :translated_error_token_code :translated_printer_code
52
52
 
53
-
54
53
  private
55
54
 
56
55
  # * ($1) yyvsp[i]
data/lib/lrama/grammar.rb CHANGED
@@ -103,6 +103,10 @@ module Lrama
103
103
  set_precedence(sym, Precedence.new(type: :right, precedence: precedence))
104
104
  end
105
105
 
106
+ def add_precedence(sym, precedence)
107
+ set_precedence(sym, Precedence.new(type: :precedence, precedence: precedence))
108
+ end
109
+
106
110
  def set_precedence(sym, precedence)
107
111
  raise "" if sym.nterm?
108
112
  sym.precedence = precedence
@@ -310,7 +314,6 @@ module Lrama
310
314
  end || (raise "Nterm not found: #{id}")
311
315
  end
312
316
 
313
-
314
317
  def append_special_symbols
315
318
  # YYEMPTY (token_id: -2, number: -2) is added when a template is evaluated
316
319
  # term = add_term(id: Token.new(Token::Ident, "YYEMPTY"), token_id: -2)
@@ -512,7 +515,7 @@ module Lrama
512
515
  sym.token_id = 11
513
516
  when "\""
514
517
  sym.token_id = 34
515
- when "\'"
518
+ when "'"
516
519
  sym.token_id = 39
517
520
  when "\\\\"
518
521
  sym.token_id = 92
@@ -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) } + 1
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
@@ -61,6 +67,7 @@ module Lrama
61
67
  define_type(:P_nonassoc) # %nonassoc
62
68
  define_type(:P_left) # %left
63
69
  define_type(:P_right) # %right
70
+ define_type(:P_precedence) # %precedence
64
71
  define_type(:P_prec) # %prec
65
72
  define_type(:User_code) # { ... }
66
73
  define_type(:Tag) # <int>
data/lib/lrama/lexer.rb CHANGED
@@ -30,7 +30,6 @@ module Lrama
30
30
  @grammar_rules = []
31
31
  @epilogue = []
32
32
 
33
- #
34
33
  @bison_declarations_tokens = []
35
34
  @grammar_rules_tokens = []
36
35
 
@@ -155,6 +154,8 @@ module Lrama
155
154
  tokens << create_token(Token::P_left, ss[0], line, ss.pos - column)
156
155
  when ss.scan(/%right/)
157
156
  tokens << create_token(Token::P_right, ss[0], line, ss.pos - column)
157
+ when ss.scan(/%precedence/)
158
+ tokens << create_token(Token::P_precedence, ss[0], line, ss.pos - column)
158
159
  when ss.scan(/%prec/)
159
160
  tokens << create_token(Token::P_prec, ss[0], line, ss.pos - column)
160
161
  when ss.scan(/{/)
@@ -212,19 +213,33 @@ module Lrama
212
213
  string, line = lex_string(ss, "'", line, lines)
213
214
  str << string
214
215
  next
216
+
217
+ # $ references
218
+ # It need to wrap an identifier with brackets to use ".-" for identifiers
215
219
  when ss.scan(/\$(<[a-zA-Z0-9_]+>)?\$/) # $$, $<long>$
216
220
  tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
217
221
  references << [:dollar, "$", tag, str.length, str.length + ss[0].length - 1]
218
222
  when ss.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $<long>1
219
223
  tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
220
224
  references << [:dollar, Integer(ss[2]), tag, str.length, str.length + ss[0].length - 1]
221
- when ss.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_.][-a-zA-Z0-9_.]*)/) # $foo, $expr, $<long>program
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)
222
229
  tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
223
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
224
234
  when ss.scan(/@\$/) # @$
225
235
  references << [:at, "$", nil, str.length, str.length + ss[0].length - 1]
226
- when ss.scan(/@(\d)+/) # @1
236
+ when ss.scan(/@(\d+)/) # @1
227
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
+
228
243
  when ss.scan(/{/)
229
244
  brace_count += 1
230
245
  when ss.scan(/}/)
@@ -314,8 +329,6 @@ module Lrama
314
329
  str << ss.getch
315
330
  next
316
331
  end
317
-
318
- str << ss[0]
319
332
  end
320
333
 
321
334
  line # Reach to end of input
@@ -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/output.rb CHANGED
@@ -252,7 +252,7 @@ module Lrama
252
252
  end
253
253
 
254
254
  def extract_param_name(param)
255
- /\A(\W*)([a-zA-Z0-9_]+)\z/.match(param.split.last)[2]
255
+ param[/\b([a-zA-Z0-9_]+)(?=\s*\z)/]
256
256
  end
257
257
 
258
258
  def parse_param_name
data/lib/lrama/parser.rb CHANGED
@@ -159,6 +159,14 @@ module Lrama
159
159
  grammar.add_right(sym, precedence_number)
160
160
  end
161
161
  precedence_number += 1
162
+ when T::P_precedence
163
+ # %precedence (ident|char|string)+
164
+ ts.next
165
+ while (id = ts.consume(T::Ident, T::Char, T::String)) do
166
+ sym = grammar.add_term(id: id)
167
+ grammar.add_precedence(sym, precedence_number)
168
+ end
169
+ precedence_number += 1
162
170
  when nil
163
171
  # end of input
164
172
  raise "Reach to end of input within declarations"
data/lib/lrama/state.rb CHANGED
@@ -62,7 +62,6 @@ module Lrama
62
62
  @items_to_state[items] = next_state
63
63
  end
64
64
 
65
- #
66
65
  def set_look_ahead(rule, look_ahead)
67
66
  reduce = reduces.find do |r|
68
67
  r.rule == rule
data/lib/lrama/states.rb CHANGED
@@ -455,6 +455,11 @@ module Lrama
455
455
 
456
456
  # shift_prec == reduce_prec, then check associativity
457
457
  case sym.precedence.type
458
+ when :precedence
459
+ # %precedence only specifies precedence and not specify associativity
460
+ # then a conflict is unresolved if precedence is same.
461
+ state.conflicts << State::ShiftReduceConflict.new(symbols: [sym], shift: shift, reduce: reduce)
462
+ next
458
463
  when :right
459
464
  # Shift is selected
460
465
  state.resolved_conflicts << State::ResolvedConflict.new(symbol: sym, reduce: reduce, which: :shift, same_prec: true)
@@ -515,9 +520,9 @@ module Lrama
515
520
 
516
521
  state.default_reduction_rule = state.reduces.map do |r|
517
522
  [r.rule, r.rule.id, (r.look_ahead || []).count]
518
- end.sort_by do |rule, rule_id, count|
523
+ end.min_by do |rule, rule_id, count|
519
524
  [-count, rule_id]
520
- end.first.first
525
+ end.first
521
526
  end
522
527
  end
523
528
 
@@ -110,7 +110,6 @@ module Lrama
110
110
  end
111
111
  io << "\n"
112
112
 
113
-
114
113
  # Report shifts
115
114
  tmp = state.term_transitions.select do |shift, _|
116
115
  !shift.not_selected
@@ -123,7 +122,6 @@ module Lrama
123
122
  end
124
123
  io << "\n" if !tmp.empty?
125
124
 
126
-
127
125
  # Report error caused by %nonassoc
128
126
  nl = false
129
127
  tmp = state.resolved_conflicts.select do |resolved|
@@ -138,7 +136,6 @@ module Lrama
138
136
  end
139
137
  io << "\n" if !tmp.empty?
140
138
 
141
-
142
139
  # Report reduces
143
140
  nl = false
144
141
  max_len = state.non_default_reduces.flat_map(&:look_ahead).compact.map(&:display_name).map(&:length).max || 0
@@ -171,7 +168,6 @@ module Lrama
171
168
  end
172
169
  io << "\n" if nl
173
170
 
174
-
175
171
  # Report nonterminal transitions
176
172
  tmp = []
177
173
  max_len = 0
@@ -189,7 +185,6 @@ module Lrama
189
185
  end
190
186
  io << "\n" if !tmp.empty?
191
187
 
192
-
193
188
  if solved
194
189
  # Report conflict resolutions
195
190
  state.resolved_conflicts.each do |resolved|
@@ -202,13 +197,13 @@ module Lrama
202
197
  # Report counterexamples
203
198
  examples = cex.compute(state)
204
199
  examples.each do |example|
205
- label0 = example.type == :shift_reduce ? "shift/reduce" : "reduce/reduce"
200
+ label0 = example.type == :shift_reduce ? "shift/reduce" : "reduce/reduce"
206
201
  label1 = example.type == :shift_reduce ? "Shift derivation" : "First Reduce derivation"
207
202
  label2 = example.type == :shift_reduce ? "Reduce derivation" : "Second Reduce derivation"
208
203
 
209
204
  io << " #{label0} conflict on token #{example.conflict_symbol.id.s_value}:\n"
210
- io << " #{example.path1_item.to_s}\n"
211
- io << " #{example.path2_item.to_s}\n"
205
+ io << " #{example.path1_item}\n"
206
+ io << " #{example.path2_item}\n"
212
207
  io << " #{label1}\n"
213
208
  example.derivations1.render_strings_for_report.each do |str|
214
209
  io << " #{str}\n"
@@ -234,7 +229,6 @@ module Lrama
234
229
  end
235
230
  io << "\n"
236
231
 
237
-
238
232
  # Report reads_relation
239
233
  io << " [Reads Relation]\n"
240
234
  @states.nterms.each do |nterm|
@@ -248,7 +242,6 @@ module Lrama
248
242
  end
249
243
  io << "\n"
250
244
 
251
-
252
245
  # Report read_sets
253
246
  io << " [Read sets]\n"
254
247
  read_sets = @states.read_sets
@@ -263,7 +256,6 @@ module Lrama
263
256
  end
264
257
  io << "\n"
265
258
 
266
-
267
259
  # Report includes_relation
268
260
  io << " [Includes Relation]\n"
269
261
  @states.nterms.each do |nterm|
@@ -277,7 +269,6 @@ module Lrama
277
269
  end
278
270
  io << "\n"
279
271
 
280
-
281
272
  # Report lookback_relation
282
273
  io << " [Lookback Relation]\n"
283
274
  @states.rules.each do |rule|
@@ -286,12 +277,11 @@ module Lrama
286
277
 
287
278
  a.each do |state_id2, nterm_id2|
288
279
  n = @states.nterms.find {|n| n.token_id == nterm_id2 }
289
- io << " (Rule: #{rule.to_s}) -> (State #{state_id2}, #{n.id.s_value})\n"
280
+ io << " (Rule: #{rule}) -> (State #{state_id2}, #{n.id.s_value})\n"
290
281
  end
291
282
  end
292
283
  io << "\n"
293
284
 
294
-
295
285
  # Report follow_sets
296
286
  io << " [Follow sets]\n"
297
287
  follow_sets = @states.follow_sets
@@ -306,7 +296,6 @@ module Lrama
306
296
  end
307
297
  io << "\n"
308
298
 
309
-
310
299
  # Report LA
311
300
  io << " [Look-Ahead Sets]\n"
312
301
  tmp = []
@@ -326,7 +315,6 @@ module Lrama
326
315
  io << "\n" if !tmp.empty?
327
316
  end
328
317
 
329
-
330
318
  # End of Report State
331
319
  io << "\n"
332
320
  end
data/lib/lrama/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lrama
2
- VERSION = "0.5.4".freeze
2
+ VERSION = "0.5.6".freeze
3
3
  end
data/lib/lrama.rb CHANGED
@@ -5,6 +5,8 @@ require "lrama/counterexamples"
5
5
  require "lrama/digraph"
6
6
  require "lrama/grammar"
7
7
  require "lrama/lexer"
8
+ require "lrama/option_parser"
9
+ require "lrama/options"
8
10
  require "lrama/output"
9
11
  require "lrama/parser"
10
12
  require "lrama/report"
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
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-08-17 00:00:00.000000000 Z
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.4.1
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