aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/nasm.c
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-31 19:58:56 +0200
committerhachem <im@hachem.wtf>2026-08-31 19:58:56 +0200
commit5b06b0e4b8effaacd23308d6a6b26c525e7d3af4 (patch)
tree351155777028e604845d3dfec27d3caf3b22257f /src/codegen/nasm.c
parentcbdb9073480c3e4d8a088b306c23406cf42e25c0 (diff)
feat: add enums and structs
Diffstat (limited to 'src/codegen/nasm.c')
-rw-r--r--src/codegen/nasm.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/src/codegen/nasm.c b/src/codegen/nasm.c
index fef68a8..9c1a178 100644
--- a/src/codegen/nasm.c
+++ b/src/codegen/nasm.c
@@ -209,6 +209,84 @@ static enum StoreSize size_from_int(struct Token token)
}
}
+static bool tokens_equal(struct Token a, struct Token b)
+{
+ return a.length == b.length && memcmp(a.start, b.start, a.length) == 0;
+}
+
+static bool token_matches(struct Token token, const char* text)
+{
+ size_t length = strlen(text);
+ return token.length == length && memcmp(token.start, text, length) == 0;
+}
+
+static struct EnumDecl* find_enum(struct Program* program, struct Token name)
+{
+ for (size_t i = 0; i < program->enum_count; i += 1)
+ if (tokens_equal(program->enums[i].name, name))
+ return &program->enums[i];
+
+ return NULL;
+}
+
+static struct StructDecl* find_struct(struct Program* program, struct Token name)
+{
+ for (size_t i = 0; i < program->struct_count; i += 1)
+ if (tokens_equal(program->structs[i].name, name))
+ return &program->structs[i];
+
+ return NULL;
+}
+
+static uint64_t store_size_bytes(enum StoreSize size)
+{
+ switch (size)
+ {
+ case STORE_SIZE_BYTE: return 1;
+ case STORE_SIZE_WORD: return 2;
+ case STORE_SIZE_DWORD: return 4;
+ default: return 8;
+ }
+}
+
+// an enum member folds to its 0-based index; a struct member folds to its byte
+// offset (or the total size for `.size`)
+static bool emit_named_member(struct Emitter* emitter, struct Token object, struct Token member)
+{
+ struct EnumDecl* enumeration = find_enum(emitter->program, object);
+ if (enumeration != NULL)
+ {
+ for (size_t i = 0; i < enumeration->member_count; i += 1)
+ if (tokens_equal(enumeration->members[i], member))
+ {
+ fprintf(emitter->out, "%zu", i);
+ return true;
+ }
+ }
+
+ struct StructDecl* layout = find_struct(emitter->program, object);
+ if (layout != NULL)
+ {
+ uint64_t offset = 0;
+ for (size_t i = 0; i < layout->field_count; i += 1)
+ {
+ if (tokens_equal(layout->fields[i].name, member))
+ {
+ fprintf(emitter->out, "%llu", (unsigned long long)offset);
+ return true;
+ }
+ offset += store_size_bytes(layout->fields[i].size);
+ }
+ if (token_matches(member, "size"))
+ {
+ fprintf(emitter->out, "%llu", (unsigned long long)offset);
+ return true;
+ }
+ }
+
+ return false;
+}
+
static bool emit_operand(struct Emitter* emitter, struct Expr* expr)
{
switch (expr->kind)
@@ -235,6 +313,11 @@ static bool emit_operand(struct Emitter* emitter, struct Expr* expr)
return true;
}
+ // enum value or struct offset
+ if (expr->member.object->kind == EXPR_PRIMARY
+ && emit_named_member(emitter, expr->member.object->primary.token, expr->member.member))
+ return true;
+
if (!emit_operand(emitter, expr->member.object))
return false;
fprintf(emitter->out, ".%.*s", (int)expr->member.member.length, expr->member.member.start);