Polygon VM

Polygon Virtual Machine (PVM) is virtual machine for the self-compiled programming language called Polygon. PVM is a register based virtual machine so this means it performs various operations using registers. Crazy, I know! This is one of my personal projects and I plan on continuing to develop it.

Introduction

PVM can work with files and through it’s dedicated REPL (Read-Eval-Print loop). PVM operates with files with .plasm extension and has the following syntax:

// examples/for_loop.plasm
load $0 1
load $1 5
load $2 16
load $3 36

gtq $0 $1
jeq $3
out $0
inc $0
jneq $2

out $0
hlt

At first glance there are many things going on. But I’ll explain in the next section. First Plasm compiler takes these instructions and check every single one for errors. If there are none, it convert these instructions in the bytecode, example:

// This is a load instruction representation in bytecode
load $0 100
^^^^ ^^ ^^^
02   00 00 64

There are total of 23 instructions (at the moment) that PVM can process. PVM is still in the development stage, so there are many more to come. Let’s go over each instruction, see what they take as arguments and what they do.

Instructions

As I said before PVM can process 23 instructions. Here’s the list of all instructions available:

hlt load move add sub mul div jmp jmpf 
jmpb out eq neq gt lt gtq ltq jeq jneq
free alloc inc dec

PVM performs operations with help of registers. There are total of 32 registers which can be referred as $<register_number>. Registers enumeration starts from 0, so for example, if we want to access 15th register, we would refer to it as $14. And by following this logic our last 32nd register will be $31. Now with that out of the way let’s get over each instruction.

hlt stands for halt. It tells the PVM to stop execution of the program.

load <register> <integer_literal> puts a specified integer literal in specified register.

move <from_register> <to_register> moves a value from a specified register to another register, whilst setting the original registers value to 0.

add <target> <register_1> <register_2> adds values from 2 registers and puts the result in target register.

sub <target> <register_1> <register_2> subtracts values from 2 registers and puts the result in target register.

mul <target> <register_1> <register_2> multiplies values from 2 registers and puts the result in target register.

div <target> <register_1> <register_2> divides values from 2 registers and puts the result in target register and stores the remainder in memory.

jmp <target> continue execution from another point.

jmpf <target> same as jmp, but can’t jmp backwards.

jmpb <target> same as jmp, but can’t jmp further.

out <target> prints value from register.

eq <register_1> <register_2> checks if two values are equal.

neq <register_1> <register_2> checks if two values are NOT equal.

gt <register_1> <register_2> checks if value_1 is greater than value_2.

lt <register_1> <register_2> checks if value_1 is less than value_2.

gtq <register_1> <register_2> checks if value_1 is greater than or equal to value_2.

ltq <register_1> <register_2> checks if value_1 is less than or equal to value_2.

jeq <target> checks if previous equality instruction resulted to true (1) and performs a jmp instruction.

jneq <target> checks if previous equality instruction resulted to false (0) and performs a jmp instruction.

free <target> sets target registers value to 0.

alloc <register> allocates number of bytes from register on the heap.

inc <register> increments a value stored in register by 1.

dec <register> decrements a value stored in register by 1.

Warning!

This is a personal project and is being maintained by 1 person. Please, do not use this project in a production environment, until it reaches stable version

Contributing

Contibutions are more than welcome. If you run into an issue with this project, feel free to open an issue or create a pull request with fixes included.

License

MIT

GitHub

View Github