Prolog 如何模拟;添加eax,1“;在序言中?
我试图用Prolog模拟一些简单的asm代码。(32位) 我是Prolog新手,在一些没有任何解决方案的问题上结巴 基本上,如果代码如下:Prolog 如何模拟;添加eax,1“;在序言中?,prolog,Prolog,我试图用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 但在
...
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
谁能给我一些帮助吗。。?谢谢大家! 可能有几种好方法可以做到这一点。答案可能会根据你目前不清楚的背景进一步细化 一种方法是,您可以为寄存器值创建动态事实:
:- 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).
% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)
reg_eax(reg(EAX, _, _, _, _, _), EAX).
reg_ebx(reg(_, EBX, _, _, _, _), EBX).
% and so on
assert
和retract
的主要缺点是它们比列表操作占用更多的CPU时间。但是我认为它们对于这样的应用程序是有意义的,在这种应用程序中,CPU“状态”由几个寄存器值表示。可能有几种好的方法来实现这一点。答案可能会根据你目前不清楚的背景进一步细化
一种方法是,您可以为寄存器值创建动态事实:
:- 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).
% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)
reg_eax(reg(EAX, _, _, _, _, _), EAX).
reg_ebx(reg(_, EBX, _, _, _, _), EBX).
% and so on
assert
和retract
的主要缺点是它们比列表操作占用更多的CPU时间。但是我认为它们对于这种应用程序来说是有意义的,在这种应用程序中,CPU的“状态”由几个寄存器值表示。用“Prolog”的方法实际上是在一个术语中维护所有寄存器的状态,这个术语由运行模拟的主谓词传递。例如:
register(eax, EAXValue).
% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)
reg_eax(reg(EAX, _, _, _, _, _), EAX).
reg_ebx(reg(_, EBX, _, _, _, _), EBX).
% and so on
但请注意:这不是一个谓词(因此结尾处缺少点)!这是一个术语,它将被初始化为全零(我在这里假设):
因此,在程序开始时,您可以使用以下命令初始化寄存器:
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.
您可以将其保留在此处,也可以使用帮助器谓词提供对所需寄存器的访问,例如:
register(eax, EAXValue).
% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)
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\u指令/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\u eax
和set\u reg\u eax
可以由一个库自动生成,library(record)
(参见),理查德·奥基夫(Richard o'Keefe)在他的《Prolog的工艺》(The Craft of Prolog)一书中提出的最初想法就是要做这类事情。如果使用库,则不需要自己编写所有访问和设置谓词
但是,如果您使用的是SWI Prolog,您也可以使用Dicts
;看见这是SWI Prolog当前开发版本(版本7)的一部分,使处理带有命名参数的结构变得更加容易。使用“Prolog”的方法是在一个术语中实际维护所有寄存器的状态,该术语由运行模拟的主谓词传递。例如:
register(eax, EAXValue).
% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)
reg_eax(reg(EAX, _, _, _, _, _), EAX).
reg_ebx(reg(_, EBX, _, _, _, _), EBX).
% and so on
但请注意:这不是一个谓词(因此结尾处缺少点)!这是一个术语,它将被初始化为全零(我在这里假设):
因此,在程序开始时,您可以使用以下命令初始化寄存器:
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.
您可以将其保留在此处,也可以使用帮助器谓词提供对所需寄存器的访问,例如:
register(eax, EAXValue).
% general-purpose registers
% regs(EAX, EBX, ECX, EDX, ESI, EDI)
regs(0, 0, 0, 0, 0, 0)
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\u指令/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\u eax
和set\u reg\u eax
可以由一个库自动生成,library(record)
(参见),理查德·奥基夫(Richard o'Keefe)在他的《Prolog的工艺》(The Craft of Prolog)一书中提出的最初想法就是要做这类事情。如果使用库,则不需要自己编写所有访问和设置谓词
但是,如果您使用的是SWI Prolog,您也可以使用
Dicts
;看见这是SWI Prolog当前开发版本(第7版)的一部分,使处理带有命名参数的结构变得更加容易。Prolog不允许修改变量。相关问题:查看@mat的评论!出于好奇,您为什么选择prolog作为解决此问题的语言。prolog不允许您修改变量。相关问题:请看@mat的评论!出于好奇,您为什么选择prolog作为解决此问题的语言。哇,这是一种非常棒的语言!!顺便问一下:你能给我一些关于如何使用列表模拟堆栈的指南吗。。。?我会遵循动态事实策略,但我不知道如何。。。非常感谢。我只使用push(Stack,Value,[Value | Stack])。应该还不够。。。无论如何,我必须使用ESP和EBP来访问堆栈…我想使用动态事实,但问题是我不知道要使用什么数据结构…这是一种非常有效的方法(您已经对解决方案的缺点进行了评论)。目前的共识(邮件列表等)似乎是,以其他方式维护一个国家更好。更迫切的方法是使用全局变量,更“Prolog”-y的方法是将状态保持在传递给循环谓词的递归调用的术语中(参见我的答案)。基于assertz/1
的方法有比断言更多CPU时间更严重的缺点,上面没有提到的内容:例如,您不能再单独地推理和测试谓词,这会破坏代码的关系性质:您不能再在各个方向上使用谓词,并且经常会失去处理部分实例化或变量参数的能力。当显式地传递状态时,这些缺点都不是固有的。@mat和Boris,谢谢你的评论,我明白你的意思。然而,如果你在寻找最好的方法,我不认为prolog是最好的语言