]> git.frustrated-labs.net Git - so-test.git/commitdiff
feat: parse load expressions
authorAlexander Goussas <[email protected]>
Thu, 31 Oct 2024 03:33:11 +0000 (22:33 -0500)
committerAlexander Goussas <[email protected]>
Thu, 31 Oct 2024 03:33:11 +0000 (22:33 -0500)
CMakeLists.txt
ast.c [new file with mode: 0644]
ast.h [new file with mode: 0644]
main.c
parser.c [new file with mode: 0644]
parser.h [new file with mode: 0644]

index 48a3c9b0ca59901870a0fd35ddc88ca025d26bf1..aa67808f78476477aaac03e56b46ba9e8c3553e3 100644 (file)
@@ -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 (file)
index 0000000..2f564d9
--- /dev/null
+++ b/ast.c
@@ -0,0 +1,73 @@
+#include "ast.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+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 (file)
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 824ac195e7bad35b4209dcc3a89fac7eab8f531f..c5d417f6b1f1693be3caff6b56bfb581e1bfac21 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,6 +1,6 @@
 #include <stdio.h>
 #include <string.h>
-#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 (file)
index 0000000..4f51343
--- /dev/null
+++ b/parser.c
@@ -0,0 +1,103 @@
+#include "ast.h"
+#include "parser.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+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 (file)
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