#include #include #include #include #include #include "val.h" #include "vm.h" #include "dis.h" void *M(void *p, size_t sz) { if (sz == 0) { free(p); return NULL; } else { return realloc(p, sz); } } Chunk chunk_new() { return (Chunk){ .blen = 0, .bcap = 0, .b = NULL, .clen = 0, .ccap = 0, .c = NULL, }; } size_t chunk_wbc(Chunk *ch, uint8_t byte) { if (ch->blen == ch->bcap) { size_t newsz = (ch->bcap == 0 ? 8 : ch->bcap * 2); ch->b = M(ch->b, newsz * sizeof(uint8_t)); ch->bcap = newsz; } size_t ix = ch->blen; ch->b[ix] = byte; ch->blen ++; return ix; } size_t chunk_wconst(Chunk *ch, Val v) { if (ch->clen == ch->ccap) { size_t newsz = (ch->ccap == 0 ? 8 : ch->ccap *2); ch->c = M(ch->c, newsz * sizeof(Val)); ch->ccap = newsz; } size_t ix = ch->clen; ch->c[ix] = v; ch->clen ++; return ix; } Vm vm_new(Chunk *ch) { Vm vm = (Vm){ .ch = ch, .ip = 0, .sp = 0 }; for (int i = 0; i < STACKSIZE; i++) { vm.stack[i] = VAL_NIL; } return vm; } static void runvm() { Chunk ch = chunk_new(); chunk_wbc(&ch, OP_LOADK); chunk_wbc(&ch, chunk_wconst(&ch, VAL_NUM(10.0))); chunk_wbc(&ch, OP_LOADK); chunk_wbc(&ch, chunk_wconst(&ch, VAL_NUM(3.0))); chunk_wbc(&ch, OP_DIV); chunk_wbc(&ch, OP_PRINT); chunk_wbc(&ch, OP_RET); disasm_chunk(&ch); Vm vm = vm_new(&ch); #define RBYTE() (vm.ch->b[vm.ip++]) #define PUSH(v) vm.stack[vm.sp++] = v; #define POP() (vm.stack[--vm.sp]) puts("---"); while (1) { uint8_t instr = RBYTE(); switch (instr) { case OP_RET: printf("done!\n"); goto done; break; case OP_LOADK:; uint8_t cix = RBYTE(); Val v = vm.ch->c[cix]; PUSH(v); // printf(" (pushing "); // print_val(v); // printf(")\n"); break; case OP_PRINT: println_val(POP()); break; #define ARITH_OP(opcode, OP) \ case opcode: { \ Val b = POP(); \ Val a = POP(); \ if (!IS_NUM(a) || !IS_NUM(b)) { \ printf("can't do arithmetic on %s and %s\n", \ valty_str(a.ty), valty_str(b.ty)); \ goto done; \ } \ PUSH(VAL_NUM(AS_NUM(a) OP AS_NUM(b))); \ } \ break; ARITH_OP(OP_ADD, +) ARITH_OP(OP_SUB, -) ARITH_OP(OP_MUL, *) ARITH_OP(OP_DIV, /) #undef ARITH_OP } } done:; } int main() { runvm(); }