From f80e73ee8d7f7b68f403033001c632e91cb5ac68 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Mon, 31 Jul 2023 18:51:46 +0100 Subject: bytecode vm start, can print constants currently --- run.c | 121 -------------------------------------------------------------- run.h | 2 +- run_old.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ val.c | 16 +++++++++ val.h | 9 ++++- vm | Bin 0 -> 20840 bytes vm.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vm.h | 42 ++++++++++++++++++++++ 8 files changed, 290 insertions(+), 123 deletions(-) delete mode 100644 run.c create mode 100644 run_old.c create mode 100644 val.c create mode 100755 vm create mode 100644 vm.c create mode 100644 vm.h diff --git a/run.c b/run.c deleted file mode 100644 index e4fa540..0000000 --- a/run.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "run.h" -#include "ast.h" -#include "ht.h" - -#include -#include - -// return pointer to nth subnode of AST_LIST node *l. -// doesn't check that l is a list, or that it has at least n elems. -#define NTH(l,n) (&(l)->as.list.vals[(n)]) - -// n is max index -#define CK_LEN(s, l, n) do { if(l.len-1 != n) { \ - printf("%s fn requires exactly %d args (%ld provided)",\ - s, n, l.len-1); return 0; } } while(0); -static int func_plus(Env *s, AstVec l) { - CK_LEN("+",l,2); - return eval(s, l.vals[1]) + eval(s, l.vals[2]); -} -static int func_id(Env *s, AstVec l) { - CK_LEN("id",l,1); - return eval(s, l.vals[1]); -} -static int func_minus(Env *s, AstVec l) { - CK_LEN("-",l,2); - return eval(s, l.vals[1]) - eval(s, l.vals[2]); -} -static int func_mult(Env *s, AstVec l) { - CK_LEN("*",l,2); - return eval(s, l.vals[1]) * eval(s, l.vals[2]); -} -static int func_div(Env *s, AstVec l) { - CK_LEN("/",l,2); - return eval(s, l.vals[1]) / eval(s, l.vals[2]); -} -static int func_print(Env *s, AstVec l) { - CK_LEN("print",l,1); - int v = eval(s, l.vals[1]); - printf("%d\n",v); - return v; -} -static int func_set(Env *s, AstVec l) { - CK_LEN("set", l, 2); - if (l.vals[1].ty != AST_SYMBOL) { - printf("can only assign to symbols"); - return 0; - } - int v = eval(s, l.vals[2]); - printf(" %p set %s %d\n", (void*)s, l.vals[1].as.str, v); - ht_put(s, l.vals[1].as.str, v); - return v; -} -static int func_do(Env *s, AstVec l) { - for (int i = 1; i < l.len; i++) { - eval(s, l.vals[i]); - } - return 0; -} - -typedef int (*builtin_func)(Env*, AstVec); -typedef struct { - char *name; - builtin_func func; -} BuiltinDesc; - -BuiltinDesc builtins[] = { - { "+", func_plus }, - { "-", func_minus }, - { "*", func_mult }, - { "/", func_div }, - { "id", func_id }, - { "print", func_print }, - { "set", func_set }, - { "do", func_do }, - - { NULL, NULL }, -}; - -static int call_builtin(Env *s, char *name, AstVec arglist) { - for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) { - if (0 == strcmp(bd->name, name)) { - return bd->func(s, arglist); - } - } - printf("couldn't find builtin fn %s\n",name); - return 0; -} - -int eval(Env *s, AstNode a) { - switch (a.ty) { - case AST_SYMBOL:; - int v; - if (ht_get(s, a.as.str, &v)) { - return v; - } else { - printf("unset variable %s\n",a.as.str); - return 0; - } - break; - case AST_NUM: - return a.as.num; - break; - case AST_LIST:; - AstVec l = a.as.list; - if (l.len < 1) { - printf("can't execute empty list\n"); - return 0; - } - AstNode *first = &l.vals[0]; - if (first->ty != AST_SYMBOL) { - printf("first element of list must be symbol\n"); - return 0; - } - return call_builtin(s, first->as.str, l); - break; - default: - printf("???\n"); - return 0; - } -} - diff --git a/run.h b/run.h index 155b59b..291897c 100644 --- a/run.h +++ b/run.h @@ -3,8 +3,8 @@ #include "ast.h" #include "ht.h" +#include "val.h" -int eval(Env *s, AstNode a); #endif diff --git a/run_old.c b/run_old.c new file mode 100644 index 0000000..e4fa540 --- /dev/null +++ b/run_old.c @@ -0,0 +1,121 @@ +#include "run.h" +#include "ast.h" +#include "ht.h" + +#include +#include + +// return pointer to nth subnode of AST_LIST node *l. +// doesn't check that l is a list, or that it has at least n elems. +#define NTH(l,n) (&(l)->as.list.vals[(n)]) + +// n is max index +#define CK_LEN(s, l, n) do { if(l.len-1 != n) { \ + printf("%s fn requires exactly %d args (%ld provided)",\ + s, n, l.len-1); return 0; } } while(0); +static int func_plus(Env *s, AstVec l) { + CK_LEN("+",l,2); + return eval(s, l.vals[1]) + eval(s, l.vals[2]); +} +static int func_id(Env *s, AstVec l) { + CK_LEN("id",l,1); + return eval(s, l.vals[1]); +} +static int func_minus(Env *s, AstVec l) { + CK_LEN("-",l,2); + return eval(s, l.vals[1]) - eval(s, l.vals[2]); +} +static int func_mult(Env *s, AstVec l) { + CK_LEN("*",l,2); + return eval(s, l.vals[1]) * eval(s, l.vals[2]); +} +static int func_div(Env *s, AstVec l) { + CK_LEN("/",l,2); + return eval(s, l.vals[1]) / eval(s, l.vals[2]); +} +static int func_print(Env *s, AstVec l) { + CK_LEN("print",l,1); + int v = eval(s, l.vals[1]); + printf("%d\n",v); + return v; +} +static int func_set(Env *s, AstVec l) { + CK_LEN("set", l, 2); + if (l.vals[1].ty != AST_SYMBOL) { + printf("can only assign to symbols"); + return 0; + } + int v = eval(s, l.vals[2]); + printf(" %p set %s %d\n", (void*)s, l.vals[1].as.str, v); + ht_put(s, l.vals[1].as.str, v); + return v; +} +static int func_do(Env *s, AstVec l) { + for (int i = 1; i < l.len; i++) { + eval(s, l.vals[i]); + } + return 0; +} + +typedef int (*builtin_func)(Env*, AstVec); +typedef struct { + char *name; + builtin_func func; +} BuiltinDesc; + +BuiltinDesc builtins[] = { + { "+", func_plus }, + { "-", func_minus }, + { "*", func_mult }, + { "/", func_div }, + { "id", func_id }, + { "print", func_print }, + { "set", func_set }, + { "do", func_do }, + + { NULL, NULL }, +}; + +static int call_builtin(Env *s, char *name, AstVec arglist) { + for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) { + if (0 == strcmp(bd->name, name)) { + return bd->func(s, arglist); + } + } + printf("couldn't find builtin fn %s\n",name); + return 0; +} + +int eval(Env *s, AstNode a) { + switch (a.ty) { + case AST_SYMBOL:; + int v; + if (ht_get(s, a.as.str, &v)) { + return v; + } else { + printf("unset variable %s\n",a.as.str); + return 0; + } + break; + case AST_NUM: + return a.as.num; + break; + case AST_LIST:; + AstVec l = a.as.list; + if (l.len < 1) { + printf("can't execute empty list\n"); + return 0; + } + AstNode *first = &l.vals[0]; + if (first->ty != AST_SYMBOL) { + printf("first element of list must be symbol\n"); + return 0; + } + return call_builtin(s, first->as.str, l); + break; + default: + printf("???\n"); + return 0; + } +} + diff --git a/val.c b/val.c new file mode 100644 index 0000000..4456148 --- /dev/null +++ b/val.c @@ -0,0 +1,16 @@ +#include +#include "val.h" + +void print_val(Val v) { + switch (v.ty) { + case TY_NIL: + printf("nil\n"); + break; + case TY_NUM: + printf("%f\n",AS_NUM(v)); + break; + case TY_BOOL: + printf("%s\n",AS_BOOL(v) ? "true" : "false"); + break; + } +} diff --git a/val.h b/val.h index 4560a1c..1f2bd8d 100644 --- a/val.h +++ b/val.h @@ -10,9 +10,9 @@ typedef struct _obj Obj; typedef enum { + TY_NIL, TY_NUM, TY_BOOL, - TY_NIL, } ValTy; struct _val { @@ -29,11 +29,18 @@ struct _obj { int foo; }; +void print_val(Val v); + #define IS_NUM(x) (x.ty == TY_NUM) #define IS_BOOL(x) (x.ty == TY_BOOL) #define IS_NIL(x) (x.ty == NIL) +#define AS_NUM(x) (x.as.d) +#define AS_BOOL(x) (x.as.b) +#define VAL_NUM(x) ((Val){.ty=TY_NUM, .as.d=x}) +#define VAL_BOOL(x) ((Val){.ty=TY_BOOL, .as.b=x}) +#define VAL_NIL ((Val){.ty=TY_NIL}) #endif diff --git a/vm b/vm new file mode 100755 index 0000000..9ecf078 Binary files /dev/null and b/vm differ diff --git a/vm.c b/vm.c new file mode 100644 index 0000000..00692b0 --- /dev/null +++ b/vm.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +#include "val.h" +#include "vm.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, 1); + chunk_wbc(&ch, OP_PRINT); + chunk_wbc(&ch, OP_LOADK); + chunk_wbc(&ch, 2); + chunk_wbc(&ch, OP_LOADK); + chunk_wbc(&ch, 0); + chunk_wbc(&ch, OP_RET); + + chunk_wconst(&ch, VAL_BOOL(false)); + chunk_wconst(&ch, VAL_NIL); + chunk_wconst(&ch, VAL_NUM(420.69)); + + Vm vm = vm_new(&ch); +#define RBYTE() (vm.ch->b[vm.ip++]) + + 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]; + print_val(v); + break; + case OP_PRINT: + printf("print\n"); + break; + } + } + done:; +} + +int main() { runvm(); } + + diff --git a/vm.h b/vm.h new file mode 100644 index 0000000..7f76e05 --- /dev/null +++ b/vm.h @@ -0,0 +1,42 @@ +#ifndef _vm_h +#define _vm_h + +#include +#include +#include + +#include "val.h" + +void *M(void *p, size_t sz); + +typedef struct { + // bytecode + size_t blen; + size_t bcap; + uint8_t *b; + // constants + size_t clen; + size_t ccap; + Val *c; +} Chunk; +Chunk chunk_new(); +size_t chunk_wbc(Chunk *ch, uint8_t byte); +size_t chunk_wconst(Chunk *ch, Val v); + +#define STACKSIZE 128 +typedef struct { + Chunk *ch; + size_t ip; + Val stack[STACKSIZE]; + size_t sp; +} Vm; +Vm vm_new(Chunk *ch); + +typedef enum { + OP_RET, + OP_LOADK, + OP_PRINT, +} Op; + + +#endif -- cgit v1.2.3