作为 DSL 主题的作业,我需要用 Ruby 编写一个内联汇编程序。我知道 The Joke Is On Us: How Ruby 1.9 Supports the Goto Statement ,但我不能使用它。这是一个非常简单的实现,汇编程序有四个寄存器 - ax
、bx
、cx
、dx
,分别保存整数值,我可以对其进行一些操作,例如设置它们的值 (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 做三件事:
- 如果方法名只是一个随机符号(不是指令名),我只返回该符号。所以现在,
cx
等同于:cx
。 - 如果是指令名,将它和参数添加到程序数组
- 如果它是一个
标签
,将下一条指令的索引添加到该名称下的标签散列中。
指令 lambda 的返回值(如果不是 nil)用作程序计数器的新值(以便可以添加更多跳转,如 jump if zero)。
关于ruby - 如何在 Ruby 中实现 goto 和 label 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21120281/