0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
|
// 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[] = {
"AK_VOID", "AK_COMM", "AK_PIPE",
};
/* 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; }
ast_free(a->lc); ast_free(a->rc); stack_free(&a->c);
free(a->rin.s); free(a->rout.s); free(a->rerr.s); free(a);
}
#define T (l->t) /* Current Token */
static ast *parse_comm(lex *l);
static ast *parse_pipe(lex *l, ast *lhs);
/* 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;
}
ast *lhs = parse_comm(l);
for (;;) switch (lex_next(l).k) {
case TK_PIPE: { lhs = parse_pipe(l, lhs); } continue;
default: {} return lhs;
}
}
/* 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;
case TK_RIN: {
if (lex_next(l), T.k == TK_WORD) { a->rin.s = lex_next(l).s; }
else { log_warn("Unexpected token \"%s\"", tok_ks[T.k]); }
} continue;
case TK_ROUT: {
if (lex_next(l), T.k == TK_WORD) { a->rout.s = lex_next(l).s; a->rout.app = false; }
else { log_warn("Unexpected token \"%s\"", tok_ks[T.k]); }
} continue;
case TK_RAPP: {
if (lex_next(l), T.k == TK_WORD) { a->rout.s = lex_next(l).s; a->rout.app = true; }
else { log_warn("Unexpected token \"%s\"", tok_ks[T.k]); }
} continue;
default: { stack_push(&a->c, NULL); } return a;
}
}
/* Parse a pipe statement. */
static ast *parse_pipe(lex *l, ast *lhs) {
ast *a = ast_init(AK_PIPE);
a->lc = lhs; a->rc = parse_comm(l); 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]);
}
if (a->rin.s) { printf(" < %s", a->rin.s); }
if (a->rout.s) { printf(a->rout.app ? " >> %s" : " > %s", a->rout.s); }
}
printf("\n");
if (a->lc) { ast_debug(a->lc, indent + 1); }
if (a->rc) { ast_debug(a->rc, indent + 1); }
}
|