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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
require 'optparse'
module Lrama
class Command
def run(argv)
opt = OptionParser.new
# opt.on('-h') {|v| p v }
opt.on('-V', '--version') {|v| puts Lrama::VERSION ; exit 0 }
# Tuning the Parser
skeleton = "bison/yacc.c"
opt.on('-S', '--skeleton=FILE') {|v| skeleton = v }
opt.on('-t') { } # Do nothing
# Output Files:
header = false
header_file = nil
report = []
report_file = nil
outfile = "y.tab.c"
opt.on('-h', '--header=[FILE]') {|v| header = true; header_file = v }
opt.on('-d') { header = true }
opt.on('-r', '--report=THINGS') {|v| report = v.split(',') }
opt.on('--report-file=FILE') {|v| report_file = v }
opt.on('-v') { } # Do nothing
opt.on('-o', '--output=FILE') {|v| outfile = v }
# Hidden
trace = []
opt.on('--trace=THINGS') {|v| trace = v.split(',') }
# Error Recovery
error_recovery = false
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 !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
if !grammar_file
puts "File should be specified\n"
exit 1
end
Report::Duration.enable if trace_opts[:time]
warning = Lrama::Warning.new
y = File.read(grammar_file)
grammar = Lrama::Parser.new(y).parse
states = Lrama::States.new(grammar, warning, trace_state: (trace_opts[:automaton] || trace_opts[:closure]))
states.compute
context = Lrama::Context.new(states)
if report_file
reporter = Lrama::StatesReporter.new(states)
File.open(report_file, "w+") do |f|
reporter.report(f, **report_opts)
end
end
File.open(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,
context: context,
grammar: grammar,
).render
end
if warning.has_error?
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[counterexamples 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
|