The VM has a stack. Almost everything happens through it:
push 5 → stack: [5]
push 3 → stack: [5, 3]
add → pops 3 and 5, adds, pushes result → stack: [8]
print → pops 8 and prints it → stack: []
Stops execution. Always at the end.
haltPushes number N onto the stack.
push 42 → stack: [42]N can be decimal (42) or hexadecimal (0x2A).
Pops the top of the stack and discards it.
push 10
push 20
pop → discards 20, stack: [10]Duplicates the top of the stack.
push 5
dup → stack: [5, 5]Useful before print if you want to keep the value.
Arithmetic operations. Pop two values, operate, push the result.
push 10
push 3
add → stack: [13]
push 10
push 3
sub → 10 - 3 = 7
push 10
push 3
mul → 10 * 3 = 30
push 10
push 3
div → 10 / 3 = 3 (integer)
push 10
push 3
mod → 10 % 3 = 1Important: sub and div do first - second and first / second.
The first pop is the second operand:
push 20 # first value (a)
push 5 # second value (b)
sub # a - b = 20 - 5 = 15Comparisons. Pop two values, push 1 (true) or 0 (false).
push 5
push 5
eq → 1 (true)
push 5
push 3
gt → 5 > 3 = 1
push 5
push 3
lt → 5 < 3 = 0- jmp label: always jumps
- jz label: jumps if top of stack is 0
- jnz label: jumps if top of stack is NOT 0
push 5
:loop
print
push 1
sub
dup
push 0
gt
jnz loop # jumps if gt gave 1 (true)
pop
haltPrints: 54321
Subroutine call. call saves the return address, jumps to the label. ret returns.
push 5
call double
print
halt
:double
dup
add
retPrints: 10
How it works:
call doublesaves "come back here" and jumps to:double- Executes
dup,add(double and add = 5+5 = 10) retreturns to where it was savedprintprints 10
Local variables. There are 256 (0 to 255).
- store N: pops from stack and stores in local N
- load N: pushes the value of local N onto the stack
push 42
store 0 # local[0] = 42
push 10
store 1 # local[1] = 10
load 0 # stack: [42]
load 1 # stack: [42, 10]
add # 42 + 10 = 52
print
haltPops the top of the stack and prints it as an integer. No newline.
push 42
print # shows "42"
push 10
prc # newline (ASCII 10 = \n)Pops the top of the stack and prints it as a character (ASCII).
push 65
prc # shows 'A'
push 10
prc # newlinepush 5
:loop
dup
print
push 1
sub
dup
push 0
gt
jnz loop
pop
push 10
prc
haltpush 5
push 3
gt # 5 > 3 → 1
jz false
push 1
print
push 10
prc
halt
:false
push 0
print
push 10
prc
haltpush 5
call fact
print
push 10
prc
halt
:fact
store 0
load 0
push 1
gt
jz base
load 0
load 0
push 1
sub
call fact
mul
ret
:base
push 1
ret- Use
dupbeforeprintif you need the value afterwards 10inprc= newline (\n)- Comments start with
# - Labels can be
:nameat the start orname:at the end retwithout a previouscall= fatal error- If you see
FATAL: stack underflow, you missed apushbefore the operation
ERROR: unknow instruccion
You misspelled an instruction.
FATAL: stack underflow
You're performing an operation that needs values on the stack and there aren't enough.
FATAL: stack overflow
You pushed more than 1024 values onto the stack (almost always an infinite loop without halt).
FATAL: ret from main
You used ret without having done call first.