summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorQuinn Stephens <quinn@osmora.org>2024-11-03 19:12:47 -0500
committerQuinn Stephens <quinn@osmora.org>2024-11-03 19:12:47 -0500
commit063c40584ae78a396b558a5e2a08e3d871450c0b (patch)
tree1acca2d57ba421530b1cfd2a23f0658e35e7ebae /compiler
parent71b10c1c765196a771ce05216395d6b78892a735 (diff)
[compiler] Parse and print procedure declarations
Signed-off-by: Quinn Stephens <quinn@osmora.org>
Diffstat (limited to 'compiler')
-rw-r--r--compiler/hashmap.c10
-rw-r--r--compiler/lexer/keywords.c1
-rw-r--r--compiler/main.c113
-rw-r--r--compiler/parser/parser.c4
-rw-r--r--compiler/parser/proc.c144
5 files changed, 237 insertions, 35 deletions
diff --git a/compiler/hashmap.c b/compiler/hashmap.c
index e5aed7b..e567224 100644
--- a/compiler/hashmap.c
+++ b/compiler/hashmap.c
@@ -17,16 +17,16 @@ hashmap_add(struct hashmap *map, struct hashmap_entry *entry)
struct hashmap_entry *
hashmap_find(struct hashmap *map, hash_t hash)
{
- struct hashmap_entry *head, *entry;
+ struct hashmap_entry *entry;
- entry = head = (struct hashmap_entry*)(map->rows[hash % map->n_rows].head);
- do {
+ entry = (struct hashmap_entry*)map->rows[hash % map->n_rows].head;
+ while (entry != (struct hashmap_entry*)&map->rows[hash % map->n_rows]) {
if (entry->hash == hash) {
return entry;
}
- entry = (struct hashmap_entry*)(entry->list_entry.next);
- } while (entry != head);
+ entry = (struct hashmap_entry*)entry->list_entry.next;
+ }
return NULL;
}
diff --git a/compiler/lexer/keywords.c b/compiler/lexer/keywords.c
index 0e95048..88c2e67 100644
--- a/compiler/lexer/keywords.c
+++ b/compiler/lexer/keywords.c
@@ -65,6 +65,7 @@ keywords_init(void)
keywords.n_rows = HASHMAP_ROWS;
hashmap_init(&keywords);
+ add_keyword("proc", TK_PROC);
add_keyword("type", TK_TYPE);
add_keyword("enum", TK_ENUM);
add_keyword("struct", TK_STRUCT);
diff --git a/compiler/main.c b/compiler/main.c
index 3666859..e614be6 100644
--- a/compiler/main.c
+++ b/compiler/main.c
@@ -11,6 +11,7 @@
#include <string.h>
#include "debug.h"
#include "hashmap.h"
+#include "parser/proc.h"
#include "parser/type.h"
#include "parser.h"
@@ -196,15 +197,11 @@ print_enum(struct type *typ)
for (size_t r = 0; r < typ->members.n_rows; r++) {
mem = (struct enum_member*)typ->members.rows[r].head;
- if (mem == (struct enum_member*)&typ->members.rows[r]) {
- continue;
- }
-
- do {
+ while (mem != (struct enum_member*)&typ->members.rows[r]) {
printf(" %.*s,\n", (int)mem->name_len, mem->name);
mem = (struct enum_member*)mem->hashmap_entry.list_entry.next;
- } while (mem != (struct enum_member*)&typ->members.rows[r]);
+ }
}
printf("}\n");
@@ -219,17 +216,13 @@ print_struct(struct type *typ)
for (size_t r = 0; r < typ->members.n_rows; r++) {
mem = (struct struct_member*)typ->members.rows[r].head;
- if (mem == (struct struct_member*)&typ->members.rows[r]) {
- continue;
- }
-
- do {
- printf(" %.*s", (int)mem->typ->name_len, mem->typ->name);
+ while (mem != (struct struct_member*)&typ->members.rows[r]) {
+ printf(" %.*s ", (int)mem->typ->name_len, mem->typ->name);
print_ptrs(mem->n_ptrs);
- printf(" %.*s;\n", (int)mem->name_len, mem->name);
+ printf("%.*s;\n", (int)mem->name_len, mem->name);
mem = (struct struct_member*)mem->hashmap_entry.list_entry.next;
- } while (mem != (struct struct_member*)&typ->members.rows[r]);
+ }
}
printf("}\n");
@@ -251,11 +244,84 @@ print_type(struct type *typ)
print_struct(typ);
break;
default:
- printf("(unknown);\n");
+ printf("unknown;\n");
break;
}
}
+static void
+print_proc(struct procedure *proc)
+{
+ struct list_entry *list_entry;
+ struct parameter *param;
+ int p;
+
+ printf("proc %.*s(", (int)proc->name_len, proc->name);
+
+ list_entry = proc->params.head;
+ p = 0;
+ while (list_entry != (struct list_entry*)&proc->params) {
+ param = (struct parameter*)((uint8_t*)list_entry - __builtin_offsetof(struct parameter, list_entry));
+
+ if (p) {
+ printf(", ");
+ }
+ printf("%.*s ", (int)param->var.typ->name_len, param->var.typ->name);
+ print_ptrs(param->var.n_ptrs);
+ printf("%.*s", (int)param->var.name_len, param->var.name);
+
+ list_entry = list_entry->next;
+ p++;
+ }
+
+ printf(")");
+
+ if (proc->ret_typ != NULL) {
+ printf(" -> %.*s", (int)proc->ret_typ->name_len, proc->ret_typ->name);
+ print_ptrs(proc->ret_n_ptrs);
+ }
+
+ printf(";\n");
+}
+
+static void
+dump_types(struct hashmap *map)
+{
+ struct type *typ, *next;
+
+ for (size_t r = 0; r < map->n_rows; r++) {
+ typ = (struct type*)map->rows[r].head;
+ while (typ != (struct type*)&map->rows[r]) {
+ print_type(typ);
+
+ next = (struct type*)typ->hashmap_entry.list_entry.next;
+ free(typ);
+ typ = next;
+ }
+ }
+
+ free(map->rows);
+}
+
+static void
+dump_procs(struct hashmap *map)
+{
+ struct procedure *proc, *next;
+
+ for (size_t r = 0; r < map->n_rows; r++) {
+ proc = (struct procedure*)map->rows[r].head;
+ while (proc != (struct procedure*)&map->rows[r]) {
+ print_proc(proc);
+
+ next = (struct procedure*)proc->hashmap_entry.list_entry.next;
+ free(proc);
+ proc = next;
+ }
+ }
+
+ free(map->rows);
+}
+
int
main(int argc, char **argv)
{
@@ -263,7 +329,6 @@ main(int argc, char **argv)
struct parser parser;
struct list *types_rows, *procs_rows;
struct hashmap types, procs;
- struct type *typ;
argv0 = argv[0];
if (argc < 2) {
@@ -297,21 +362,9 @@ main(int argc, char **argv)
parser_init(&parser, input);
parser_parse(&parser);
- /* Print parsed types */
- for (size_t r = 0; r < types.n_rows; r++) {
- typ = (struct type*)types.rows[r].head;
- if (typ == (struct type*)&types.rows[r]) {
- continue;
- }
-
- do {
- print_type(typ);
- typ = (struct type*)typ->hashmap_entry.list_entry.next;
- } while (typ != (struct type*)&types.rows[r]);
- }
+ dump_types(parser.types);
+ dump_procs(parser.procs);
- free(procs_rows);
- free(types_rows);
free(input);
return 0;
}
diff --git a/compiler/parser/parser.c b/compiler/parser/parser.c
index a630e37..7ee3270 100644
--- a/compiler/parser/parser.c
+++ b/compiler/parser/parser.c
@@ -12,6 +12,7 @@
#include "debug.h"
#include "hashmap.h"
#include "parser/type.h"
+#include "parser/proc.h"
#include "parser.h"
static void
@@ -62,6 +63,9 @@ parser_parse(struct parser *ctx)
next_token(ctx);
while (ctx->tok.kind != TK_EOF) {
switch (ctx->tok.kind) {
+ case TK_PROC:
+ parse_proc(ctx);
+ break;
case TK_TYPE:
parse_type(ctx);
break;
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);
+}