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
|
# frozen_string_literal: true
# $Id$
require 'optparse'
def main
output = nil
template = nil
parser = OptionParser.new
parser.banner = "Usage: #{File.basename($0)} [--output=PATH] [--template=PATH] <parse.y>"
parser.on('--output=PATH', 'An output file.') {|path|
output = path
}
parser.on('--template=PATH', 'An template file.') {|path|
template = path
}
parser.on('--help', 'Prints this message and quit.') {
puts parser.help
exit true
}
begin
parser.parse!
rescue OptionParser::ParseError => err
warn err.message
abort parser.help
end
out = "".dup
if ARGV[0] == "-"
unless ARGV.size == 2
abort "wrong number of arguments (#{ARGV.size} for 2)"
end
process STDIN, out, ARGV[1], template
else
unless ARGV.size == 1
abort "wrong number of arguments (#{ARGV.size} for 1)"
end
File.open(ARGV[0]) {|f|
process f, out, ARGV[0], template
}
end
if output
File.write(output, out)
else
print out
end
end
def process(f, out, path, template)
prelude f, out
grammar f, out
usercode f, out, path, template
end
def prelude(f, out)
@exprs = {}
lex_state_def = false
while line = f.gets
case line
when /\A%%/
out << "%%\n"
return
when /\A%token/, /\A} <node>/
out << line.sub(/<\w+>/, '<val>')
when /\A%type/
out << line.sub(/<\w+>/, '<val>')
when /^enum lex_state_(?:bits|e) \{/
lex_state_def = true
out << line
when /^\}/
lex_state_def = false
out << line
else
out << line
end
if lex_state_def
case line
when /^\s*(EXPR_\w+),\s+\/\*(.+)\*\//
@exprs[$1.chomp("_bit")] = $2.strip
when /^\s*(EXPR_\w+)\s+=\s+(.+)$/
name = $1
val = $2.chomp(",")
@exprs[name] = "equals to " + (val.start_with?("(") ? "<tt>#{val}</tt>" : "+#{val}+")
end
end
end
end
require_relative "dsl"
def grammar(f, out)
while line = f.gets
case line
when %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
out << DSL.new($2, ($1 || "").split(",")).generate << "\n"
when %r</\*%%%\*/>
out << "#if 0\n"
when %r</\*%>
out << "#endif\n"
when %r<%\*/>
out << "\n"
when /\A%%/
out << "%%\n"
return
else
out << line
end
end
end
def usercode(f, out, path, template)
require 'erb'
lineno = nil
src = nil
compiler = ERB::Compiler.new('%-')
compiler.put_cmd = compiler.insert_cmd = "out.<<"
if template
File.open(template) do |f|
out.clear
lineno = f.lineno
src, = compiler.compile(f.read)
path = template
end
else
lineno = f.lineno
src, = compiler.compile(f.read)
end
eval(src, binding, path, lineno)
end
main
|