1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
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 'STDIN mode:'
o.separator 'lrama [options] - FILE read grammar from STDIN'
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('-h=[FILE]', 'also produce a header file named FILE (deprecated)') {|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
|