lrama 0.5.4 → 0.5.6

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: 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