diff --git a/example.script b/example.script index ce2dd49..64a1509 100644 --- a/example.script +++ b/example.script @@ -1,4 +1,4 @@ -/*x := 1 +x := 1 y := 1 i := 60 @@ -8,10 +8,4 @@ while i { x = z print(z) i = i - 1 -}*/ - -f := 2.0 - -a := int(pow(f, 2.0)) + 1 - -print(a) +} diff --git a/main.c b/main.c index e5a8669..f202cca 100644 --- a/main.c +++ b/main.c @@ -9,6 +9,7 @@ #include "lex.h" #include "parse.h" #include "util.h" +#include "vm.h" static void usage(const char *prgname); static void die(const char *fmt, ...); @@ -155,6 +156,13 @@ int main(int argc, const char **argv) { if (opt_emit_ir) print_ir(&ir, funcs); /* run the IR */ - /* TODO... */ + if (!opt_dry) { + run(&ir, funcs); + if (err) { + irtoks_term(&ir); + fprintf(stderr, C_IRED "Runtime error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf); + return 1; + } + } irtoks_term(&ir); } diff --git a/parse.c b/parse.c index 3efd4f1..11100e8 100644 --- a/parse.c +++ b/parse.c @@ -260,12 +260,7 @@ static void expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, To if (v->kind == TokVal) { /* immediately negate value */ t->tok.kind = TokVal; - t->tok.Val.type.kind = v->Val.type.kind; - switch (v->Val.type.kind) { - case TypeInt: t->tok.Val.Int = -v->Val.Int; break; - case TypeFloat: t->tok.Val.Float = -v->Val.Float; break; - default: ASSERT_UNREACHED(); - } + t->tok.Val = eval_unary(IRNeg, &v->Val); } else { /* use the predefined storage address if it was requested and we're on the last operation */ size_t res_addr; diff --git a/runtime.c b/runtime.c index d848f3c..b04c8eb 100644 --- a/runtime.c +++ b/runtime.c @@ -45,6 +45,32 @@ Value eval_arith(IRInstr instr, const Value *lhs, const Value *rhs) { return (Value){0}; } +Value eval_unary(IRInstr instr, const Value *v) { + switch (instr) { + case IRSet: + return *v; + case IRNeg: + if (v->type.kind == TypeInt) + return (Value){ .type.kind = TypeInt, .Int = -v->Int }; + else if (v->type.kind == TypeFloat) + return (Value){ .type.kind = TypeFloat, .Float = -v->Float }; + else { + set_err("Unsupported types for operation '%s'", irinstr_str[instr]); + return (Value){0}; + } + default: + ASSERT_UNREACHED(); + } +} + +bool is_nonzero(const Value *v) { + switch (v->type.kind) { + case TypeInt: return v->Int != 0; + case TypeFloat: return v->Float != 0.0; + default: ASSERT_UNREACHED(); + } +} + Value zero_val(Type ty) { Value ret; ret.type = ty; diff --git a/runtime.h b/runtime.h index 170982c..9205218 100644 --- a/runtime.h +++ b/runtime.h @@ -4,6 +4,8 @@ #include "ir.h" Value eval_arith(IRInstr instr, const Value *lhs, const Value *rhs); +Value eval_unary(IRInstr instr, const Value *v); +bool is_nonzero(const Value *v); Value zero_val(Type ty); #endif /* RUNTIME_H */ diff --git a/vm.c b/vm.c index a199988..446b3d4 100644 --- a/vm.c +++ b/vm.c @@ -1 +1,93 @@ #include "vm.h" + +#include "runtime.h" +#include "util.h" + +#define INIT_STACK_CAP 256 + +typedef struct Stack { + Value *mem; + size_t len, cap; +} Stack; + +static Stack stack_make(void); +static void stack_term(Stack *s); +static void stack_fit(Stack *s, size_t idx); + +static Stack stack_make(void) { + Stack s; + s.mem = xmalloc(sizeof(Value) * INIT_STACK_CAP); + s.cap = INIT_STACK_CAP; + s.len = 0; + return s; +} + +static void stack_term(Stack *s) { + free(s->mem); +} + +static void stack_fit(Stack *s, size_t idx) { + size_t size = idx+1; + if (size > s->cap) { + s->mem = xrealloc(s->mem, sizeof(Value) * (size + (s->cap *= 2))); + } +} + +static Value *irparam_to_val(Stack *s, IRParam *v) { + if (v->kind == IRParamLiteral) + return &v->Literal; + else if (v->kind == IRParamAddr) + return &s->mem[v->Addr]; + else + ASSERT_UNREACHED(); +} + +void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) { + Stack s = stack_make(); + for (size_t i = 0; i < ir->len;) { + IRTok *instr = &ir->toks[i]; + switch (instr->instr) { + case IRSet: + case IRNeg: + stack_fit(&s, instr->Unary.addr); + s.mem[instr->Unary.addr] = eval_unary(instr->instr, irparam_to_val(&s, &instr->Unary.val)); + break; + case IRAdd: + case IRSub: + case IRDiv: + case IRMul: + stack_fit(&s, instr->Arith.addr); + s.mem[instr->Arith.addr] = eval_arith(instr->instr, + irparam_to_val(&s, &instr->Arith.lhs), + irparam_to_val(&s, &instr->Arith.rhs) + ); + break; + case IRJmp: + i = instr->Jmp.iaddr; + continue; + case IRJnz: + if (is_nonzero(irparam_to_val(&s, &instr->CJmp.condition))) { + i = instr->Jmp.iaddr; + continue; + } + break; + case IRCallInternal: { + const BuiltinFunc *f = &builtin_funcs[instr->CallI.fid]; + Value *args = xmalloc(sizeof(Value) * f->n_args); + for (size_t i = 0; i < f->n_args; i++) + args[i] = *irparam_to_val(&s, &instr->CallI.args[i]); + + stack_fit(&s, instr->CallI.ret_addr); + s.mem[instr->CallI.ret_addr] = f->func(args); + + free(args); + break; + } + default: + ASSERT_UNREACHED(); + } + + i++; + } + stack_term(&s); +} diff --git a/vm.h b/vm.h index 40420f6..8378da1 100644 --- a/vm.h +++ b/vm.h @@ -1,4 +1,8 @@ #ifndef __VM_H__ #define __VM_H__ +#include "ir.h" + +void run(const IRToks *ir, const BuiltinFunc *builtin_funcs); + #endif /* VM_H */