From cbb0ce85de8f5b8fe282e613bfabb65186ea5b53 Mon Sep 17 00:00:00 2001 From: Quinn Stephens Date: Tue, 10 Jun 2025 16:49:58 -0400 Subject: parser: Parse parameter declarations Signed-off-by: Quinn Stephens --- include/parser/ast.h | 8 ++- src/main.c | 37 +++++++++++++- src/parser/parser.c | 135 ++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 155 insertions(+), 25 deletions(-) diff --git a/include/parser/ast.h b/include/parser/ast.h index d4baf92..e8052c6 100644 --- a/include/parser/ast.h +++ b/include/parser/ast.h @@ -38,7 +38,8 @@ enum ast_node_kind { NOK_UNKNOWN, NOK_FUNCTION, - NOK_VARIABLE + NOK_VARIABLE, + NOK_PARAMETER }; struct ast_node { @@ -46,11 +47,14 @@ struct ast_node { enum ast_node_kind kind; + /* Function, variable, parameter */ const char *name; size_t name_len; - struct type *type; int ptr_levels; + + /* Function */ + struct hashmap params; }; #endif /* !_PARSER_AST_H */ diff --git a/src/main.c b/src/main.c index 4387972..ab5d4e8 100644 --- a/src/main.c +++ b/src/main.c @@ -33,7 +33,40 @@ #include "parser.h" #include "parser/ast.h" -static const char *src = "int x;void **ptr;\nvoid *alloc();\nvoid test();\nint main()\n{\n}\n"; +static const char *src = "int x;void **ptr;\nvoid test(void);\nint add(int a, int b);\nint\nmain(int argc, void **argv)\n{\n}\n"; + +static void + +print_param(struct ast_node *param) +{ + if (param->ptr_levels > 0) { + log_debug("found parameter \"%.*s\" (%d-level pointer to %s)\n", param->name_len, param->name, param->ptr_levels, param->type->name); + } else { + log_debug("found parameter \"%.*s\" (%s)\n", param->name_len, param->name, param->type->name); + } +} + +static void +print_locals(struct hashmap *locals) +{ + struct list *list; + struct ast_node *node; + + /* Iterate hashmap rows */ + for (size_t r = 0; r < locals->row_count; r++) { + /* Iterate row entries */ + list = &locals->rows[r]; + node = (struct ast_node *)list->head; + while (node != (struct ast_node *)list) { + if (node->kind == NOK_PARAMETER) { + print_param(node); + } + + node = (struct ast_node *)node->hashmap_entry.list_entry.next; + } + } +} + static void print_func(struct ast_node *func) @@ -43,6 +76,8 @@ print_func(struct ast_node *func) } else { log_debug("found function \"%.*s\" (returns %s)\n", func->name_len, func->name, func->type->name); } + + print_locals(&func->params); } static void diff --git a/src/parser/parser.c b/src/parser/parser.c index a74da06..6b6d015 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -35,7 +35,8 @@ #include "parser/ast.h" #include "parser/types.h" -#define SYMS_HASHMAP_ROWS 16 +#define SYMS_HASHMAP_ROWS 16 +#define PARAMS_HASHMAP_ROWS 4 static void tok_error(struct token *tok, const char *fmt, ...) @@ -48,17 +49,122 @@ tok_error(struct token *tok, const char *fmt, ...) va_end(args); } +static void +tok_warn(struct token *tok, const char *fmt, ...) +{ + va_list args; + + fprintf(stderr, "\033[1;97m%d:%d: \033[1;95mwarning: \033[0m", tok->line, tok->col); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + +static struct type * +parse_type_ref(struct parser *ctx, int *ptr_levels_out) +{ + struct type *type; + int ptr_levels; + + /* + * TODO: Parse custom types. + */ + if (!(ctx->tok.flags & TF_BUILTIN_TYPE)) { + tok_error(&ctx->tok, "expected built-in type name\n"); + return NULL; + } + + type = types_find_builtin(ctx->tok.kind); + if (type == NULL) { + return NULL; + } + + parser_advance(ctx); + ptr_levels = 0; + while (ctx->tok.kind == TOK_ASTERISK) { + ptr_levels++; + parser_advance(ctx); + } + + *ptr_levels_out = ptr_levels; + return type; +} + static bool -parse_func_decl(struct parser *ctx, struct ast_node *func) +parse_params(struct parser *ctx, struct ast_node *func) { - func->kind = NOK_FUNCTION; + struct type *type; + int ptr_levels; + struct ast_node *node; + + func->params.rows = malloc(PARAMS_HASHMAP_ROWS * sizeof(struct list)); + if (func->params.rows == NULL) { + return false; + } + + func->params.row_count = PARAMS_HASHMAP_ROWS; + hashmap_init(func->params); /* - * TODO: Parse parameters. + * TODO: Free memory if parsing parameters fails. */ + while (ctx->tok.kind != TOK_RPAREN) { + type = parse_type_ref(ctx, &ptr_levels); + if (type == NULL) { + return false; + } + + if (ctx->tok.kind != TOK_IDENTIFIER) { + tok_error(&ctx->tok, "expected parameter name after type\n"); + return false; + } + + node = malloc(sizeof(struct ast_node)); + if (node == NULL) { + log_error("failed to allocate memory for AST node\n"); + return false; + } + + node->kind = NOK_PARAMETER; + node->name = ctx->tok.pos; + node->name_len = ctx->tok.len; + node->type = type; + node->ptr_levels = ptr_levels; + node->hashmap_entry.hash = ctx->tok.hash; + hashmap_add(func->params, &node->hashmap_entry); + + parser_advance(ctx); + if (ctx->tok.kind == TOK_COMMA) { + parser_advance(ctx); + if (ctx->tok.kind == TOK_RPAREN) { + tok_warn(&ctx->tok, "extra \",\" at end of parameter list\n"); + } + + continue; + } + } + + return true; +} + +static bool +parse_func_decl(struct parser *ctx, struct ast_node *func) +{ + func->kind = NOK_FUNCTION; + + /* Skip "void" marking no parameters */ parser_advance(ctx); - if (ctx->tok.kind != TOK_RPAREN) { - tok_error(&ctx->tok, "expected \")\" after \"(\"\n"); + if (ctx->tok.kind == TOK_VOID) { + parser_advance(ctx); + if (ctx->tok.kind != TOK_RPAREN) { + tok_error(&ctx->tok, "expected \")\" after \"void\"\n"); + free(func); + return false; + } + } + + /* Parse parameters if present */ + if (ctx->tok.kind != TOK_RPAREN && !parse_params(ctx, func)) { free(func); return false; } @@ -112,26 +218,11 @@ parse_decl(struct parser *ctx) int ptr_levels; struct ast_node *node; - /* - * TODO: Parse custom types. - */ - if (!(ctx->tok.flags & TF_BUILTIN_TYPE)) { - tok_error(&ctx->tok, "expected type\n"); - return false; - } - - type = types_find_builtin(ctx->tok.kind); + type = parse_type_ref(ctx, &ptr_levels); if (type == NULL) { return false; } - parser_advance(ctx); - ptr_levels = 0; - while (ctx->tok.kind == TOK_ASTERISK) { - ptr_levels++; - parser_advance(ctx); - } - if (ctx->tok.kind != TOK_IDENTIFIER) { tok_error(&ctx->tok, "expected identifier after type\n"); return false; -- cgit v1.2.3