From e7f69c8fbbbcbddde84933b2becd91e787d1ac63 Mon Sep 17 00:00:00 2001 From: Johnny Richard Date: Fri, 11 Apr 2025 01:15:01 +0200 Subject: Intial commit Signed-off-by: Johnny Richard --- src/vm.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 src/vm.c (limited to 'src/vm.c') diff --git a/src/vm.c b/src/vm.c new file mode 100644 index 0000000..c7f91f0 --- /dev/null +++ b/src/vm.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include "array.h" +#include "stack.h" +#include "vm.h" + +void +vm_init(vm_t *vm) +{ + assert(vm); + vm->stack = (stack_t) { + .capacity = STACK_CAPACITY, + .size = 0, + .data = calloc(sizeof(int), STACK_CAPACITY) + }; + vm->call_stack = (stack_t) { + .capacity = 3000, + .size = 0, + .data = calloc(sizeof(int), 3000) + }; + vm->heap = calloc(sizeof(int), HEAP_CAPACITY); + vm->labels = array(label_t); +} + +void +vm_run(vm_t *vm, inst_t *insts) +{ + size_t program_size = array_length(insts); + + // resolve lables + for (size_t ip = 0; ip < program_size; ++ip) { + if (insts[ip].type == INST_LABEL) { + int name = insts[ip].operand; + label_t label = { .name = name, .index = ip }; + array_append(vm->labels, label); + } + } + + // resolve jumps + for (size_t ip = 0; ip < program_size; ++ip) { + switch (insts[ip].type) { + case INST_CALL: + case INST_JMP: + case INST_JMPN: + case INST_JMPZ: { + int label_name = insts[ip].operand; + size_t i = 0; + size_t labels_size = array_length(vm->labels); + for (; i < labels_size; ++i) { + if (vm->labels[i].name == label_name) { + insts[ip].operand = vm->labels[i].index; + break; + } + } + assert(i < labels_size); + } + default: break; + } + } + + // run + for (size_t ip = 0; ip < program_size; ++ip) { + switch (insts[ip].type) { + case INST_PUSH: { + stack_push(&vm->stack, insts[ip].operand); + break; + } + case INST_DUP: { + stack_push(&vm->stack, vm->stack.data[vm->stack.size - 1]); + break; + } + case INST_COPY: { + int operand = insts[ip].operand; + stack_push(&vm->stack, vm->stack.data[vm->stack.size - 1 - operand]); + break; + } + case INST_SWAP: { + int a = stack_pop(&vm->stack); + int b = stack_pop(&vm->stack); + stack_push(&vm->stack, a); + stack_push(&vm->stack, b); + break; + } + case INST_DROP: { + stack_pop(&vm->stack); + break; + } + case INST_SLIDE: { + int operand = insts[ip].operand; + int top = stack_pop(&vm->stack); + while (operand-- > 0) { + stack_pop(&vm->stack); + } + stack_push(&vm->stack, top); + break; + } + case INST_ADD: { + int lhs = stack_pop(&vm->stack); + int rhs = stack_pop(&vm->stack); + stack_push(&vm->stack, lhs + rhs); + break; + } + case INST_SUB: { + int rhs = stack_pop(&vm->stack); + int lhs = stack_pop(&vm->stack); + stack_push(&vm->stack, lhs - rhs); + break; + } + case INST_MUL: { + int rhs = stack_pop(&vm->stack); + int lhs = stack_pop(&vm->stack); + stack_push(&vm->stack, lhs * rhs); + break; + } + case INST_DIV: { + int rhs = stack_pop(&vm->stack); + int lhs = stack_pop(&vm->stack); + stack_push(&vm->stack, lhs / rhs); + break; + } + case INST_MOD: { + int rhs = stack_pop(&vm->stack); + int lhs = stack_pop(&vm->stack); + stack_push(&vm->stack, lhs % rhs); + break; + } + case INST_STORE: { + int value = stack_pop(&vm->stack); + int address = stack_pop(&vm->stack); + vm->heap[address] = value; + break; + } + case INST_LOAD: { + int address = stack_pop(&vm->stack); + stack_push(&vm->stack, vm->heap[address]); + break; + } + case INST_CALL: { + stack_push(&vm->call_stack, ip + 1); + ip = insts[ip].operand; + break; + } + case INST_RET: { + ip = stack_pop(&vm->call_stack); + break; + } + case INST_JMP: { + ip = insts[ip].operand; + break; + } + case INST_JMPZ: { + int value = stack_pop(&vm->stack); + if (value == 0) { + ip = insts[ip].operand; + } + break; + } + case INST_JMPN: { + int value = stack_pop(&vm->stack); + if (value < 0) { + ip = insts[ip].operand; + } + break; + } + case INST_PRINTI: { + int value = stack_pop(&vm->stack); + printf("%d", value); + break; + } + case INST_PRINTC: { + int value = stack_pop(&vm->stack); + printf("%c", value); + break; + } + case INST_READI: { + int address = stack_pop(&vm->stack); + scanf("%d", vm->heap + address); + break; + } + case INST_READC: { + int address = stack_pop(&vm->stack); + vm->heap[address] = getchar(); + break; + } + case INST_END: { + return; + } + case INST_LABEL: { + break; + } + default: { + assert(0 && "Unsupported instruction"); + break; + } + } + } +} -- cgit v1.2.3