#!/usr/local/bin/ruby

require 'racc/info'
require 'racc/grammar'
require 'racc/state'
require 'racc/output'


def openread( fn )
  fn = File.expand_path( fn )
  f = File.open( fn )
  ret = f.read
  f.close
  ret
end

module Racc


class LALRstate
  def sr_conflict( *args )
    bug! 'sr conflict in build'
  end
  def rr_conflict( *args )
    bug! 'sr conflict in build'
  end
end
    
class Compiler

  attr :ruletable
  attr :symboltable
  attr :statetable

  def filename() '(build)' end

  def debug_parser() @dflag end
  def convert_line() true end
  def omit_action()  true end
  def result_var()   true end

  def debug()   false end
  def d_parse() false end
  def d_rule()  false end
  def d_token() false end
  def d_state() false end
  def d_la()    false end
  def d_prec()  false end


  def r( targ, symlist, act )
    targ = @symboltable.get( targ ) if targ

    symlist.collect! do |i|
      bug! 'nil in symlist' unless i
      @symboltable.get(i)
    end
    act.sub!( /\A\s*\n/, '' )
    act.sub!( /\s+\z/, '' )

    /:(\d+)(?:\z|:)/ === caller(1)[0]
    lineno = $1.to_i + 1
    symlist.push UserAction.new( act, lineno )

    @ruletable.register_rule( targ, symlist )
  end


  def build( debugflag )
    @dflag = debugflag

    @symboltable = SymbolTable.new( self )
    @ruletable   = RuleTable.new( self )
    @statetable  = StateTable.new( self )

############
    # 1
    r :xclass, [ :XCLASS, :class, :params, :XRULE, :rules, :XEND ], %{
      @ruletable.end_register_rule
    }
############
    r :class, [ :rubyconst ], %{
      @class_name = val[0]
    }
    r nil, [ :rubyconst, '<', :rubyconst ], %{
      @class_name = val[0]
      @super_class = val[2]
    }
############
    r :rubyconst, [ :XSYMBOL ], %{
      result = result.id2name
    }
    r nil, [ :rubyconst, ':', ':', :XSYMBOL ], %{
      result << '::' << val[3].id2name
    }
############
    # 2
    r :params, [], ''
    # 3
    r nil, [ :params, :param_seg ], ''
############
    # 4
    r :param_seg, [ :XCONV, :convdefs, :XEND ], %{
      @symboltable.end_register_conv
    }
    # 5
    r nil, [ :xprec ], ''
    # 6
    r nil, [ :XSTART, :symbol ], %{
      @ruletable.register_start val[1]
    }
    # 7
    r nil, [ :XTOKEN, :symbol_list ], %{
      @symboltable.register_token val[1]
    }
    # 8
    r nil, [ :XOPTION, :bare_symlist ], %{
      val[1].each do |s|
        @ruletable.register_option s.to_s
      end
    }
    r nil, [ :XEXPECT, :DIGIT ], %{
      @ruletable.expect val[1]
    }
############
    # 7
    r :convdefs, [ :symbol, :STRING ], %{
      @symboltable.register_conv( val[0], val[1] )
    }
    # 8
    r nil, [ :convdefs, :symbol, :STRING ], %{
      @symboltable.register_conv( val[1], val[2] )
    }
############
    # 9
    r :xprec, [ :XPRECHIGH, :preclines, :XPRECLOW ], %{
      @symboltable.end_register_prec( true )
    }
    # 10
    r nil, [ :XPRECLOW, :preclines, :XPRECHIGH ], %{
      @symboltable.end_register_prec( false )
    }
############
    # 11
    r :preclines, [ :precline ], ''
    # 12
    r nil, [ :preclines, :precline ], ''
############
    # 13
    r :precline, [ :XLEFT, :symbol_list ], %{
      @symboltable.register_prec( :Left, val[1] )
    }
    # 14
    r nil, [ :XRIGHT, :symbol_list ], %{
      @symboltable.register_prec( :Right, val[1] )
    }
    # 15
    r nil, [ :XNONASSOC, :symbol_list ], %{
      @symboltable.register_prec( :Nonassoc, val[1] )
    }
############
    # 16
    r :symbol_list, [ :symbol ], %{
      result = val
    }
    # 17
    r nil, [ :symbol_list, :symbol ], %{
      result.push val[1]
    }
    r nil, [ :symbol_list, '|' ], ''
############
    # 18
    r :symbol, [ :XSYMBOL ], %{
      result = @symboltable.get( result )
    }
    # 19
    r nil,    [ :STRING ], %{
      result = @symboltable.get( eval '"' + val[0] + '"' )
    }
############
    # 20
    r :rules, [ :rules_core ], %{
      unless result.empty? then
        @ruletable.register_rule_from_array result
      end
    }
    # 21
    r nil, [], ''
############
    # 22
    r :rules_core, [ :symbol ], %{
      result = val
    }
    # 23
    r nil,         [ :rules_core, :rule_item ], %{
      result.push val[1]
    }
    # 24
    r nil,         [ :rules_core, ';' ], %{
      unless result.empty? then
        @ruletable.register_rule_from_array result
      end
      result.clear
    }
    # 25
    r nil,         [ :rules_core, ':' ], %{
      pre = result.pop
      unless result.empty? then
        @ruletable.register_rule_from_array result
      end
      result = [pre]
    }
############
    # 26
    r :rule_item, [ :symbol ], ''
    # 27
    r nil,        [ '|' ], %{
      result = OrMark.new( @scanner.lineno )
    }
    # 28
    r nil,        [ '=', :symbol ], %{
      result = Prec.new( val[1], @scanner.lineno )
    }
    # 29
    r nil,        [ :ACTION ], %{
      result = UserAction.new( *result )
    }
############
    r :bare_symlist, [ :XSYMBOL ], %{
      result = [ result.id2name ]
    }
    r nil,           [ :bare_symlist, :XSYMBOL ], %{
      result.push val[1].id2name
    }
############

    @ruletable.init
    @statetable.init
    @statetable.determine

    File.open( 'raccp.rb', 'w' ) do |f|
      f.write <<'HEADER_END'
#
# This file is automatically generated. DO NOT MODIFY!!
#
# raccp.rb
#
#   Copyright (c) 1999-2001 Minero Aoki <aamine@loveruby.net>
#
#   This program is free software.
#   You can distribute/modify this program under the terms of
#   the GNU Lesser General Public License version 2.
#

require 'racc/parser'
require 'racc/raccs'
require 'racc/ucodep'


module Racc

  class GrammarFileParser < Parser

    def initialize( racc )
      @yydebug     = racc.d_parse && Racc_debug_parser
      @ruletable   = racc.ruletable
      @symboltable = racc.symboltable

      @class_name = nil
      @super_class = nil
    end

    attr :class_name
    attr :super_class

    def parse( str )
      @scanner = GrammarFileScanner.new( str )
      @scanner.debug = @yydebug

      do_parse
    end


    private

    def next_token
      @scanner.scan
    end

    def on_error( tok, val, _values )
      if val.respond_to? :id2name then
        v = val.id2name
      elsif String === val then
        v = val
      else
        v = val.inspect
      end
      raise ParseError, "#{@scanner.lineno}: unexpected token '#{v}'"
    end

HEADER_END
      fmt = CodeGenerator.new( self )
      fmt.output( f )
      f.write <<'FOOTER_END'
  end

end   # module Racc
FOOTER_END
    end

    ver = VerboseOutputter.new( self )
    File.open( 'b.output', 'w' ) do |f|
      ver.output( f )
    end
  end

end

end


de = false
ARGV.each do |i|
  case i
  when '-g' then de = true
  end
end
Racc::Compiler.new.build de
