From 6ab9c3732793b6fd40e6388cf1b08756194c0ea6 Mon Sep 17 00:00:00 2001 From: Quinn Stephens Date: Thu, 7 Nov 2024 16:59:19 -0500 Subject: [compiler] Parse return statements Laid groundwork for statements and AST trees. Currently return values are not supported, expression parsing must be implemented first. Also stopped dumping parsed type definitions. Signed-off-by: Quinn Stephens --- Makefile | 2 +- compiler/lexer/keywords.c | 1 + compiler/main.c | 97 +++++++++++------------------------------------ compiler/parser/proc.c | 22 ++++++----- compiler/parser/stmt.c | 62 ++++++++++++++++++++++++++++++ include/lexer/token.h | 1 + include/list.h | 7 ++++ include/parser/ast.h | 38 ++++++++++++++++++- include/parser/proc.h | 3 ++ include/parser/stmt.h | 16 ++++++++ test.q | 5 ++- 11 files changed, 168 insertions(+), 86 deletions(-) create mode 100644 compiler/parser/stmt.c create mode 100644 include/parser/stmt.h diff --git a/Makefile b/Makefile index 5dfb0a2..9363239 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ CC = clang LD = ld.ldd EXENAME = quarkc -OFILES = $(addprefix compiler/,debug.o hash.o hashmap.o lexer/char_info.o lexer/keywords.o lexer/lexer.o parser/type.o parser/proc.o parser/parser.o main.o) +OFILES = $(addprefix compiler/,debug.o hash.o hashmap.o lexer/char_info.o lexer/keywords.o lexer/lexer.o parser/type.o parser/stmt.o parser/proc.o parser/parser.o main.o) CFLAGS = -Wall -Wextra -Iinclude LDFLAGS = diff --git a/compiler/lexer/keywords.c b/compiler/lexer/keywords.c index 88c2e67..dbae881 100644 --- a/compiler/lexer/keywords.c +++ b/compiler/lexer/keywords.c @@ -69,6 +69,7 @@ keywords_init(void) add_keyword("type", TK_TYPE); add_keyword("enum", TK_ENUM); add_keyword("struct", TK_STRUCT); + add_keyword("ret", TK_RET); initialized = true; } diff --git a/compiler/main.c b/compiler/main.c index e614be6..aa3bcdc 100644 --- a/compiler/main.c +++ b/compiler/main.c @@ -183,69 +183,31 @@ print_ptrs(int n_ptrs) } static void -print_alias(struct type *typ) +print_ret(struct ast_node *node) { - printf("alias (%lu bytes, %d pointer(s));\n", typ->size, typ->n_ptrs); -} - -static void -print_enum(struct type *typ) -{ - struct enum_member *mem; + (void)node; - printf("enum {\n"); - - for (size_t r = 0; r < typ->members.n_rows; r++) { - mem = (struct enum_member*)typ->members.rows[r].head; - 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; - } - } - - printf("}\n"); + /* TODO: Print return value */ + printf(" ret;\n"); } static void -print_struct(struct type *typ) +print_stmt_block(struct ast_node *parent) { - struct struct_member *mem; - - printf("struct (%lu bytes) {\n", typ->size); - - for (size_t r = 0; r < typ->members.n_rows; r++) { - mem = (struct struct_member*)typ->members.rows[r].head; - 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); - - mem = (struct struct_member*)mem->hashmap_entry.list_entry.next; + struct ast_node *node; + + node = (struct ast_node*)parent->children.head; + while (node != (struct ast_node*)&parent->children) { + switch (node->kind) { + case NK_RETURN: + print_ret(node); + break; + default: + printf(" /* Unknown */\n"); + break; } - } - - printf("}\n"); -} -static void -print_type(struct type *typ) -{ - printf("type %.*s: ", (int)typ->name_len, typ->name); - - switch (typ->kind) { - case TYK_ALIAS: - print_alias(typ); - break; - case TYK_ENUM: - print_enum(typ); - break; - case TYK_STRUCT: - print_struct(typ); - break; - default: - printf("unknown;\n"); - break; + node = (struct ast_node*)node->list_entry.next; } } @@ -281,26 +243,14 @@ print_proc(struct procedure *proc) 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; - } + if (list_is_empty(&proc->node->children)) { + printf(";\n"); + return; } - free(map->rows); + printf(" {\n"); + print_stmt_block(proc->node); + printf("}\n"); } static void @@ -362,7 +312,6 @@ main(int argc, char **argv) parser_init(&parser, input); parser_parse(&parser); - dump_types(parser.types); dump_procs(parser.procs); free(input); diff --git a/compiler/parser/proc.c b/compiler/parser/proc.c index bbbdad1..b32f5e9 100644 --- a/compiler/parser/proc.c +++ b/compiler/parser/proc.c @@ -7,6 +7,7 @@ #include #include "debug.h" #include "parser/proc.h" +#include "parser/stmt.h" #include "parser/type.h" #include "parser.h" @@ -119,26 +120,29 @@ parse_proc(struct parser *ctx) } } - /* 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) { + proc->node = NULL; + + /* Add procedure to parser's registry */ + hashmap_add(ctx->procs, &proc->hashmap_entry); + next_token(ctx); return; } if (ctx->tok.kind != TK_LBRACE) { + proc->node = NULL; tok_error(&ctx->tok, "Expected \";\" or \"{\"\n"); return; } - /* TODO: Parse body/code */ + /* Allocate AST root node for body */ + proc->node = ast_new_node(NK_PROCEDURE); - if (next_token(ctx)->kind != TK_RBRACE) { - tok_error(&ctx->tok, "Expected \"}\" after procedure body\n"); - return; - } + /* Parse procedure body (code) */ + parse_stmt_block(ctx, proc->node, proc); - next_token(ctx); + /* Add procedure to parser's registry */ + hashmap_add(ctx->procs, &proc->hashmap_entry); } diff --git a/compiler/parser/stmt.c b/compiler/parser/stmt.c new file mode 100644 index 0000000..6fe3d6d --- /dev/null +++ b/compiler/parser/stmt.c @@ -0,0 +1,62 @@ +/* + * Statement parser. + * Copyright (c) 2023-2024, Quinn Stephens and the OSMORA team. + * Provided under the BSD 3-Clause license. + */ + +#include +#include "debug.h" +#include "parser/ast.h" +#include "parser/stmt.h" +#include "parser/proc.h" +#include "parser.h" + +static bool +parse_ret(struct parser *ctx, struct ast_node *parent, struct procedure *proc) +{ + struct ast_node *node; + + (void)proc; + + debug("Parsing return statement...\n"); + + /* TODO: Parse return value */ + next_token(ctx); + + if (ctx->tok.kind != TK_SEMICOLON) { + tok_error(&ctx->tok, "Expected \";\"\n"); + return false; + } + next_token(ctx); + + node = ast_new_node(NK_RETURN); + ast_append_child(parent, node); + + return true; +} + +void +parse_stmt_block(struct parser *ctx, struct ast_node *parent, struct procedure *proc) +{ + bool success; + + debug("Parsing statement block...\n"); + + next_token(ctx); + while (ctx->tok.kind != TK_RBRACE) { + switch (ctx->tok.kind) { + case TK_RET: + success = parse_ret(ctx, parent, proc); + break; + default: + tok_error(&ctx->tok, "Expected statement\n"); + success = false; + break; + } + + if (!success) { + return; + } + } + next_token(ctx); +} diff --git a/include/lexer/token.h b/include/lexer/token.h index 2ba5408..cc04c95 100644 --- a/include/lexer/token.h +++ b/include/lexer/token.h @@ -25,6 +25,7 @@ typedef enum { TK_TYPE, TK_ENUM, TK_STRUCT, + TK_RET, /* * Operators. diff --git a/include/list.h b/include/list.h index 0364f7c..69d0c33 100644 --- a/include/list.h +++ b/include/list.h @@ -7,6 +7,7 @@ #ifndef _LIST_H #define _LIST_H +#include #include struct list_entry { @@ -20,6 +21,12 @@ struct list { size_t length; }; +static inline bool +list_is_empty(struct list *list) +{ + return list->head == (struct list_entry*)list; +} + static inline void list_remove(struct list_entry *entry) { diff --git a/include/parser/ast.h b/include/parser/ast.h index 03be1bd..9463511 100644 --- a/include/parser/ast.h +++ b/include/parser/ast.h @@ -7,14 +7,50 @@ #ifndef _PARSER_AST_H #define _PARSER_AST_H +#include +#include "list.h" + enum ast_node_kind { NK_UNKNOWN, - NK_ + NK_PROCEDURE, + NK_RETURN }; struct ast_node { + struct list_entry list_entry; + enum ast_node_kind kind; + + struct ast_node *parent; + struct list children; }; +static inline void +ast_append_child(struct ast_node *parent, struct ast_node *child) +{ + child->parent = parent; + list_append(&parent->children, &child->list_entry); +} + +static inline void +ast_remove_child(struct ast_node *child) +{ + list_remove(&child->list_entry); + child->parent->children.length--; +} + +static inline struct ast_node * +ast_new_node(enum ast_node_kind kind) +{ + struct ast_node *node; + + node = malloc(sizeof(struct ast_node)); + node->kind = kind; + node->parent = NULL; + list_init(&node->children); + + return node; +} + #endif /* !_PARSER_AST_H */ diff --git a/include/parser/proc.h b/include/parser/proc.h index 0cc8471..f74fee6 100644 --- a/include/parser/proc.h +++ b/include/parser/proc.h @@ -9,6 +9,7 @@ #include "list.h" #include "hashmap.h" +#include "parser/ast.h" #include "parser/var.h" struct parameter { @@ -27,6 +28,8 @@ struct procedure { struct type *ret_typ; int ret_n_ptrs; + + struct ast_node *node; }; void parse_proc(struct parser *ctx); diff --git a/include/parser/stmt.h b/include/parser/stmt.h new file mode 100644 index 0000000..caf022c --- /dev/null +++ b/include/parser/stmt.h @@ -0,0 +1,16 @@ +/* + * Statement parser. + * Copyright (c) 2023-2024, Quinn Stephens and the OSMORA team. + * Provided under the BSD 3-Clause license. + */ + +#ifndef _PARSER_STMT_H +#define _PARSER_STMT_H + +#include "parser/ast.h" +#include "parser/proc.h" +#include "parser.h" + +void parse_stmt_block(struct parser *ctx, struct ast_node *parent, struct procedure *proc); + +#endif /* !_PARSER_STMT_H */ diff --git a/test.q b/test.q index 0769752..4b9a944 100644 --- a/test.q +++ b/test.q @@ -48,4 +48,7 @@ type EfiSystemTable: struct { EfiConfigurationTable *configurationTable; } -proc efiEntry(EfiHandle imageHandle, EfiSystemTable *systemTable) -> EfiStatus; +proc efiEntry(EfiHandle imgHandle, EfiSystemTable *sysTable) -> EfiStatus +{ + ret; +} -- cgit v1.2.3