ruby/ext/ripper/tools/preproc.rb

125 строки
2.4 KiB
Ruby

# 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
require_relative 'dsl'
def generate_line(f, out)
while line = f.gets
case
when gen = DSL.line?(line, f.lineno)
out << gen.generate << "\n"
when line.start_with?("%%")
out << "%%\n"
break
else
out << yield(line)
end
end
end
def prelude(f, out)
@exprs = {}
generate_line(f, out) do |line|
if (/^enum lex_state_(?:bits|e) \{/ =~ line)..(/^\}/ =~ line)
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
line
end
end
def grammar(f, out)
generate_line(f, out) do |line|
case line
when %r</\*%%%\*/>
"#if 0\n"
when %r</\*%>
"#endif\n"
when %r<%\*/>
"\n"
else
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