summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuinn Stephens <quinn@osmora.org>2024-11-02 09:55:58 -0400
committerQuinn Stephens <quinn@osmora.org>2024-11-02 09:55:58 -0400
commit2cb992bfd4fea07fcdb3df1b9ffe1e11d34c70f3 (patch)
treeb6a9c13b291c09151ee87e2b2dbac979c6254de3
parentfc26be4293b03cac62d6db7bb597d0c8cf1d5b3a (diff)
[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 <quinn@osmora.org>
-rw-r--r--compiler/parser/parser.c19
-rw-r--r--compiler/parser/type.c95
-rw-r--r--test.q12
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;
-};
+}