diff options
| author | hachem <im@hachem.wtf> | 2026-09-08 12:16:51 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-09-08 12:16:51 +0200 |
| commit | 60c0e084b159801a45570b56f152f0f5e9193d72 (patch) | |
| tree | ad6c72d6782ab5d9edff336e1e852ca7b995bcdc /src/nasm.c | |
| parent | 9d47486aac9cd1a4422b78ee273b7a27bf7b733a (diff) | |
feat: add while loops
Diffstat (limited to 'src/nasm.c')
| -rw-r--r-- | src/nasm.c | 105 |
1 files changed, 73 insertions, 32 deletions
@@ -999,51 +999,64 @@ static void emit_float_operand(struct Emitter* emitter, const struct Expr* expr) fprintf(emitter->out, "%.*s", (int)token.length, token.start); } -static void emit_if(struct Emitter* emitter, struct IfStatement* branch) +// Emits the comparison for `left cmp right` and a jump to `target` taken when +// the condition is false, so the code that follows runs when it is true. Both +// if and while build on this. Returns false (after a TODO note) for a form that +// isn't supported yet. +static bool emit_branch_test(struct Emitter* emitter, struct Expr* left, + struct Token comparison, struct Expr* right, const char* target) { - 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_"; + bool is_float = value_is_float(emitter, left) || value_is_float(emitter, right); if (is_float) { - const char* jump = float_jump_if_false(branch->comparison.type); - bool left_reg = branch->left->kind == EXPR_PRIMARY - && is_float_register(resolve_register(emitter, branch->left->primary.token)); - if (jump == NULL || !left_reg || !value_is_float(emitter, branch->right)) + const char* jump = float_jump_if_false(comparison.type); + bool left_reg = left->kind == EXPR_PRIMARY + && is_float_register(resolve_register(emitter, left->primary.token)); + if (jump == NULL || !left_reg || !value_is_float(emitter, right)) { - fprintf(emitter->out, "\t; TODO: unsupported if\n"); - return; + fprintf(emitter->out, "\t; TODO: unsupported condition\n"); + return false; } fprintf(emitter->out, "\tucomisd "); - emit_float_operand(emitter, branch->left); + emit_float_operand(emitter, left); fprintf(emitter->out, ", "); - emit_float_operand(emitter, branch->right); - fprintf(emitter->out, "\n\t%s %s%u\n", jump, target, id); + emit_float_operand(emitter, right); + fprintf(emitter->out, "\n\t%s %s\n", jump, target); + return true; } - else - { - 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); + const char* jump = jump_if_false(comparison.type); + if (jump == NULL + || left->kind == EXPR_BINARY || left->kind == EXPR_DEREF + || right->kind == EXPR_BINARY || right->kind == EXPR_DEREF) + { + fprintf(emitter->out, "\t; TODO: unsupported condition\n"); + return false; } + fprintf(emitter->out, "\tcmp "); + emit_operand(emitter, left); + fprintf(emitter->out, ", "); + emit_operand(emitter, right); + fprintf(emitter->out, "\n\t%s %s\n", jump, target); + return true; +} + +static void emit_if(struct Emitter* emitter, struct IfStatement* branch) +{ + bool has_else = branch->else_count > 0; + + uint32_t id = emitter->label_id; + emitter->label_id += 1; + + char target[32]; + snprintf(target, sizeof(target), ".if_%s_%u", has_else ? "else" : "end", id); + + if (!emit_branch_test(emitter, branch->left, branch->comparison, branch->right, target)) + return; + emit_block(emitter, branch->body, branch->body_count); if (has_else) @@ -1056,6 +1069,25 @@ static void emit_if(struct Emitter* emitter, struct IfStatement* branch) fprintf(emitter->out, ".if_end_%u:\n", id); } +static void emit_while(struct Emitter* emitter, struct WhileStatement* loop) +{ + uint32_t id = emitter->label_id; + emitter->label_id += 1; + + char target[32]; + snprintf(target, sizeof(target), ".while_end_%u", id); + + fprintf(emitter->out, ".while_%u:\n", id); + + if (!emit_branch_test(emitter, loop->left, loop->comparison, loop->right, target)) + return; + + emit_block(emitter, loop->body, loop->body_count); + + fprintf(emitter->out, "\tjmp .while_%u\n", id); + fprintf(emitter->out, ".while_end_%u:\n", id); +} + static void emit_statement(struct Emitter* emitter, struct Statement* statement) { FILE* out = emitter->out; @@ -1076,6 +1108,9 @@ static void emit_statement(struct Emitter* emitter, struct Statement* statement) case STATEMENT_IF: emit_if(emitter, &statement->branch); break; + case STATEMENT_WHILE: + emit_while(emitter, &statement->loop); + break; case STATEMENT_CALL: emit_call(emitter, &statement->call); break; @@ -1161,6 +1196,12 @@ static void collect_floats_statement(struct FloatTable* floats, struct Statement for (size_t i = 0; i < statement->branch.else_count; i += 1) collect_floats_statement(floats, &statement->branch.else_body[i]); break; + case STATEMENT_WHILE: + collect_floats_expr(floats, statement->loop.left); + collect_floats_expr(floats, statement->loop.right); + for (size_t i = 0; i < statement->loop.body_count; i += 1) + collect_floats_statement(floats, &statement->loop.body[i]); + break; case STATEMENT_CALL: for (size_t i = 0; i < statement->call.arg_count; i += 1) collect_floats_expr(floats, statement->call.args[i]); |
