From 2cb992bfd4fea07fcdb3df1b9ffe1e11d34c70f3 Mon Sep 17 00:00:00 2001 From: Quinn Stephens Date: Sat, 2 Nov 2024 09:55:58 -0400 Subject: [parser] Improve error handling parse_enum() and parse_struct() now free all allocated memory in case of an error. They also no longer allow the type to be registered if an error occurs. parse_type() no longer allows/requires semicolons after enum/struct definitions. Signed-off-by: Quinn Stephens --- compiler/parser/parser.c | 19 +++++----- compiler/parser/type.c | 95 ++++++++++++++++++++++++++++++++++-------------- test.q | 12 +++--- 3 files changed, 83 insertions(+), 43 deletions(-) diff --git a/compiler/parser/parser.c b/compiler/parser/parser.c index 261385b..a630e37 100644 --- a/compiler/parser/parser.c +++ b/compiler/parser/parser.c @@ -15,7 +15,7 @@ #include "parser.h" static void -add_builtin(struct hashmap *map, char *name, size_t size, int n_ptrs) +add_builtin(struct hashmap *map, char *name, size_t size) { struct type *type; size_t name_len; @@ -27,7 +27,7 @@ add_builtin(struct hashmap *map, char *name, size_t size, int n_ptrs) type->name = name; type->name_len = name_len; type->size = size; - type->n_ptrs = n_ptrs; + type->n_ptrs = 0; hashmap_add(map, &type->hashmap_entry); } @@ -67,8 +67,7 @@ parser_parse(struct parser *ctx) break; default: tok_error(&ctx->tok, "unexpected \"%.*s\"\n", (int)ctx->tok.len, ctx->tok.pos); - next_token(ctx); - break; + return; } } } @@ -79,10 +78,10 @@ parser_init(struct parser *ctx, char *source) debug("Initializing parser...\n"); lexer_init(&ctx->lexer, source); - add_builtin(ctx->types, "any", 0, 0); - add_builtin(ctx->types, "uint", sizeof(void*), 0); - add_builtin(ctx->types, "uint64", 8, 0); - add_builtin(ctx->types, "uint32", 4, 0); - add_builtin(ctx->types, "uint16", 2, 0); - add_builtin(ctx->types, "uint8", 1, 0); + add_builtin(ctx->types, "any", 0); + add_builtin(ctx->types, "uint", sizeof(void*)); + add_builtin(ctx->types, "uint64", 8); + add_builtin(ctx->types, "uint32", 4); + add_builtin(ctx->types, "uint16", 2); + add_builtin(ctx->types, "uint8", 1); } diff --git a/compiler/parser/type.c b/compiler/parser/type.c index e0990c3..5e161b4 100644 --- a/compiler/parser/type.c +++ b/compiler/parser/type.c @@ -27,6 +27,21 @@ type_new(struct token *tok) return typ; } +static void +free_all(struct hashmap *map) +{ + struct hashmap_entry *ent, *next; + + for (size_t r = 0; r < map->n_rows; r++) { + ent = (struct hashmap_entry*)map->rows[r].head; + while (ent != (struct hashmap_entry*)&map->rows[r]) { + next = (struct hashmap_entry*)ent->list_entry.next; + free(ent); + ent = next; + } + } +} + static bool parse_type_ref(struct parser *ctx, struct type **typ_out, int *n_ptrs_out) { @@ -72,6 +87,12 @@ parse_alias(struct parser *ctx, struct type *typ) return false; } + if (ctx->tok.kind != TK_SEMICOLON) { + tok_error(&ctx->tok, "expected \";\" after type definition\n"); + return false; + } + next_token(ctx); + if (typ->n_ptrs >= 1) { typ->size = sizeof(void*); } else { @@ -86,26 +107,29 @@ parse_enum(struct parser *ctx, struct type *typ) { struct enum_member *mem; uint64_t value; + bool error; debug("Parsing enum definition...\n"); - typ->kind = TYK_ENUM; - if (next_token(ctx)->kind != TK_LBRACE) { tok_error(&ctx->tok, "expected \"{\" after \"enum\"\n"); return false; } + /* Set up type and members hashmap */ + typ->kind = TYK_ENUM; typ->members.rows = malloc(HASHMAP_ROWS * sizeof(struct list)); typ->members.n_rows = HASHMAP_ROWS; hashmap_init(&typ->members); value = 0; + error = false; next_token(ctx); while (ctx->tok.kind != TK_RBRACE) { if (ctx->tok.kind != TK_IDENTIFIER) { tok_error(&ctx->tok, "expected enum member name\n"); - return true; + error = true; + break; } mem = malloc(sizeof(struct enum_member)); @@ -122,10 +146,18 @@ parse_enum(struct parser *ctx, struct type *typ) if (ctx->tok.kind != TK_RBRACE) { tok_error(&ctx->tok, "expected \",\" or \"}\" after enum member name\n"); - return true; + error = true; + break; } } + /* Free hashmap data if error occurred */ + if (error) { + free_all(&typ->members); + free(typ->members.rows); + return false; + } + next_token(ctx); return true; } @@ -134,64 +166,80 @@ static bool parse_struct(struct parser *ctx, struct type *typ) { struct struct_member *mem; - uint64_t off; + struct type *mem_typ; + int mem_n_ptrs; + size_t off; + bool error; debug("Parsing struct definition...\n"); - typ->kind = TYK_STRUCT; - if (next_token(ctx)->kind != TK_LBRACE) { tok_error(&ctx->tok, "expected \"{\" after \"struct\"\n"); return false; } + /* Set up type and members hashmap */ + typ->kind = TYK_STRUCT; typ->members.rows = malloc(HASHMAP_ROWS * sizeof(struct list)); typ->members.n_rows = HASHMAP_ROWS; hashmap_init(&typ->members); off = 0; + error = false; next_token(ctx); while (ctx->tok.kind != TK_RBRACE) { if (ctx->tok.kind != TK_IDENTIFIER) { tok_error(&ctx->tok, "expected type name\n"); - return true; + error = true; + break; } - mem = malloc(sizeof(struct struct_member)); - mem->hashmap_entry.hash = ctx->tok.hash; - mem->name = ctx->tok.pos; - mem->name_len = ctx->tok.len; - mem->off = off; - - if (!parse_type_ref(ctx, &mem->typ, &mem->n_ptrs)) { - return true; + if (!parse_type_ref(ctx, &mem_typ, &mem_n_ptrs)) { + error = true; + break; } if (ctx->tok.kind != TK_IDENTIFIER) { tok_error(&ctx->tok, "expected struct member name\n"); - return true; + error = true; + break; } + + mem = malloc(sizeof(struct struct_member)); + mem->hashmap_entry.hash = ctx->tok.hash; mem->name = ctx->tok.pos; mem->name_len = ctx->tok.len; + mem->off = off; + mem->typ = mem_typ; + mem->n_ptrs = mem_n_ptrs; if (mem->n_ptrs >= 1) { mem->size = sizeof(void*); } else { mem->size = mem->typ->size; } - off += mem->size; hashmap_add(&typ->members, &mem->hashmap_entry); + off += mem->size; + if (next_token(ctx)->kind != TK_SEMICOLON) { tok_error(&ctx->tok, "expected \";\" after struct member name\n"); - return true; + error = true; + break; } next_token(ctx); } - typ->size = off; + + /* Free hashmap data if error occurred */ + if (error) { + free_all(&typ->members); + free(typ->members.rows); + return false; + } next_token(ctx); + typ->size = off; return true; } @@ -243,13 +291,6 @@ parse_type(struct parser *ctx) return; } - if (ctx->tok.kind != TK_SEMICOLON) { - tok_error(&ctx->tok, "expected \";\" after type definition\n"); - free(typ); - return; - } - next_token(ctx); - /* Add type to parser's registry */ hashmap_add(ctx->types, &typ->hashmap_entry); } diff --git a/test.q b/test.q index 6e92c35..dbdd857 100644 --- a/test.q +++ b/test.q @@ -5,7 +5,7 @@ type EfiGuid: struct { uint32 data1; uint16 data2; uint16 data3; -}; +} type EfiTableHeader: struct { uint64 signature; @@ -13,20 +13,20 @@ type EfiTableHeader: struct { uint32 headerSize; uint32 crc32; uint32 reserved; -}; +} type EfiRuntimeServices: struct { EfiTableHeader hdr; -}; +} type EfiBootServices: struct { EfiTableHeader hdr; -}; +} type EfiConfigurationTable: struct { EfiGuid vendorGuid; any* vendorTable; -}; +} type EfiSystemTable: struct { EfiTableHeader hdr; @@ -46,4 +46,4 @@ type EfiSystemTable: struct { uint numberOfTableEntries; EfiConfigurationTable* configurationTable; -}; +} -- cgit v1.2.3