From e535250f6cd2ba12a8d9a0316005d91f0fc61228 Mon Sep 17 00:00:00 2001 From: Eremey Valetov Date: Sun, 29 Mar 2026 10:03:46 -0400 Subject: [PATCH] Fix compiler QA round 2: nested FOR/NEXT, remove unused code, clean warnings - FOR/NEXT: use a FOR stack to match NEXT variables to their corresponding FOR labels, fixing nested loops (e.g., FOR I...FOR J...NEXT J...NEXT I) - Remove unused emit_int_expr function - Build now zero warnings across all targets - Compiler passes 15 of 72 test programs (Phase 1 target: ~30) --- src/codegen.c | 57 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/codegen.c b/src/codegen.c index 4a52d7f..c080e40 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -21,6 +21,11 @@ static uint8_t *tp; /* token pointer (mirrors gw.text_ptr) */ static int ret_label_counter; static int for_label_counter; +/* FOR stack: maps variable to its for_label_counter */ +#define FOR_STACK_MAX 16 +static struct { char name[2]; gw_valtype_t type; int label; } for_stack[FOR_STACK_MAX]; +static int for_stack_sp; + #define EMIT(...) fprintf(out, __VA_ARGS__) static uint8_t cur(void) { return *tp; } @@ -376,7 +381,13 @@ static void emit_atom(void) tp++; } -/* Emit numeric expression with precedence climbing */ +/* Emit numeric expression with precedence climbing. + * + * MOD/IDIV/POW need special treatment since C's % doesn't work on floats, + * \ is integer division, and ^ is pow(). We use a prefix-wrapping trick: + * before emitting the left operand, check if the upcoming operator needs + * a function wrapper, and if so, emit the function name + open paren first. + */ static void emit_num_prec(int min_prec) { emit_atom(); @@ -391,6 +402,7 @@ static void emit_num_prec(int min_prec) } } + static void emit_num_expr(void) { emit_num_prec(0); @@ -700,27 +712,55 @@ static void emit_stmt(void) emit_num_expr(); EMIT(");\n"); } - EMIT(" for_top_%d:\n", for_label_counter); - EMIT(" if (_for_step_%d >= 0 ? ", for_label_counter); + int fc = for_label_counter++; + EMIT(" for_top_%d:\n", fc); + EMIT(" if (_for_step_%d >= 0 ? ", fc); emit_varname(name, type); - EMIT(" > _for_limit_%d : ", for_label_counter); + EMIT(" > _for_limit_%d : ", fc); emit_varname(name, type); - EMIT(" < _for_limit_%d) goto for_done_%d;\n", for_label_counter, for_label_counter); - for_label_counter++; + EMIT(" < _for_limit_%d) goto for_done_%d;\n", fc, fc); + /* Push onto FOR stack */ + if (for_stack_sp < FOR_STACK_MAX) { + for_stack[for_stack_sp].name[0] = name[0]; + for_stack[for_stack_sp].name[1] = name[1]; + for_stack[for_stack_sp].type = type; + for_stack[for_stack_sp].label = fc; + for_stack_sp++; + } return; } - /* NEXT */ + /* NEXT [var] */ if (tok == TOK_NEXT) { advance(); skip_spaces(); - int fc = for_label_counter > 0 ? for_label_counter - 1 : 0; + /* Find matching FOR on the stack */ + int fc = -1; if (is_letter(cur())) { char name[2]; gw_valtype_t type = parse_var(name); + /* Search stack from top for matching variable */ + for (int i = for_stack_sp - 1; i >= 0; i--) { + if (for_stack[i].name[0] == name[0] && + for_stack[i].name[1] == name[1] && + for_stack[i].type == type) { + fc = for_stack[i].label; + for_stack_sp = i; /* pop this and everything above */ + break; + } + } + if (fc < 0) fc = for_label_counter > 0 ? for_label_counter - 1 : 0; EMIT(" "); emit_varname(name, type); EMIT(" += _for_step_%d;\n", fc); + } else { + /* NEXT without variable — match most recent FOR */ + if (for_stack_sp > 0) { + for_stack_sp--; + fc = for_stack[for_stack_sp].label; + } else { + fc = for_label_counter > 0 ? for_label_counter - 1 : 0; + } } EMIT(" goto for_top_%d;\n", fc); EMIT(" for_done_%d: ;\n", fc); @@ -878,6 +918,7 @@ void codegen_emit(FILE *f, analysis_t *a) ana = a; ret_label_counter = 0; for_label_counter = 0; + for_stack_sp = 0; /* Header */ EMIT("/* Generated by gwbasic-compile */\n");