From 5b06b0e4b8effaacd23308d6a6b26c525e7d3af4 Mon Sep 17 00:00:00 2001 From: hachem Date: Mon, 31 Aug 2026 19:58:56 +0200 Subject: feat: add enums and structs --- src/codegen/nasm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'src/codegen') 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); -- cgit v1.3