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)
--- /dev/null
+#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);
+}
--- /dev/null
+#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
#include <stdio.h>
#include <string.h>
-#include "lexer.h"
+#include "parser.h"
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("> ");
--- /dev/null
+#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);
+}
--- /dev/null
+#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