Before I forget I had meant to write about a toy virtual machine which I'ce been playing with.
It is register-based with ten registers, each of which can hold either a string or int, and there are enough instructions to make it fun to use.
I didn't go overboard and write a complete grammer, or a real compiler, but I did do enough that you can compile and execute obvious programs.
First compile from the source to the bytecodes:
$ ./compiler examples/loop.in
Mmm bytecodes are fun:
$ xxd ./examples/loop.raw 0000000: 3001 1943 6f75 6e74 696e 6720 6672 6f6d 0..Counting from 0000010: 2074 656e 2074 6f20 7a65 726f 3101 0101 ten to zero1... 0000020: 0a00 0102 0100 2201 0102 0201 1226 0030 ......"......&.0 0000030: 0104 446f 6e65 3101 00 ..Done1..
Now the compiled program can be executed:
$ ./simple-vm ./examples/loop.raw [stdout] register R01 = Counting from ten to zero [stdout] register R01 = 9 [Hex:0009] [stdout] register R01 = 8 [Hex:0008] [stdout] register R01 = 7 [Hex:0007] [stdout] register R01 = 6 [Hex:0006] [stdout] register R01 = 5 [Hex:0005] [stdout] register R01 = 4 [Hex:0004] [stdout] register R01 = 3 [Hex:0003] [stdout] register R01 = 2 [Hex:0002] [stdout] register R01 = 1 [Hex:0001] [stdout] register R01 = 0 [Hex:0000] [stdout] register R01 = Done
There could be more operations added, but I'm pleased with the general behaviour, and embedding is trivial. The only two things that make this even remotely interesting are:
- Most toy virtual machines don't cope with labels and jumps. This does.
- Even though it was a real pain to go patching up the offsets.
- Having labels be callable before they're defined is pretty mandatory in practice.
- Most toy virtual machines don't allow integers and strings to be stored in registers.
- Now I've done that I'm not 100% sure its a good idea.
Anyway that concludes todays computer-fun.