summaryrefslogtreecommitdiff
path: root/libexec/racc2y
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/racc2y')
-rwxr-xr-xlibexec/racc2y195
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