Author | Jakob Wakeling <[email protected]> |
Date | 2023-12-27 03:22:43 |
Commit | 4681f43be8f6000ca434160684a57036247c5750 |
Parent | 83443356e0b7800961022bbba57700e3cb6411d1 |
Add basic parser
Diffstat
M | src/eval.c | | | 8 | +++++++- |
M | src/lex.c | | | 2 | +- |
A | src/parse.c | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | src/parse.h | | | 29 | +++++++++++++++++++++++++++++ |
4 files changed, 110 insertions, 2 deletions
diff --git a/src/eval.c b/src/eval.c index b8762c7..0e6aeb1 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3,6 +3,7 @@ #include "eval.h" #include "lex.h" +#include "parse.h" bool Eflag, pflag; @@ -10,5 +11,10 @@ void eval(char *src, u64 len) { lex l = lex_init(src, len); if (Eflag) { lex_debug(&l); return; } - /* TODO parse and execute */ + for (ast *a; l.t.k != TK_EOF; ast_free(a)) { + a = parse(&l); if (!a) { return; } + if (pflag) { ast_debug(a, 0); continue; } + + /* TODO execute */ + } } diff --git a/src/lex.c b/src/lex.c index 7c49270..98a87b9 100644 --- a/src/lex.c +++ b/src/lex.c @@ -11,7 +11,7 @@ #include <string.h> char *tok_ks[] = { - "NULL", "EOF", "WORD", "END", + "VOID", "EOF", "WORD", "END", }; #define is_space(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..05dd994 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,73 @@ +// Copyright (C) 2023, Jakob Wakeling +// All rights reserved. + +#include "parse.h" +#include "util/log.h" +#include "util/stack.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +char *ast_ks[] = { + "VOID", "COMM", +}; + +/* Initialise an AST node. */ +extern ast *ast_init(ast_k kind) { + ast *a = xcalloc(1, sizeof(*a)); + a->k = kind; return a; +} + +/* Uninitialise an AST node and its children. */ +extern void ast_free(ast *a) { + if (a == NULL) { return; } + free(a); +} + +#define T (l->t) /* Current Token */ + +static ast *parse_comm(lex *l); + +/* Parse a program. */ +extern ast *parse(lex *l) { + for (; T.k == TK_END; lex_next(l)); + if (T.k == TK_EOF) { return NULL; } + + if (T.k != TK_WORD) { + log_warn("Unexpected \"%s\", was expecting a word", tok_ks[T.k]); return NULL; + } + + return parse_comm(l); +} + +/* Parse a command statement. */ +static ast *parse_comm(lex *l) { + assert(T.k == TK_WORD); + + ast *a = ast_init(AK_COMM); + a->c = stack_init(sizeof (char *), &free); + + /* Push each command argument onto the child stack */ + stack_push(&a->c, (a->s = lex_next(l).s)); + + for (;;) switch (lex_peek(l).k) { + case TK_WORD: { stack_push(&a->c, lex_next(l).s); } continue; + default: { stack_push(&a->c, NULL); } return a; + } +} + +/* Print parser debug output. */ +extern void ast_debug(ast *a, u64 indent) { + for (u64 i = 0; i != indent; i += 1) { printf("\t"); } + + printf("%s: %s", ast_ks[a->k], a->s); + + if (a->k == AK_COMM) { + for (u64 i = 1; i != a->c.al - 1; i += 1) { + printf(" %s", ((char **)a->c.a)[i]); + } + } + + printf("\n"); +} diff --git a/src/parse.h b/src/parse.h new file mode 100644 index 0000000..36a744e --- /dev/null +++ b/src/parse.h @@ -0,0 +1,29 @@ +// Copyright (C) 2023, Jakob Wakeling +// All rights reserved. + +#ifndef ESH_PARSE_H_EQMN0ZSE +#define ESH_PARSE_H_EQMN0ZSE + +#include "lex.h" +#include "util/stack.h" + +/* Remember to update ast_ks in parse.c */ +typedef enum { + AK_VOID, AK_COMM, +} ast_k; + +/* k : Kind, s : String, c : Children */ +typedef struct ast_s { + ast_k k; char *s; stack c; +} ast; + +extern char *ast_ks[]; + +extern ast *ast_init(ast_k kind); +extern void ast_free(ast *a); + +extern ast *parse(lex *l); + +extern void ast_debug(ast *a, u64 indent); + +#endif // ESH_PARSE_H_EQMN0ZSE