def output_op(code, op, indent=2)
      case op
      when Dot
        code << indentify("_tmp = get_byte\n", indent)
      when LiteralString
        code << indentify("_tmp = match_string(#{op.string.dump})\n", indent)
      when LiteralRegexp
        if op.regexp.respond_to?(:kcode)
          lang = op.regexp.kcode.to_s[0,1]
        else
          # Let default ruby string handling figure it out
          lang = ""
        end
        code << indentify("_tmp = scan(/\\A#{op.regexp}/#{lang})\n", indent)
      when CharRange
        ss = save()
        if op.start.bytesize == 1 and op.fin.bytesize == 1
          code << indentify("#{ss} = self.pos\n", indent)
          code << indentify("_tmp = get_byte\n", indent)
          code << indentify("if _tmp\n", indent)

          if op.start.respond_to? :getbyte
            left  = op.start.getbyte 0
            right = op.fin.getbyte 0
          else
            left  = op.start[0]
            right = op.fin[0]
          end

          code << indentify("  unless _tmp >= #{left} and _tmp <= #{right}\n", indent)
          code << indentify("    self.pos = #{ss}\n", indent)
          code << indentify("    _tmp = nil\n", indent)
          code << indentify("  end\n", indent)
          code << indentify("end\n", indent)
        else
          raise "Unsupported char range - #{op.inspect}"
        end
      when Choice
        ss = save()
        code << "\n"
        code << indentify("#{ss} = self.pos\n", indent)
        code << indentify("while true # choice\n", indent)
        op.ops.each_with_index do |n,idx|
          output_op code, n, (indent+1)

          code << indentify("  break if _tmp\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          if idx == op.ops.size - 1
            code << indentify("  break\n", indent)
          end
        end
        code << indentify("end # end choice\n\n", indent)
      when Multiple
        ss = save()
        if op.min == 0 and op.max == 1
          code << indentify("#{ss} = self.pos\n", indent)
          output_op code, op.op, indent
          if op.save_values
            code << indentify("@result = nil unless _tmp\n", indent)
          end
          code << indentify("unless _tmp\n", indent)
          code << indentify("  _tmp = true\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          code << indentify("end\n", indent)
        elsif op.min == 0 and !op.max
          if op.save_values
            code << indentify("_ary = []\n", indent)
          end

          code << indentify("while true\n", indent)
          output_op code, op.op, (indent+1)
          if op.save_values
            code << indentify("  _ary << @result if _tmp\n", indent)
          end
          code << indentify("  break unless _tmp\n", indent)
          code << indentify("end\n", indent)
          code << indentify("_tmp = true\n", indent)

          if op.save_values
            code << indentify("@result = _ary\n", indent)
          end

        elsif op.min == 1 and !op.max
          code << indentify("#{ss} = self.pos\n", indent)
          if op.save_values
            code << indentify("_ary = []\n", indent)
          end
          output_op code, op.op, indent
          code << indentify("if _tmp\n", indent)
          if op.save_values
            code << indentify("  _ary << @result\n", indent)
          end
          code << indentify("  while true\n", indent)
          output_op code, op.op, (indent+2)
          if op.save_values
            code << indentify("    _ary << @result if _tmp\n", indent)
          end
          code << indentify("    break unless _tmp\n", indent)
          code << indentify("  end\n", indent)
          code << indentify("  _tmp = true\n", indent)
          if op.save_values
            code << indentify("  @result = _ary\n", indent)
          end
          code << indentify("else\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          code << indentify("end\n", indent)
        else
          code << indentify("#{ss} = self.pos\n", indent)
          code << indentify("_count = 0\n", indent)
          code << indentify("while true\n", indent)
          output_op code, op.op, (indent+1)
          code << indentify("  if _tmp\n", indent)
          code << indentify("    _count += 1\n", indent)
          code << indentify("    break if _count == #{op.max}\n", indent)
          code << indentify("  else\n", indent)
          code << indentify("    break\n", indent)
          code << indentify("  end\n", indent)
          code << indentify("end\n", indent)
          code << indentify("if _count >= #{op.min}\n", indent)
          code << indentify("  _tmp = true\n", indent)
          code << indentify("else\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          code << indentify("  _tmp = nil\n", indent)
          code << indentify("end\n", indent)
        end

      when Sequence
        ss = save()
        code << "\n"
        code << indentify("#{ss} = self.pos\n", indent)
        code << indentify("while true # sequence\n", indent)
        op.ops.each_with_index do |n, idx|
          output_op code, n, (indent+1)

          if idx == op.ops.size - 1
            code << indentify("  unless _tmp\n", indent)
            code << indentify("    self.pos = #{ss}\n", indent)
            code << indentify("  end\n", indent)
            code << indentify("  break\n", indent)
          else
            code << indentify("  unless _tmp\n", indent)
            code << indentify("    self.pos = #{ss}\n", indent)
            code << indentify("    break\n", indent)
            code << indentify("  end\n", indent)
          end
        end
        code << indentify("end # end sequence\n\n", indent)
      when AndPredicate
        ss = save()
        code << indentify("#{ss} = self.pos\n", indent)
        if op.op.kind_of? Action
          code << indentify("_tmp = begin; #{op.op.action}; end\n", indent)
        else
          output_op code, op.op, indent
        end
        code << indentify("self.pos = #{ss}\n", indent)
      when NotPredicate
        ss = save()
        code << indentify("#{ss} = self.pos\n", indent)
        if op.op.kind_of? Action
          code << indentify("_tmp = begin; #{op.op.action}; end\n", indent)
        else
          output_op code, op.op, indent
        end
        code << indentify("_tmp = _tmp ? nil : true\n", indent)
        code << indentify("self.pos = #{ss}\n", indent)
      when RuleReference
        if op.arguments
          code << indentify("_tmp = apply_with_args(:#{method_name op.rule_name}, #{op.arguments[1..-2]})\n", indent)
        else
          code << indentify("_tmp = apply(:#{method_name op.rule_name})\n", indent)
        end
      when InvokeRule
        if op.arguments
          code << indentify("_tmp = #{method_name op.rule_name}#{op.arguments}\n", indent)
        else
          code << indentify("_tmp = #{method_name op.rule_name}()\n", indent)
        end
      when ForeignInvokeRule
        if op.arguments
          code << indentify("_tmp = @_grammar_#{op.grammar_name}.external_invoke(self, :#{method_name op.rule_name}, #{op.arguments[1..-2]})\n", indent)
        else
          code << indentify("_tmp = @_grammar_#{op.grammar_name}.external_invoke(self, :#{method_name op.rule_name})\n", indent)
        end
      when Tag
        if op.tag_name and !op.tag_name.empty?
          output_op code, op.op, indent
          code << indentify("#{op.tag_name} = @result\n", indent)
        else
          output_op code, op.op, indent
        end
      when Action
        code << indentify("@result = begin; ", indent)
        code << op.action << "; end\n"
        if @debug
          code << indentify("puts \"   => \" #{op.action.dump} \" => \#{@result.inspect} \\n\"\n", indent)
        end
        code << indentify("_tmp = true\n", indent)
      when Collect
        code << indentify("_text_start = self.pos\n", indent)
        output_op code, op.op, indent
        code << indentify("if _tmp\n", indent)
        code << indentify("  text = get_text(_text_start)\n", indent)
        code << indentify("end\n", indent)
      when Bounds
        code << indentify("_bounds_start = self.pos\n", indent)
        output_op code, op.op, indent
        code << indentify("if _tmp\n", indent)
        code << indentify("  bounds = [_bounds_start, self.pos]\n", indent)
        code << indentify("end\n", indent)
      else
        raise "Unknown op - #{op.class}"
      end
    end
def output_op(code, op, indent=2)
      case op
      when Dot
        code << indentify("_tmp = get_byte\n", indent)
      when LiteralString
        code << indentify("_tmp = match_string(#{op.string.dump})\n", indent)
      when LiteralRegexp
        if op.regexp.respond_to?(:kcode)
          lang = op.regexp.kcode.to_s[0,1]
        else
          # Let default ruby string handling figure it out
          lang = ""
        end
        code << indentify("_tmp = scan(/\\A#{op.regexp}/#{lang})\n", indent)
      when CharRange
        ss = save()
        if op.start.bytesize == 1 and op.fin.bytesize == 1
          code << indentify("#{ss} = self.pos\n", indent)
          code << indentify("_tmp = get_byte\n", indent)
          code << indentify("if _tmp\n", indent)

          if op.start.respond_to? :getbyte
            left  = op.start.getbyte 0
            right = op.fin.getbyte 0
          else
            left  = op.start[0]
            right = op.fin[0]
          end

          code << indentify("  unless _tmp >= #{left} and _tmp <= #{right}\n", indent)
          code << indentify("    self.pos = #{ss}\n", indent)
          code << indentify("    _tmp = nil\n", indent)
          code << indentify("  end\n", indent)
          code << indentify("end\n", indent)
        else
          raise "Unsupported char range - #{op.inspect}"
        end
      when Choice
        ss = save()
        code << "\n"
        code << indentify("#{ss} = self.pos\n", indent)
        code << indentify("while true # choice\n", indent)
        op.ops.each_with_index do |n,idx|
          output_op code, n, (indent+1)

          code << indentify("  break if _tmp\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          if idx == op.ops.size - 1
            code << indentify("  break\n", indent)
          end
        end
        code << indentify("end # end choice\n\n", indent)
      when Multiple
        ss = save()
        if op.min == 0 and op.max == 1
          code << indentify("#{ss} = self.pos\n", indent)
          output_op code, op.op, indent
          if op.save_values
            code << indentify("@result = nil unless _tmp\n", indent)
          end
          code << indentify("unless _tmp\n", indent)
          code << indentify("  _tmp = true\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          code << indentify("end\n", indent)
        elsif op.min == 0 and !op.max
          if op.save_values
            code << indentify("_ary = []\n", indent)
          end

          code << indentify("while true\n", indent)
          output_op code, op.op, (indent+1)
          if op.save_values
            code << indentify("  _ary << @result if _tmp\n", indent)
          end
          code << indentify("  break unless _tmp\n", indent)
          code << indentify("end\n", indent)
          code << indentify("_tmp = true\n", indent)

          if op.save_values
            code << indentify("@result = _ary\n", indent)
          end

        elsif op.min == 1 and !op.max
          code << indentify("#{ss} = self.pos\n", indent)
          if op.save_values
            code << indentify("_ary = []\n", indent)
          end
          output_op code, op.op, indent
          code << indentify("if _tmp\n", indent)
          if op.save_values
            code << indentify("  _ary << @result\n", indent)
          end
          code << indentify("  while true\n", indent)
          output_op code, op.op, (indent+2)
          if op.save_values
            code << indentify("    _ary << @result if _tmp\n", indent)
          end
          code << indentify("    break unless _tmp\n", indent)
          code << indentify("  end\n", indent)
          code << indentify("  _tmp = true\n", indent)
          if op.save_values
            code << indentify("  @result = _ary\n", indent)
          end
          code << indentify("else\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          code << indentify("end\n", indent)
        else
          code << indentify("#{ss} = self.pos\n", indent)
          code << indentify("_count = 0\n", indent)
          code << indentify("while true\n", indent)
          output_op code, op.op, (indent+1)
          code << indentify("  if _tmp\n", indent)
          code << indentify("    _count += 1\n", indent)
          code << indentify("    break if _count == #{op.max}\n", indent)
          code << indentify("  else\n", indent)
          code << indentify("    break\n", indent)
          code << indentify("  end\n", indent)
          code << indentify("end\n", indent)
          code << indentify("if _count >= #{op.min}\n", indent)
          code << indentify("  _tmp = true\n", indent)
          code << indentify("else\n", indent)
          code << indentify("  self.pos = #{ss}\n", indent)
          code << indentify("  _tmp = nil\n", indent)
          code << indentify("end\n", indent)
        end

      when Sequence
        ss = save()
        code << "\n"
        code << indentify("#{ss} = self.pos\n", indent)
        code << indentify("while true # sequence\n", indent)
        op.ops.each_with_index do |n, idx|
          output_op code, n, (indent+1)

          if idx == op.ops.size - 1
            code << indentify("  unless _tmp\n", indent)
            code << indentify("    self.pos = #{ss}\n", indent)
            code << indentify("  end\n", indent)
            code << indentify("  break\n", indent)
          else
            code << indentify("  unless _tmp\n", indent)
            code << indentify("    self.pos = #{ss}\n", indent)
            code << indentify("    break\n", indent)
            code << indentify("  end\n", indent)
          end
        end
        code << indentify("end # end sequence\n\n", indent)
      when AndPredicate
        ss = save()
        code << indentify("#{ss} = self.pos\n", indent)
        if op.op.kind_of? Action
          code << indentify("_tmp = begin; #{op.op.action}; end\n", indent)
        else
          output_op code, op.op, indent
        end
        code << indentify("self.pos = #{ss}\n", indent)
      when NotPredicate
        ss = save()
        code << indentify("#{ss} = self.pos\n", indent)
        if op.op.kind_of? Action
          code << indentify("_tmp = begin; #{op.op.action}; end\n", indent)
        else
          output_op code, op.op, indent
        end
        code << indentify("_tmp = _tmp ? nil : true\n", indent)
        code << indentify("self.pos = #{ss}\n", indent)
      when RuleReference
        if op.arguments
          code << indentify("_tmp = apply_with_args(:#{method_name op.rule_name}, #{op.arguments[1..-2]})\n", indent)
        else
          code << indentify("_tmp = apply(:#{method_name op.rule_name})\n", indent)
        end
      when InvokeRule
        if op.arguments
          code << indentify("_tmp = #{method_name op.rule_name}#{op.arguments}\n", indent)
        else
          code << indentify("_tmp = #{method_name op.rule_name}()\n", indent)
        end
      when ForeignInvokeRule
        if op.arguments
          code << indentify("_tmp = @_grammar_#{op.grammar_name}.external_invoke(self, :#{method_name op.rule_name}, #{op.arguments[1..-2]})\n", indent)
        else
          code << indentify("_tmp = @_grammar_#{op.grammar_name}.external_invoke(self, :#{method_name op.rule_name})\n", indent)
        end
      when Tag
        if op.tag_name and !op.tag_name.empty?
          output_op code, op.op, indent
          code << indentify("#{op.tag_name} = @result\n", indent)
        else
          output_op code, op.op, indent
        end
      when Action
        code << indentify("@result = begin; ", indent)
        code << op.action << "; end\n"
        if @debug
          code << indentify("puts \"   => \" #{op.action.dump} \" => \#{@result.inspect} \\n\"\n", indent)
        end
        code << indentify("_tmp = true\n", indent)
      when Collect
        code << indentify("_text_start = self.pos\n", indent)
        output_op code, op.op, indent
        code << indentify("if _tmp\n", indent)
        code << indentify("  text = get_text(_text_start)\n", indent)
        code << indentify("end\n", indent)
      when Bounds
        code << indentify("_bounds_start = self.pos\n", indent)
        output_op code, op.op, indent
        code << indentify("if _tmp\n", indent)
        code << indentify("  bounds = [_bounds_start, self.pos]\n", indent)
        code << indentify("end\n", indent)
      else
        raise "Unknown op - #{op.class}"
      end
    end
Default indent is 4 spaces (indent=2)