/* Definitions: A machine state consists of three parts: a program counter (PC), current contents of memory, and a program. The program counter is a non-negative integer value. The current contents of memory is a list of non-negative integer values. The program is a list of instructions. An instruction consistes of three parts: an operation code, a first index, and a second index. The supported operation codes are: move, add, decrement, jump, and jump_on_zero. Indices are non-negative integer values used either as indexes into the memory list (addresses in memory), indexes into the program list (new values of the program counter), or ignored. */ /* Rule 1: The result of simulating a particular machine state is the contents of memory in that state when the PC is 0. */ simulate(state(0, Memory, Program), Memory) :- . /* Rule 2: If the PC is not zero, then simulating the current state can be performed by simulating the current instruction and then simulating the new state that results from that instruction. The result of simulating the new state is the result for simulating the current state. */ /* Rule 3: Simulating a one instruction from the current state is the new state that results from performing the instruction indicated by the current PC (which is an index into the Program list). */ simulate_one_instruction(state(PC, CurrentMemory, Program), state(NewPC, NewMemory, Program)) :- current_instruction(PC, Program, Instruction), perform_instruction(Instruction, PC, CurrentMemory, NewPC, NewMemory). /* Rule 4: Performing a move X Y instruction means moving the value stored in memory at location X to location Y. The program counter is incremented by 1. */ perform_instruction(instruction(move, X, Y), PC, CurrentMemory, NewPC, NewMemory) :- integer(PC), integer(X), integer(Y), plus(PC, 1, NewPC), extract_memory(X, CurrentMemory, ContentsAtX), change_memory(Y, CurrentMemory, ContentsAtX, NewMemory). /* Rule 5: Performing an add X Y instruction means moving adding the value stored at location X to the value stored at location Y and putting the result in location Y. The program counter is incremented by 1. */ /* Rule 6: Performing a decrement X Y instruction means that memory is not changed if the value stored at location X is 0. The program counter is incremented by 1. */ perform_instruction(instruction(decrement, X, Y), PC, CurrentMemory, NewPC, CurrentMemory) :- integer(PC), integer(X), plus(PC, 1, NewPC), extract_memory(X, CurrentMemory, 0). /* Rule 7: Performing a decrement X Y instruction means that when the value stored at location X is not 0, then it is replaced by the result of adding -1 to the current value at location X. The program counter is incremented by 1. */ perform_instruction(instruction(decrement, X, Y), PC, CurrentMemory, NewPC, NewMemory) :- integer(PC), integer(X), plus(PC, 1, NewPC), extract_memory(X, CurrentMemory, ContentsAtX), not X = 0, plus(NewValue, 1, ContentsAtX), change_memory(X, CurrentMemory, NewValue, NewMemory). /* Rule 8: Performing a jump X Y instruction means that the program counter becomes the value X. */ perform_instruction(instruction(jump, X, Y), PC, CurrentMemory, X, CurrentMemory) :- . /* Rule 9: Performing a jump_on_zero X Y instruction means that if the contents of location Y are zero, then the program counter is changed to X. */ /* Rule 10: Performing a jump_on_zero X Y instruction means that if the contents of location Y are not zero, then the program counter is incremented. */ /* Rule 11: If the PC is 1, then the first instruction in the instruction list is the current instruction. */ current_instruction(1, Instruction:RestOfProgram, Instruction) :- . /* Rule 12: If the PC is not 1, then we can find the current instruction by removing the first instruction from the list, decrementing the PC, and looking for the instruction at the new PC in the new list. */ current_instruction(PC, Instruction: RestOfProgram, NewInstruction) :- integer(PC), plus(NewPC, 1, PC), current_instruction(NewPC, RestOfProgram, NewInstruction). /* Rule 13: If the memory location is 1, then the first memory cell is the sought after memory cell. */ /* Rule 14: If the memory location is not 1, but there is only one cell left in memory, then the value of the sought after cell is 0. */ extract_memory(Location, CurrentCell:nil, 0) :- not Location = 1. /* Rule 15: If the memory location is not 1, but there is more than one cell left in memory, then the value of the cell sought can be gotten by subtracting 1 from the location sought, removing the first cell from the memory, and then looking for the new location in the new memory list. */ extract_memory(Location, CurrentCell:RestOfMemory, AnotherCell) :- not RestOfMemory = nil, not Location = 1, integer(Location), plus(NewLocation, 1, Location), extract_memory(NewLocation, RestOfMemory, AnotherCell). /* Rule 16: If we want to change the first cell in memory, then we replace it with the new value, but leave the rest of memory unchanged. */ change_memory(1, CurrentCell:RestOfMemory, NewValue, NewValue:RestOfMemory) :- . /* Rule 17: If we want to change a memory location that is not 1 in a memory list that has only one cell and the new value is to be 0, then the memory is left unchanged. */ /* Rule 18: If we want to change a memory location that is not 1 in a memory list that has only one cell and the new value is not 0, then we want to handle the current memory list as if it had an extra 0 at its end. We do this by looking at the result of adding into a memory list containing just one 0 at a location that is one less than the current memory location. When we see the memory list that results from this change, we then append to it the one cell in the original memory list. */ /* Rule 19: If we want to change a memory location that is not 1 in a memory list that has more than one cell, then we do this by decreasing the current memory location by 1 and removing the first element from the memory list. Once we find the result of changing the new location in the new memory list, we append the first cell from the original memory list to that result to get the new memory list that represents this change in the original list. */