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/parser/ast.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ src/parser/ast.h | 54 +++++++++++++++++++++++++----- src/parser/parser.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 8 deletions(-) (limited to 'src/parser') diff --git a/src/parser/ast.c b/src/parser/ast.c index 704e9a4..f8bd9cc 100644 --- a/src/parser/ast.c +++ b/src/parser/ast.c @@ -70,6 +70,12 @@ struct Program create_program(void) program.data_decls = NULL; program.data_count = 0; program.data_capacity = 0; + program.enums = NULL; + program.enum_count = 0; + program.enum_capacity = 0; + program.structs = NULL; + program.struct_count = 0; + program.struct_capacity = 0; program.procs = NULL; program.proc_count = 0; program.proc_capacity = 0; @@ -83,6 +89,14 @@ void free_program(struct Program* program) free(program->consts); free(program->data_decls); + for (size_t i = 0; i < program->enum_count; i += 1) + free(program->enums[i].members); + free(program->enums); + + for (size_t i = 0; i < program->struct_count; i += 1) + free(program->structs[i].fields); + free(program->structs); + for (size_t i = 0; i < program->proc_count; i += 1) free_proc(&program->procs[i]); free(program->procs); @@ -93,6 +107,12 @@ void free_program(struct Program* program) program->data_decls = NULL; program->data_count = 0; program->data_capacity = 0; + program->enums = NULL; + program->enum_count = 0; + program->enum_capacity = 0; + program->structs = NULL; + program->struct_count = 0; + program->struct_capacity = 0; program->procs = NULL; program->proc_count = 0; program->proc_capacity = 0; @@ -125,6 +145,76 @@ void add_data(struct Program* program, struct DataDecl decl) program->data_count += 1; } +struct EnumDecl create_enum(void) +{ + struct EnumDecl decl; + decl.members = NULL; + decl.member_count = 0; + decl.member_capacity = 0; + return decl; +} + +void add_enum_member(struct EnumDecl* decl, struct Token member) +{ + if (decl->member_count == decl->member_capacity) + { + size_t capacity = decl->member_capacity < 8 ? 8 : decl->member_capacity * 2; + decl->members = realloc(decl->members, capacity * sizeof(struct Token)); + decl->member_capacity = capacity; + } + + decl->members[decl->member_count] = member; + decl->member_count += 1; +} + +void add_enum(struct Program* program, struct EnumDecl decl) +{ + if (program->enum_count == program->enum_capacity) + { + size_t capacity = program->enum_capacity < 8 ? 8 : program->enum_capacity * 2; + program->enums = realloc(program->enums, capacity * sizeof(struct EnumDecl)); + program->enum_capacity = capacity; + } + + program->enums[program->enum_count] = decl; + program->enum_count += 1; +} + +struct StructDecl create_struct(void) +{ + struct StructDecl decl; + decl.fields = NULL; + decl.field_count = 0; + decl.field_capacity = 0; + return decl; +} + +void add_struct_field(struct StructDecl* decl, struct StructField field) +{ + if (decl->field_count == decl->field_capacity) + { + size_t capacity = decl->field_capacity < 8 ? 8 : decl->field_capacity * 2; + decl->fields = realloc(decl->fields, capacity * sizeof(struct StructField)); + decl->field_capacity = capacity; + } + + decl->fields[decl->field_count] = field; + decl->field_count += 1; +} + +void add_struct(struct Program* program, struct StructDecl decl) +{ + if (program->struct_count == program->struct_capacity) + { + size_t capacity = program->struct_capacity < 8 ? 8 : program->struct_capacity * 2; + program->structs = realloc(program->structs, capacity * sizeof(struct StructDecl)); + program->struct_capacity = capacity; + } + + program->structs[program->struct_count] = decl; + program->struct_count += 1; +} + struct ProcDecl create_proc(void) { struct ProcDecl proc; diff --git a/src/parser/ast.h b/src/parser/ast.h index 98e8dea..b114fb1 100644 --- a/src/parser/ast.h +++ b/src/parser/ast.h @@ -6,6 +6,15 @@ #include "lexer/lexer.h" +enum StoreSize +{ + STORE_SIZE_NONE, + STORE_SIZE_BYTE, + STORE_SIZE_WORD, + STORE_SIZE_DWORD, + STORE_SIZE_QWORD, +}; + struct ConstDecl { struct Token name; @@ -18,19 +27,32 @@ struct DataDecl struct Token value; }; -struct Param +struct EnumDecl { struct Token name; - struct Token reg; + struct Token* members; + size_t member_count; + size_t member_capacity; }; -enum StoreSize +struct StructField { - STORE_SIZE_NONE, - STORE_SIZE_BYTE, - STORE_SIZE_WORD, - STORE_SIZE_DWORD, - STORE_SIZE_QWORD, + struct Token name; + enum StoreSize size; +}; + +struct StructDecl +{ + struct Token name; + struct StructField* fields; + size_t field_count; + size_t field_capacity; +}; + +struct Param +{ + struct Token name; + struct Token reg; }; enum ExprKind @@ -175,6 +197,14 @@ struct Program size_t data_count; size_t data_capacity; + struct EnumDecl* enums; + size_t enum_count; + size_t enum_capacity; + + struct StructDecl* structs; + size_t struct_count; + size_t struct_capacity; + struct ProcDecl* procs; size_t proc_count; size_t proc_capacity; @@ -185,6 +215,14 @@ void free_program(struct Program* program); void add_const(struct Program* program, struct ConstDecl decl); void add_data(struct Program* program, struct DataDecl decl); +struct EnumDecl create_enum(void); +void add_enum_member(struct EnumDecl* decl, struct Token member); +void add_enum(struct Program* program, struct EnumDecl decl); + +struct StructDecl create_struct(void); +void add_struct_field(struct StructDecl* decl, struct StructField field); +void add_struct(struct Program* program, struct StructDecl decl); + struct ProcDecl create_proc(void); void free_proc(struct ProcDecl* proc); void add_param(struct ProcDecl* proc, struct Param param); diff --git a/src/parser/parser.c b/src/parser/parser.c index 87dedbd..682e193 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -53,6 +53,7 @@ static bool consume(struct Parser* parser, enum TokenType type, const char* mess } static struct Expr* parse_expression(struct Parser* parser); +static enum StoreSize parse_store_size(struct Parser* parser); static bool parse_const(struct Parser* parser, struct Program* program) { @@ -92,6 +93,89 @@ static bool parse_data(struct Parser* parser, struct Program* program) return true; } +static bool parse_enum(struct Parser* parser, struct Program* program) +{ + struct EnumDecl decl = create_enum(); + + if (!consume(parser, TOKEN_IDENTIFIER, "expected enum name after 'enum'")) + goto error; + decl.name = parser->previous; + + if (!consume(parser, TOKEN_LEFT_BRACE, "expected '{' after enum name")) + goto error; + + while (!check(parser, TOKEN_RIGHT_BRACE)) + { + if (check(parser, TOKEN_EOF)) + { + error_at(parser, parser->current, "unterminated enum"); + goto error; + } + + if (!consume(parser, TOKEN_IDENTIFIER, "expected an enum member name")) + goto error; + add_enum_member(&decl, parser->previous); + + match_token(parser, TOKEN_COMMA); + } + advance_parser(parser); + + add_enum(program, decl); + return true; + +error: + free(decl.members); + return false; +} + +static bool parse_struct(struct Parser* parser, struct Program* program) +{ + struct StructDecl decl = create_struct(); + + if (!consume(parser, TOKEN_IDENTIFIER, "expected struct name after 'struct'")) + goto error; + decl.name = parser->previous; + + if (!consume(parser, TOKEN_LEFT_BRACE, "expected '{' after struct name")) + goto error; + + while (!check(parser, TOKEN_RIGHT_BRACE)) + { + if (check(parser, TOKEN_EOF)) + { + error_at(parser, parser->current, "unterminated struct"); + goto error; + } + + struct StructField field; + if (!consume(parser, TOKEN_IDENTIFIER, "expected a field name")) + goto error; + field.name = parser->previous; + + field.size = STORE_SIZE_QWORD; + if (match_token(parser, TOKEN_COLON)) + { + field.size = parse_store_size(parser); + if (field.size == STORE_SIZE_NONE) + { + error_at(parser, parser->current, "expected a size (byte, word, dword, qword) after ':'"); + goto error; + } + } + + add_struct_field(&decl, field); + match_token(parser, TOKEN_COMMA); + } + advance_parser(parser); + + add_struct(program, decl); + return true; + +error: + free(decl.fields); + return false; +} + static bool parse_params(struct Parser* parser, struct ProcDecl* proc) { if (check(parser, TOKEN_RIGHT_PAREN)) @@ -555,6 +639,18 @@ bool parse_program(struct Lexer* lexer, struct Program* out) if (!parse_data(&parser, out)) return false; } + else if (check(&parser, TOKEN_ENUM)) + { + advance_parser(&parser); + if (!parse_enum(&parser, out)) + return false; + } + else if (check(&parser, TOKEN_STRUCT)) + { + advance_parser(&parser); + if (!parse_struct(&parser, out)) + return false; + } else if (check(&parser, TOKEN_PROC)) { advance_parser(&parser); -- cgit v1.3