diff options
Diffstat (limited to 'src/parser')
-rw-r--r-- | src/parser/parser.c | 135 |
1 files changed, 113 insertions, 22 deletions
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; |