commit 21984842672b546b40015dbe443e24de4e2e44c9
parent 9eb42807448acfbed5c88c8d121984560c87e30b
Author: Brian Swetland <swetland@frotz.net>
Date:   Mon,  6 Dec 2021 01:08:09 -0800
compiler2: fixing bugs
- track last function ast node and error-relevant ast node and dump
  the ast subtree relevent to errors when generating code
- fix up if/else/elseif ast generation
- fix up if/else/elseif code generation
Diffstat:
2 files changed, 98 insertions(+), 39 deletions(-)
diff --git a/src/codegen-risc5-simple.c b/src/codegen-risc5-simple.c
@@ -209,6 +209,17 @@ void gen_trace(str msg) {
 void gen_block(Ast node);
 u32 gen_expr(Ast node);
 
+Ast err_last_func = nil;
+Ast err_ast = nil;
+
+void dump_error_ctxt() {
+	fprintf(stderr, "\n");
+	if (err_last_func) {
+		ast_dump(err_last_func, err_ast);
+	}
+	fprintf(stderr, "\n");
+}
+
 void sym_get_loc(Symbol sym, u32* base, i32* offset) {
 	if (sym->kind == SYM_LOCAL) {
 		*base = FP;
@@ -246,6 +257,7 @@ u32 gen_call(Ast node) {
 		emit_mem(STW, r, R11, 0x100 + sym->value * 4);
 		put_reg(r);
 	} else if (sym->type->len > 0) {
+		// XXX: must save regs
 		emit_opi(SUB, SP, SP, 4 * sym->type->len);
 		u32 n = 0;
 		while (arg != nil) {
@@ -257,12 +269,17 @@ u32 gen_call(Ast node) {
 		}
 		gen_branch_sym(AL|L, sym);
 		emit_opi(ADD, SP, SP, 4 * sym->type->len);
+		// XXX: must restore regs
 	} else {
 		// no args
 		gen_branch_sym(AL|L, sym);
 	}
 	// return is in r0, if it exists
-	return 0;
+	// stash it somewhere where it won't get stomped
+	// by other calls in this expr
+	u32 r = get_reg_tmp();
+	emit_mov(r, R0);
+	return r;
 }
 
 u32 gen_lexpr(Ast node) {
@@ -295,6 +312,7 @@ u32 gen_relop(Ast node, u32 cc) {
 }
 
 u32 gen_expr(Ast node) {
+	err_ast = node;
 	gen_trace("gen_expr()\n");
 	if (node->kind == AST_U32) {
 		u32 r = get_reg_tmp();
@@ -342,7 +360,6 @@ u32 gen_expr(Ast node) {
 			error("gen_expr cannot handle unop %s\n", tnames[op]);
 		}
 		return r;
-		error("sorry no unops");
 	} else if (node->kind == AST_CALL) {
 		return gen_call(node);
 	} else {
@@ -380,18 +397,42 @@ void gen_while(Ast node) {
 }
 
 void gen_if_else(Ast node) {
-	gen_expr(node->c0);
-	Ast ifthen = node->c1;
-	Ast ifelse = node->c2;
-	gen_block(ifthen);
-	if (ifelse != nil) {
-		gen_block(ifelse);
+	// compute if expr
+	// branch ahead if false;
+	u32 r = gen_expr(node->c0);
+	emit_mov(R11, r); // set z flag;
+	put_reg(r);
+	u32 l0_br_false = ctx.pc;
+	emit_bi(EQ, 0);
+
+	// exec then block
+	gen_block(node->c1);
+
+	node = node->c2;
+	while (node != nil) {
+		fixup_branch_fwd(l0_br_false);
+
+		if (node->kind == AST_IF) { // ifelse ...
+			r = gen_expr(node->c0);
+			emit_mov(R11, r); // set z flag
+			put_reg(r);
+			l0_br_false = ctx.pc;
+			emit_bi(EQ, 0);
+			gen_block(node->c1);
+			node = node->c2;
+		} else { // else ...
+			gen_block(node);
+			return;
+		}
 	}
+
+	fixup_branch_fwd(l0_br_false);
 }
 
 void gen_block(Ast node);
 
 void gen_stmt(Ast node) {
+	err_ast = node;
 	gen_trace("gen_stmt()\n");
 	u32 kind = node->kind;
 	if (kind == AST_EXPR) {
@@ -455,6 +496,8 @@ void gen_block(Ast node) {
 //                  SP -> locn
 
 void gen_func(Ast node) {
+	err_last_func = node;
+	err_ast = node;
 	gen_trace("gen_func()\n");
 
 	// local space plus saved lr and fp
@@ -505,6 +548,8 @@ void gen_risc5_simple(Ast node) {
 		node = node->c2;
 	}
 
+	err_last_func = nil;
+
 	Symbol sym = symbol_find(string_make("start", 5));
 	if (sym == nil) {
 		error("no 'start' function\n");
diff --git a/src/compiler2.c b/src/compiler2.c
@@ -574,6 +574,7 @@ void ctx_init() {
 }
 
 void dump_file_line(const char* fn, u32 offset);
+void dump_error_ctxt();
 
 #if C
 void error(const char *fmt, ...)
@@ -593,6 +594,8 @@ void error(const char *fmt)
 	}
 	fprintf(stderr, "\n");
 
+	dump_error_ctxt();
+
 	if (ctx.flags & cfAbortOnError) {
 		abort();
 	} else {
@@ -1326,45 +1329,36 @@ Ast parse_while() {
 }
 
 Ast parse_if() {
-	// Scope outer = scope_push(SCOPE_BLOCK, nil);
-	Ast expr = parse_expr();
+	// if expr { block }
+	Ast ifnode = ast_make_simple(AST_IF, 0);
+	ifnode->c0 = parse_expr();
 	require(tOBRACE);
 	scope_push(SCOPE_BLOCK, nil);
-	Ast block = parse_block();
-	block->sym = scope_pop();
-	Ast ifnode = ast_make_simple(AST_IF, 0);
-	ifnode->c0 = expr;
-	ifnode->c1 = block;
-	Ast last = block;
+	ifnode->c1 = parse_block();
+	ifnode->c1->sym = scope_pop();
 	while (ctx.tok == tELSE) {
 		next();
+		// ... else ...
 		if (ctx.tok == tIF) {
+			// ... if expr { block }
 			next();
-			Ast expr = parse_expr();
-
-			// generate "if else" code
+			Ast ifelse = ast_make_simple(AST_IF, 0);
+			ifelse->c0 = parse_expr();
 			require(tOBRACE);
 			scope_push(SCOPE_BLOCK, nil);
-			Ast block = parse_block();
-			block->sym = scope_pop();
-
-			last->c2 = expr;
-			expr->c2 = block;
-			last = block;
+			ifelse->c1 = parse_block();
+			ifelse->c1->sym = scope_pop();
+			ifnode->c2 = ifelse;
+			ifnode = ifelse;
 		} else {
-			// generate "else" code
+			// ... { block }
 			require(tOBRACE);
 			scope_push(SCOPE_BLOCK, nil);
-			Ast block = parse_block();
-			block->sym = scope_pop();
-			last->c2 = block;
-			last = block;
+			ifnode->c2 = parse_block();
+			ifnode->c2->sym = scope_pop();
 			break;
 		}
 	}
-
-	// close outer scope
-	// scope_pop();
 	return ifnode;
 }
 
@@ -1848,9 +1842,15 @@ void ast_dump_rtype(Symbol sym, u32 indent) {
 	printf("\n");
 }
 
-void ast_dump(Ast node, u32 indent, bool dumplist) {
+int _ast_dump(Ast node, u32 indent, bool dumplist, Ast mark) {
 	u32 i = 0;
-	while (i < indent) { printf("  "); i++; }
+	i32 r = 0;
+
+	if (mark == node) {
+		while (i < indent) { printf(">>"); i++; }
+	} else {
+		while (i < indent) { printf("  "); i++; }
+	}
 	indent = indent + 1;
 
 	printf("%s ", ast_kind[node->kind]);
@@ -1888,19 +1888,33 @@ void ast_dump(Ast node, u32 indent, bool dumplist) {
 	if (node->kind == AST_BLOCK) {
 		ast_dump_syms(node->sym, "Local", indent);
 	}
+	if (mark == node) {
+		return 1;
+	}
 	if (node->c0 != nil) {
-		ast_dump(node->c0, indent, true);
+		if (_ast_dump(node->c0, indent, true, mark)) {
+			return 1;
+		}
 	}
 	if (node->c1 != nil) {
-		ast_dump(node->c1, indent, true);
+		if (_ast_dump(node->c1, indent, true, mark)) {
+			return 1;
+		}
 	}
 	if (dumplist) {
 		node = node->c2;
 		while (node != nil) {
-			ast_dump(node, indent, false);
+			if (_ast_dump(node, indent, false, mark)) {
+				return 1;
+			}
 			node = node->c2;
 		}
 	}
+	return 0;
+}
+
+void ast_dump(Ast node, Ast mark) {
+	_ast_dump(node, 0, true, mark);
 }
 
 #include "codegen-risc5-simple.c"
@@ -2083,7 +2097,7 @@ i32 main(int argc, args argv) {
 	Ast a = parse_program();
 
 	if (astdump) {
-		ast_dump(a, 0, true);
+		ast_dump(a, nil);
 	}
 
 	gen_risc5_simple(a);