diff options
Diffstat (limited to 'libexec/racc2y')
-rwxr-xr-x | libexec/racc2y | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/libexec/racc2y b/libexec/racc2y new file mode 100755 index 0000000000..f88d73ed2c --- /dev/null +++ b/libexec/racc2y @@ -0,0 +1,195 @@ +#!/usr/local/bin/ruby +# +# $Id$ +# +# Copyright (c) 1999-2006 Minero Aoki +# +# This program is feee software. +# You can distribute/modify this program under the terms of +# the GNU LGPL, Lesser General Public License version 2.1. +# For details of the LGPL, see the file "COPYING". +# + +require 'racc/grammarfileparser' +require 'racc/info' +require 'optparse' + +def main + @with_action = true + with_header = false + with_inner = false + with_footer = false + output = nil + parser = OptionParser.new + parser.banner = "Usage: #{File.basename($0)} [-AHIF] [-oFILENAME] GRAMMARFILE" + parser.on('-o', '--output=FILENAME', 'output file name [<input>.yacc]') {|name| + output = name + } + parser.on('-A', '--without-action', 'Does not include actions.') { + @with_action = false + } + parser.on('-H', '--with-header', 'Includes header part.') { + with_header = true + } + parser.on('-I', '--with-inner', 'Includes inner part.') { + with_inner = true + } + parser.on('-F', '--with-footer', 'Includes footer part.') { + with_footer = true + } + parser.on('--version', 'Prints version and quit.') { + puts "racc2y version #{Racc::Version}" + exit 0 + } + parser.on('--copyright', 'Prints copyright and quit.') { + puts Racc::Copyright + exit 0 + } + parser.on('--help', 'Prints this message and quit.') { + puts parser.help + exit 1 + } + begin + parser.parse! + rescue OptionParser::ParseError => err + $stderr.puts err.message + $stderr.puts parser.help + exit 1 + end + if ARGV.empty? + $stderr.puts "no input file" + exit 1 + end + unless ARGV.size == 1 + $stderr.puts "too many inputs" + exit 1 + end + input = ARGV[0] + + begin + result = Racc::GrammarFileParser.parse_file(input) + result.grammar.init + File.open(output || "#{input}.yacc", 'w') {|f| + f.puts "/* generated from #{input} */" + if with_header + f.puts + f.puts '%{' + print_user_codes f, result.params.header + f.puts '%}' + end + f.puts + print_terminals f, result.grammar + f.puts + print_precedence_table f, precedence_table(result.grammar) + f.puts + f.puts '%%' + print_grammar f, result.grammar + f.puts '%%' + if with_inner + f.puts '/*---- inner ----*/' + print_user_codes f, result.params.inner + end + if with_footer + f.puts '/*---- footer ----*/' + print_user_codes f, result.params.footer + end + } + rescue SystemCallError => err + $stderr.puts err.message + exit 1 + end +end + +def print_terminals(f, grammar) + init_indent = '%token'.size + f.print '%token' + columns = init_indent + grammar.symboltable.each_terminal do |t| + next unless t.terminal? + next if t.dummy? + next if t == grammar.symboltable.anchor + next if t == grammar.symboltable.error + unless t.value.kind_of?(String) + if columns > 60 + f.puts + f.print ' ' * init_indent + columns = init_indent + end + columns += f.write(" #{yacc_symbol(t)}") + end + end + f.puts +end + +def precedence_table(grammar) + table = [] + grammar.symboltable.select {|sym| sym.precedence }.each do |sym| + (table[sym.prec] ||= [sym.assoc]).push sym + end + table.compact +end + +def print_precedence_table(f, table) + return if table.empty? + f.puts '/* precedance table */' + table.each do |syms| + assoc = syms.shift + f.printf '%%%-8s ', assoc.to_s.downcase + f.puts syms.map {|s| yacc_symbol(s) }.join(' ') + end + f.puts +end + +def print_grammar(f, grammar) + prev_target = nil + indent = 10 + embactions = [] + grammar.each do |rule| + if rule.target.dummy? + embactions.push rule.action unless rule.action.empty? + next + end + if rule.target == prev_target + f.print ' ' * indent, '|' + else + prev_target = rule.target + f.printf "\n%-10s:", yacc_symbol(prev_target) + end + rule.symbols.each do |s| + if s.dummy? # target of dummy rule for embedded action + f.puts + print_action f, embactions.shift, indent + f.print ' ' * (indent + 1) + else + f.print ' ', yacc_symbol(s) + end + end + if rule.specified_prec + f.print ' %prec ', yacc_symbol(rule.specified_prec) + end + f.puts + unless rule.action.empty? + print_action f, rule.action, indent + end + end +end + +def print_action(f, action, indent) + return unless @with_action + f.print ' ' * (indent + 4), "{\n" + f.print ' ' * (indent + 6), action.source.text.strip, "\n" + f.print ' ' * (indent + 4) , "}\n" +end + +def print_user_codes(f, srcs) + return if srcs.empty? + srcs.each do |src| + f.puts src.text + end +end + +def yacc_symbol(s) + s.to_s.gsub('"', "'") +end + +main |