Как смоделировать "добавить eax, 1" в прологе?

Я пытаюсь смоделировать некоторый простой ASM-код, используя Пролог. (32 бита)

Я новичок в Прологе, и я застрял в некоторых проблемах без каких-либо решений.

В основном, если здесь код:

...
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 в следующих инструкциях?

Может ли кто-нибудь помочь мне? Спасибо!

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 в том, что они занимают гораздо больше процессорного времени, чем манипуляции со списком. Но я думаю, что они имеют смысл для такого рода приложений, где у вас есть "состояние" процессора, которое представлено несколькими значениями регистра.

Путь "Пролог" состоит в том, чтобы фактически поддерживать состояние всех ваших регистров в терминах, которые вы передаете по главному предикату, который запускает симуляцию. Так, например:

% 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) (см. здесь), с первоначальной идеей, предложенной Ричардом О'Кифом в его книге "Ремесло Пролога", для точного выполнения подобных вещей. Если вы используете библиотеку, вам не нужно писать все права доступа и устанавливать предикаты самостоятельно.

Если вы используете SWI-Prolog, вы также можете использовать Dicts; смотрите здесь. Это является частью текущей версии разработки SWI-Prolog (версия 7) и значительно упрощает работу со структурами с именованными аргументами.

Другие вопросы по тегам