Prolog 如何模拟;添加eax,1“;在序言中?

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 但在

我试图用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


谁能给我一些帮助吗。。?谢谢大家!

可能有几种好方法可以做到这一点。答案可能会根据你目前不清楚的背景进一步细化

一种方法是,您可以为寄存器值创建动态事实:

:- 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是最好的语言