a simple virtual machine is written in c++
to compile:
git clone https://github.com/radinParsaei/VM --recursive #clone this repository
cd VM
make
to build with gmplib:
make EXT_CFLAGS='-DUSE_GMP_LIB' EXT_LDFLAGS='-lgmp -lgmpxx'
to optimize generated VM use -Os
and -O3
in command-line arguments(EXT_CFLAGS)
you can build VM for esp8266 with esp8266 Arduino board version 2.3 and EARLIER with ArduinoSTL (see mike-matera/ArduinoSTL#58) or without ArduinoSTL with any version of esp8266 or esp32 and for Arduino UNO, VM is tested with Arduino ide and platformio ide (ArduinoSTL needed) a problem: not working with the latest Arduino AVR core (see mike-matera/ArduinoSTL#56)
use make apple-universal2
to build universal binaries for macOS 11, Big Sur, with Xcode 12
use emmake make wasm
to build repl and VM for wasm (VM need a VM binary file (default is out.bin) to add that file in wasm binary)
in windows have two ways: 1- use Cygwin 2- use MinGW + https://github.com/meganz/mingw-std-threads (run utility_scripts)
when VM is built output files are: VM the VM main, repl a simple repl built with gnu readline if can, assembler, disassembler, and mkcc
mkcc (make c++ code from VM binary): it converts VM binary files to c++ code
PUT TXTHello\n
PRINT
-------------------------
vm.run(PUT, "Hello\n");
vm.run(PRINT);
cat VM.h | egrep '#define .+ [0-9]+' | cut -d' ' -f2
-> list all opcodes
close VM with exit status: pop()
put a value to VM stack
pop one value from VM stack
push(pop() + pop())
push(pop() - pop())
push(pop() * pop())
push(pop() / pop())
push(pop() % pop())
push(pop() ** pop())
push(pop() == pop())
(1 == "1"
), (1 == True
)
push(pop() === pop())
(1 !== "1"
) but (1 === 1
), (1 !== true
)
push(pop() > pop())
push(pop() >= pop())
push(pop() < pop())
push(pop() <= pop())
push(pop() && pop())
(equals to and
in python)
push(pop() || pop())
(equals to or
in python)
push(pop() & pop())
(bitwise)
push(pop() | pop())
(bitwise)
push(~pop())
(bitwise)
push(!pop())
(equals to not
in python)
push(pop() << pop())
push(pop() >> pop())
push(pop() ^ pop())
if pop() is number: push(-pop()) else: push(reverse(pop()))
mem[pop()] = pop()
push(mem[pop()])
push(mem.size())
mem.append(pop())
mem.insert(pop(), pop()) -> [0, 2]; insert 1, 1 -> [0, 1, 2]
del mem[pop()]
push(pop().toNumber())
push(pop().toString())
push(get().type == Number)
push(get().canNum())
push(pop().toBool())
records programs
end recording
run recorded program
RUN * pop()
break running recorded program
if (pop()) RUN
if (!pop()) RUN
pop()
RUN
}
pop()
RUN
}
run program on a real or proto thread
call libraries from files *.vmso
or locally from "internalLibraryFunction"
print(pop())
skips opcodes with the count of pop()
skips opcodes with the count of `pop()`
}
make function with number and program (name of functions only should be number)
call function named with the number in pop()
acts like return (doesn't return data and you should PUT
your data)
push(stack[pop()]) & delete stack[pop()]
stack.insert(pop(), pop())
example: PUT TXTHello PUT TXTWorld PUT NUM0 STCKMOV PRINT PRINT ; output = HelloWorld
delete stack[pop()]
push(stack[pop()])
continue in the loop
push([]) create empty array and puts it to stack
append data to end of array
sets data in array
get data from array
insert data in array