summaryrefslogtreecommitdiff
path: root/compiler/parser/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/parser/proc.c')
-rw-r--r--compiler/parser/proc.c144
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 = &param->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, &param->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);
+}