[前][次][番号順一覧][スレッド一覧]

ruby-changes:2960

From: ko1@a...
Date: 22 Dec 2007 10:34:19 +0900
Subject: [ruby-changes:2960] ko1 - Ruby:r14451 (trunk): * tool/insns2vm.rb: moved from lib/vm/instruction.rb.

ko1	2007-12-22 10:34:09 +0900 (Sat, 22 Dec 2007)

  New Revision: 14451

  Added files:
    trunk/tool/instruction.rb
  Removed files:
    trunk/lib/vm/instruction.rb
  Modified files:
    trunk/ChangeLog
    trunk/tool/insns2vm.rb

  Log:
    * tool/insns2vm.rb: moved from lib/vm/instruction.rb.
    


  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14451&r2=14450
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/tool/insns2vm.rb?r1=14451&r2=14450
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/tool/instruction.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/vm/instruction.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 14450)
+++ ChangeLog	(revision 14451)
@@ -1,3 +1,7 @@
+Sat Dec 22 10:30:45 2007  Koichi Sasada  <ko1@a...>
+
+	* tool/insns2vm.rb: moved from lib/vm/instruction.rb.
+
 Sat Dec 22 10:25:44 2007  Yukihiro Matsumoto  <matz@r...>
 
 	* parse.y (reg_named_capture_assign_iter): captured name should
Index: lib/vm/instruction.rb
===================================================================
--- lib/vm/instruction.rb	(revision 14450)
+++ lib/vm/instruction.rb	(revision 14451)
@@ -1,1381 +0,0 @@
-#
-#
-#
-
-require 'erb'
-
-module RubyVM
-  class Instruction
-    def initialize name, opes, pops, rets, comm, body, tvars, sp_inc,
-                   orig = self, defopes = [], type = nil,
-                   nsc = [], psc = [[], []]
-
-      @name = name
-      @opes = opes # [[type, name], ...]
-      @pops = pops # [[type, name], ...]
-      @rets = rets # [[type, name], ...]
-      @comm = comm # {:c => category, :e => en desc, :j => ja desc}
-      @body = body # '...'
-
-      @orig    = orig
-      @defopes = defopes
-      @type    = type
-      @tvars   = tvars
-
-      @nextsc = nsc
-      @pushsc = psc
-      @sc     = []
-      @unifs  = []
-      @optimized = []
-      @is_sc  = false
-      @sp_inc = sp_inc
-    end
-
-    def add_sc sci
-      @sc << sci
-      sci.set_sc
-    end
-    
-    attr_reader :name, :opes, :pops, :rets
-    attr_reader :body, :comm
-    attr_reader :nextsc, :pushsc
-    attr_reader :orig, :defopes, :type
-    attr_reader :sc
-    attr_reader :unifs, :optimized
-    attr_reader :is_sc
-    attr_reader :tvars
-    attr_reader :sp_inc
-    
-    def set_sc
-      @is_sc = true
-    end
-    
-    def add_unif insns
-      @unifs << insns
-    end
-
-    def add_optimized insn
-      @optimized << insn
-    end
-
-    def sp_increase_c_expr
-      if(pops.any?{|t, v| v == '...'} ||
-         rets.any?{|t, v| v == '...'})
-        # user definision
-        raise "no sp increase definition" if @sp_inc.nil?
-        ret = "int inc = 0;\n"
-
-        @opes.each_with_index{|(t, v), i|
-          if t == 'rb_num_t'
-            ret << "        unsigned long #{v} = FIX2INT(opes[#{i}]);\n"
-          end
-        }
-        @defopes.each_with_index{|((t, var), val), i|
-          if t == 'rb_num_t' && val != '*'
-            ret << "        unsigned long #{var} = #{val};\n"
-          end
-        }
-
-        ret << "        #{@sp_inc};\n"
-        ret << "        return depth + inc;"
-        ret
-      else
-        "return depth + #{rets.size - pops.size};"
-      end
-    end
-    
-    def inspect
-      "#<Instruction:#{@name}>"
-    end
-  end
-
-  class InstructionsLoader
-    def initialize opts = {}
-      @insns    = []
-      @insn_map = {}
-
-      @vpath = opts[:VPATH] || File
-      @use_const = opts[:use_const]
-      @verbose   = opts[:verbose]
-      @destdir   = opts[:destdir]
-
-      (@vm_opts = load_vm_opts).each {|k, v|
-        @vm_opts[k] = opts[k] if opts.key?(k)
-      }
-
-      load_insns_def opts[:"insns.def"] || 'insns.def'
-
-      load_opt_operand_def opts[:"opope.def"] || 'opt_operand.def'
-      load_insn_unification_def opts[:"unif.def"] || 'opt_insn_unif.def'
-      make_stackcaching_insns if vm_opt?('STACK_CACHING')
-    end
-
-    attr_reader :vpath
-    attr_reader :destdir
-  
-    %w[use_const verbose].each do |attr|
-      attr_reader attr
-      alias_method "#{attr}?", attr
-      remove_method attr
-    end
-
-    def [](s)
-      @insn_map[s.to_s]
-    end
-
-    def each
-      @insns.each{|insn|
-        yield insn
-      }
-    end
-
-    def size
-      @insns.size
-    end
-
-    ###
-    private
-
-    def vm_opt? name
-      @vm_opts[name]
-    end
-
-    def load_vm_opts file = nil
-      file ||= 'vm_opts.h'
-      opts = {}
-      vpath.open(file) do |f|
-        f.grep(/^\#define\s+OPT_([A-Z_]+)\s+(\d+)/) do
-          opts[$1] = !$2.to_i.zero?
-        end
-      end
-      opts
-    end
-
-    SKIP_COMMENT_PATTERN = Regexp.compile(Regexp.escape('/** ##skip'))
-
-    include Enumerable
-
-    def add_insn insn
-      @insns << insn
-      @insn_map[insn.name] = insn
-    end
-
-    def make_insn name, opes, pops, rets, comm, body, sp_inc
-      add_insn Instruction.new(name, opes, pops, rets, comm, body, [], sp_inc)
-    end
-
-    # str -> [[type, var], ...]
-    def parse_vars line
-      raise unless /\((.*?)\)/ =~ line
-      vars = $1.split(',')
-      vars.map!{|v|
-        if /\s*(\S+)\s+(\S+)\s*/ =~ v
-          type = $1
-          var  = $2
-        elsif /\s*\.\.\.\s*/ =~ v
-          type = var  = '...'
-        else
-          raise
-        end
-        [type, var]
-      }
-      vars
-    end
-
-    def parse_comment comm
-      c = 'others'
-      j = ''
-      e = ''
-      comm.each_line{|line|
-        case line
-        when /@c (.+)/
-          c = $1
-        when /@e (.+)/
-          e = $1
-        when /@e\s*$/
-          e = ''
-        when /@j (.+)$/
-          j = $1
-        when /@j\s*$/
-          j = ''
-        end
-      }
-      { :c => c,
-        :e => e,
-        :j => j,
-      }
-    end
-
-    def load_insns_def file
-      body = insn = opes = pops = rets = nil
-      comment = ''
-
-      vpath.open(file) {|f|
-        f.instance_variable_set(:@line_no, 0)
-        class << f
-          def line_no
-            @line_no
-          end
-          def gets
-            @line_no += 1
-            super
-          end
-        end
-
-        while line = f.gets
-          line.chomp!
-          case line
-
-          when SKIP_COMMENT_PATTERN
-            while line = f.gets.chomp
-              if /\s+\*\/$/ =~ line
-                break
-              end
-            end
-
-            # collect instruction comment
-          when /^\/\*\*$/
-            while line = f.gets
-              if /\s+\*\/\s*$/ =~ line
-                break
-              else
-                comment << line
-              end
-            end
-
-            # start instruction body
-          when /^DEFINE_INSN$/
-            insn = f.gets.chomp
-            opes = parse_vars(f.gets.chomp)
-            pops = parse_vars(f.gets.chomp).reverse
-            rets_str = f.gets.chomp
-            rets = parse_vars(rets_str).reverse
-            comment = parse_comment(comment)
-            insn_in = true
-            body    = ''
-
-            sp_inc = rets_str[%r"//\s*(.+)", 1]
-
-            raise unless /^\{$/ =~ f.gets.chomp
-            line_no = f.line_no
-
-          # end instruction body
-          when /^\}/
-            if insn_in
-              body.instance_variable_set(:@line_no, line_no)
-              body.instance_variable_set(:@file, f.path)
-              insn = make_insn(insn, opes, pops, rets, comment, body, sp_inc)
-              insn_in = false
-              comment = ''
-            end
-
-          else
-            if insn_in
-              body << line + "\n"
-            end
-          end
-        end
-      }
-    end
-
-    ## opt op
-    def load_opt_operand_def file
-      vpath.foreach(file) {|line|
-        line = line.gsub(/\#.*/, '').strip
-        next  if line.length == 0
-        break if /__END__/ =~ line
-        /(\S+)\s+(.+)/ =~ line
-        insn = $1
-        opts = $2
-        add_opt_operand insn, opts.split(/,/).map{|e| e.strip}
-      } if file
-    end
-
-    def label_escape label
-      label.gsub(/\(/, '_O_').
-      gsub(/\)/, '_C_').
-      gsub(/\*/, '_WC_')
-    end
-
-    def add_opt_operand insn_name, opts
-      insn = @insn_map[insn_name]
-      opes = insn.opes
-
-      if opes.size != opts.size
-        raise "operand size mismatcvh for #{insn.name} (opes: #{opes.size}, opts: #{opts.size})"
-      end
-
-      ninsn = insn.name + '_OP_' + opts.map{|e| label_escape(e)}.join('_')
-      nopes = []
-      defv  = []
-
-      opts.each_with_index{|e, i|
-        if e == '*'
-          nopes << opes[i]
-        end
-        defv  << [opes[i], e]
-      }
-
-      make_insn_operand_optimiized(insn, ninsn, nopes, defv)
-    end
-
-    def make_insn_operand_optimiized orig_insn, name, opes, defopes
-      comm = orig_insn.comm.dup
-      comm[:c] = 'optimize'
-      add_insn insn = Instruction.new(
-        name, opes, orig_insn.pops, orig_insn.rets, comm,
-        orig_insn.body, orig_insn.tvars, orig_insn.sp_inc,
-        orig_insn, defopes)
-      orig_insn.add_optimized insn
-    end
-
-    ## insn unif
-    def load_insn_unification_def file
-      vpath.foreach(file) {|line|
-        line = line.gsub(/\#.*/, '').strip
-        next  if line.length == 0
-        break if /__END__/ =~ line
-        make_unified_insns line.split.map{|e|
-          raise "unknown insn: #{e}" unless @insn_map[e]
-          @insn_map[e]
-        }
-      } if file
-    end
-
-    def all_combination sets
-      ret = sets.shift.map{|e| [e]}
-
-      sets.each{|set|
-        prev = ret
-        ret  = []
-        prev.each{|ary|
-          set.each{|e|
-            eary = ary.dup
-            eary << e
-            ret  << eary
-          }
-        }
-      }
-      ret
-    end
-
-    def make_unified_insns insns
-      if vm_opt?('UNIFY_ALL_COMBINATION')
-        insn_sets = insns.map{|insn|
-          [insn] + insn.optimized
-        }
-
-        all_combination(insn_sets).each{|insns_set|
-          make_unified_insn_each insns_set
-        }
-      else
-        make_unified_insn_each insns
-      end
-    end
-
-    def mk_private_val vals, i, redef
-      vals.dup.map{|v|
-        # v[0] : type
-        # v[1] : var name
-
-        v = v.dup
-        if v[0] != '...'
-          redef[v[1]] = v[0]
-          v[1] = "#{v[1]}_#{i}"
-        end
-        v
-      }
-    end
-
-    def mk_private_val2 vals, i, redef
-      vals.dup.map{|v|
-        # v[0][0] : type
-        # v[0][1] : var name
-        # v[1] : default val
-
-        pv = v.dup
-        v = pv[0] = pv[0].dup
-        if v[0] != '...'
-          redef[v[1]] = v[0]
-          v[1] = "#{v[1]}_#{i}"
-        end
-        pv
-      }
-    end
-
-    def make_unified_insn_each insns
-      names = []
-      opes = []
-      pops = []
-      rets = []
-      comm = {
-        :c => 'optimize',
-        :e => 'unified insn',
-        :j => 'unified insn',
-      }
-      body = ''
-      passed = []
-      tvars = []
-      defopes = []
-      sp_inc = ''
-
-      insns.each_with_index{|insn, i|
-        names << insn.name
-        redef_vars = {}
-
-        e_opes = mk_private_val(insn.opes, i, redef_vars)
-        e_pops = mk_private_val(insn.pops, i, redef_vars)
-        e_rets = mk_private_val(insn.rets, i, redef_vars)
-        # ToDo: fix it
-        e_defs = mk_private_val2(insn.defopes, i, redef_vars)
-
-        passed_vars = []
-        while pvar = e_pops.pop
-          rvar = rets.pop
-          if rvar
-            raise "unsupported unif insn: #{insns.inspect}" if rvar[0] == '...'
-            passed_vars << [pvar, rvar]
-            tvars << rvar
-          else
-            e_pops.push pvar
-            break
-          end
-        end
-
-        opes.concat e_opes
-        pops.concat e_pops
-        rets.concat e_rets
-        defopes.concat e_defs
-        sp_inc += "#{insn.sp_inc}"
-
-        body += "{ /* unif: #{i} */\n" +
-                passed_vars.map{|rpvars|
-                  pv = rpvars[0]
-                  rv = rpvars[1]
-                  "#define #{pv[1]} #{rv[1]}"
-                }.join("\n") +
-                "\n" + 
-                redef_vars.map{|v, type|
-                  "#define #{v} #{v}_#{i}"
-                }.join("\n") + "\n" +
-                insn.body +
-                passed_vars.map{|rpvars|
-                  "#undef #{rpvars[0][1]}"
-                }.join("\n") +
-                "\n" +
-                redef_vars.keys.map{|v|
-                  "#undef  #{v}"
-                }.join("\n") +
-                "\n}\n"
-      }
-
-      tvars_ary = []
-      tvars.each{|tvar|
-        unless opes.any?{|var|
-          var[1] == tvar[1]
-        } || defopes.any?{|pvar|
-          pvar[0][1] == tvar[1]
-        }
-          tvars_ary << tvar
-        end
-      }
-      add_insn insn = Instruction.new("UNIFIED_" + names.join('_'),
-                                   opes, pops, rets.reverse, comm, body,
-                                   tvars_ary, sp_inc)
-      insn.defopes.replace defopes
-      insns[0].add_unif [insn, insns]
-    end
-
-    ## sc
-    SPECIAL_INSN_FOR_SC_AFTER = {
-      /\Asend/      => [:a],
-      /\Aend/       => [:a],
-      /\Ayield/     => [:a],
-      /\Aclassdef/  => [:a],
-      /\Amoduledef/ => [:a],
-    }
-    FROM_SC = [[], [:a], [:b], [:a, :b], [:b, :a]]
-
-    def make_stackcaching_insns
-      pops = rets = nil
-
-      @insns.dup.each{|insn|
-        opops = insn.pops
-        orets = insn.rets
-        oopes = insn.opes
-        ocomm = insn.comm
-
-        after = nil
-        SPECIAL_INSN_FOR_SC_AFTER.any?{|k, v|
-          if k =~ insn.name
-            after = v
-            break
-          end
-        }
-
-        insns = []
-        FROM_SC.each{|from|
-          name, pops, rets, pushs1, pushs2, nextsc =
-          *calc_stack(insn, from, after, opops, orets)
-
-          make_insn_sc(insn, name, oopes, pops, rets, [pushs1, pushs2], nextsc)
-        }
-      }
-    end
-
-    def make_insn_sc orig_insn, name, opes, pops, rets, pushs, nextsc
-      comm = orig_insn.comm.dup
-      comm[:c] = 'optimize(sc)'
-
-      scinsn = Instruction.new(
-        name, opes, pops, rets, comm,
-        orig_insn.body, orig_insn.tvars, orig_insn.sp_inc,
-        orig_insn, orig_insn.defopes, :sc, nextsc, pushs)
-
-      add_insn scinsn
-      orig_insn.add_sc scinsn
-    end
-
-    def self.complement_name st
-      "#{st[0] ? st[0] : 'x'}#{st[1] ? st[1] : 'x'}"
-    end
-
-    def add_stack_value st
-      len = st.length
-      if len == 0
-        st[0] = :a
-        [nil, :a]
-      elsif len == 1
-        if st[0] == :a
-          st[1] = :b
-        else
-          st[1] = :a
-        end
-        [nil, st[1]]
-      else
-        st[0], st[1] = st[1], st[0]
-        [st[1], st[1]]
-      end
-    end
-
-    def calc_stack insn, ofrom, oafter, opops, orets
-      from = ofrom.dup
-      pops = opops.dup
-      rets = orets.dup
-      rest_scr = ofrom.dup
-
-      pushs_before = []
-      pushs= []
-
-      pops.each_with_index{|e, i|
-        if e[0] == '...'
-          pushs_before = from
-          from = []
-        end
-        r = from.pop
-        break unless r
-        pops[i] = pops[i].dup << r
-      }
-
-      if oafter
-        from = oafter
-        from.each_with_index{|r, i|
-          rets[i] = rets[i].dup << r if rets[i]
-        }
-      else
-        rets = rets.reverse
-        rets.each_with_index{|e, i|
-          break if e[0] == '...'
-          pushed, r = add_stack_value from
-          rets[i] = rets[i].dup << r
-          if pushed
-            if rest_scr.pop
-              pushs << pushed
-            end
-
-            if i - 2 >= 0
-              rets[i-2].pop
-            end
-          end
-        }
-      end
-
-      if false #|| insn.name =~ /test3/
-        p ofrom
-        p pops
-        p rets
-        p pushs_before
-        p pushs
-        p from
-        exit
-      end
-
-      ret = ["#{insn.name}_SC_#{InstructionsLoader.complement_name(ofrom)}_#{complement_name(from)}",
-            pops, rets, pushs_before, pushs, from]
-    end
-  end
-
-  class SourceCodeGenerator
-    def initialize insns
-      @insns = insns
-    end
-
-    attr_reader :insns
-
-    def generate
-      raise "should not reach here"
-    end
-
-    def vpath
-      @insns.vpath
-    end
-
-    def verbose?
-      @insns.verbose?
-    end
-
-    def use_const?
-      @insns.use_const?
-    end
-
-    def build_string
-      @lines = []
-      yield
-      @lines.join("\n")
-    end
-
-    EMPTY_STRING = ''.freeze
-
-    def commit str = EMPTY_STRING
-      @lines << str
-    end
-
-    def comment str
-      @lines << str if verbose?
-    end
-
-    def output_path(fn)
-      d = @insns.destdir
-      fn = File.join(d, fn) if d
-      fn
-    end
-  end
-
-  ###################################################################
-  # vm.inc
-  class VmBodyGenerator < SourceCodeGenerator
-    # vm.inc
-    def generate
-      vm_body = ''
-      @insns.each{|insn|
-        vm_body << "\n"
-        vm_body << make_insn_def(insn)
-      }
-      src = vpath.read('template/vm.inc.tmpl')
-      ERB.new(src).result(binding)
-    end
-
-    def generate_from_insnname insnname
-      make_insn_def @insns[insnname.to_s]
-    end
-
-    #######
-    private
-
-    def make_header_prepare_stack insn
-      comment "  /* prepare stack status */"
-
-      push_ba = insn.pushsc
-      raise "unsupport" if push_ba[0].size > 0 && push_ba[1].size > 0
-
-      push_ba.each{|pushs|
-        pushs.each{|r|
-          commit "  PUSH(SCREG(#{r}));"
-        }
-      }
-    end
-  
-    def make_header_operands insn
-      comment "  /* declare and get from iseq */"
-
-      vars = insn.opes
-      n = 0
-      ops = []
-
-      vars.each_with_index{|(type, var), i|
-        if type == '...'
-          break
-        end
-
-        ops << "  #{type} #{var} = (#{type})GET_OPERAND(#{i+1});"
-        n   += 1
-      }
-      @opn = n
-
-      # reverse or not?
-      # ops.join
-      commit ops.reverse
-    end
-  
-    def make_header_default_operands insn
-      vars = insn.defopes
-
-      vars.each{|e|
-        next if e[1] == '*'
-        if use_const?
-          commit "  const #{e[0][0]} #{e[0][1]} = #{e[1]};"
-        else
-          commit "  #define #{e[0][1]} #{e[1]}"
-        end
-      }
-    end
-
-    def make_footer_default_operands insn
-      comment " /* declare and initialize default opes */"
-      if use_const?
-        commit
-      else
-        vars = insn.defopes
-
-        vars.each{|e|
-          next if e[1] == '*'
-          commit "#undef #{e[0][1]}"
-        }
-      end
-    end
-
-    def make_header_stack_pops insn
-      comment "  /* declare and pop from stack */"
-
-      n = 0
-      pops = []
-      vars = insn.pops
-      vars.each_with_index{|iter, i|
-        type, var, r = *iter
-        if type == '...'
-          break
-        end
-        if r
-          pops << "  #{type} #{var} = SCREG(#{r});"
-        else
-          pops << "  #{type} #{var} = TOPN(#{n});"
-          n += 1
-        end
-      }
-      @popn = n
-
-      # reverse or not?
-      commit pops.reverse
-    end
-
-    def make_header_temporary_vars insn
-      comment "  /* declare temporary vars */"
-
-      insn.tvars.each{|var|
-        commit "  #{var[0]} #{var[1]};"
-      }
-    end
-
-    def make_header_stack_val insn
-      comment "/* declare stack push val */"
-
-      vars = insn.opes + insn.pops + insn.defopes.map{|e| e[0]}
-
-      insn.rets.each{|var|
-        if vars.all?{|e| e[1] != var[1]} && var[1] != '...'
-          commit "  #{var[0]} #{var[1]};"
-        end
-      }
-    end
-
-    def make_header_analysis insn
-      commit "  USAGE_ANALYSIS_INSN(BIN(#{insn.name}));"
-      insn.opes.each_with_index{|op, i|
-        commit "  USAGE_ANALYSIS_OPERAND(BIN(#{insn.name}), #{i}, #{op[1]});"
-      }
-    end
-
-    def make_header_pc insn
-      commit  "  ADD_PC(1+#{@opn});"
-      commit  "  PREFETCH(GET_PC());"
-    end
-
-    def make_header_popn insn
-      comment "  /* management */"
-      commit  "  POPN(#{@popn});" if @popn > 0
-    end
-
-    def make_hader_debug insn
-      comment "  /* for debug */"
-      commit  "  DEBUG_ENTER_INSN(\"#{insn.name}\");"
-    end
-
-    def make_header_defines insn
-      commit  "  #define CURRENT_INSN_#{insn.name} 1"
-      commit  "  #define INSN_IS_SC()     #{insn.sc ? 0 : 1}"
-      commit  "  #define INSN_LABEL(lab)  LABEL_#{insn.name}_##lab"
-      commit  "  #define LABEL_IS_SC(lab) LABEL_##lab##_###{insn.sc.size == 0 ? 't' : 'f'}"
-    end
-
-    def make_footer_stack_val insn
-      comment "  /* push stack val */"
-
-      insn.rets.reverse_each{|v|
-        if v[1] == '...'
-          break
-        end
-        if v[2]
-          commit "  SCREG(#{v[2]}) = #{v[1]};"
-        else
-          commit "  PUSH(#{v[1]});"
-        end
-      }
-    end
-
-    def make_footer_undefs insn
-      commit "#undef CURRENT_INSN_#{insn.name}"
-      commit "#undef INSN_IS_SC"
-      commit "#undef INSN_LABEL"
-      commit "#undef LABEL_IS_SC"
-    end
-
-    def make_header insn
-      commit "INSN_ENTRY(#{insn.name}){"
-      make_header_prepare_stack insn
-      commit "{"
-      make_header_stack_val  insn
-      make_header_default_operands insn
-      make_header_operands   insn
-      make_header_stack_pops insn
-      make_header_temporary_vars insn
-      #
-      make_hader_debug insn
-      make_header_pc insn
-      make_header_popn insn
-      make_header_defines insn
-      make_header_analysis insn
-      commit  "{"
-    end
-
-    def make_footer insn
-      make_footer_stack_val insn
-      make_footer_default_operands insn
-      make_footer_undefs insn
-      commit "  END_INSN(#{insn.name});}}}"
-    end
-
-    def make_insn_def insn
-      build_string do
-        make_header insn
-        if line = insn.body.instance_variable_get(:@line_no)
-          file = insn.body.instance_variable_get(:@file)
-          commit "#line #{line+1} \"#{file}\""
-          commit insn.body
-          commit '#line __CURRENT_LINE__ "__CURRENT_FILE__"'
-        else
-          insn.body
-        end
-        make_footer(insn)
-      end
-    end
-  end
-
-  ###################################################################
-  # vmtc.inc
-  class VmTCIncGenerator < SourceCodeGenerator
-    def generate
-
-      insns_table = build_string do
-        @insns.each{|insn|
-          commit "  LABEL_PTR(#{insn.name}),"
-        }
-      end
-
-      insn_end_table = build_string do
-        @insns.each{|insn|
-          commit "  ELABEL_PTR(#{insn.name}),\n"
-        }
-      end
-    
-      ERB.new(vpath.read('template/vmtc.inc.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # insns_info.inc
-  class InsnsInfoIncGenerator < SourceCodeGenerator
-    def generate
-      insns_info_inc
-    end
-
-    ###
-    private
-
-    def op2typesig op
-      case op
-      when /^OFFSET/
-        "TS_OFFSET"
-      when /^rb_num_t/
-        "TS_NUM"
-      when /^lindex_t/
-        "TS_LINDEX"
-      when /^dindex_t/
-        "TS_DINDEX"
-      when /^VALUE/
-        "TS_VALUE"
-      when /^ID/
-        "TS_ID"
-      when /GENTRY/
-        "TS_GENTRY"
-      when /^IC/
-        "TS_IC"
-      when /^\.\.\./
-        "TS_VARIABLE"
-      when /^CDHASH/
-        "TS_CDHASH"
-      when /^ISEQ/
-        "TS_ISEQ"
-      when /rb_insn_func_t/
-        "TS_FUNCPTR"
-      else
-        raise "unknown op type: #{op}"
-      end
-    end
-
-    TYPE_CHARS = {
-      'TS_OFFSET'    => 'O',
-      'TS_NUM'       => 'N',
-      'TS_LINDEX'    => 'L',
-      'TS_DINDEX'    => 'D',
-      'TS_VALUE'     => 'V',
-      'TS_ID'        => 'I',
-      'TS_GENTRY'    => 'G',
-      'TS_IC'        => 'C',
-      'TS_CDHASH'    => 'H',
-      'TS_ISEQ'      => 'S',
-      'TS_VARIABLE'  => '.',
-      'TS_FUNCPTR'   => 'F',
-    }
-
-    # insns_info.inc
-    def insns_info_inc
-      # insn_type_chars
-      insn_type_chars = TYPE_CHARS.map{|t, c|
-        "#define #{t} '#{c}'"
-      }.join("\n")
-
-      # insn_names
-      insn_names = ''
-      @insns.each{|insn|
-        insn_names << "  \"#{insn.name}\",\n"
-      }
-
-      # operands info
-      operands_info = ''
-      operands_num_info = ''
-      @insns.each{|insn|
-        opes = insn.opes
-        operands_info << '  '
-        ot = opes.map{|type, var|
-          TYPE_CHARS.fetch(op2typesig(type))
-        }
-        operands_info << "\"#{ot.join}\"" << ", \n"
-
-        num = opes.size + 1
-        operands_num_info << "  #{num},\n"
-      }
-
-      # stack num
-      stack_num_info = ''
-      @insns.each{|insn|
-        num = insn.rets.size
-        stack_num_info << "  #{num},\n"
-      }
-
-      # stack increase
-      stack_increase = ''
-      @insns.each{|insn|
-        stack_increase << <<-EOS
-        case BIN(#{insn.name}):{
-          #{insn.sp_increase_c_expr}
-        }
-        EOS
-      }
-      ERB.new(vpath.read('template/insns_info.inc.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # insns.inc
-  class InsnsIncGenerator < SourceCodeGenerator
-    def generate
-      i=0
-      insns = build_string do
-        @insns.each{|insn|
-          commit "  %-30s = %d,\n" % ["BIN(#{insn.name})", i]
-          i+=1
-        }
-      end
-
-      ERB.new(vpath.read('template/insns.inc.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # minsns.inc
-  class MInsnsIncGenerator < SourceCodeGenerator
-    def generate
-      i=0
-      defs = build_string do
-        @insns.each{|insn|
-          commit "  rb_define_const(mYarvInsns, %-30s, INT2FIX(%d));\n" %
-                 ["\"I#{insn.name}\"", i]
-          i+=1
-        }
-      end
-      ERB.new(vpath.read('template/minsns.inc.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # optinsn.inc
-  class OptInsnIncGenerator < SourceCodeGenerator
-    def generate
-      optinsn_inc
-    end
-
-    ###
-    private
-
-    def val_as_type op
-      type = op[0][0]
-      val  = op[1]
-
-      case type
-      when /^long/, /^rb_num_t/, /^lindex_t/, /^dindex_t/
-        "INT2FIX(#{val})"
-      when /^VALUE/
-        val
-      when /^ID/
-        "INT2FIX(#{val})"
-      when /^ISEQ/, /^rb_insn_func_t/
-        val
-      when /GENTRY/
-        raise
-      when /^\.\.\./
-        raise
-      else
-        raise "type: #{type}"
-      end
-    end
-
-    # optinsn.inc
-    def optinsn_inc
-      rule = ''
-      opt_insns_map = Hash.new{|h, k| h[k] = []}
-
-      @insns.each{|insn|
-        next if insn.defopes.size == 0
-        next if insn.type         == :sc
-        next if /^UNIFIED/ =~ insn.name.to_s
-
-        originsn = insn.orig
-        opt_insns_map[originsn] << insn
-      }
-
-      rule = build_string do
-        opt_insns_map.each{|originsn, optinsns|
-          commit "case BIN(#{originsn.name}):"
-
-          optinsns.sort_by{|opti|
-            opti.defopes.find_all{|e| e[1] == '*'}.size
-          }.each{|opti|
-            commit "  if("
-            i = 0
-            commit "    " + opti.defopes.map{|opinfo|
-              i += 1
-              next if opinfo[1] == '*'
-              "insnobj->operands[#{i-1}] == #{val_as_type(opinfo)}"
-            }.compact.join('&&  ')
-            commit "  ){"
-            idx = 0
-            n = 0
-            opti.defopes.each{|opinfo|
-              if opinfo[1] == '*'
-                if idx != n
-                  commit "    insnobj->operands[#{idx}] = insnobj->operands[#{n}];"
-                end
-                idx += 1
-              else
-                # skip
-              end
-              n += 1
-            }
-            commit "    insnobj->insn_id = BIN(#{opti.name});"
-            commit "    insnobj->operand_size = #{idx};"
-            commit "    break;\n  }\n"
-          }
-          commit "  break;";
-        }
-      end
-
-      ERB.new(vpath.read('template/optinsn.inc.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # optunifs.inc
-  class OptUnifsIncGenerator < SourceCodeGenerator
-    def generate
-      unif_insns_each = ''
-      unif_insns      = ''
-      unif_insns_data = []
-
-      insns = @insns.find_all{|insn| !insn.is_sc}
-      insns.each{|insn|
-        size = insn.unifs.size
-        if size > 0
-          insn.unifs.sort_by{|unif| -unif[1].size}.each_with_index{|unif, i|
-
-          uni_insn, uni_insns = *unif
-          uni_insns = uni_insns[1..-1]
-          unif_insns_each << "static int UNIFIED_#{insn.name}_#{i}[] = {" +
-                             "  BIN(#{uni_insn.name}), #{uni_insns.size + 2}, \n  " +
-                             uni_insns.map{|e| "BIN(#{e.name})"}.join(", ") + "};\n"
-          }
-        else
-          
-        end
-        if size > 0
-          unif_insns << "static int *UNIFIED_#{insn.name}[] = {(int *)#{size+1}, \n"
-          unif_insns << (0...size).map{|e| "  UNIFIED_#{insn.name}_#{e}"}.join(",\n") + "};\n"
-          unif_insns_data << "  UNIFIED_#{insn.name}"
-        else
-          unif_insns_data << "  0"
-        end
-      }
-      unif_insns_data = "static int **unified_insns_data[] = {\n" +
-                        unif_insns_data.join(",\n") + "};\n"
-      ERB.new(vpath.read('template/optunifs.inc.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # opt_sc.inc
-  class OptSCIncGenerator < SourceCodeGenerator
-    def generate
-      sc_insn_info = []
-      @insns.each{|insn|
-        insns = insn.sc
-        if insns.size > 0
-          insns = ['SC_ERROR'] + insns.map{|e| "    BIN(#{e.name})"}
-        else
-          insns = Array.new(6){'SC_ERROR'}
-        end
-        sc_insn_info << "  {\n#{insns.join(",\n")}}"
-      }
-      sc_insn_info = sc_insn_info.join(",\n")
-
-      sc_insn_next = @insns.map{|insn|
-        "  SCS_#{InstructionsLoader.complement_name(insn.nextsc).upcase}" +
-        (verbose? ? " /* #{insn.name} */" : '')
-      }.join(",\n")
-      ERB.new(vpath.read('template/opt_sc.inc.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # yasmdata.rb
-  class YASMDataRbGenerator < SourceCodeGenerator
-    def generate
-      insn_id2no = ''
-      @insns.each_with_index{|insn, i|
-        insn_id2no << "        :#{insn.name} => #{i},\n"
-      }
-      ERB.new(vpath.read('template/yasmdata.rb.tmpl')).result(binding)
-    end
-  end
-
-  ###################################################################
-  # yarvarch.*
-  class YARVDocGenerator < SourceCodeGenerator
-    def generate
-
-    end
-
-    def desc lang
-      d = ''
-      i = 0
-      cat = nil
-      @insns.each{|insn|
-        seq    = insn.opes.map{|t,v| v}.join(' ')
-        before = insn.pops.reverse.map{|t,v| v}.join(' ')
-        after  = insn.rets.reverse.map{|t,v| v}.join(' ')
-
-        if cat != insn.comm[:c]
-          d << "** #{insn.comm[:c]}\n\n"
-          cat = insn.comm[:c]
-        end
-
-        d << "*** #{insn.name}\n"
-        d << "\n"
-        d << insn.comm[lang] + "\n\n"
-        d << ":instruction sequence: 0x%02x #{seq}\n" % i
-        d << ":stack: #{before} => #{after}\n\n"
-        i+=1
-      }
-      d
-    end
-
-    def desc_ja
-      d = desc :j
-      ERB.new(vpath.read('template/yarvarch.ja')).result(binding)
-    end
-
-    def desc_en
-      d = desc :e
-      ERB.new(vpath.read('template/yarvarch.en')).result(binding)
-    end
-  end
-
-  module VPATH
-    def search(meth, base, *rest)
-      begin
-        meth.call(base, *rest)
-      rescue Errno::ENOENT => error
-        each do |dir|
-          return meth.call(File.join(dir, base), *rest) rescue nil
-        end
-        raise error
-      end
-    end
-
-    def process(*args, &block)
-      search(File.method(__callee__), *args, &block)
-    end
-
-    alias stat process
-    alias lstat process
-
-    def open(*args)
-      f = search(File.method(:open), *args)
-      if block_given?
-        begin
-          yield f
-        ensure
-          f.close unless f.closed?
-        end
-      else
-        f
-      end
-    end
-
-    def read(*args)
-      open(*args) {|f| f.read}
-    end
-
-    def foreach(file, *args, &block)
-      open(file) {|f| f.each(*args, &block)}
-    end
-
-    def self.def_options(opt)
-      vpath = []
-      path_sep = ':'
-
-      opt.on("-I", "--srcdir=DIR", "add a directory to search path") {|dir|
-        vpath |= [dir]
-      }
-      opt.on("-L", "--vpath=PATH LIST", "add directories to search path") {|dirs|
-        vpath |= dirs.split(path_sep)
-      }
-      opt.on("--path-separator=SEP", /\A\W\z/, "separator for vpath") {|sep|
-        path_sep = sep
-      }
-
-      proc {
-        vpath.extend(self) unless vpath.empty?
-      }
-    end
-  end
-
-  class SourceCodeGenerator
-    Files = { # codes
-      'vm.inc'         => VmBodyGenerator,
-      'vmtc.inc'       => VmTCIncGenerator,
-      'insns.inc'      => InsnsIncGenerator,
-      'insns_info.inc' => InsnsInfoIncGenerator,
-    # 'minsns.inc'     => MInsnsIncGenerator,
-      'optinsn.inc'    => OptInsnIncGenerator,
-      'optunifs.inc'   => OptUnifsIncGenerator,
-      'opt_sc.inc'     => OptSCIncGenerator,
-      'yasmdata.rb'    => YASMDataRbGenerator,
-    }
-
-    def generate args = []
-      args = Files.keys if args.empty?
-      args.each{|fn|
-        s = Files[fn].new(@insns).generate
-        open(output_path(fn), 'w') {|f| f.puts(s)}
-      }
-    end
-
-    def self.def_options(opt)
-      opts = {
-        :"insns.def" => 'insns.def',
-        :"opope.def" => 'opt_operand.def',
-        :"unif.def"  => 'opt_insn_unif.def',
-      }
-
-      opt.on("-Dname", /\AOPT_(\w+)\z/, "enable VM option") {|s, v|
-        opts[v] = true
-      }
-      opt.on("--enable=name[,name...]", Array,
-        "enable VM options (without OPT_ prefix)") {|*a|
-        a.each {|v| opts[v] = true}
-      }
-      opt.on("-Uname", /\AOPT_(\w+)\z/, "disable VM option") {|s, v|
-        opts[v] = false
-      }
-      opt.on("--disable=name[,name...]", Array,
-        "disable VM options (without OPT_ prefix)") {|*a|
-          a.each {|v| opts[v] = false}
-      }
-      opt.on("-i", "--insnsdef=FILE", "--instructions-def",
-        "instructions definition file") {|n|
-        opts[:insns_def] = n
-      }
-      opt.on("-o", "--opt-operanddef=FILE", "--opt-operand-def",
-        "vm option: operand definition file") {|n|
-        opts[:opope_def] = n
-      }
-      opt.on("-u", "--opt-insnunifdef=FILE", "--opt-insn-unif-def",
-        "vm option: instruction unification file") {|n|
-        opts[:unif_def] = n
-      }
-      opt.on("-C", "--[no-]use-const",
-        "use consts for default operands instead of macros") {|v|
-        opts[:use_const] = v
-      }
-      opt.on("-d", "--destdir", "--output-directory=DIR",
-        "make output file underneath DIR") {|v|
-        opts[:destdir] = v
-      }
-      opt.on("-V", "--[no-]verbose") {|v|
-        opts[:verbose] = v
-      }
-
-      vpath = VPATH.def_options(opt)
-
-      proc {
-        opts[:VPATH] = vpath.call
-        build opts
-      }
-    end
-
-    def self.build opts, vpath = ['./']
-      opts[:VPATH] = vpath.extend(VPATH) unless opts[:VPATH]
-      self.new InstructionsLoader.new(opts)
-    end
-  end
-end
-
Index: tool/insns2vm.rb
===================================================================
--- tool/insns2vm.rb	(revision 14450)
+++ tool/insns2vm.rb	(revision 14451)
@@ -4,7 +4,7 @@
 
 Version = %w$Revision: 11626 $[1..-1]
 
-require "#{File.join(File.dirname(__FILE__), '../lib/vm/instruction')}"
+require "#{File.join(File.dirname(__FILE__), 'instruction')}"
 
 if $0 == __FILE__
   opts = ARGV.options
Index: tool/instruction.rb
===================================================================
--- tool/instruction.rb	(revision 0)
+++ tool/instruction.rb	(revision 14451)
@@ -0,0 +1,1381 @@
+#
+#
+#
+
+require 'erb'
+
+module RubyVM
+  class Instruction
+    def initialize name, opes, pops, rets, comm, body, tvars, sp_inc,
+                   orig = self, defopes = [], type = nil,
+                   nsc = [], psc = [[], []]
+
+      @name = name
+      @opes = opes # [[type, name], ...]
+      @pops = pops # [[type, name], ...]
+      @rets = rets # [[type, name], ...]
+      @comm = comm # {:c => category, :e => en desc, :j => ja desc}
+      @body = body # '...'
+
+      @orig    = orig
+      @defopes = defopes
+      @type    = type
+      @tvars   = tvars
+
+      @nextsc = nsc
+      @pushsc = psc
+      @sc     = []
+      @unifs  = []
+      @optimized = []
+      @is_sc  = false
+      @sp_inc = sp_inc
+    end
+
+    def add_sc sci
+      @sc << sci
+      sci.set_sc
+    end
+    
+    attr_reader :name, :opes, :pops, :rets
+    attr_reader :body, :comm
+    attr_reader :nextsc, :pushsc
+    attr_reader :orig, :defopes, :type
+    attr_reader :sc
+    attr_reader :unifs, :optimized
+    attr_reader :is_sc
+    attr_reader :tvars
+    attr_reader :sp_inc
+    
+    def set_sc
+      @is_sc = true
+    end
+    
+    def add_unif insns
+      @unifs << insns
+    end
+
+    def add_optimized insn
+      @optimized << insn
+    end
+
+    def sp_increase_c_expr
+      if(pops.any?{|t, v| v == '...'} ||
+         rets.any?{|t, v| v == '...'})
+        # user definision
+        raise "no sp increase definition" if @sp_inc.nil?
+        ret = "int inc = 0;\n"
+
+        @opes.each_with_index{|(t, v), i|
+          if t == 'rb_num_t'
+            ret << "        unsigned long #{v} = FIX2INT(opes[#{i}]);\n"
+          end
+        }
+        @defopes.each_with_index{|((t, var), val), i|
+          if t == 'rb_num_t' && val != '*'
+            ret << "        unsigned long #{var} = #{val};\n"
+          end
+        }
+
+        ret << "        #{@sp_inc};\n"
+        ret << "        return depth + inc;"
+        ret
+      else
+        "return depth + #{rets.size - pops.size};"
+      end
+    end
+    
+    def inspect
+      "#<Instruction:#{@name}>"
+    end
+  end
+
+  class InstructionsLoader
+    def initialize opts = {}
+      @insns    = []
+      @insn_map = {}
+
+      @vpath = opts[:VPATH] || File
+      @use_const = opts[:use_const]
+      @verbose   = opts[:verbose]
+      @destdir   = opts[:destdir]
+
+      (@vm_opts = load_vm_opts).each {|k, v|
+        @vm_opts[k] = opts[k] if opts.key?(k)
+      }
+
+      load_insns_def opts[:"insns.def"] || 'insns.def'
+
+      load_opt_operand_def opts[:"opope.def"] || 'opt_operand.def'
+      load_insn_unification_def opts[:"unif.def"] || 'opt_insn_unif.def'
+      make_stackcaching_insns if vm_opt?('STACK_CACHING')
+    end
+
+    attr_reader :vpath
+    attr_reader :destdir
+  
+    %w[use_const verbose].each do |attr|
+      attr_reader attr
+      alias_method "#{attr}?", attr
+      remove_method attr
+    end
+
+    def [](s)
+      @insn_map[s.to_s]
+    end
+
+    def each
+      @insns.each{|insn|
+        yield insn
+      }
+    end
+
+    def size
+      @insns.size
+    end
+
+    ###
+    private
+
+    def vm_opt? name
+      @vm_opts[name]
+    end
+
+    def load_vm_opts file = nil
+      file ||= 'vm_opts.h'
+      opts = {}
+      vpath.open(file) do |f|
+        f.grep(/^\#define\s+OPT_([A-Z_]+)\s+(\d+)/) do
+          opts[$1] = !$2.to_i.zero?
+        end
+      end
+      opts
+    end
+
+    SKIP_COMMENT_PATTERN = Regexp.compile(Regexp.escape('/** ##skip'))
+
+    include Enumerable
+
+    def add_insn insn
+      @insns << insn
+      @insn_map[insn.name] = insn
+    end
+
+    def make_insn name, opes, pops, rets, comm, body, sp_inc
+      add_insn Instruction.new(name, opes, pops, rets, comm, body, [], sp_inc)
+    end
+
+    # str -> [[type, var], ...]
+    def parse_vars line
+      raise unless /\((.*?)\)/ =~ line
+      vars = $1.split(',')
+      vars.map!{|v|
+        if /\s*(\S+)\s+(\S+)\s*/ =~ v
+          type = $1
+          var  = $2
+        elsif /\s*\.\.\.\s*/ =~ v
+          type = var  = '...'
+        else
+          raise
+        end
+        [type, var]
+      }
+      vars
+    end
+
+    def parse_comment comm
+      c = 'others'
+      j = ''
+      e = ''
+      comm.each_line{|line|
+        case line
+        when /@c (.+)/
+          c = $1
+        when /@e (.+)/
+          e = $1
+        when /@e\s*$/
+          e = ''
+        when /@j (.+)$/
+          j = $1
+        when /@j\s*$/
+          j = ''
+        end
+      }
+      { :c => c,
+        :e => e,
+        :j => j,
+      }
+    end
+
+    def load_insns_def file
+      body = insn = opes = pops = rets = nil
+      comment = ''
+
+      vpath.open(file) {|f|
+        f.instance_variable_set(:@line_no, 0)
+        class << f
+          def line_no
+            @line_no
+          end
+          def gets
+            @line_no += 1
+            super
+          end
+        end
+
+        while line = f.gets
+          line.chomp!
+          case line
+
+          when SKIP_COMMENT_PATTERN
+            while line = f.gets.chomp
+              if /\s+\*\/$/ =~ line
+                break
+              end
+            end
+
+            # collect instruction comment
+          when /^\/\*\*$/
+            while line = f.gets
+              if /\s+\*\/\s*$/ =~ line
+                break
+              else
+                comment << line
+              end
+            end
+
+            # start instruction body
+          when /^DEFINE_INSN$/
+            insn = f.gets.chomp
+            opes = parse_vars(f.gets.chomp)
+            pops = parse_vars(f.gets.chomp).reverse
+            rets_str = f.gets.chomp
+            rets = parse_vars(rets_str).reverse
+            comment = parse_comment(comment)
+            insn_in = true
+            body    = ''
+
+            sp_inc = rets_str[%r"//\s*(.+)", 1]
+
+            raise unless /^\{$/ =~ f.gets.chomp
+            line_no = f.line_no
+
+          # end instruction body
+          when /^\}/
+            if insn_in
+              body.instance_variable_set(:@line_no, line_no)
+              body.instance_variable_set(:@file, f.path)
+              insn = make_insn(insn, opes, pops, rets, comment, body, sp_inc)
+              insn_in = false
+              comment = ''
+            end
+
+          else
+            if insn_in
+              body << line + "\n"
+            end
+          end
+        end
+      }
+    end
+
+    ## opt op
+    def load_opt_operand_def file
+      vpath.foreach(file) {|line|
+        line = line.gsub(/\#.*/, '').strip
+        next  if line.length == 0
+        break if /__END__/ =~ line
+        /(\S+)\s+(.+)/ =~ line
+        insn = $1
+        opts = $2
+        add_opt_operand insn, opts.split(/,/).map{|e| e.strip}
+      } if file
+    end
+
+    def label_escape label
+      label.gsub(/\(/, '_O_').
+      gsub(/\)/, '_C_').
+      gsub(/\*/, '_WC_')
+    end
+
+    def add_opt_operand insn_name, opts
+      insn = @insn_map[insn_name]
+      opes = insn.opes
+
+      if opes.size != opts.size
+        raise "operand size mismatcvh for #{insn.name} (opes: #{opes.size}, opts: #{opts.size})"
+      end
+
+      ninsn = insn.name + '_OP_' + opts.map{|e| label_escape(e)}.join('_')
+      nopes = []
+      defv  = []
+
+      opts.each_with_index{|e, i|
+        if e == '*'
+          nopes << opes[i]
+        end
+        defv  << [opes[i], e]
+      }
+
+      make_insn_operand_optimiized(insn, ninsn, nopes, defv)
+    end
+
+    def make_insn_operand_optimiized orig_insn, name, opes, defopes
+      comm = orig_insn.comm.dup
+      comm[:c] = 'optimize'
+      add_insn insn = Instruction.new(
+        name, opes, orig_insn.pops, orig_insn.rets, comm,
+        orig_insn.body, orig_insn.tvars, orig_insn.sp_inc,
+        orig_insn, defopes)
+      orig_insn.add_optimized insn
+    end
+
+    ## insn unif
+    def load_insn_unification_def file
+      vpath.foreach(file) {|line|
+        line = line.gsub(/\#.*/, '').strip
+        next  if line.length == 0
+        break if /__END__/ =~ line
+        make_unified_insns line.split.map{|e|
+          raise "unknown insn: #{e}" unless @insn_map[e]
+          @insn_map[e]
+        }
+      } if file
+    end
+
+    def all_combination sets
+      ret = sets.shift.map{|e| [e]}
+
+      sets.each{|set|
+        prev = ret
+        ret  = []
+        prev.each{|ary|
+          set.each{|e|
+            eary = ary.dup
+            eary << e
+            ret  << eary
+          }
+        }
+      }
+      ret
+    end
+
+    def make_unified_insns insns
+      if vm_opt?('UNIFY_ALL_COMBINATION')
+        insn_sets = insns.map{|insn|
+          [insn] + insn.optimized
+        }
+
+        all_combination(insn_sets).each{|insns_set|
+          make_unified_insn_each insns_set
+        }
+      else
+        make_unified_insn_each insns
+      end
+    end
+
+    def mk_private_val vals, i, redef
+      vals.dup.map{|v|
+        # v[0] : type
+        # v[1] : var name
+
+        v = v.dup
+        if v[0] != '...'
+          redef[v[1]] = v[0]
+          v[1] = "#{v[1]}_#{i}"
+        end
+        v
+      }
+    end
+
+    def mk_private_val2 vals, i, redef
+      vals.dup.map{|v|
+        # v[0][0] : type
+        # v[0][1] : var name
+        # v[1] : default val
+
+        pv = v.dup
+        v = pv[0] = pv[0].dup
+        if v[0] != '...'
+          redef[v[1]] = v[0]
+          v[1] = "#{v[1]}_#{i}"
+        end
+        pv
+      }
+    end
+
+    def make_unified_insn_each insns
+      names = []
+      opes = []
+      pops = []
+      rets = []
+      comm = {
+        :c => 'optimize',
+        :e => 'unified insn',
+        :j => 'unified insn',
+      }
+      body = ''
+      passed = []
+      tvars = []
+      defopes = []
+      sp_inc = ''
+
+      insns.each_with_index{|insn, i|
+        names << insn.name
+        redef_vars = {}
+
+        e_opes = mk_private_val(insn.opes, i, redef_vars)
+        e_pops = mk_private_val(insn.pops, i, redef_vars)
+        e_rets = mk_private_val(insn.rets, i, redef_vars)
+        # ToDo: fix it
+        e_defs = mk_private_val2(insn.defopes, i, redef_vars)
+
+        passed_vars = []
+        while pvar = e_pops.pop
+          rvar = rets.pop
+          if rvar
+            raise "unsupported unif insn: #{insns.inspect}" if rvar[0] == '...'
+            passed_vars << [pvar, rvar]
+            tvars << rvar
+          else
+            e_pops.push pvar
+            break
+          end
+        end
+
+        opes.concat e_opes
+        pops.concat e_pops
+        rets.concat e_rets
+        defopes.concat e_defs
+        sp_inc += "#{insn.sp_inc}"
+
+        body += "{ /* unif: #{i} */\n" +
+                passed_vars.map{|rpvars|
+                  pv = rpvars[0]
+                  rv = rpvars[1]
+                  "#define #{pv[1]} #{rv[1]}"
+                }.join("\n") +
+                "\n" + 
+                redef_vars.map{|v, type|
+                  "#define #{v} #{v}_#{i}"
+                }.join("\n") + "\n" +
+                insn.body +
+                passed_vars.map{|rpvars|
+                  "#undef #{rpvars[0][1]}"
+                }.join("\n") +
+                "\n" +
+                redef_vars.keys.map{|v|
+                  "#undef  #{v}"
+                }.join("\n") +
+                "\n}\n"
+      }
+
+      tvars_ary = []
+      tvars.each{|tvar|
+        unless opes.any?{|var|
+          var[1] == tvar[1]
+        } || defopes.any?{|pvar|
+          pvar[0][1] == tvar[1]
+        }
+          tvars_ary << tvar
+        end
+      }
+      add_insn insn = Instruction.new("UNIFIED_" + names.join('_'),
+                                   opes, pops, rets.reverse, comm, body,
+                                   tvars_ary, sp_inc)
+      insn.defopes.replace defopes
+      insns[0].add_unif [insn, insns]
+    end
+
+    ## sc
+    SPECIAL_INSN_FOR_SC_AFTER = {
+      /\Asend/      => [:a],
+      /\Aend/       => [:a],
+      /\Ayield/     => [:a],
+      /\Aclassdef/  => [:a],
+      /\Amoduledef/ => [:a],
+    }
+    FROM_SC = [[], [:a], [:b], [:a, :b], [:b, :a]]
+
+    def make_stackcaching_insns
+      pops = rets = nil
+
+      @insns.dup.each{|insn|
+        opops = insn.pops
+        orets = insn.rets
+        oopes = insn.opes
+        ocomm = insn.comm
+
+        after = nil
+        SPECIAL_INSN_FOR_SC_AFTER.any?{|k, v|
+          if k =~ insn.name
+            after = v
+            break
+          end
+        }
+
+        insns = []
+        FROM_SC.each{|from|
+          name, pops, rets, pushs1, pushs2, nextsc =
+          *calc_stack(insn, from, after, opops, orets)
+
+          make_insn_sc(insn, name, oopes, pops, rets, [pushs1, pushs2], nextsc)
+        }
+      }
+    end
+
+    def make_insn_sc orig_insn, name, opes, pops, rets, pushs, nextsc
+      comm = orig_insn.comm.dup
+      comm[:c] = 'optimize(sc)'
+
+      scinsn = Instruction.new(
+        name, opes, pops, rets, comm,
+        orig_insn.body, orig_insn.tvars, orig_insn.sp_inc,
+        orig_insn, orig_insn.defopes, :sc, nextsc, pushs)
+
+      add_insn scinsn
+      orig_insn.add_sc scinsn
+    end
+
+    def self.complement_name st
+      "#{st[0] ? st[0] : 'x'}#{st[1] ? st[1] : 'x'}"
+    end
+
+    def add_stack_value st
+      len = st.length
+      if len == 0
+        st[0] = :a
+        [nil, :a]
+      elsif len == 1
+        if st[0] == :a
+          st[1] = :b
+        else
+          st[1] = :a
+        end
+        [nil, st[1]]
+      else
+        st[0], st[1] = st[1], st[0]
+        [st[1], st[1]]
+      end
+    end
+
+    def calc_stack insn, ofrom, oafter, opops, orets
+      from = ofrom.dup
+      pops = opops.dup
+      rets = orets.dup
+      rest_scr = ofrom.dup
+
+      pushs_before = []
+      pushs= []
+
+      pops.each_with_index{|e, i|
+        if e[0] == '...'
+          pushs_before = from
+          from = []
+        end
+        r = from.pop
+        break unless r
+        pops[i] = pops[i].dup << r
+      }
+
+      if oafter
+        from = oafter
+        from.each_with_index{|r, i|
+          rets[i] = rets[i].dup << r if rets[i]
+        }
+      else
+        rets = rets.reverse
+        rets.each_with_index{|e, i|
+          break if e[0] == '...'
+          pushed, r = add_stack_value from
+          rets[i] = rets[i].dup << r
+          if pushed
+            if rest_scr.pop
+              pushs << pushed
+            end
+
+            if i - 2 >= 0
+              rets[i-2].pop
+            end
+          end
+        }
+      end
+
+      if false #|| insn.name =~ /test3/
+        p ofrom
+        p pops
+        p rets
+        p pushs_before
+        p pushs
+        p from
+        exit
+      end
+
+      ret = ["#{insn.name}_SC_#{InstructionsLoader.complement_name(ofrom)}_#{complement_name(from)}",
+            pops, rets, pushs_before, pushs, from]
+    end
+  end
+
+  class SourceCodeGenerator
+    def initialize insns
+      @insns = insns
+    end
+
+    attr_reader :insns
+
+    def generate
+      raise "should not reach here"
+    end
+
+    def vpath
+      @insns.vpath
+    end
+
+    def verbose?
+      @insns.verbose?
+    end
+
+    def use_const?
+      @insns.use_const?
+    end
+
+    def build_string
+      @lines = []
+      yield
+      @lines.join("\n")
+    end
+
+    EMPTY_STRING = ''.freeze
+
+    def commit str = EMPTY_STRING
+      @lines << str
+    end
+
+    def comment str
+      @lines << str if verbose?
+    end
+
+    def output_path(fn)
+      d = @insns.destdir
+      fn = File.join(d, fn) if d
+      fn
+    end
+  end
+
+  ###################################################################
+  # vm.inc
+  class VmBodyGenerator < SourceCodeGenerator
+    # vm.inc
+    def generate
+      vm_body = ''
+      @insns.each{|insn|
+        vm_body << "\n"
+        vm_body << make_insn_def(insn)
+      }
+      src = vpath.read('template/vm.inc.tmpl')
+      ERB.new(src).result(binding)
+    end
+
+    def generate_from_insnname insnname
+      make_insn_def @insns[insnname.to_s]
+    end
+
+    #######
+    private
+
+    def make_header_prepare_stack insn
+      comment "  /* prepare stack status */"
+
+      push_ba = insn.pushsc
+      raise "unsupport" if push_ba[0].size > 0 && push_ba[1].size > 0
+
+      push_ba.each{|pushs|
+        pushs.each{|r|
+          commit "  PUSH(SCREG(#{r}));"
+        }
+      }
+    end
+  
+    def make_header_operands insn
+      comment "  /* declare and get from iseq */"
+
+      vars = insn.opes
+      n = 0
+      ops = []
+
+      vars.each_with_index{|(type, var), i|
+        if type == '...'
+          break
+        end
+
+        ops << "  #{type} #{var} = (#{type})GET_OPERAND(#{i+1});"
+        n   += 1
+      }
+      @opn = n
+
+      # reverse or not?
+      # ops.join
+      commit ops.reverse
+    end
+  
+    def make_header_default_operands insn
+      vars = insn.defopes
+
+      vars.each{|e|
+        next if e[1] == '*'
+        if use_const?
+          commit "  const #{e[0][0]} #{e[0][1]} = #{e[1]};"
+        else
+          commit "  #define #{e[0][1]} #{e[1]}"
+        end
+      }
+    end
+
+    def make_footer_default_operands insn
+      comment " /* declare and initialize default opes */"
+      if use_const?
+        commit
+      else
+        vars = insn.defopes
+
+        vars.each{|e|
+          next if e[1] == '*'
+          commit "#undef #{e[0][1]}"
+        }
+      end
+    end
+
+    def make_header_stack_pops insn
+      comment "  /* declare and pop from stack */"
+
+      n = 0
+      pops = []
+      vars = insn.pops
+      vars.each_with_index{|iter, i|
+        type, var, r = *iter
+        if type == '...'
+          break
+        end
+        if r
+          pops << "  #{type} #{var} = SCREG(#{r});"
+        else
+          pops << "  #{type} #{var} = TOPN(#{n});"
+          n += 1
+        end
+      }
+      @popn = n
+
+      # reverse or not?
+      commit pops.reverse
+    end
+
+    def make_header_temporary_vars insn
+      comment "  /* declare temporary vars */"
+
+      insn.tvars.each{|var|
+        commit "  #{var[0]} #{var[1]};"
+      }
+    end
+
+    def make_header_stack_val insn
+      comment "/* declare stack push val */"
+
+      vars = insn.opes + insn.pops + insn.defopes.map{|e| e[0]}
+
+      insn.rets.each{|var|
+        if vars.all?{|e| e[1] != var[1]} && var[1] != '...'
+          commit "  #{var[0]} #{var[1]};"
+        end
+      }
+    end
+
+    def make_header_analysis insn
+      commit "  USAGE_ANALYSIS_INSN(BIN(#{insn.name}));"
+      insn.opes.each_with_index{|op, i|
+        commit "  USAGE_ANALYSIS_OPERAND(BIN(#{insn.name}), #{i}, #{op[1]});"
+      }
+    end
+
+    def make_header_pc insn
+      commit  "  ADD_PC(1+#{@opn});"
+      commit  "  PREFETCH(GET_PC());"
+    end
+
+    def make_header_popn insn
+      comment "  /* management */"
+      commit  "  POPN(#{@popn});" if @popn > 0
+    end
+
+    def make_hader_debug insn
+      comment "  /* for debug */"
+      commit  "  DEBUG_ENTER_INSN(\"#{insn.name}\");"
+    end
+
+    def make_header_defines insn
+      commit  "  #define CURRENT_INSN_#{insn.name} 1"
+      commit  "  #define INSN_IS_SC()     #{insn.sc ? 0 : 1}"
+      commit  "  #define INSN_LABEL(lab)  LABEL_#{insn.name}_##lab"
+      commit  "  #define LABEL_IS_SC(lab) LABEL_##lab##_###{insn.sc.size == 0 ? 't' : 'f'}"
+    end
+
+    def make_footer_stack_val insn
+      comment "  /* push stack val */"
+
+      insn.rets.reverse_each{|v|
+        if v[1] == '...'
+          break
+        end
+        if v[2]
+          commit "  SCREG(#{v[2]}) = #{v[1]};"
+        else
+          commit "  PUSH(#{v[1]});"
+        end
+      }
+    end
+
+    def make_footer_undefs insn
+      commit "#undef CURRENT_INSN_#{insn.name}"
+      commit "#undef INSN_IS_SC"
+      commit "#undef INSN_LABEL"
+      commit "#undef LABEL_IS_SC"
+    end
+
+    def make_header insn
+      commit "INSN_ENTRY(#{insn.name}){"
+      make_header_prepare_stack insn
+      commit "{"
+      make_header_stack_val  insn
+      make_header_default_operands insn
+      make_header_operands   insn
+      make_header_stack_pops insn
+      make_header_temporary_vars insn
+      #
+      make_hader_debug insn
+      make_header_pc insn
+      make_header_popn insn
+      make_header_defines insn
+      make_header_analysis insn
+      commit  "{"
+    end
+
+    def make_footer insn
+      make_footer_stack_val insn
+      make_footer_default_operands insn
+      make_footer_undefs insn
+      commit "  END_INSN(#{insn.name});}}}"
+    end
+
+    def make_insn_def insn
+      build_string do
+        make_header insn
+        if line = insn.body.instance_variable_get(:@line_no)
+          file = insn.body.instance_variable_get(:@file)
+          commit "#line #{line+1} \"#{file}\""
+          commit insn.body
+          commit '#line __CURRENT_LINE__ "__CURRENT_FILE__"'
+        else
+          insn.body
+        end
+        make_footer(insn)
+      end
+    end
+  end
+
+  ###################################################################
+  # vmtc.inc
+  class VmTCIncGenerator < SourceCodeGenerator
+    def generate
+
+      insns_table = build_string do
+        @insns.each{|insn|
+          commit "  LABEL_PTR(#{insn.name}),"
+        }
+      end
+
+      insn_end_table = build_string do
+        @insns.each{|insn|
+          commit "  ELABEL_PTR(#{insn.name}),\n"
+        }
+      end
+    
+      ERB.new(vpath.read('template/vmtc.inc.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # insns_info.inc
+  class InsnsInfoIncGenerator < SourceCodeGenerator
+    def generate
+      insns_info_inc
+    end
+
+    ###
+    private
+
+    def op2typesig op
+      case op
+      when /^OFFSET/
+        "TS_OFFSET"
+      when /^rb_num_t/
+        "TS_NUM"
+      when /^lindex_t/
+        "TS_LINDEX"
+      when /^dindex_t/
+        "TS_DINDEX"
+      when /^VALUE/
+        "TS_VALUE"
+      when /^ID/
+        "TS_ID"
+      when /GENTRY/
+        "TS_GENTRY"
+      when /^IC/
+        "TS_IC"
+      when /^\.\.\./
+        "TS_VARIABLE"
+      when /^CDHASH/
+        "TS_CDHASH"
+      when /^ISEQ/
+        "TS_ISEQ"
+      when /rb_insn_func_t/
+        "TS_FUNCPTR"
+      else
+        raise "unknown op type: #{op}"
+      end
+    end
+
+    TYPE_CHARS = {
+      'TS_OFFSET'    => 'O',
+      'TS_NUM'       => 'N',
+      'TS_LINDEX'    => 'L',
+      'TS_DINDEX'    => 'D',
+      'TS_VALUE'     => 'V',
+      'TS_ID'        => 'I',
+      'TS_GENTRY'    => 'G',
+      'TS_IC'        => 'C',
+      'TS_CDHASH'    => 'H',
+      'TS_ISEQ'      => 'S',
+      'TS_VARIABLE'  => '.',
+      'TS_FUNCPTR'   => 'F',
+    }
+
+    # insns_info.inc
+    def insns_info_inc
+      # insn_type_chars
+      insn_type_chars = TYPE_CHARS.map{|t, c|
+        "#define #{t} '#{c}'"
+      }.join("\n")
+
+      # insn_names
+      insn_names = ''
+      @insns.each{|insn|
+        insn_names << "  \"#{insn.name}\",\n"
+      }
+
+      # operands info
+      operands_info = ''
+      operands_num_info = ''
+      @insns.each{|insn|
+        opes = insn.opes
+        operands_info << '  '
+        ot = opes.map{|type, var|
+          TYPE_CHARS.fetch(op2typesig(type))
+        }
+        operands_info << "\"#{ot.join}\"" << ", \n"
+
+        num = opes.size + 1
+        operands_num_info << "  #{num},\n"
+      }
+
+      # stack num
+      stack_num_info = ''
+      @insns.each{|insn|
+        num = insn.rets.size
+        stack_num_info << "  #{num},\n"
+      }
+
+      # stack increase
+      stack_increase = ''
+      @insns.each{|insn|
+        stack_increase << <<-EOS
+        case BIN(#{insn.name}):{
+          #{insn.sp_increase_c_expr}
+        }
+        EOS
+      }
+      ERB.new(vpath.read('template/insns_info.inc.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # insns.inc
+  class InsnsIncGenerator < SourceCodeGenerator
+    def generate
+      i=0
+      insns = build_string do
+        @insns.each{|insn|
+          commit "  %-30s = %d,\n" % ["BIN(#{insn.name})", i]
+          i+=1
+        }
+      end
+
+      ERB.new(vpath.read('template/insns.inc.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # minsns.inc
+  class MInsnsIncGenerator < SourceCodeGenerator
+    def generate
+      i=0
+      defs = build_string do
+        @insns.each{|insn|
+          commit "  rb_define_const(mYarvInsns, %-30s, INT2FIX(%d));\n" %
+                 ["\"I#{insn.name}\"", i]
+          i+=1
+        }
+      end
+      ERB.new(vpath.read('template/minsns.inc.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # optinsn.inc
+  class OptInsnIncGenerator < SourceCodeGenerator
+    def generate
+      optinsn_inc
+    end
+
+    ###
+    private
+
+    def val_as_type op
+      type = op[0][0]
+      val  = op[1]
+
+      case type
+      when /^long/, /^rb_num_t/, /^lindex_t/, /^dindex_t/
+        "INT2FIX(#{val})"
+      when /^VALUE/
+        val
+      when /^ID/
+        "INT2FIX(#{val})"
+      when /^ISEQ/, /^rb_insn_func_t/
+        val
+      when /GENTRY/
+        raise
+      when /^\.\.\./
+        raise
+      else
+        raise "type: #{type}"
+      end
+    end
+
+    # optinsn.inc
+    def optinsn_inc
+      rule = ''
+      opt_insns_map = Hash.new{|h, k| h[k] = []}
+
+      @insns.each{|insn|
+        next if insn.defopes.size == 0
+        next if insn.type         == :sc
+        next if /^UNIFIED/ =~ insn.name.to_s
+
+        originsn = insn.orig
+        opt_insns_map[originsn] << insn
+      }
+
+      rule = build_string do
+        opt_insns_map.each{|originsn, optinsns|
+          commit "case BIN(#{originsn.name}):"
+
+          optinsns.sort_by{|opti|
+            opti.defopes.find_all{|e| e[1] == '*'}.size
+          }.each{|opti|
+            commit "  if("
+            i = 0
+            commit "    " + opti.defopes.map{|opinfo|
+              i += 1
+              next if opinfo[1] == '*'
+              "insnobj->operands[#{i-1}] == #{val_as_type(opinfo)}"
+            }.compact.join('&&  ')
+            commit "  ){"
+            idx = 0
+            n = 0
+            opti.defopes.each{|opinfo|
+              if opinfo[1] == '*'
+                if idx != n
+                  commit "    insnobj->operands[#{idx}] = insnobj->operands[#{n}];"
+                end
+                idx += 1
+              else
+                # skip
+              end
+              n += 1
+            }
+            commit "    insnobj->insn_id = BIN(#{opti.name});"
+            commit "    insnobj->operand_size = #{idx};"
+            commit "    break;\n  }\n"
+          }
+          commit "  break;";
+        }
+      end
+
+      ERB.new(vpath.read('template/optinsn.inc.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # optunifs.inc
+  class OptUnifsIncGenerator < SourceCodeGenerator
+    def generate
+      unif_insns_each = ''
+      unif_insns      = ''
+      unif_insns_data = []
+
+      insns = @insns.find_all{|insn| !insn.is_sc}
+      insns.each{|insn|
+        size = insn.unifs.size
+        if size > 0
+          insn.unifs.sort_by{|unif| -unif[1].size}.each_with_index{|unif, i|
+
+          uni_insn, uni_insns = *unif
+          uni_insns = uni_insns[1..-1]
+          unif_insns_each << "static int UNIFIED_#{insn.name}_#{i}[] = {" +
+                             "  BIN(#{uni_insn.name}), #{uni_insns.size + 2}, \n  " +
+                             uni_insns.map{|e| "BIN(#{e.name})"}.join(", ") + "};\n"
+          }
+        else
+          
+        end
+        if size > 0
+          unif_insns << "static int *UNIFIED_#{insn.name}[] = {(int *)#{size+1}, \n"
+          unif_insns << (0...size).map{|e| "  UNIFIED_#{insn.name}_#{e}"}.join(",\n") + "};\n"
+          unif_insns_data << "  UNIFIED_#{insn.name}"
+        else
+          unif_insns_data << "  0"
+        end
+      }
+      unif_insns_data = "static int **unified_insns_data[] = {\n" +
+                        unif_insns_data.join(",\n") + "};\n"
+      ERB.new(vpath.read('template/optunifs.inc.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # opt_sc.inc
+  class OptSCIncGenerator < SourceCodeGenerator
+    def generate
+      sc_insn_info = []
+      @insns.each{|insn|
+        insns = insn.sc
+        if insns.size > 0
+          insns = ['SC_ERROR'] + insns.map{|e| "    BIN(#{e.name})"}
+        else
+          insns = Array.new(6){'SC_ERROR'}
+        end
+        sc_insn_info << "  {\n#{insns.join(",\n")}}"
+      }
+      sc_insn_info = sc_insn_info.join(",\n")
+
+      sc_insn_next = @insns.map{|insn|
+        "  SCS_#{InstructionsLoader.complement_name(insn.nextsc).upcase}" +
+        (verbose? ? " /* #{insn.name} */" : '')
+      }.join(",\n")
+      ERB.new(vpath.read('template/opt_sc.inc.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # yasmdata.rb
+  class YASMDataRbGenerator < SourceCodeGenerator
+    def generate
+      insn_id2no = ''
+      @insns.each_with_index{|insn, i|
+        insn_id2no << "        :#{insn.name} => #{i},\n"
+      }
+      ERB.new(vpath.read('template/yasmdata.rb.tmpl')).result(binding)
+    end
+  end
+
+  ###################################################################
+  # yarvarch.*
+  class YARVDocGenerator < SourceCodeGenerator
+    def generate
+
+    end
+
+    def desc lang
+      d = ''
+      i = 0
+      cat = nil
+      @insns.each{|insn|
+        seq    = insn.opes.map{|t,v| v}.join(' ')
+        before = insn.pops.reverse.map{|t,v| v}.join(' ')
+        after  = insn.rets.reverse.map{|t,v| v}.join(' ')
+
+        if cat != insn.comm[:c]
+          d << "** #{insn.comm[:c]}\n\n"
+          cat = insn.comm[:c]
+        end
+
+        d << "*** #{insn.name}\n"
+        d << "\n"
+        d << insn.comm[lang] + "\n\n"
+        d << ":instruction sequence: 0x%02x #{seq}\n" % i
+        d << ":stack: #{before} => #{after}\n\n"
+        i+=1
+      }
+      d
+    end
+
+    def desc_ja
+      d = desc :j
+      ERB.new(vpath.read('template/yarvarch.ja')).result(binding)
+    end
+
+    def desc_en
+      d = desc :e
+      ERB.new(vpath.read('template/yarvarch.en')).result(binding)
+    end
+  end
+
+  module VPATH
+    def search(meth, base, *rest)
+      begin
+        meth.call(base, *rest)
+      rescue Errno::ENOENT => error
+        each do |dir|
+          return meth.call(File.join(dir, base), *rest) rescue nil
+        end
+        raise error
+      end
+    end
+
+    def process(*args, &block)
+      search(File.method(__callee__), *args, &block)
+    end
+
+    alias stat process
+    alias lstat process
+
+    def open(*args)
+      f = search(File.method(:open), *args)
+      if block_given?
+        begin
+          yield f
+        ensure
+          f.close unless f.closed?
+        end
+      else
+        f
+      end
+    end
+
+    def read(*args)
+      open(*args) {|f| f.read}
+    end
+
+    def foreach(file, *args, &block)
+      open(file) {|f| f.each(*args, &block)}
+    end
+
+    def self.def_options(opt)
+      vpath = []
+      path_sep = ':'
+
+      opt.on("-I", "--srcdir=DIR", "add a directory to search path") {|dir|
+        vpath |= [dir]
+      }
+      opt.on("-L", "--vpath=PATH LIST", "add directories to search path") {|dirs|
+        vpath |= dirs.split(path_sep)
+      }
+      opt.on("--path-separator=SEP", /\A\W\z/, "separator for vpath") {|sep|
+        path_sep = sep
+      }
+
+      proc {
+        vpath.extend(self) unless vpath.empty?
+      }
+    end
+  end
+
+  class SourceCodeGenerator
+    Files = { # codes
+      'vm.inc'         => VmBodyGenerator,
+      'vmtc.inc'       => VmTCIncGenerator,
+      'insns.inc'      => InsnsIncGenerator,
+      'insns_info.inc' => InsnsInfoIncGenerator,
+    # 'minsns.inc'     => MInsnsIncGenerator,
+      'optinsn.inc'    => OptInsnIncGenerator,
+      'optunifs.inc'   => OptUnifsIncGenerator,
+      'opt_sc.inc'     => OptSCIncGenerator,
+      'yasmdata.rb'    => YASMDataRbGenerator,
+    }
+
+    def generate args = []
+      args = Files.keys if args.empty?
+      args.each{|fn|
+        s = Files[fn].new(@insns).generate
+        open(output_path(fn), 'w') {|f| f.puts(s)}
+      }
+    end
+
+    def self.def_options(opt)
+      opts = {
+        :"insns.def" => 'insns.def',
+        :"opope.def" => 'opt_operand.def',
+        :"unif.def"  => 'opt_insn_unif.def',
+      }
+
+      opt.on("-Dname", /\AOPT_(\w+)\z/, "enable VM option") {|s, v|
+        opts[v] = true
+      }
+      opt.on("--enable=name[,name...]", Array,
+        "enable VM options (without OPT_ prefix)") {|*a|
+        a.each {|v| opts[v] = true}
+      }
+      opt.on("-Uname", /\AOPT_(\w+)\z/, "disable VM option") {|s, v|
+        opts[v] = false
+      }
+      opt.on("--disable=name[,name...]", Array,
+        "disable VM options (without OPT_ prefix)") {|*a|
+          a.each {|v| opts[v] = false}
+      }
+      opt.on("-i", "--insnsdef=FILE", "--instructions-def",
+        "instructions definition file") {|n|
+        opts[:insns_def] = n
+      }
+      opt.on("-o", "--opt-operanddef=FILE", "--opt-operand-def",
+        "vm option: operand definition file") {|n|
+        opts[:opope_def] = n
+      }
+      opt.on("-u", "--opt-insnunifdef=FILE", "--opt-insn-unif-def",
+        "vm option: instruction unification file") {|n|
+        opts[:unif_def] = n
+      }
+      opt.on("-C", "--[no-]use-const",
+        "use consts for default operands instead of macros") {|v|
+        opts[:use_const] = v
+      }
+      opt.on("-d", "--destdir", "--output-directory=DIR",
+        "make output file underneath DIR") {|v|
+        opts[:destdir] = v
+      }
+      opt.on("-V", "--[no-]verbose") {|v|
+        opts[:verbose] = v
+      }
+
+      vpath = VPATH.def_options(opt)
+
+      proc {
+        opts[:VPATH] = vpath.call
+        build opts
+      }
+    end
+
+    def self.build opts, vpath = ['./']
+      opts[:VPATH] = vpath.extend(VPATH) unless opts[:VPATH]
+      self.new InstructionsLoader.new(opts)
+    end
+  end
+end
+

Property changes on: tool/instruction.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]