ESH

Executive Shell
git clone http://git.omkov.net/ESH
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2023-12-27 03:22:43
Commit4681f43be8f6000ca434160684a57036247c5750
Parent83443356e0b7800961022bbba57700e3cb6411d1

Add basic parser

Diffstat

M src/eval.c | 7 +++++++
M src/lex.c | 2 +-
A src/parse.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A src/parse.h | 29 +++++++++++++++++++++++++++++

4 files changed, 110 insertions, 1 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