diff options
Diffstat (limited to 'compiler/parser/proc.c')
-rw-r--r-- | compiler/parser/proc.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/compiler/parser/proc.c b/compiler/parser/proc.c new file mode 100644 index 0000000..bbbdad1 --- /dev/null +++ b/compiler/parser/proc.c @@ -0,0 +1,144 @@ +/* + * Procedure parser. + * Copyright (c) 2023-2024, Quinn Stephens and the OSMORA team. + * Provided under the BSD 3-Clause license. + */ + +#include <stdbool.h> +#include "debug.h" +#include "parser/proc.h" +#include "parser/type.h" +#include "parser.h" + +#define HASHMAP_ROWS 8 + +static bool +parse_params(struct parser *ctx, struct procedure *proc) +{ + struct parameter *param; + struct variable *var; + struct type *typ; + int n_ptrs; + + debug("Parsing procedure parameters...\n"); + + while (ctx->tok.kind != TK_RPAREN) { + if (ctx->tok.kind != TK_IDENTIFIER) { + tok_error(&ctx->tok, "expected parameter type name or \")\"\n"); + return false; + } + + if (!parse_type_ref(ctx, &typ, &n_ptrs)) { + return false; + } + + if (ctx->tok.kind != TK_IDENTIFIER) { + tok_error(&ctx->tok, "expected parameter name\n"); + return false; + } + + param = malloc(sizeof(struct parameter)); + var = ¶m->var; + var->hashmap_entry.hash = ctx->tok.hash; + var->name = ctx->tok.pos; + var->name_len = ctx->tok.len; + var->typ = typ; + var->n_ptrs = n_ptrs; + hashmap_add(&proc->vars, &var->hashmap_entry); + list_append(&proc->params, ¶m->list_entry); + + if (next_token(ctx)->kind == TK_COMMA && next_token(ctx)->kind == TK_RPAREN) { + tok_warn(&ctx->tok, "extra \",\" at end of parameter list\n"); + } + } + next_token(ctx); + + return true; +} + +void +parse_proc(struct parser *ctx) +{ + struct procedure *proc; + + debug("Parsing procedure declaration...\n"); + + /* Procedure name */ + if (next_token(ctx)->kind != TK_IDENTIFIER) { + tok_error(&ctx->tok, "expected identifier after \"proc\"\n"); + return; + } + + /* Ensure procedure does not already exist */ + proc = (struct procedure*)hashmap_find(ctx->procs, ctx->tok.hash); + if (proc != NULL) { + tok_error(&ctx->tok, "procedure \"%.*s\" already declared\n", (int)ctx->tok.len, ctx->tok.pos); + return; + } + + /* Create procedure */ + proc = malloc(sizeof(struct procedure)); + proc->hashmap_entry.hash = ctx->tok.hash; + proc->name = ctx->tok.pos; + proc->name_len = ctx->tok.len; + + if (next_token(ctx)->kind != TK_LPAREN) { + tok_error(&ctx->tok, "expected \"(\" after procedure name\n"); + free(proc); + return; + } + + /* Set up variables hashmap */ + proc->vars.rows = malloc(HASHMAP_ROWS * sizeof(struct list)); + proc->vars.n_rows = HASHMAP_ROWS; + hashmap_init(&proc->vars); + + /* Set up parameter list */ + list_init(&proc->params); + + /* Parse parameters */ + if (next_token(ctx)->kind != TK_RPAREN) { + if (!parse_params(ctx, proc)) { + hashmap_free_entries(&proc->vars); + free(proc->vars.rows); + free(proc); + return; + } + } else { + next_token(ctx); + } + + /* Parse return type if specified */ + if (ctx->tok.kind == TK_ARROW) { + next_token(ctx); + if (!parse_type_ref(ctx, &proc->ret_typ, &proc->ret_n_ptrs)) { + hashmap_free_entries(&proc->vars); + free(proc->vars.rows); + free(proc); + return; + } + } + + /* Add procedure to parser's registry */ + hashmap_add(ctx->procs, &proc->hashmap_entry); + + /* We are finished now if this is just a declaration */ + if (ctx->tok.kind == TK_SEMICOLON) { + next_token(ctx); + return; + } + + if (ctx->tok.kind != TK_LBRACE) { + tok_error(&ctx->tok, "Expected \";\" or \"{\"\n"); + return; + } + + /* TODO: Parse body/code */ + + if (next_token(ctx)->kind != TK_RBRACE) { + tok_error(&ctx->tok, "Expected \"}\" after procedure body\n"); + return; + } + + next_token(ctx); +} |