mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			195 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			195 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			Ruby
		
	
	
		
			Executable file
		
	
	
	
	
#!/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
 |