add VM
This commit is contained in:
parent
5dd15ce9f1
commit
d7860fdac0
@ -1,4 +1,4 @@
|
|||||||
/*x := 1
|
x := 1
|
||||||
y := 1
|
y := 1
|
||||||
|
|
||||||
i := 60
|
i := 60
|
||||||
@ -8,10 +8,4 @@ while i {
|
|||||||
x = z
|
x = z
|
||||||
print(z)
|
print(z)
|
||||||
i = i - 1
|
i = i - 1
|
||||||
}*/
|
}
|
||||||
|
|
||||||
f := 2.0
|
|
||||||
|
|
||||||
a := int(pow(f, 2.0)) + 1
|
|
||||||
|
|
||||||
print(a)
|
|
||||||
|
10
main.c
10
main.c
@ -9,6 +9,7 @@
|
|||||||
#include "lex.h"
|
#include "lex.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
static void usage(const char *prgname);
|
static void usage(const char *prgname);
|
||||||
static void die(const char *fmt, ...);
|
static void die(const char *fmt, ...);
|
||||||
@ -155,6 +156,13 @@ int main(int argc, const char **argv) {
|
|||||||
if (opt_emit_ir)
|
if (opt_emit_ir)
|
||||||
print_ir(&ir, funcs);
|
print_ir(&ir, funcs);
|
||||||
/* run the IR */
|
/* 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);
|
irtoks_term(&ir);
|
||||||
}
|
}
|
||||||
|
7
parse.c
7
parse.c
@ -260,12 +260,7 @@ static void expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, To
|
|||||||
if (v->kind == TokVal) {
|
if (v->kind == TokVal) {
|
||||||
/* immediately negate value */
|
/* immediately negate value */
|
||||||
t->tok.kind = TokVal;
|
t->tok.kind = TokVal;
|
||||||
t->tok.Val.type.kind = v->Val.type.kind;
|
t->tok.Val = eval_unary(IRNeg, &v->Val);
|
||||||
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();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* use the predefined storage address if it was requested and we're on the last operation */
|
/* use the predefined storage address if it was requested and we're on the last operation */
|
||||||
size_t res_addr;
|
size_t res_addr;
|
||||||
|
26
runtime.c
26
runtime.c
@ -45,6 +45,32 @@ Value eval_arith(IRInstr instr, const Value *lhs, const Value *rhs) {
|
|||||||
return (Value){0};
|
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 zero_val(Type ty) {
|
||||||
Value ret;
|
Value ret;
|
||||||
ret.type = ty;
|
ret.type = ty;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include "ir.h"
|
#include "ir.h"
|
||||||
|
|
||||||
Value eval_arith(IRInstr instr, const Value *lhs, const Value *rhs);
|
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);
|
Value zero_val(Type ty);
|
||||||
|
|
||||||
#endif /* RUNTIME_H */
|
#endif /* RUNTIME_H */
|
||||||
|
92
vm.c
92
vm.c
@ -1 +1,93 @@
|
|||||||
#include "vm.h"
|
#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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user