This repository has been archived on 2025-11-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Aryadev Chavali ec87245724 Implemented preprocess_const_blocks
Once again quite similar to preprocess_macro_blocks but shorter,
easier to use and easier to read. (76 vs 109)
2024-04-15 04:55:51 +06:30
2024-04-15 04:55:51 +06:30
2024-04-14 16:49:37 +06:30
2023-11-01 18:20:03 +00:00
2023-10-15 01:25:24 +01:00
2024-04-09 21:23:54 +06:30
2024-04-14 02:36:30 +06:30

Oreo's Virtual Machine (OVM)

A stack based virtual machine in C11, with a dynamic register setup which acts as variable space. Deals primarily in bytes, doesn't make assertions about typing and is very simple to target.

How to build

Requires GNU make and a compliant C11 compiler. Code base has been tested against gcc and clang, but given how the project has been written without use of GNU'isms (that I'm aware of) it shouldn't be an issue to compile using something like tcc or another compiler (look at here to change the compiler).

To build everything simply run make. This will build:

You may also build each component individually through the corresponding recipe:

  • make lib
  • make vm
  • make asm
  • make examples

Instructions to target the virtual machine

You need to link with the object files for base.c, darr.c and inst.c to be able to properly target the OVM. The basic idea is to create some instructions via inst_t, instantiating a prog_t structure which wraps those instructions (includes a header and other useful things for the runtime), then using prog_write_file to serialise and write bytecode to a file pointer.

To execute directly compiled bytecode use the ovm.out executable on the bytecode file.

For clarity, one may build lib (make lib) then use the resulting object files to link and create bytecode for the virtual machine.

In memory virtual machine

Instead of serialising and writing bytecode to a file, one may instead serialise bytecode in memory using prog_write_bytecode which writes bytecode to a dynamic byte buffer, so called in memory compilation. To execute this bytecode, deserialise the bytecode into a program then load it into a complete vm_t structure (linking with runtime.c).

In fact, you may skip the process of serialising entirely. You can emit a prog_t structure corresponding to source code, load it directly into the vm_t structure, then execute. To do so is a bit involved, so I recommend looking at vm/main.c. In rough steps:

  • Create a virtual machine "from scratch" (load the necessary components (the stack, heap and call stack) by hand)
  • Load program into VM (vm_load_program)
  • Run vm_execute_all

This is recommended if writing an interpreted language such as a Lisp, where on demand execution of code is more suitable.

Lines of code

301 ./vm/runtime.h
92 ./vm/main.c
1059 ./vm/runtime.c
500 ./lib/inst.c
39 ./lib/darr.h
265 ./lib/inst.h
42 ./lib/heap.h
90 ./lib/base.h
101 ./lib/heap.c
39 ./lib/base.c
77 ./lib/darr.c
654 ./asm/parser.c
142 ./asm/main.c
83 ./asm/lexer.h
65 ./asm/parser.h
549 ./asm/lexer.c
Description
No description provided
Readme 27 KiB
Languages
C 70.2%
C++ 26.5%
Makefile 3.3%