From 3e20038bbf7206e2270655418d7884ccfe91a4e4 Mon Sep 17 00:00:00 2001 From: hachem Date: Mon, 31 Aug 2026 00:19:10 +0200 Subject: add directives and directive based entry points --- src/codegen/nasm.c | 16 +++++++----- src/parser/ast.c | 3 +++ src/parser/ast.h | 11 ++++++++ src/parser/parser.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/sema/sema.c | 12 +++++---- 5 files changed, 103 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/codegen/nasm.c b/src/codegen/nasm.c index 323adfc..adae143 100644 --- a/src/codegen/nasm.c +++ b/src/codegen/nasm.c @@ -449,11 +449,12 @@ static void emit_proc(struct Program* program, struct ProcDecl* proc, FILE* out) emitter.out = out; emitter.label_id = 0; - 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); + struct Config config = program->config; + bool is_entry = config.has_entry + && proc->name.length == config.entry.length + && memcmp(proc->name.start, config.entry.start, proc->name.length) == 0; + + fprintf(out, "%.*s:\n", (int)proc->name.length, proc->name.start); uint64_t stack_size = proc_stack_size(proc); if (stack_size > 0) @@ -476,6 +477,8 @@ static void emit_proc(struct Program* program, struct ProcDecl* proc, FILE* out) void generate_nasm(struct Program* program, FILE* out) { + fprintf(out, "bits %u\n\n", program->config.bits); + if (program->const_count > 0) { emit_consts(program, out); @@ -486,7 +489,8 @@ void generate_nasm(struct Program* program, FILE* out) fprintf(out, "\n"); fprintf(out, "section .text\n"); - fprintf(out, "global _start\n"); + if (program->config.has_entry) + fprintf(out, "global %.*s\n", (int)program->config.entry.length, program->config.entry.start); for (size_t i = 0; i < program->proc_count; i += 1) { diff --git a/src/parser/ast.c b/src/parser/ast.c index 1aa1d38..96ee479 100644 --- a/src/parser/ast.c +++ b/src/parser/ast.c @@ -58,6 +58,9 @@ void free_proc(struct ProcDecl* proc) struct Program create_program(void) { struct Program program; + program.config.bits = 64; + program.config.has_entry = false; + program.config.logical_registers = false; program.consts = NULL; program.const_count = 0; program.const_capacity = 0; diff --git a/src/parser/ast.h b/src/parser/ast.h index 6071c4a..a98f43b 100644 --- a/src/parser/ast.h +++ b/src/parser/ast.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "lexer/lexer.h" @@ -146,8 +147,18 @@ struct ProcDecl size_t body_capacity; }; +struct Config +{ + uint32_t bits; + bool has_entry; + struct Token entry; + bool logical_registers; +}; + struct Program { + struct Config config; + struct ConstDecl* consts; size_t const_count; size_t const_capacity; diff --git a/src/parser/parser.c b/src/parser/parser.c index ca14023..8603c46 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,5 +1,6 @@ #include #include +#include #include "parser/parser.h" @@ -436,6 +437,70 @@ error: return false; } +static bool token_text_is(struct Token token, const char* text) +{ + size_t length = strlen(text); + return token.length == length && memcmp(token.start, text, length) == 0; +} + +static bool parse_directive(struct Parser* parser, struct Program* program) +{ + if (!consume(parser, TOKEN_IDENTIFIER, "expected directive name after '['")) + return false; + struct Token key = parser->previous; + + if (!consume(parser, TOKEN_COLON, "expected ':' after directive name")) + return false; + + if (!check(parser, TOKEN_IDENTIFIER) && !check(parser, TOKEN_INTEGER)) + { + error_at(parser, parser->current, "expected a directive value"); + return false; + } + advance_parser(parser); + struct Token value = parser->previous; + + if (!consume(parser, TOKEN_RIGHT_BRACKET, "expected ']' to close directive")) + return false; + + if (token_text_is(key, "bits")) + { + if (value.type != TOKEN_INTEGER || (!token_text_is(value, "64") && !token_text_is(value, "32"))) + { + error_at(parser, value, "bits must be 32 or 64"); + return false; + } + program->config.bits = token_text_is(value, "64") ? 64 : 32; + return true; + } + + if (token_text_is(key, "entry")) + { + if (value.type != TOKEN_IDENTIFIER) + { + error_at(parser, value, "entry must be a procedure name"); + return false; + } + program->config.has_entry = true; + program->config.entry = value; + return true; + } + + if (token_text_is(key, "enable")) + { + if (value.type == TOKEN_IDENTIFIER && token_text_is(value, "logical_registers")) + { + program->config.logical_registers = true; + return true; + } + error_at(parser, value, "unknown extension"); + return false; + } + + error_at(parser, key, "unknown directive"); + return false; +} + bool parse_program(struct Lexer* lexer, struct Program* out) { struct Parser parser; @@ -447,7 +512,13 @@ bool parse_program(struct Lexer* lexer, struct Program* out) while (!check(&parser, TOKEN_EOF)) { - if (check(&parser, TOKEN_CONST)) + if (check(&parser, TOKEN_LEFT_BRACKET)) + { + advance_parser(&parser); + if (!parse_directive(&parser, out)) + return false; + } + else if (check(&parser, TOKEN_CONST)) { advance_parser(&parser); if (!parse_const(&parser, out)) diff --git a/src/sema/sema.c b/src/sema/sema.c index 99ec4f1..55f4a93 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -49,14 +49,16 @@ static bool check_duplicate_names(struct Program* program) static bool check_entry_point(struct Program* program) { + if (!program->config.has_entry) + return true; + + struct Token entry = program->config.entry; for (size_t i = 0; i < program->proc_count; i += 1) - { - struct Token name = program->procs[i].name; - if (name.length == 4 && memcmp(name.start, "main", 4) == 0) + if (names_equal(program->procs[i].name, entry)) return true; - } - fprintf(stderr, "error: no 'main' procedure defined\n"); + fprintf(stderr, "error: line %u: entry point '%.*s' is not defined\n", + entry.line, (int)entry.length, entry.start); return false; } -- cgit v1.3