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:
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;
}