如何在Ruby中实现goto和label方法?

前端之家收集整理的这篇文章主要介绍了如何在Ruby中实现goto和label方法?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
作为主题DSL的作业,我需要在 Ruby中编写内联汇编程序.我知道 The Joke Is On Us: How Ruby 1.9 Supports the Goto Statement,但我不能使用它.这是一个非常简单的实现,汇编器有四个寄存器 – ax,bx,cx,dx,保存整数值,我可以在其上做一些操作,比如设置它们的值(mov),比较两个寄存器(cmp),递增a register(inc),跳到某个特定的地方(jmp)和其他一些类别.界面将是这样的:
Asm.asm do
  mov cx,1
  jmp l1
  mov ax,1
  label l1
  mov dx,1
end

jmp方法将接受标签名称或其他功能之一的序列号.所以我的问题是:在块中:

{
mov cx,1
jmp l1
mov ax,1
label l1
mov dx,1
}

如何跟踪当前的功能数量.我的实现看起来大致如下:

module Asm
  def self.asm(&block)
    memory = Memory.new
    memory.instance_eval(&block)
    memory.table.values
  end

  class Memory
    attr_reader :table

    def initialize
      @table = { ax: 0,bx: 0,cx: 0,dx: 0 }
      ...
    end

    ...

    def mov(destination_register,source)
      ...
    end

    def inc(destination_register,value = 1)
      ...
    end

    def dec(destination_register,value = 1)
      ...
    end

    ...
  end
end

我被困在实现jmp aka goto方法.我的一个想法是使用一个哈希来保存所有被调用方法及其参数,或者循环块,包含指令并根据全局变量中保存的条件执行或不执行方法,但我对此无能为力.因此,例如,有没有办法打破块并将每个指令保存在数组/散列中,然后根据其索引或类似的东西执行它.任何帮助表示赞赏.非常感谢你提前.

解决方法

这是一个想法:预先“解析”汇编代码后执行它.这包括改变一些事情.这将是我的Memory类的实现:
class Memory
  attr_reader :table
  def initialize
    @table = { ax: 0,dx: 0 }
    @program = []
    @labels = {}
  end
  OPS = {
    "mov" => lambda {|dest,src| @table[dest] = (src.is_a?(Symbol) ? @table[src] : src); nil},"inc" => lambda {|dest,incval = 1| @table[dest] += incval; nil},"jmp" => lambda {|lblname| @labels[lblname]}
    #and so on
  }
  def method_missing(name,*args)
    if(OPS.keys.include?(name.to_s)) 
      @program << [name.to_s,args]
    elsif(name.to_s == "label")
      @labels[args.first] = @program.length
    else
      return name
    end
  end
  def load_program(&block)
    self.instance_exec(&block)
  end
  def run_program
    pc = 0
    until(pc == @program.length)
      instruction = @program[pc]
      retval = self.instance_exec(*instruction[1],&OPS[instruction[0]])
      if(retval)
        pc = retval
      else
        pc += 1
      end
    end
  end
  def asm(&block)
    load_program(&block)
    run_program
    @table
  end
end

让我们一步一步来看看.我没有使用每条指令的方法,而是使用lambdas的哈希值.然后,我使用method_missing做三件事:

>如果方法名称只是一个随机符号(不是指令名称),我只返回符号.所以现在,cx与:cx相同.
>如果是指令名称,请将其和参数添加到程序数组中
>如果是标签,请将下一条指令的索引添加到该名称下的标签哈希中.

指令lambda的返回值(如果不是nil)用作程序计数器的新值(因此,如果可以添加零,则跳转更多跳转).

猜你在找的Ruby相关文章