Как смоделировать "добавить 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) и значительно упрощает работу со структурами с именованными аргументами.