summaryrefslogtreecommitdiff
path: root/tool
diff options
context:
space:
mode:
authoryui-knk <spiketeika@gmail.com>2023-09-13 13:06:03 +0900
committerYuichiro Kaneko <spiketeika@gmail.com>2023-09-13 18:03:49 +0900
commit4655d2108ef14e66f64496f9029f65ba2302d9ea (patch)
tree79c5295698a0476a96c16fa28ba2e4f0853624ed /tool
parentc75d54a36ca94ec25b5eb31925a0414f998df78c (diff)
Lrama v0.5.6
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/8428
Diffstat (limited to 'tool')
-rwxr-xr-xtool/lrama/exe/lrama2
-rw-r--r--tool/lrama/lib/lrama.rb2
-rw-r--r--tool/lrama/lib/lrama/command.rb152
-rw-r--r--tool/lrama/lib/lrama/lexer.rb16
-rw-r--r--tool/lrama/lib/lrama/lexer/token.rb8
-rw-r--r--tool/lrama/lib/lrama/option_parser.rb124
-rw-r--r--tool/lrama/lib/lrama/options.rb23
-rw-r--r--tool/lrama/lib/lrama/version.rb2
8 files changed, 188 insertions, 141 deletions
diff --git a/tool/lrama/exe/lrama b/tool/lrama/exe/lrama
index 5e1ee582cf..ba5fb06c82 100755
--- a/tool/lrama/exe/lrama
+++ b/tool/lrama/exe/lrama
@@ -3,4 +3,4 @@
$LOAD_PATH << File.join(__dir__, "../lib")
require "lrama"
-Lrama::Command.new(ARGV.dup).run
+Lrama::Command.new.run(ARGV.dup)
diff --git a/tool/lrama/lib/lrama.rb b/tool/lrama/lib/lrama.rb
index 12e635d8b6..880e64df5f 100644
--- a/tool/lrama/lib/lrama.rb
+++ b/tool/lrama/lib/lrama.rb
@@ -5,6 +5,8 @@ require "lrama/counterexamples"
require "lrama/digraph"
require "lrama/grammar"
require "lrama/lexer"
+require "lrama/option_parser"
+require "lrama/options"
require "lrama/output"
require "lrama/parser"
require "lrama/report"
diff --git a/tool/lrama/lib/lrama/command.rb b/tool/lrama/lib/lrama/command.rb
index 45670ae405..39e3c3665b 100644
--- a/tool/lrama/lib/lrama/command.rb
+++ b/tool/lrama/lib/lrama/command.rb
@@ -1,53 +1,34 @@
-require 'optparse'
-
module Lrama
class Command
- def initialize(argv)
- @argv = argv
-
- @skeleton = "bison/yacc.c"
- @header = false
- @header_file = nil
- @report = []
- @report_file = nil
- @outfile = "y.tab.c"
- @trace = []
- @error_recovery = false
- @grammar_file = nil
- @report_file = nil
- @trace_opts = nil
- @report_opts = nil
- end
+ def run(argv)
+ options = OptionParser.new.parse(argv)
- def run
- parse_option
-
- Report::Duration.enable if @trace_opts[:time]
+ Report::Duration.enable if options.trace_opts[:time]
warning = Lrama::Warning.new
- grammar = Lrama::Parser.new(@y.read).parse
- @y.close if @y != STDIN
- states = Lrama::States.new(grammar, warning, trace_state: (@trace_opts[:automaton] || @trace_opts[:closure]))
+ grammar = Lrama::Parser.new(options.y.read).parse
+ options.y.close if options.y != STDIN
+ states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
states.compute
context = Lrama::Context.new(states)
- if @report_file
+ if options.report_file
reporter = Lrama::StatesReporter.new(states)
- File.open(@report_file, "w+") do |f|
- reporter.report(f, **@report_opts)
+ File.open(options.report_file, "w+") do |f|
+ reporter.report(f, **options.report_opts)
end
end
- File.open(@outfile, "w+") do |f|
+ File.open(options.outfile, "w+") do |f|
Lrama::Output.new(
out: f,
- output_file_path: @outfile,
- template_name: @skeleton,
- grammar_file_path: @grammar_file,
- header_file_path: @header_file,
+ output_file_path: options.outfile,
+ template_name: options.skeleton,
+ grammar_file_path: options.grammar_file,
+ header_file_path: options.header_file,
context: context,
grammar: grammar,
- error_recovery: @error_recovery,
+ error_recovery: options.error_recovery,
).render
end
@@ -55,108 +36,5 @@ module Lrama
exit 1
end
end
-
- private
-
- def validate_report(report)
- bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
- others = %w[verbose]
- list = bison_list + others
- not_supported = %w[cex none]
- h = { grammar: true }
-
- report.each do |r|
- if list.include?(r) && !not_supported.include?(r)
- h[r.to_sym] = true
- else
- raise "Invalid report option \"#{r}\"."
- end
- end
-
- if h[:all]
- (bison_list - not_supported).each do |r|
- h[r.to_sym] = true
- end
-
- h.delete(:all)
- end
-
- return h
- end
-
- def validate_trace(trace)
- list = %w[
- none locations scan parse automaton bitsets
- closure grammar resource sets muscles tools
- m4-early m4 skeleton time ielr cex all
- ]
- h = {}
-
- trace.each do |t|
- if list.include?(t)
- h[t.to_sym] = true
- else
- raise "Invalid trace option \"#{t}\"."
- end
- end
-
- return h
- end
-
- def parse_option
- opt = OptionParser.new
-
- # opt.on('-h') {|v| p v }
- opt.on('-V', '--version') {|v| puts "lrama #{Lrama::VERSION}"; exit 0 }
-
- # Tuning the Parser
- opt.on('-S', '--skeleton=FILE') {|v| @skeleton = v }
- opt.on('-t') { } # Do nothing
-
- # Output Files:
- opt.on('-h', '--header=[FILE]') {|v| @header = true; @header_file = v }
- opt.on('-d') { @header = true }
- opt.on('-r', '--report=THINGS', Array) {|v| @report = v }
- opt.on('--report-file=FILE') {|v| @report_file = v }
- opt.on('-v') { } # Do nothing
- opt.on('-o', '--output=FILE') {|v| @outfile = v }
-
- # Hidden
- opt.on('--trace=THINGS', Array) {|v| @trace = v }
-
- # Error Recovery
- opt.on('-e') {|v| @error_recovery = true }
-
- opt.parse!(@argv)
-
- @trace_opts = validate_trace(@trace)
- @report_opts = validate_report(@report)
-
- @grammar_file = @argv.shift
-
- if !@grammar_file
- abort "File should be specified\n"
- end
-
- if @grammar_file == '-'
- @grammar_file = @argv.shift or abort "File name for STDIN should be specified\n"
- @y = STDIN
- else
- @y = File.open(@grammar_file, 'r')
- end
-
- if !@report.empty? && @report_file.nil? && @grammar_file
- @report_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".output"
- end
-
- if !@header_file && @header
- case
- when @outfile
- @header_file = File.dirname(@outfile) + "/" + File.basename(@outfile, ".*") + ".h"
- when @grammar_file
- @header_file = File.dirname(@grammar_file) + "/" + File.basename(@grammar_file, ".*") + ".h"
- end
- end
- end
end
end
diff --git a/tool/lrama/lib/lrama/lexer.rb b/tool/lrama/lib/lrama/lexer.rb
index c591684a05..72ce90195f 100644
--- a/tool/lrama/lib/lrama/lexer.rb
+++ b/tool/lrama/lib/lrama/lexer.rb
@@ -213,19 +213,33 @@ module Lrama
string, line = lex_string(ss, "'", line, lines)
str << string
next
+
+ # $ references
+ # It need to wrap an identifier with brackets to use ".-" for identifiers
when ss.scan(/\$(<[a-zA-Z0-9_]+>)?\$/) # $$, $<long>$
tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
references << [:dollar, "$", tag, str.length, str.length + ss[0].length - 1]
when ss.scan(/\$(<[a-zA-Z0-9_]+>)?(\d+)/) # $1, $2, $<long>1
tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
references << [:dollar, Integer(ss[2]), tag, str.length, str.length + ss[0].length - 1]
- when ss.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_.][-a-zA-Z0-9_.]*)/) # $foo, $expr, $<long>program
+ when ss.scan(/\$(<[a-zA-Z0-9_]+>)?([a-zA-Z_][a-zA-Z0-9_]*)/) # $foo, $expr, $<long>program (named reference without brackets)
+ tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
+ references << [:dollar, ss[2], tag, str.length, str.length + ss[0].length - 1]
+ when ss.scan(/\$(<[a-zA-Z0-9_]+>)?\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # $expr.right, $expr-right, $<long>program (named reference with brackets)
tag = ss[1] ? create_token(Token::Tag, ss[1], line, str.length) : nil
references << [:dollar, ss[2], tag, str.length, str.length + ss[0].length - 1]
+
+ # @ references
+ # It need to wrap an identifier with brackets to use ".-" for identifiers
when ss.scan(/@\$/) # @$
references << [:at, "$", nil, str.length, str.length + ss[0].length - 1]
when ss.scan(/@(\d+)/) # @1
references << [:at, Integer(ss[1]), nil, str.length, str.length + ss[0].length - 1]
+ when ss.scan(/@([a-zA-Z][a-zA-Z0-9_]*)/) # @foo, @expr (named reference without brackets)
+ references << [:at, ss[1], nil, str.length, str.length + ss[0].length - 1]
+ when ss.scan(/@\[([a-zA-Z_.][-a-zA-Z0-9_.]*)\]/) # @expr.right, @expr-right (named reference with brackets)
+ references << [:at, ss[1], nil, str.length, str.length + ss[0].length - 1]
+
when ss.scan(/{/)
brace_count += 1
when ss.scan(/}/)
diff --git a/tool/lrama/lib/lrama/lexer/token.rb b/tool/lrama/lib/lrama/lexer/token.rb
index 4eca6f6007..a6180746cc 100644
--- a/tool/lrama/lib/lrama/lexer/token.rb
+++ b/tool/lrama/lib/lrama/lexer/token.rb
@@ -28,7 +28,13 @@ module Lrama
if lhs.referred_by?(ref_name)
'$'
else
- rhs.find_index {|token| token.referred_by?(ref_name) } + 1
+ index = rhs.find_index {|token| token.referred_by?(ref_name) }
+
+ if index
+ index + 1
+ else
+ raise "'#{ref_name}' is invalid name."
+ end
end
[ref[0], value, ref[2], ref[3], ref[4]]
else
diff --git a/tool/lrama/lib/lrama/option_parser.rb b/tool/lrama/lib/lrama/option_parser.rb
new file mode 100644
index 0000000000..d8ed62ee07
--- /dev/null
+++ b/tool/lrama/lib/lrama/option_parser.rb
@@ -0,0 +1,124 @@
+require 'optparse'
+
+module Lrama
+ # Handle option parsing for the command line interface.
+ class OptionParser
+ def initialize
+ @options = Options.new
+ @trace = []
+ @report = []
+ end
+
+ def parse(argv)
+ parse_by_option_parser(argv)
+
+ @options.trace_opts = validate_trace(@trace)
+ @options.report_opts = validate_report(@report)
+ @options.grammar_file = argv.shift
+
+ if !@options.grammar_file
+ abort "File should be specified\n"
+ end
+
+ if @options.grammar_file == '-'
+ @options.grammar_file = argv.shift or abort "File name for STDIN should be specified\n"
+ else
+ @options.y = File.open(@options.grammar_file, 'r')
+ end
+
+ if !@report.empty? && @options.report_file.nil? && @options.grammar_file
+ @options.report_file = File.dirname(@options.grammar_file) + "/" + File.basename(@options.grammar_file, ".*") + ".output"
+ end
+
+ if !@options.header_file && @options.header
+ case
+ when @options.outfile
+ @options.header_file = File.dirname(@options.outfile) + "/" + File.basename(@options.outfile, ".*") + ".h"
+ when @options.grammar_file
+ @options.header_file = File.dirname(@options.grammar_file) + "/" + File.basename(@options.grammar_file, ".*") + ".h"
+ end
+ end
+
+ @options
+ end
+
+ private
+
+ def parse_by_option_parser(argv)
+ ::OptionParser.new do |o|
+ o.banner = <<~BANNER
+ Lrama is LALR (1) parser generator written by Ruby.
+
+ Usage: lrama [options] FILE
+ BANNER
+ o.separator ''
+ o.separator 'Tuning the Parser:'
+ o.on('-S', '--skeleton=FILE', 'specify the skeleton to use') {|v| @options.skeleton = v }
+ o.on('-t', 'reserved, do nothing') { }
+ o.separator ''
+ o.separator 'Output:'
+ o.on('-h', '--header=[FILE]', 'also produce a header file named FILE') {|v| @options.header = true; @options.header_file = v }
+ o.on('-d', 'also produce a header file') { @options.header = true }
+ o.on('-r', '--report=THINGS', Array, 'also produce details on the automaton') {|v| @report = v }
+ o.on('--report-file=FILE', 'also produce details on the automaton output to a file named FILE') {|v| @options.report_file = v }
+ o.on('-o', '--output=FILE', 'leave output to FILE') {|v| @options.outfile = v }
+ o.on('--trace=THINGS', Array, 'also output trace logs at runtime') {|v| @trace = v }
+ o.on('-v', 'reserved, do nothing') { }
+ o.separator ''
+ o.separator 'Error Recovery:'
+ o.on('-e', 'enable error recovery') {|v| @options.error_recovery = true }
+ o.separator ''
+ o.separator 'Other options:'
+ o.on('-V', '--version', "output version information and exit") {|v| puts "lrama #{Lrama::VERSION}"; exit 0 }
+ o.on('--help', "display this help and exit") {|v| puts o; exit 0 }
+ o.separator ''
+ o.parse!(argv)
+ end
+ end
+
+ def validate_report(report)
+ bison_list = %w[states itemsets lookaheads solved counterexamples cex all none]
+ others = %w[verbose]
+ list = bison_list + others
+ not_supported = %w[cex none]
+ h = { grammar: true }
+
+ report.each do |r|
+ if list.include?(r) && !not_supported.include?(r)
+ h[r.to_sym] = true
+ else
+ raise "Invalid report option \"#{r}\"."
+ end
+ end
+
+ if h[:all]
+ (bison_list - not_supported).each do |r|
+ h[r.to_sym] = true
+ end
+
+ h.delete(:all)
+ end
+
+ return h
+ end
+
+ def validate_trace(trace)
+ list = %w[
+ none locations scan parse automaton bitsets
+ closure grammar resource sets muscles tools
+ m4-early m4 skeleton time ielr cex all
+ ]
+ h = {}
+
+ trace.each do |t|
+ if list.include?(t)
+ h[t.to_sym] = true
+ else
+ raise "Invalid trace option \"#{t}\"."
+ end
+ end
+
+ return h
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/options.rb b/tool/lrama/lib/lrama/options.rb
new file mode 100644
index 0000000000..01b3e701d9
--- /dev/null
+++ b/tool/lrama/lib/lrama/options.rb
@@ -0,0 +1,23 @@
+module Lrama
+ # Command line options.
+ class Options
+ attr_accessor :skeleton, :header, :header_file,
+ :report_file, :outfile,
+ :error_recovery, :grammar_file,
+ :report_file, :trace_opts, :report_opts, :y
+
+ def initialize
+ @skeleton = "bison/yacc.c"
+ @header = false
+ @header_file = nil
+ @report_file = nil
+ @outfile = "y.tab.c"
+ @error_recovery = false
+ @grammar_file = nil
+ @report_file = nil
+ @trace_opts = nil
+ @report_opts = nil
+ @y = STDIN
+ end
+ end
+end
diff --git a/tool/lrama/lib/lrama/version.rb b/tool/lrama/lib/lrama/version.rb
index 41215c1aee..fe695873e5 100644
--- a/tool/lrama/lib/lrama/version.rb
+++ b/tool/lrama/lib/lrama/version.rb
@@ -1,3 +1,3 @@
module Lrama
- VERSION = "0.5.5".freeze
+ VERSION = "0.5.6".freeze
end