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

标签 ruby goto

作为 DSL 主题的作业,我需要用 Ruby 编写一个内联汇编程序。我知道 The Joke Is On Us: How Ruby 1.9 Supports the Goto Statement ,但我不能使用它。这是一个非常简单的实现,汇编程序有四个寄存器 - axbxcxdx,分别保存整数值,我可以对其进行一些操作,例如设置它们的值 (mov)、比较两个寄存器 (cmp)、递增寄存器 (inc), 跳转到一个特定的地方 (jmp) 和其他一些类似的。界面将是这样的:

Asm.asm do
  mov cx, 1
  jmp l1
  mov ax, 1
  label l1
  mov dx, 1
end

jmp 方法将接受标签名称或其他函数之一的序号。所以我的问题是:在 block 中:

{
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 方法。我的一个想法是使用一个散列来保存所有被调用的方法及其参数,或者循环 block ,包含指令并根据保存在全局变量中的条件执行或不执行方法,但我对此无能为力。因此,例如,有没有办法打破 block 并将每条指令保存在数组/哈希中,然后根据其索引或类似的东西执行它。任何帮助表示赞赏。非常感谢您。

最佳答案

这里有一个想法:预先“解析”您的汇编代码,然后执行它。这包括改变一些事情。这是我对 Memory 类的实现:

class Memory
  attr_reader :table
  def initialize
    @table = { ax: 0, bx: 0, cx: 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

让我们一步步过一遍。我没有为每条指令使用方法,而是使用 lambda 散列。然后,我使用 method_missing 做三件事:

  1. 如果方法名只是一个随机符号(不是指令名),我只返回该符号。所以现在,cx 等同于 :cx
  2. 如果是指令名,将它和参数添加到程序数组
  3. 如果它是一个标签,将下一条指令的索引添加到该名称下的标签散列中。

指令 lambda 的返回值(如果不是 nil)用作程序计数器的新值(以便可以添加更多跳转,如 jump if zero)。

关于ruby - 如何在 Ruby 中实现 goto 和 label 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21120281/

相关文章:

c - 在两个函数中使用 Goto 函数

ruby - 从 ruby​​ 哈希中获取所有 key

ruby - gem install pg 不适用于 OSX Lion

jQuery onClick 转到 ID 或类

c - 返回到 if 语句的开头

python - 相当于条件中的 GOTO,Python

Ruby Gem 包管理器因 Gem::GemNotFoundException 失败

ruby - 在 Ruby 中序列化扩展的 String 类

ruby - 获取 Ruby 字符串中特定单词后的单词?

python - 如何根据参数值 "skip"多功能 python 脚本中的各个函数