Execute Computer/Zero: Difference between revisions

Added Easylang
(Add Go)
(Added Easylang)
 
(6 intermediate revisions by 4 users not shown)
Line 135:
400 DATA "LINKED LIST",45,111,69,112,71,0,78,0,171,79,192,46,224,32,0,28,1,0,0,0,6,0,2,26,5,20,3,30,1,22,4,24
500 DATA "PRISONER",0,0,224,0,0,35,157,178,35,93,174,33,127,65,194,32,127,64,192,35,93,33,126,99,</syntaxhighlight>
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
The original version of the virtual machine has a provision of entering user choices in the Prisoner's dilema game. It works allowing the user to enter a number when executing a Stop instruction. There is no simple way to do this with Rosetta Code instructions that the program should return a value when it reaches a Stop instruction. As a result, all the versions displayed in the Rosetta Code examples, simply returns a zero when it reaches the stop instruction.
<syntaxhighlight lang="Delphi">
 
{structure that holds name of program and code}
 
type TProgram = record
Name, Code: string;
end;
 
{List of programs}
 
var ProgList: array [0..4] of TProgram =(
(Name: 'Two plus two'; Code: 'LDA 3 ADD 4 STP 2 2'),
(Name: 'Seven times eight'; Code: 'LDA 12 ADD 10 STA 12 LDA 11 SUB 13 STA 11 BRZ 8 JMP 0 LDA 12 STP 8 7 0 1'),
(Name: 'The Fibonacci sequence'; Code: 'LDA 14 STA 15 ADD 13 STA 14 LDA 15 STA 13 LDA 16 SUB 17 BRZ 11 STA 16 JMP 0 LDA 14 STP 1 1 0 8 1'),
(Name: 'Linked list'; Code: 'LDA 13 ADD 15 STA 5 ADD 16 STA 7 NOP STA 14 NOP BRZ 11 STA 15 JMP 0 LDA 14 STP LDA 0 0 28 1 0 0 0 6 0 2 26 5 20 3 30 1 22 4 24'),
(Name: 'Prisoner’s Dilemma'; Code: '0 0 STP NOP LDA 3 SUB 29 BRZ 18 LDA 3 STA 29 BRZ 14 LDA 1 ADD 31 STA 1 JMP 2 LDA 0 ADD 31 STA 0 JMP 2 LDA 3 STA 29 LDA 0 ADD 30 ADD 3 STA 0 LDA 1 ADD 30 ADD 3 STA 1 JMP 2 0 1 3')
);
 
{Defines opcode function call}
 
type TOpProc = function(Opcode: byte): boolean;
 
{Defines argument type for opcode}
 
type TArgType = (atNone,atAddress,atMemory);
 
{Defines Opcode information}
 
type TOpcode = record
OpCode: integer;
ArgType: TArgType;
Mnemonic: string[3];
Proc: TOpProc;
end;
 
{Simulated memory, program counter and accumulator}
 
var Memory: array [0..31] of byte;
var ProgramCounter: integer;
var Accumulator: byte;
 
{Routines to carry out actions of opcodes}
 
function DoNoOp(Operand: byte): boolean;
{ ($00) = NOP - (no operation)}
begin
Inc(ProgramCounter);
Result:=True;
end;
 
 
function DoLDA(Operand: byte): boolean;
{ ($20) LDA - (load accumulator) - a := memory [xxxxx]}
begin
Accumulator:=Memory[Operand];
Inc(ProgramCounter);
Result:=True;
end;
 
 
function DoSTA(Operand: byte): boolean;
{ ($40) STA - (store accumulator) - memory [xxxxx] := a}
begin
Memory[Operand]:=Accumulator;
Inc(ProgramCounter);
Result:=True;
end;
 
 
function DoADD(Operand: byte): boolean;
{ ($60) ADD - (add) - a := a + memory [xxxxx]}
begin
Accumulator:=Accumulator + Memory[Operand];
Inc(ProgramCounter);
Result:=True;
end;
 
 
function DoSUB(Operand: byte): boolean;
{ ($80) SUB - (subtract) - a := a – memory [xxxxx]}
begin
Accumulator:=Accumulator - Memory[Operand];
Inc(ProgramCounter);
Result:=True;
end;
 
 
function DoBRZ(Operand: byte): boolean;
{ ($A0) BRZ - (branch on zero) - if a = 0 then goto xxxxx}
begin
if Accumulator=0 then ProgramCounter:=Operand
else Inc(ProgramCounter);
Result:=True;
end;
 
 
function DoJMP(Operand: byte): boolean;
{ ($C0) JMP - (jump) - goto xxxxx}
begin
ProgramCounter:=Operand;
Result:=True;
end;
 
 
function DoSTP(Operand: byte): boolean;
{ ($E0) STP - (stop)}
begin
Result:=False;
end;
 
{Table of opcodes}
 
var OpTable: array [0..7] of TOpcode= (
(Opcode: $00; ArgType: atNone; Mnemonic: 'NOP'; Proc: DoNoOp),
(Opcode: $20; ArgType: atMemory; Mnemonic: 'LDA'; Proc: DoLDA),
(Opcode: $40; ArgType: atMemory; Mnemonic: 'STA'; Proc: DoSTA),
(Opcode: $60; ArgType: atMemory; Mnemonic: 'ADD'; Proc: DoADD),
(Opcode: $80; ArgType: atMemory; Mnemonic: 'SUB'; Proc: DoSUB),
(Opcode: $A0; ArgType: atAddress; Mnemonic: 'BRZ'; Proc: DoBRZ),
(Opcode: $C0; ArgType: atAddress; Mnemonic: 'JMP'; Proc: DoJMP),
(Opcode: $E0; ArgType: atNone; Mnemonic: 'STP'; Proc: DoSTP));
 
 
 
procedure ClearMemory;
{Set all memory locations to zero}
var I: integer;
begin
for I:=0 to High(Memory) do
Memory[I]:=0;
end;
 
 
function DecodeMnemonic(NMem: string): TOpcode;
{Convert 3-char Mnemonic to opcode info}
var I: integer;
begin
for I:=0 to High(OpTable) do
if NMem=OpTable[I].Mnemonic then
begin
Result:=OpTable[I];
exit;
end;
raise Exception.Create('Opcode Not Found');
end;
 
 
procedure AssembleProgram(Prog: string);
{Convert text source code into machine code and store in memory}
var Inx,MemInx,IntAtom,T: integer;
var Atom: string;
var OC: TOpcode;
begin
ClearMemory;
MemInx:=0;
Inx:=1;
while true do
begin
{Get one space delimited atom}
Atom:=ExtractToken(Prog,' ',Inx);
{exit if end of source code}
if Atom='' then break;
{Is the atom text (Mnemonic) or number?}
if Atom[1] in ['A'..'Z','a'..'z'] then
begin
{Convert Mnemonic to opcode info}
OC:=DecodeMnemonic(Atom);
{Get machine value of opcode}
IntAtom:=OC.OpCode;
{Is operand of of memory or address type?}
if OC.ArgType in [atMemory,atAddress] then
begin
{if so combine opcode and operand}
Atom:=ExtractToken(Prog,' ',Inx);
T:=StrToInt(Atom);
IntAtom:=IntAtom or T;
end;
end
else IntAtom:=StrToInt(Atom);
{Store machine code in memory}
Memory[MemInx]:=IntAtom;
{Point to next memory location}
Inc(MemInx);
end;
end;
 
 
function DecodeOpcode(Inst: byte; var Opcode: TOpcode): boolean;
{Convert machine instruction to opcode information}
var I: integer;
var Op: byte;
begin
Result:=True;
{Get opcode part of instruction}
Op:=$E0 and Inst;
{Look for it in table}
for I:=0 to High(OpTable) do
if OpTable[I].OpCode=Op then
begin
Opcode:=OpTable[I];
exit;
end;
Result:=False;
end;
 
 
function ExecuteInstruction(Instruct: byte): boolean;
{Execute a single instruction}
var I: integer;
var Opcode: TOpcode;
var Operand: byte;
begin
if not DecodeOpcode(Instruct,Opcode) then raise Exception.Create('Illegal Opcode');
{Separate instruction and operand}
Operand:=$1F and Instruct;
{Execute instruction}
Result:=Opcode.Proc(Operand);
end;
 
 
procedure DisplayInstruction(Memo: TMemo; PC: integer);
{Display instruction information}
var Opcode: TOpcode;
var Inst,Operand: integer;
var S: string;
begin
Inst:=Memory[PC];
if not DecodeOpcode(Inst,Opcode) then raise Exception.Create('Illegal Opcode');
Operand:=Inst and $1F;
S:=IntToStr(PC)+' $'+IntToHex(Inst,2);
S:=S+' '+Opcode.Mnemonic;
case Opcode.ArgType of
atMemory:
begin
S:=S+' Mem['+IntToStr(Operand)+']=';
S:=S+' '+IntToStr(Memory[Operand]);
end;
atAddress: S:=S+' '+IntToStr(Operand);
end;
Memo.Lines.Add(S);
end;
 
 
procedure ExecuteProgram(Memo: TMemo; Prog: TProgram);
{Executed program until stop instruction reached}
begin
Memo.Lines.Add(Prog.Name);
AssembleProgram(Prog.Code);
ProgramCounter:=0;
Accumulator:=0;
repeat
begin
DisplayInstruction(Memo,ProgramCounter);
end
until not ExecuteInstruction(Memory[ProgramCounter]);
Memo.Lines.Add('Result='+IntToStr(Accumulator));
Memo.Lines.Add('');
end;
 
 
 
procedure ShowComputerZero(Memo: TMemo);
{Execute and display all five sample programs.}
begin
ExecuteProgram(Memo,ProgList[0]);
ExecuteProgram(Memo,ProgList[1]);
ExecuteProgram(Memo,ProgList[2]);
ExecuteProgram(Memo,ProgList[3]);
ExecuteProgram(Memo,ProgList[4]);
end;
 
</syntaxhighlight>
{{out}}
<pre>
Two plus two
0 $23 LDA Mem[3]= 2
1 $64 ADD Mem[4]= 2
2 $E0 STP
Result=4
 
Seven times eight
0 $2C LDA Mem[12]= 0
1 $6A ADD Mem[10]= 8
2 $4C STA Mem[12]= 0
3 $2B LDA Mem[11]= 7
4 $8D SUB Mem[13]= 1
5 $4B STA Mem[11]= 7
6 $A8 BRZ 8
7 $C0 JMP 0
0 $2C LDA Mem[12]= 8
1 $6A ADD Mem[10]= 8
2 $4C STA Mem[12]= 8
3 $2B LDA Mem[11]= 6
4 $8D SUB Mem[13]= 1
5 $4B STA Mem[11]= 6
6 $A8 BRZ 8
7 $C0 JMP 0
0 $2C LDA Mem[12]= 16
1 $6A ADD Mem[10]= 8
2 $4C STA Mem[12]= 16
3 $2B LDA Mem[11]= 5
4 $8D SUB Mem[13]= 1
5 $4B STA Mem[11]= 5
6 $A8 BRZ 8
7 $C0 JMP 0
0 $2C LDA Mem[12]= 24
1 $6A ADD Mem[10]= 8
2 $4C STA Mem[12]= 24
3 $2B LDA Mem[11]= 4
4 $8D SUB Mem[13]= 1
5 $4B STA Mem[11]= 4
6 $A8 BRZ 8
7 $C0 JMP 0
0 $2C LDA Mem[12]= 32
1 $6A ADD Mem[10]= 8
2 $4C STA Mem[12]= 32
3 $2B LDA Mem[11]= 3
4 $8D SUB Mem[13]= 1
5 $4B STA Mem[11]= 3
6 $A8 BRZ 8
7 $C0 JMP 0
0 $2C LDA Mem[12]= 40
1 $6A ADD Mem[10]= 8
2 $4C STA Mem[12]= 40
3 $2B LDA Mem[11]= 2
4 $8D SUB Mem[13]= 1
5 $4B STA Mem[11]= 2
6 $A8 BRZ 8
7 $C0 JMP 0
0 $2C LDA Mem[12]= 48
1 $6A ADD Mem[10]= 8
2 $4C STA Mem[12]= 48
3 $2B LDA Mem[11]= 1
4 $8D SUB Mem[13]= 1
5 $4B STA Mem[11]= 1
6 $A8 BRZ 8
8 $2C LDA Mem[12]= 56
9 $E0 STP
Result=56
 
The Fibonacci sequence
0 $2E LDA Mem[14]= 1
1 $4F STA Mem[15]= 0
2 $6D ADD Mem[13]= 1
3 $4E STA Mem[14]= 1
4 $2F LDA Mem[15]= 1
5 $4D STA Mem[13]= 1
6 $30 LDA Mem[16]= 8
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
9 $50 STA Mem[16]= 8
10 $C0 JMP 0
0 $2E LDA Mem[14]= 2
1 $4F STA Mem[15]= 1
2 $6D ADD Mem[13]= 1
3 $4E STA Mem[14]= 2
4 $2F LDA Mem[15]= 2
5 $4D STA Mem[13]= 1
6 $30 LDA Mem[16]= 7
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
9 $50 STA Mem[16]= 7
10 $C0 JMP 0
0 $2E LDA Mem[14]= 3
1 $4F STA Mem[15]= 2
2 $6D ADD Mem[13]= 2
3 $4E STA Mem[14]= 3
4 $2F LDA Mem[15]= 3
5 $4D STA Mem[13]= 2
6 $30 LDA Mem[16]= 6
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
9 $50 STA Mem[16]= 6
10 $C0 JMP 0
0 $2E LDA Mem[14]= 5
1 $4F STA Mem[15]= 3
2 $6D ADD Mem[13]= 3
3 $4E STA Mem[14]= 5
4 $2F LDA Mem[15]= 5
5 $4D STA Mem[13]= 3
6 $30 LDA Mem[16]= 5
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
9 $50 STA Mem[16]= 5
10 $C0 JMP 0
0 $2E LDA Mem[14]= 8
1 $4F STA Mem[15]= 5
2 $6D ADD Mem[13]= 5
3 $4E STA Mem[14]= 8
4 $2F LDA Mem[15]= 8
5 $4D STA Mem[13]= 5
6 $30 LDA Mem[16]= 4
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
9 $50 STA Mem[16]= 4
10 $C0 JMP 0
0 $2E LDA Mem[14]= 13
1 $4F STA Mem[15]= 8
2 $6D ADD Mem[13]= 8
3 $4E STA Mem[14]= 13
4 $2F LDA Mem[15]= 13
5 $4D STA Mem[13]= 8
6 $30 LDA Mem[16]= 3
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
9 $50 STA Mem[16]= 3
10 $C0 JMP 0
0 $2E LDA Mem[14]= 21
1 $4F STA Mem[15]= 13
2 $6D ADD Mem[13]= 13
3 $4E STA Mem[14]= 21
4 $2F LDA Mem[15]= 21
5 $4D STA Mem[13]= 13
6 $30 LDA Mem[16]= 2
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
9 $50 STA Mem[16]= 2
10 $C0 JMP 0
0 $2E LDA Mem[14]= 34
1 $4F STA Mem[15]= 21
2 $6D ADD Mem[13]= 21
3 $4E STA Mem[14]= 34
4 $2F LDA Mem[15]= 34
5 $4D STA Mem[13]= 21
6 $30 LDA Mem[16]= 1
7 $91 SUB Mem[17]= 1
8 $AB BRZ 11
11 $2E LDA Mem[14]= 55
12 $E0 STP
Result=55
 
Linked list
0 $2D LDA Mem[13]= 32
1 $6F ADD Mem[15]= 28
2 $45 STA Mem[5]= 0
3 $70 ADD Mem[16]= 1
4 $47 STA Mem[7]= 0
5 $3C LDA Mem[28]= 1
6 $4E STA Mem[14]= 0
7 $3D LDA Mem[29]= 22
8 $AB BRZ 11
9 $4F STA Mem[15]= 28
10 $C0 JMP 0
0 $2D LDA Mem[13]= 32
1 $6F ADD Mem[15]= 22
2 $45 STA Mem[5]= 60
3 $70 ADD Mem[16]= 1
4 $47 STA Mem[7]= 61
5 $36 LDA Mem[22]= 2
6 $4E STA Mem[14]= 1
7 $37 LDA Mem[23]= 26
8 $AB BRZ 11
9 $4F STA Mem[15]= 22
10 $C0 JMP 0
0 $2D LDA Mem[13]= 32
1 $6F ADD Mem[15]= 26
2 $45 STA Mem[5]= 54
3 $70 ADD Mem[16]= 1
4 $47 STA Mem[7]= 55
5 $3A LDA Mem[26]= 3
6 $4E STA Mem[14]= 2
7 $3B LDA Mem[27]= 30
8 $AB BRZ 11
9 $4F STA Mem[15]= 26
10 $C0 JMP 0
0 $2D LDA Mem[13]= 32
1 $6F ADD Mem[15]= 30
2 $45 STA Mem[5]= 58
3 $70 ADD Mem[16]= 1
4 $47 STA Mem[7]= 59
5 $3E LDA Mem[30]= 4
6 $4E STA Mem[14]= 3
7 $3F LDA Mem[31]= 24
8 $AB BRZ 11
9 $4F STA Mem[15]= 30
10 $C0 JMP 0
0 $2D LDA Mem[13]= 32
1 $6F ADD Mem[15]= 24
2 $45 STA Mem[5]= 62
3 $70 ADD Mem[16]= 1
4 $47 STA Mem[7]= 63
5 $38 LDA Mem[24]= 5
6 $4E STA Mem[14]= 4
7 $39 LDA Mem[25]= 20
8 $AB BRZ 11
9 $4F STA Mem[15]= 24
10 $C0 JMP 0
0 $2D LDA Mem[13]= 32
1 $6F ADD Mem[15]= 20
2 $45 STA Mem[5]= 56
3 $70 ADD Mem[16]= 1
4 $47 STA Mem[7]= 57
5 $34 LDA Mem[20]= 6
6 $4E STA Mem[14]= 5
7 $35 LDA Mem[21]= 0
8 $AB BRZ 11
11 $2E LDA Mem[14]= 6
12 $E0 STP
Result=6
 
Prisoner’s Dilemma
0 $00 NOP
1 $00 NOP
2 $E0 STP
Result=0
Elapsed Time: 611.666 ms.
</pre>
 
 
=={{header|EasyLang}}==
<syntaxhighlight>
proc run name$ mem[] . .
write name$ & ": "
pc = 1
len mem[] 32
repeat
ppc = mem[pc]
op = ppc div 32
addr = ppc mod 32 + 1
pc += 1
if op = 1
acc = mem[addr]
elif op = 2
mem[addr] = acc
elif op = 3
acc = (acc + mem[addr]) mod 255
elif op = 4
acc = (acc - mem[addr]) mod 255
elif op = 5
if acc = 0
pc = addr
.
elif op = 6
pc = addr
.
until op = 7 or pc > 32
.
print acc
.
run "2+2" [ 35 100 224 2 2 ]
run "7*8" [ 44 106 76 43 141 75 168 192 44 224 8 7 0 1 ]
run "Fibonacci" [ 46 79 109 78 47 77 48 145 171 80 192 46 224 1 1 0 8 1 ]
run "List" [ 45 111 69 112 71 0 78 0 171 79 192 46 224 32 0 28 1 0 0 0 6 0 2 26 5 20 3 30 1 22 4 24 ]
run "Prisoner" [ 0 0 224 0 0 35 157 178 35 93 174 33 127 65 194 32 127 64 192 35 93 33 126 99 ]
</syntaxhighlight>
 
{{out}}
<pre>
2+2: 4
7*8: 56
Fibonacci: 55
List: 6
Prisoner: 0
</pre>
 
=={{header|Forth}}==
Line 1,272 ⟶ 1,831:
1
255
0
</pre>
 
=={{header|jq}}==
'''Adapted from [[#Wren|Wren]]'''
{{works with|jq}}
'''Also works with gojq, the Go implementation of jq'''
 
This entry assumes all the programs have been placed in a text file
in which each program takes the form of a header followed
by the instructions, one per line, followed by at least one blank line.
 
The header is assumed to have the form:
<pre>
; title
</pre>
<syntaxhighlight lang="jq">
### Utility
def trim: sub("^ +";"") | sub(" +$";"");
 
### Computer/Zero
def NOP: 0;
def LDA: 1;
def STA: 2;
def ADD: 3;
def SUB: 4;
def BRZ: 5;
def JMP: 6;
def STP: 7;
 
def ops: {"NOP": NOP, "LDA": LDA, "STA": STA, "ADD": ADD,
"SUB": SUB, "BRZ": BRZ, "JMP": JMP, "STP": STP};
 
# Input: the program in the form of an array of strings,
# each string corresponding to an input line of the form
# "INSTR N" or "N"
# Output: an array of integers
def load:
map([splits(" *")] as $split
| $split[0] as $instr
| (if ($split|length == 2) then $split[1]|tonumber
else 0
end) as $addr
| if ops[$instr]
then ops[$instr] * 32 + $addr
else try ($instr|tonumber) catch 0
end );
 
# input: an array as produced by `load`
def interp:
{ acc: 0, pc: 0, mem: .}
| until(.break;
(.mem[.pc] % 32) as $addr
| ((.mem[.pc] - $addr) / 32) as $instr
| .pc += 1
| if $instr == LDA then .acc = .mem[$addr]
elif $instr == STA then .mem[$addr] = .acc
elif $instr == ADD then .acc += .mem[$addr]
| if .acc > 255 then .acc += -256 else . end
elif $instr == SUB then .acc += (- .mem[$addr])
| if .acc < 0 then .acc += 256 else . end
elif $instr == BRZ
then if .acc == 0 then .pc = $addr else . end
elif $instr == JMP then .pc = $addr
else .
end
| .break = $instr == STP or .pc > 31 )
| .acc;
 
# Assume the input file consists of several programs, each structured as:
# ; program name
# one instruction per line
#
def task:
def init: map_values(null);
foreach (inputs, null) as $line ({};
if $line == null then .program = .buffer
elif $line[0:1] == ";" then init | .title = $line
else ($line|trim) as $line
| if $line == "" then .program = .buffer | .buffer = []
else .buffer += [$line]
end
end)
| .title as $title
| .program
| if length == 0 then empty
else
$title, (load|interp)
end ;
 
task
</syntaxhighlight>
'''Program file - scrollable window''' (programs.txt)
<div style="overflow:scroll; height:400px;">
<pre>
; 2+2
LDA 3
ADD 4
STP
2
2
 
; 7 * 8
LDA 12
ADD 10
STA 12
LDA 11
SUB 13
STA 11
BRZ 8
JMP 0
LDA 12
STP
8
7
0
1
 
; fibonacci
LDA 14
STA 15
ADD 13
STA 14
LDA 15
STA 13
LDA 16
SUB 17
BRZ 11
STA 16
JMP 0
LDA 14
STP
1
1
0
8
1
 
; linkedList
LDA 13
ADD 15
STA 5
ADD 16
STA 7
NOP
STA 14
NOP
BRZ 11
STA 15
JMP 0
LDA 14
STP
LDA 0
0
28
1
0
0
0
6
0
2
26
5
20
3
30
1
22
4
24
 
; prisoner
0
0
STP
NOP
LDA 3
SUB 29
BRZ 18
LDA 3
STA 29
BRZ 14
LDA 1
ADD 31
STA 1
JMP 2
LDA 0
ADD 31
STA 0
JMP 2
LDA 3
STA 29
LDA 0
ADD 30
ADD 3
STA 0
LDA 1
ADD 30
ADD 3
STA 1
JMP 2
0
1
3
</pre>
</div>
 
{{output}}
'''Invocation:''' jq -nR -f execute-computer-zero.jq programs.txt
<pre>
"; 2+2"
4
"; 7 * 8"
56
"; fibonacci"
55
"; linkedList"
6
"; prisoner"
0
</pre>
Line 1,930 ⟶ 2,710:
Round: 4 Move: coop Player: 6 Computer: 6
Round: 5 Move: defe Player: 6 Computer: 9</pre>
 
=={{header|Nim}}==
We don’t use an assembly language but define the memory values using functions named NOP, LDA, STA, etc. To be able to use Uniform Function Call Syntax (i.e. call without parentheses),
all these functions have an argument, even NOP and STP.
 
In the last example, “Prisoners”, an input is expected from the user. We defined a function “enterValue” which stores the input value into the byte at address referenced by the PC then increments the PC by one. We have chosen the same player strategy as the one used by the Lua program and, of course, we get the same result.
 
<syntaxhighlight lang="Nim">import std/strformat
 
type
OpCode = enum opNOP, opLDA, opSTA, opADD, opSUB, opBRZ, opJMP, opSTP
Instruction = byte
Address = 0..31
# Definition of a computer zero.
Computer = object
mem: array[Address, byte] # Memory.
pc: Address # Program counter.
acc: byte # Accumulator.
Program = tuple
name: string # Name of the program.
code: seq[Instruction] # List of instructions.
 
proc split(inst: Instruction): tuple[code: OpCode, address: Address] =
## Split an instruction into an opCode and a value.
(OpCode((inst and 0b11100000u8) shr 5), Address(inst and 0b00011111u8))
 
proc toInst(opCode: OpCode; address: int): Instruction =
## Build an instruction with given opcode and value.
if address notin Address.low..Address.high:
raise newException(ValueError, "address out of range.")
byte(opCode) shl 5 or byte(address)
 
# Functions to build instructions.
func NOP(n: int): Instruction = toInst(opNOP, n)
func LDA(n: int): Instruction = toInst(opLDA, n)
func STA(n: int): Instruction = toInst(opSTA, n)
func ADD(n: int): Instruction = toInst(opADD, n)
func SUB(n: int): Instruction = toInst(opSUB, n)
func BRZ(n: int): Instruction = toInst(opBRZ, n)
func JMP(n: int): Instruction = toInst(opJMP, n)
func STP(n: int): Instruction = toInst(opSTP, n)
 
proc reset(comp: var Computer) =
## Reset the computer state.
comp.mem.reset()
comp.pc = 0
comp.acc = 0
 
proc load(comp: var Computer; program: Program) =
## Load a program into a computer.
comp.reset()
var idx = 0
for inst in program.code:
comp.mem[idx] = inst
inc idx
 
proc run(comp: var Computer) =
## Run a computer.
## The execution starts or resumes at the instruction
## at current PC, with current value in the accumulator.
while true:
let (opCode, address) = comp.mem[comp.pc].split()
inc comp.pc
case opCode
of opNOP:
discard
of opLDA:
comp.acc = comp.mem[address]
of opSTA:
comp.mem[address] = comp.acc
of opADD:
comp.acc += comp.mem[address]
of opSUB:
comp.acc -= comp.mem[address]
of opBRZ:
if comp.acc == 0:
comp.pc = address
of opJMP:
comp.pc = address
of opSTP:
break
 
proc enterValue(comp: var Computer; value: byte) =
## Enter a value into memory at address given by the PC,
## then increment the PC.
comp.mem[comp.pc] = value
inc comp.pc
 
 
# Programs are built using the functions NOP, LDA, STA, etc.
# To be able to use Uniform Function Call Syntax (i.e. call without parentheses),
# all these functions have an argument, even NOP and STP.
const
Prog1 = (name: "2+2",
code: @[LDA 3, ADD 4, STP 0, 2, 2])
Prog2 = (name: "7*8",
code: @[LDA 12, ADD 10, STA 12, LDA 11, SUB 13, STA 11, BRZ 8, JMP 0,
LDA 12, STP 0, 8, 7, 0, 1])
Prog3 = (name: "Fibonacci",
code: @[LDA 14, STA 15, ADD 13, STA 14, LDA 15, STA 13, LDA 16, SUB 17,
BRZ 11, STA 16, JMP 0, LDA 14, STP 0, 1, 1, 0,
8, 1])
Prog4 = (name: "List",
code: @[LDA 13, ADD 15, STA 5, ADD 16, STA 7, NOP 0, STA 14, NOP 0,
BRZ 11, STA 15, JMP 0, LDA 14, STP 0, LDA 0, 0, 28,
1, 0, 0, 0, 6, 0, 2, 26,
5, 20, 3, 30, 1, 22, 4, 24])
Prog5 = (name: "Prisoner",
code: @[NOP 0, NOP 0, STP 0, NOP 0, LDA 3, SUB 29, BRZ 18, LDA 3,
STA 29, BRZ 14, LDA 1, ADD 31, STA 1, JMP 2, LDA 0, ADD 31,
STA 0, JMP 2, LDA 3, STA 29, LDA 1, ADD 30, ADD 3, STA 1,
LDA 0, ADD 30, ADD 3, STA 0, JMP 2, 0, 1, 3])
 
var computer: Computer
 
for prog in [Prog1, Prog2, Prog3, Prog4]:
computer.load prog
computer.run()
echo &"Result for {prog.name}: {computer.acc}"
 
# "Prog5" is different as it stops and waits for an input from the user.
# Input is stored at address 3 (current PC value) and scores are stored at addresses 0 and 1.
 
type Action = enum cooperate, defect
 
echo &"\nResult for {Prog5.name}:"
computer.load Prog5
computer.run()
 
for round in 1..5:
let action = Action(round and 1)
computer.enterValue(byte(action))
computer.run()
echo &"Round {round} Action: {action:9} Player: {computer.mem[0]} Computer: {computer.mem[1]}"
</syntaxhighlight>
 
{{out}}
<pre>Result for 2+2: 4
Result for 7*8: 56
Result for Fibonacci: 55
Result for List: 6
 
Result for Prisoner:
Round 1 Action: defect Player: 0 Computer: 3
Round 2 Action: cooperate Player: 3 Computer: 3
Round 3 Action: defect Player: 3 Computer: 6
Round 4 Action: cooperate Player: 6 Computer: 6
Round 5 Action: defect Player: 6 Computer: 9
</pre>
 
=={{header|Phix}}==
Line 2,533 ⟶ 3,462:
 
Although I've entered the fifth program, it just returns 0 when reaching the STP instruction. I'm unclear how we can make it interactive without having another instruction though possibly, if STP had address bits other than 0, this could signal that user input was required.
<syntaxhighlight lang="ecmascriptwren">var NOP = 0
var LDA = 1
var STA = 2
1,978

edits