From 81ff797c1e443ac935dbb0706a5770631a727ea7 Mon Sep 17 00:00:00 2001 From: Alexander Goussas Date: Wed, 30 Oct 2024 22:33:11 -0500 Subject: [PATCH] feat: parse load expressions --- CMakeLists.txt | 2 +- ast.c | 73 +++++++++++++++++++++++++++++++++++ ast.h | 46 ++++++++++++++++++++++ main.c | 16 ++++---- parser.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ parser.h | 24 ++++++++++++ 6 files changed, 255 insertions(+), 9 deletions(-) create mode 100644 ast.c create mode 100644 ast.h create mode 100644 parser.c create mode 100644 parser.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 48a3c9b..aa67808 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,5 +4,5 @@ project(sotest) set(CMAKE_C_STANDARD 11) -add_executable(sotest main.c lexer.c) +add_executable(sotest main.c lexer.c ast.c parser.c) target_compile_options(sotest PRIVATE -Wall -Wextra) diff --git a/ast.c b/ast.c new file mode 100644 index 0000000..2f564d9 --- /dev/null +++ b/ast.c @@ -0,0 +1,73 @@ +#include "ast.h" +#include +#include +#include + +so_expr *create_string_node(const char *s) +{ + so_expr *e = malloc(sizeof(so_expr)); + e->tag = SO_EXPR_STRING; + e->as.string = strdup(s); + return e; +} + +so_expr *create_number_node(int n) +{ + so_expr *e = malloc(sizeof(so_expr)); + e->tag = SO_EXPR_INT; + e->as.number = n; + return e; +} + +so_expr *create_call_node(const char *name, int nargs, so_expr *args[]) +{ + so_expr *e = malloc(sizeof(so_expr)); + e->tag = SO_EXPR_CALL; + e->as.call = (so_expr_call){.name = strdup(name), .nargs = nargs}; + for (int i = 0; i < nargs; i++) + e->as.call.args[i] = args[i]; + return e; +} + +so_expr *create_load_node(const char *name) +{ + so_expr *e = malloc(sizeof(so_expr)); + e->tag = SO_EXPR_LOAD; + e->as.load = (so_expr_load){.name = strdup(name)}; + return e; +} + +void print_ast(so_expr *e) +{ + switch (e->tag) + { + case SO_EXPR_INT: + printf("%d\n", e->as.number); + break; + case SO_EXPR_STRING: + printf("%s\n", e->as.string); + break; + case SO_EXPR_LOAD: + printf("USE %s\n", e->as.load.name); + break; + case SO_EXPR_CALL: + printf("CALL %s (%d)\n", e->as.call.name, e->as.call.nargs); + break; + } +} + +void free_ast(so_expr *e) +{ + switch (e->tag) + { + case SO_EXPR_INT: + break; + case SO_EXPR_STRING: + free(e->as.string); + break; + case SO_EXPR_LOAD: + free(e->as.load.name); + break; + } + free(e); +} diff --git a/ast.h b/ast.h new file mode 100644 index 0000000..2630e01 --- /dev/null +++ b/ast.h @@ -0,0 +1,46 @@ +#ifndef ast_h__ +#define ast_h__ + +#define MAX_CALL_ARGS 100 + +typedef struct so_expr so_expr; + +typedef struct +{ + char *name; + int nargs; + so_expr *args[MAX_CALL_ARGS]; +} so_expr_call; + +typedef struct +{ + char *name; +} so_expr_load; + +struct so_expr +{ + enum + { + SO_EXPR_CALL, + SO_EXPR_LOAD, + SO_EXPR_INT, + SO_EXPR_STRING, + } tag; + union + { + so_expr_call call; + so_expr_load load; + int number; + char *string; + } as; +}; + +so_expr *create_string_node(const char *s); +so_expr *create_number_node(int n); +so_expr *create_call_node(const char *name, int nargs, so_expr *args[]); +so_expr *create_load_node(const char *name); + +void print_ast(so_expr *); +void free_ast(so_expr *); + +#endif diff --git a/main.c b/main.c index 824ac19..c5d417f 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,6 @@ #include #include -#include "lexer.h" +#include "parser.h" int repl() { @@ -13,17 +13,17 @@ int repl() if (strcmp(buffer, ".quit\n") == 0) return 0; - so_lexer lexer; - so_lexer_init(&lexer, buffer); + so_parser parser; + so_parser_init(&parser, buffer); + so_parser_parse(&parser); - so_token token; - while ((token = so_lexer_next_token(&lexer)).type != SO_TT_EOF) + for (int i = 0; i < parser.ncommands; i++) { - printf("%s\n", token.lexeme); - so_token_deinit(&token); + print_ast(parser.commands[i]); + free_ast(parser.commands[i]); } - so_token_deinit(&token); + so_parser_deinit(&parser); memset(buffer, 0, sizeof(buffer)); printf("> "); diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..4f51343 --- /dev/null +++ b/parser.c @@ -0,0 +1,103 @@ +#include "ast.h" +#include "parser.h" +#include +#include +#include + +static void so_parse_call(so_parser *); +static void so_parse_load(so_parser *); + +static so_token so_parser_advance(so_parser *p) +{ + p->current = so_lexer_next_token(&p->lexer); + return p->current; +} + +static int so_parser_expect(so_parser *p, so_token_type tt) +{ + if (p->current.type != tt) + { + fprintf(stderr, "warning: expected a different type of token\n"); + return 0; + } + return 1; +} + +static void add_command(so_parser *p, so_expr *e) +{ + if (p->ncommands >= MAX_COMMANDS) + { + fprintf(stderr, "warning: maximum number of commands reached\n"); + return; + } + p->commands[p->ncommands++] = e; +} + +void so_parser_init(so_parser *p, const char *source) +{ + p->source = source; + p->ncommands = 0; + so_lexer_init(&p->lexer, source); +} + +void so_parser_deinit(so_parser *p) +{ + p->source = NULL; + p->ncommands = 0; + memset(p->commands, 0, MAX_COMMANDS * sizeof(so_expr *)); + so_lexer_deinit(&p->lexer); +} + +void so_parser_parse(so_parser *p) +{ + while (so_parser_advance(p).type != SO_TT_EOF) + { + switch (p->current.type) + { + case SO_TT_USE: + so_parse_load(p); + break; + case SO_TT_CALL: + so_parse_call(p); + break; + case SO_TT_EOF: + so_token_deinit(&p->current); + return; + default: + fprintf(stderr, "warning: invalid start of simple expression: %s\n", p->current.lexeme); + so_token_deinit(&p->current); + } + } + + so_token_deinit(&p->current); +} + +void so_parse_call(so_parser *p) +{ + so_token_deinit(&p->current); +} + +void so_parse_load(so_parser *p) +{ + if (!so_parser_expect(p, SO_TT_USE)) + { + so_token_deinit(&p->current); + return; + } + + so_token use = p->current; + so_parser_advance(p); + + if (!so_parser_expect(p, SO_TT_STRING)) + { + so_token_deinit(&use); + so_token_deinit(&p->current); + return; + } + + so_expr *e = create_load_node(p->current.lexeme); + add_command(p, e); + + so_token_deinit(&use); + so_token_deinit(&p->current); +} diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..5b8ac01 --- /dev/null +++ b/parser.h @@ -0,0 +1,24 @@ +#ifndef parser_h__ +#define parser_h__ + +#include "ast.h" +#include "lexer.h" + +#define MAX_COMMANDS 100 + +typedef struct +{ + const char *source; + so_lexer lexer; + so_token current; + int ncommands; + so_expr *commands[MAX_COMMANDS]; +} so_parser; + +void so_parser_init(so_parser *, const char *source); + +void so_parser_deinit(so_parser *); + +void so_parser_parse(so_parser *); + +#endif -- 2.43.0