diff options
| author | hachem <im@hachem.wtf> | 2026-08-30 18:26:15 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-08-30 18:26:15 +0200 |
| commit | 287b075294610e224c67eb7a746c9fd7ae318275 (patch) | |
| tree | 3e1a7dd3f4a1bede22f5f4d67a9283459fc3f485 /src | |
| parent | ea2ebf063cc6a87c73068a3e8b06fb744655159f (diff) | |
add: start nasm code gen
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen/nasm.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/src/codegen/nasm.c b/src/codegen/nasm.c index 0782ee1..37d13a7 100644 --- a/src/codegen/nasm.c +++ b/src/codegen/nasm.c @@ -1,5 +1,7 @@ #include <stdio.h> #include <stddef.h> +#include <string.h> +#include <stdbool.h> #include "codegen/nasm.h" @@ -32,6 +34,89 @@ static void emit_data(struct Program* program, FILE* out) } } +static const char* assign_mnemonic(enum TokenType op) +{ + switch (op) + { + case TOKEN_EQUAL: return "mov"; + case TOKEN_PLUS_EQUAL: return "add"; + case TOKEN_MINUS_EQUAL: return "sub"; + case TOKEN_STAR_EQUAL: return "imul"; + default: return NULL; + } +} + +static bool emit_operand(struct Expr* expr, FILE* out) +{ + switch (expr->kind) + { + case EXPR_PRIMARY: + fprintf(out, "%.*s", (int)expr->primary.token.length, expr->primary.token.start); + return true; + case EXPR_MEMBER: + if (!emit_operand(expr->member.object, out)) + return false; + fprintf(out, ".%.*s", (int)expr->member.member.length, expr->member.member.start); + return true; + case EXPR_BINARY: + return false; + } + + return false; +} + +static void emit_assign(struct AssignStatement* assign, FILE* out) +{ + const char* mnemonic = assign_mnemonic(assign->op.type); + if (mnemonic == NULL || assign->value->kind == EXPR_BINARY) + { + fprintf(out, "\t; TODO: unsupported assignment\n"); + return; + } + + if (assign->target_deref) + fprintf(out, "\t%s [%.*s], ", mnemonic, (int)assign->target.length, assign->target.start); + else + fprintf(out, "\t%s %.*s, ", mnemonic, (int)assign->target.length, assign->target.start); + + emit_operand(assign->value, out); + fprintf(out, "\n"); +} + +static void emit_statement(struct Statement* statement, FILE* out) +{ + switch (statement->kind) + { + case STATEMENT_ASSIGN: + emit_assign(&statement->assign, out); + break; + case STATEMENT_LABEL: + fprintf(out, "%.*s:\n", (int)statement->label.name.length, statement->label.name.start); + break; + case STATEMENT_GOTO: + fprintf(out, "\tjmp %.*s\n", (int)statement->jump.label.length, statement->jump.label.start); + break; + case STATEMENT_SYSCALL: + fprintf(out, "\tsyscall\n"); + break; + default: + fprintf(out, "\t; TODO: unsupported statement\n"); + break; + } +} + +static void emit_proc(struct ProcDecl* proc, FILE* out) +{ + bool is_entry = proc->name.length == 4 && memcmp(proc->name.start, "main", 4) == 0; + if (is_entry) + fprintf(out, "_start:\n"); + else + fprintf(out, "%.*s:\n", (int)proc->name.length, proc->name.start); + + for (size_t i = 0; i < proc->body_count; i += 1) + emit_statement(&proc->body[i], out); +} + void generate_nasm(struct Program* program, FILE* out) { if (program->const_count > 0) @@ -45,4 +130,10 @@ void generate_nasm(struct Program* program, FILE* out) fprintf(out, "section .text\n"); fprintf(out, "global _start\n"); + + for (size_t i = 0; i < program->proc_count; i += 1) + { + fprintf(out, "\n"); + emit_proc(&program->procs[i], out); + } } |
