我正在尝试使用Prolog来模拟一些简单的asm代码。 (32位)
我是Prolog的新手,我在没有任何解决方案的情况下遇到了一些问题。
基本上如果这是代码:
...
add eax, 1
...
我希望以这种方式模拟:
...
EAX is EAX - 1,
...
和swipl会产生如下错误:
Call: (7) 1 is 1-1 ? creep
Fail: (7) 1 is 1-1 ? creep
....
false
我基本上知道我可以这样做:
EAX_temp is EAX + 1
但是如何在下一条指令中继续操纵EAX ..?
任何人都能给我一些帮助..?谢谢!
答案 0 :(得分:2)
可能有几种好方法可以做到这一点。答案可能会进一步通过您目前尚不清楚的背景进一步完善。
一种方法是,您可以为寄存器值创建动态事实:
:- dynamic(register/2). % Fill in as needed
register(eax, 0).
register(ebx, 0).
...
add(Reg, Value) :-
( retract(register(Reg, OldValue))
-> NewValue is OldValue + Value
; NewValue = Value % If the register wasn't defined
),
assertz(register(Reg, NewValue)).
然后做:
add(eax, 4). % add eax,4
要读取寄存器,您只需使用,例如:
register(eax, EAXValue).
assert
和retract
的主要缺点是它们比列表操作占用了更多的CPU时间。但我认为它们对于这种应用程序是有意义的,在这种应用程序中,你有一个CPU“状态”,由几个寄存器值表示。
答案 1 :(得分:2)
“Prolog”方式是在一个术语中实际维护所有寄存器的状态,该术语通过运行模拟的主谓词传递。所以,例如:
% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)
但请注意:这不是谓词(因此最后会丢失一点)!这是一个术语,它将被初始化为全零(我假设在这里):
init_regs(regs(0,0,0,0,0,0)).
因此,在程序开始时,您可以使用以下命令初始化寄存器:
main :-
init_regs(Regs),
step(Regs).
step(Regs) :-
read_instruction(Instruction),
apply_instruction(Instruction, Regs, New_regs),
step(New_regs).
apply_instruction(add(eax, Addend),
regs(EAX, EBX, ECX, EDX, ESI, EDI),
regs(New_EAX, EBX, ECX, EDX, ESI, EDI)) :-
New_EAX is EAX + Addend.
您可以将其保留在此处,或者您可以使用帮助程序谓词来访问所需的一个寄存器,例如:
reg_eax(reg(EAX, _, _, _, _, _), EAX).
reg_ebx(reg(_, EBX, _, _, _, _), EBX).
% and so on
设置寄存器:
set_reg_eax(reg(EAX, EBX, ECX, EDX, ESI, EDI),
New_EAX,
reg(New_EAX, EBX, ECX, EDX, ESI, EDI)).
% and so on
然后您可以使用这样来定义apply_instruction/3
:
apply_instruction(add(eax, Addend), Regs, New_regs) :-
reg_eax(Regs, EAX),
New_EAX is EAX + Addend,
set_reg_eax(Regs, New_EAX, New_regs).
一种谓词,reg_eax
和set_reg_eax
可以由图书馆library(record)
(参见here)自动生成,其中最初的想法由Richard o提出Keefe在他的书“The Prop of Prolog”中做了exaclty这种东西。如果使用libary,则无需自己编写所有访问权限并设置谓词。
但是,如果您使用的是SWI-Prolog,您也可以使用Dicts
;见here。这是SWI-Prolog(版本7)当前开发版本的一部分,使得处理具有命名参数的结构变得更加容易。