An MVP stack-based bytecode VM
This VM runs a simplistic, Turing complete instruction set.
In ~250 LOC with extensive comments, it's meant to be simple to understand and easily reproducible in languages other than Rust.
It also includes a rudimentary compiler which can execute programs in the test_files folder.
| Instruction | Description |
|---|---|
| Push (isize) | Pushes the argument to the top of the stack |
| Pop | Removes the value on top of the stack |
| Add | Pops the top two values and pushes their sum |
| Sub | Pops the top two values and pushes their difference |
| Mul | Pops the top two values and pushes their product |
| Div | Pops the top two values and pushes their quotient |
| Jump (label) | Sets the instruction pointer to the label |
| JNE (label) | Jumps if the top of the stack is not zero |
| JE (label) | Jumps if the top of the stack is zero |
| JGT (label) | Jumps if the top of the stack is greater than zero |
| JLT (label) | Jumps if the top of the stack is less than zero |
| JGE (label) | Jumps if the top of the stack is greater than or equal to zero |
| JLE (label) | Jumps if the top of the stack is less than or equal to zero |
| Call (procedure) | Calls a procedure, setting the stack offset to the current s stack length |
| Get (usize) | Gets index of the stack and copies it to the top |
| Set (usize) | Copies value at the top of the stack to the index |
| GetArg (usize) | Gets nth argument from top of callstack stack offset, used for procedures |
| SetArg (usize) | Sets nth argument from top of callstack stack offset, used for procedures |
| Noop | Doesn't do anything, used by comments to keep instruction pointers correspondent to lines |
| Prints value at the top of the stack as an integer | |
| PrintC | Prints value at the top of the stack as an ASCII character |
| PrintStack | Prints the whole stack, used mostly for debugging |
You can also set a label with the line label $name, and you can declare a procedure by using Proc $name, Ret, and End. See test_files/procedure.bytecode or test_files/fib_recurse.bytecode for more details.
In test_files/:
hello_world.bytecode prints "Hello World"
sum.bytecode prints the sum of all integers from 0 to 100
fib.bytecode prints the first 40 fibonacci numbers
fib_recurse.bytecode recursively calculates 35th fibonacci number
Push 0
Push 0
label loop
-- [accumulator, index]
Get 0
Get 1
-- [accumulator, index, accumulator, index]
Add
-- [accumulator, index, accumulator + index]
Set 0
Pop
-- [accumulator + index, index]
-- [accumulator, index]
Incr
-- [accumulator, index + 1]
-- [accumulator, index]
Get 1
Push 100
Sub
-- [accumulator, index, index - 100]
JNE loop
Pop
Get 0
Print
Push 10
PrintC
> cargo run --release sum.bytecode
4950
>