作为关于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
方法将接受标签名称或其他功能之一的序列号。所以我的问题是:在块中:
{
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
又名goto
方法。我的一个想法是使用一个哈希来保存所有被调用的方法及其参数,或者循环块,包含指令并根据全局变量中保存的条件执行或不执行方法,但我对此无能为力。因此,例如,有没有办法打破块并将每个指令保存在数组/散列中,然后根据其索引或类似的东西执行它。任何帮助表示赞赏。非常感谢你提前。
答案 0 :(得分:7)
这是一个想法:预先“解析”你的汇编代码,然后执行它。这包括改变一些事情。这将是我对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
让我们一步一步来看看。我没有使用每条指令的方法,而是使用lambdas的哈希值。然后,我使用method_missing做三件事:
cx
与:cx
等效。label
,请将下一条指令的索引添加到该名称下的标签哈希中。指令lambda的返回值(如果不是nil)用作程序计数器的新值(如果可以添加零,则跳转更多跳转)。
答案 1 :(得分:4)
我会让每个函数调用将一个表示指令的对象推送到一个数组,然后在块结束时,你可以知道整个程序知道所有指令的位置(正如你的建议)。
对于标签,指令可能应该将标签添加到来自label => instruction index
的哈希映射中,这样如果你得到标签,就可以快速查找跳转目标。