代码之家  ›  专栏  ›  技术社区  ›  lllllllllllll

如何在Prolog中模拟“添加eax,1”?

  •  1
  • lllllllllllll  · 技术社区  · 12 年前

    我正在尝试使用Prolog模拟一些简单的asm代码。(32位)

    我是Prolog的新手,我陷入了一些没有任何解决方案的问题。

    基本上,如果代码如下:

    ...
    add eax, 1
    ...
    

    我想这样模拟:

    ...
    EAX is EAX - 1,
    ...
    

    并且滑动将产生如下错误:

      Call: (7) 1 is 1-1 ? creep
     Fail: (7) 1 is 1-1 ? creep
     ....
     false
    

    我知道基本上我可以这样做:

    EAX_temp is EAX + 1 
    

    但我如何在接下来的指令中继续操纵EAX。。?

    有人能帮我吗。。?非常感谢。

    2 回复  |  直到 12 年前
        1
  •  3
  •   user1812457 user1812457    12 年前

    “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)在其著作《Prolog的工艺》(the Craft of Prolog)中提出的。如果使用libary,则不需要自己编写所有的访问和设置谓词。

    但是,如果您使用SWI Prolog,也可以使用 Dicts ; 看见 here 这是SWI Prolog(版本7)当前开发版本的一部分,使处理带有命名参数的结构变得更加容易。

        2
  •  2
  •   lurker    12 年前

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

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

    :- 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的“状态”由几个寄存器值表示。

    推荐文章