compiler

Unnamed Compiled Systems Language Project
git clone http://frotz.net/git/compiler.git
Log | Files | Refs

commit 8b2ca898f644b4a68690cb61b09d48c1fa11e62d
parent 43faedf40c49d318d2bf4f575f5287e0b2a20b82
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed, 11 Mar 2020 01:54:04 -0700

compiler: initial local var support

- break parse_expr_statement() out of parse_block()
- correctly generate code for ++ and --
- parse_local_var() handles basic local var declaration
- todo: type inference, non-word-sized vars
- simplify test/1025-fibonacci with these exciting improvements

Diffstat:
Msrc/compiler.c | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mtest/1025-fibonacci.src | 11++++-------
2 files changed, 76 insertions(+), 27 deletions(-)

diff --git a/src/compiler.c b/src/compiler.c @@ -108,9 +108,10 @@ struct StringRec { struct ScopeRec { u32 kind; - Scope next; // next in scope stack - Object first; // first object in this scope - u32 level; // height in stack (0 == globals, ...) + Scope next; // next in scope stack + Object first; // first object in this scope + u32 level; // height in stack (0 == globals, ...) + u32 save_stack; // previous alloc_stack to restore on pop Fixup fixups; }; @@ -236,7 +237,9 @@ struct CtxRec { Object fn; // function being compiled if non-nil u32 spill_stack; // where to spill temp regs (TODO: dynamic) - u32 local_stack; // how much stack we use (adjusted for vars, etc) + u32 local_stack; // total stack for all locals (params, vars, tmps) + u32 alloc_stack; // where to allocate next var (grows/shrinks as + // we enter/exit scopes) Type type_void; Type type_byte; @@ -784,6 +787,9 @@ Scope push_scope(u32 kind, Object obj) { scope->level = ctx.scope->level + 1; scope->fixups = nil; + // save current stack offset (next local var) + scope->save_stack = ctx.alloc_stack; + ctx.scope = scope; return scope; // XXX lazy scopes @@ -793,6 +799,10 @@ void pop_scope() { if (ctx.scope->level == 0) { error("cannot pop the global scope"); } + + // restore prev stack offset (next local var) + ctx.alloc_stack = ctx.scope->save_stack; + fixup_branches_fwd(ctx.scope->fixups); // XXX delete? ctx.scope = ctx.scope->next; @@ -1193,6 +1203,58 @@ void parse_break() { add_scope_fixup(scope); } +void parse_local_var() { + String name = parse_name("variable name"); + // TODO: allow type inference + Type type = parse_type(false); + + Object lvar = make_param(name, type, 0, ctx.alloc_stack); + lvar->next = ctx.scope->first; + ctx.scope->first = lvar; + + // TODO: size from type + ctx.alloc_stack = ctx.alloc_stack + 4; + if (ctx.local_stack < ctx.alloc_stack) { + ctx.local_stack = ctx.alloc_stack; + } + + if (ctx.tok == tASSIGN) { + next(); + ItemRec x, y; + parse_expr(&x); + set_item(&y, iParam, type, 0, lvar->value, 0); + gen_store(&x, &y); + } + require(tSEMI); +} + +void parse_expr_statement() { + ItemRec x; + parse_expr(&x); + if (ctx.tok == tASSIGN) { + next(); + ItemRec y; + parse_expr(&y); + gen_store(&y, &x); + } else if ((ctx.tok == tINC) || (ctx.tok == tDEC)) { + ItemRec y, z; + set_item(&y, iConst, ctx.type_int32, 0, 1, 0); + // loading x will transform it, so save a copy for storing after + set_item(&z, x.kind, x.type, x.r, x.a, x.b); + z.flags = x.flags; + if (ctx.tok == tINC) { + gen_add_op(aADD, &x, &y); + } else { + gen_add_op(aSUB, &x, &y); + } + gen_store(&x, &z); + next(); + } else { + gen_discard(&x); + } + require(tSEMI); +} + void parse_block() { while (true) { if (ctx.tok == tCBRACE) { @@ -1210,25 +1272,14 @@ void parse_block() { } else if (ctx.tok == tIF) { next(); parse_if(); + } else if (ctx.tok == tVAR) { + next(); + parse_local_var(); } else if (ctx.tok == tSEMI) { next(); // empty statement } else { - ItemRec x; - parse_expr(&x); - if (ctx.tok == tASSIGN) { - next(); - ItemRec y; - parse_expr(&y); - gen_store(&y, &x); - } else if ((ctx.tok == tINC) || (ctx.tok == tDEC)) { - ItemRec y; - set_item(&y, iConst, ctx.type_int32, 0, 1, 0); - next(); - } else { - gen_discard(&x); - } - require(tSEMI); + parse_expr_statement(); } } } @@ -1584,7 +1635,7 @@ void gen_load_reg(Item x, u32 r) { } else if (x->kind == iParam) { emit_mem(LDW, r, SP, x->a); } else { - error("gen_load failed"); + error("gen_load failed (kind %u)", x->kind); } x->kind = iReg; x->r = r; @@ -1889,6 +1940,7 @@ void gen_prologue(Object fn) { // OPT: would be nice to only reserve space we need ctx.spill_stack = off; ctx.local_stack = off + 4 * tmp_reg_count; + ctx.alloc_stack = ctx.local_stack; } void gen_epilogue(Object fn) { diff --git a/test/1025-fibonacci.src b/test/1025-fibonacci.src @@ -7,14 +7,11 @@ func fib(n i32) i32 { } } -func test(n i32, end i32) { - while (n < end) { +func start() i32 { + var n i32 = 0; + while n < 30 { _hexout_(fib(n)); - n = n + 1; + n++; } -} - -func start() i32 { - test(0, 30); return 7; }