aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-04 20:00:52 +0200
committerhachem <im@hachem.wtf>2026-09-04 20:00:52 +0200
commit9283b46a08a1c58c321b6c7ebad1353725c3bc47 (patch)
tree5fba917f42bdbaf86f27abc01577b3c1b232e409 /src/codegen
parent56ba8b2a373dd1386950592bda9c68ff9f25c203 (diff)
feat: add if/else blocks
if now guards a { } block or bare statement with an optional else (and now else-if chaining). The branch body becomes a statement list; a bare guarded statement is a list of length one.
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/nasm.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/src/codegen/nasm.c b/src/codegen/nasm.c
index 6df22a4..8bcdda3 100644
--- a/src/codegen/nasm.c
+++ b/src/codegen/nasm.c
@@ -908,6 +908,12 @@ static void emit_call(struct Emitter* emitter, struct CallStatement* call)
static void emit_statement(struct Emitter* emitter, struct Statement* statement);
+static void emit_block(struct Emitter* emitter, struct Statement* body, size_t count)
+{
+ for (size_t i = 0; i < count; i += 1)
+ emit_statement(emitter, &body[i]);
+}
+
// ucomisd sets the flags like an unsigned compare, so float branches use the
// unsigned jump family (ja/jae/jb/jbe) rather than the signed one
static const char* float_jump_if_false(enum TokenType comparison)
@@ -939,10 +945,13 @@ static void emit_float_operand(struct Emitter* emitter, const struct Expr* expr)
static void emit_if(struct Emitter* emitter, struct IfStatement* branch)
{
bool is_float = value_is_float(emitter, branch->left) || value_is_float(emitter, branch->right);
+ bool has_else = branch->else_count > 0;
uint32_t id = emitter->label_id;
emitter->label_id += 1;
+ const char* target = has_else ? ".if_else_" : ".if_end_";
+
if (is_float)
{
const char* jump = float_jump_if_false(branch->comparison.type);
@@ -958,30 +967,34 @@ static void emit_if(struct Emitter* emitter, struct IfStatement* branch)
emit_float_operand(emitter, branch->left);
fprintf(emitter->out, ", ");
emit_float_operand(emitter, branch->right);
- fprintf(emitter->out, "\n\t%s .if_end_%u\n", jump, id);
-
- emit_statement(emitter, branch->body);
- fprintf(emitter->out, ".if_end_%u:\n", id);
- return;
+ fprintf(emitter->out, "\n\t%s %s%u\n", jump, target, id);
}
-
- const char* jump = jump_if_false(branch->comparison.type);
- if (jump == NULL
- || branch->left->kind == EXPR_BINARY || branch->left->kind == EXPR_DEREF
- || branch->right->kind == EXPR_BINARY || branch->right->kind == EXPR_DEREF)
+ else
{
- fprintf(emitter->out, "\t; TODO: unsupported if\n");
- return;
+ const char* jump = jump_if_false(branch->comparison.type);
+ if (jump == NULL
+ || branch->left->kind == EXPR_BINARY || branch->left->kind == EXPR_DEREF
+ || branch->right->kind == EXPR_BINARY || branch->right->kind == EXPR_DEREF)
+ {
+ fprintf(emitter->out, "\t; TODO: unsupported if\n");
+ return;
+ }
+
+ fprintf(emitter->out, "\tcmp ");
+ emit_operand(emitter, branch->left);
+ fprintf(emitter->out, ", ");
+ emit_operand(emitter, branch->right);
+ fprintf(emitter->out, "\n\t%s %s%u\n", jump, target, id);
}
- fprintf(emitter->out, "\tcmp ");
- emit_operand(emitter, branch->left);
- fprintf(emitter->out, ", ");
- emit_operand(emitter, branch->right);
- fprintf(emitter->out, "\n");
- fprintf(emitter->out, "\t%s .if_end_%u\n", jump, id);
+ emit_block(emitter, branch->body, branch->body_count);
- emit_statement(emitter, branch->body);
+ if (has_else)
+ {
+ fprintf(emitter->out, "\tjmp .if_end_%u\n", id);
+ fprintf(emitter->out, ".if_else_%u:\n", id);
+ emit_block(emitter, branch->else_body, branch->else_count);
+ }
fprintf(emitter->out, ".if_end_%u:\n", id);
}
@@ -1083,7 +1096,10 @@ static void collect_floats_statement(struct FloatTable* floats, struct Statement
case STATEMENT_IF:
collect_floats_expr(floats, statement->branch.left);
collect_floats_expr(floats, statement->branch.right);
- collect_floats_statement(floats, statement->branch.body);
+ for (size_t i = 0; i < statement->branch.body_count; i += 1)
+ collect_floats_statement(floats, &statement->branch.body[i]);
+ for (size_t i = 0; i < statement->branch.else_count; i += 1)
+ collect_floats_statement(floats, &statement->branch.else_body[i]);
break;
case STATEMENT_CALL:
for (size_t i = 0; i < statement->call.arg_count; i += 1)