aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/rc/parse.c
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-19 14:44:54 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-19 14:44:54 -0700
commit91c673b37782d4cd90e5cf9a8e4491723e6c04bf (patch)
tree0c334edf4729283b08cd95ae577f890b089f26fc /sys/cmd/rc/parse.c
parent765ff8b3423599396d0aa33885e2495ad86dbb19 (diff)
fix: many small bug fixes with parser and lexer
Diffstat (limited to 'sys/cmd/rc/parse.c')
-rw-r--r--sys/cmd/rc/parse.c226
1 files changed, 145 insertions, 81 deletions
diff --git a/sys/cmd/rc/parse.c b/sys/cmd/rc/parse.c
index d963c12..c5c77d3 100644
--- a/sys/cmd/rc/parse.c
+++ b/sys/cmd/rc/parse.c
@@ -3,17 +3,18 @@
// -----------------------------------------------------------------------
// global data
-static int lasta, nexta=EOF;
+static int lastt, nextt=EOF;
static Tree *node; /* if token was lexed as a tree node (redirs and words), its here */
+/* anything that is not listed will automatically terminate parsing the given command */
static uchar prectab[256] = {
- [Kif] = 1, [Kfor] = 1, [Kswitch] = 1, [Kelse] = 1,
- [Aandand] = 2, [Aoror] = 2,
- [Kbang] = 3, [Ksubsh] = 3,
- [Apipe] = 4,
- [Acarot] = 5,
- [Adol] = 6, [Acount] = 6, [Aquote] = 6,
- [Asub] = 7,
+ [Tif] = 1, [Tfor] = 1, [Tswitch] = 1, /* NOTE: we give else lower precedence than if [Telse] = 1, */
+ [Tandand] = 2, [Toror] = 2,
+ [Tbang] = 3, [Tsubshell] = 3,
+ [Tpipe] = 4,
+ [Tcarot] = 5,
+ [Tdol] = 6, [Tcount] = 6, [Tquote] = 6,
+ [Tsub] = 7,
};
// -----------------------------------------------------------------------
@@ -25,11 +26,11 @@ lookahead(void)
{
int tok;
- if (nexta != EOF)
- return nexta;
+ if (nextt != EOF)
+ return nextt;
tok = lex(&node);
- return nexta = tok;
+ return nextt = tok;
}
static
@@ -37,7 +38,7 @@ int
advance(void)
{
int tok = lookahead();
- lasta = nexta, nexta = EOF;
+ lastt = nextt, nextt = EOF;
node = nil;
return tok;
@@ -57,17 +58,48 @@ nextis(int tok)
// -----------------------------------------------------------------------
// subparsers
+/* forward declarations */
static Tree *word(void);
+static Tree *words(void);
+static Tree* body(int c);
static Tree *comword(void);
static Tree *cmd(int prec);
+/* implementations */
+
+/*
+ * TODO:
+ * i don't like all this branching.
+ * think of a better way
+ */
+
+static
+Tree*
+case_or_cmd(int c)
+{
+ Tree *t;
+ if (!c || !nextis(Tcase))
+ return cmd(1);
+
+ t = words();
+ if (!nextis(';') && !nextis('\n'))
+ rcerror("case: missing terminator: recieved %d", nextt);
+
+ t = tree2(Tcase, t, body(0));
+ pfmt(errio, "%t\n", t);
+
+ return t;
+}
+
static
Tree*
-body(void)
+body(int c)
{
int tok;
Tree *l, *r;
- l = cmd(1);
+
+ skipnl();
+ l = case_or_cmd(c);
loop:
switch((tok=lookahead())){
case '&':
@@ -75,9 +107,13 @@ loop:
/* fallthrough */
case ';': case '\n':
advance();
- r = cmd(1);
- l = tree2(';', l, r);
- goto loop;
+ /* fallthrough */
+ case Tcase:
+ if ((r = case_or_cmd(c))) {
+ l = tree2(';', l, r);
+ goto loop;
+ }
+ /* fallthrough */
default:
;
}
@@ -87,15 +123,15 @@ loop:
static
Tree*
-brace(void)
+brace(int c)
{
Tree *t;
if (!nextis('{'))
- rcerror("not a brace");
- t = tree1(Abrace, body());
+ rcerror("brace: expected { found: %c", nextt);
+ t = tree1(Tbrace, body(c));
if (!nextis('}'))
- rcerror("unmatched brace");
+ rcerror("brace: expected } found: %c", nextt);
return t;
}
@@ -108,7 +144,7 @@ paren(void)
if (!nextis('('))
rcerror("not a paren");
- t = tree1(Aparen, body());
+ t = tree1(Tparen, body(0));
if (!nextis(')'))
rcerror("unmatched paren");
@@ -131,13 +167,14 @@ redir(void)
Tree *t;
switch (tok = lookahead()) {
- case Adup:
+ case Tdup:
t = node;
advance();
break;
- case Aredir:
+ case Tredir:
+ t = node;
advance();
- t = hang1(node, (node->redir.type == Rhere) ? heredoc(word()) : word());
+ t = hang1(t, (t->redir.type == Rhere) ? heredoc(word()) : word());
break;
default:
t = nil;
@@ -192,11 +229,17 @@ words(void)
Tree *t, *tt;
t = word();
while((tt=word()))
- t = tree2(Awords, t, tt);
+ t = tree2(Twords, t, tt);
return t;
}
+/*
+ * NOTE: we divergence from Duff's yacc grammar here.
+ * he has [dol|count|"]->word, we have [dol|count]->sword
+ * calling sword ensures we don't cat strings
+ * this was done in Tom's version by setting precedence
+ */
static
Tree*
comword(void)
@@ -205,29 +248,31 @@ comword(void)
Tree *t, *tt;
switch(tok=lookahead()){
- case Adol:
+ case Tdol:
advance();
- t = word();
+ t = sword();
if(nextis('(')) {
- t = tree2(Asub, t, words());
+ t = tree2(Tsub, t, words());
if (!nextis(')'))
rcerror("malformed index expression");
}
- return tree1(Adol, t);
- case Acount:
+ return tree1(Tdol, t);
+ case Tquote:
+ return tree1(Tquote, sword());
+ case Tcount:
advance();
- return tree1(Acount, word());
- case Atick:
+ return tree1(Tcount, sword());
+ case Ttick:
advance();
- return tree1(Atick, brace());
- case Alparen:
+ return tree1(Ttick, brace(0));
+ case Tlparen:
return paren();
- case Aredir:
+ case Tredir:
advance();
- t = hang1(node, brace());
- t->type = Apipefd;
+ t = hang1(node, brace(0));
+ t->type = Tpipefd;
return t;
- case Aword:
+ case Tword:
t = node;
advance();
return t;
@@ -264,19 +309,21 @@ simple_or_assign(void)
/* is an assignment */
assign:
- if(nextis('='))
- return tree3(Aeq, t, word(), cmd(prectab[Kbang]));
+ if(nextis('=')) {
+ tt = word();
+ return tree3(Teq, t, tt, cmd(prectab[Tbang]));
+ }
/* is a 'simple' */
simple:
switch ((tok=lookahead())) {
- case Aredir:
- case Adup:
- t = tree2(Aargs, t, redir());
+ case Tredir:
+ case Tdup:
+ t = tree2(Targs, t, redir());
goto simple;
default:
if ((tt = word())) {
- t = tree2(Aargs, t, tt);
+ t = tree2(Targs, t, tt);
goto simple;
}
/* fallthrough */
@@ -293,79 +340,91 @@ opand(void)
Tree *t, *tt;
switch(tok=lookahead()) {
- case Kif:
+ case Tif:
advance();
t = paren();
skipnl();
- tt = cmd(prectab[Kif]);
- t = tree2(Kif, t, tt);
+ tt = cmd(prectab[Tif]);
+ if (nextis(Telse)) {
+ skipnl();
+ t = tree3(Tif, t, tt, cmd(prectab[Tif]));
+ } else
+ t = tree3(Tif, t, tt, nil);
return t;
+ case Telse:
+ rcerror("invalid hanging else");
+ break;
- case Kelse:
+ case Tswitch:
advance();
+ t = word();
skipnl();
- t = tree1(Kelse, cmd(prectab[Kelse]));
+ tt = brace(1);
+ t = tree2(Tswitch, t, tt);
return t;
- case Kfor:
+ case Tfor:
advance();
+
if (!nextis('('))
- rcerror("malformed for statement");
+ rcerror("for: missing opening paren");
t = word();
- if (nextis(Kin)) {
+ if (nextis(Tin)) {
advance();
tt = words();
- t = tree3(Kin, t, tt, nil);
+ t = tree3(Tfor, t, tt, nil);
} else
- t = tree3(Kin, t, nil, nil);
+ t = tree3(Tfor, t, nil, nil);
+ if (!nextis(')'))
+ rcerror("for: missing closing paren");
+
skipnl();
- tt = cmd(prectab[Kfor]);
+ tt = cmd(prectab[Tfor]);
t->child[2] = tt;
return t;
- case Kswitch:
+ case Twhile:
advance();
- t = word();
+ t = paren();
skipnl();
- tt = brace();
- t = tree2(Kswitch, t, tt);
- return t;
+ tt = cmd(1);
+ return tree2(Twhile, t, tt);
- case Kfunc:
+ case Tfunc:
advance();
t = words();
if ((tok=lookahead()) == '{') {
- tt = brace();
- t = tree2(Kfunc, t, tt);
+ tt = brace(0);
+ t = tree2(Tfunc, t, tt);
} else
- t = tree1(Kfunc, t);
+ t = tree1(Tfunc, t);
return t;
- case Ksubsh:
+ case Tsubshell:
advance();
- t = tree1(Ksubsh, cmd(prectab[Ksubsh]));
+ t = tree1(Tsubshell, cmd(prectab[Tsubshell]));
return t;
- case Kbang:
+ case Tbang:
advance();
- t = tree1(Kbang, cmd(prectab[Kbang]));
+ t = tree1(Tbang, cmd(prectab[Tbang]));
return t;
- case Ktwiddle:
+ case Ttwiddle:
advance();
tt = word();
- t = tree2(Ktwiddle, tt, words());
+ t = tree2(Ttwiddle, tt, words());
return t;
- case Albrace:
- t = brace();
+ case Tlbrace:
+ t = brace(0);
tt = epilog();
return epihang(t, tt);
- case Aredir: /* fallthrough */
- case Adup:
+ case Tredir: /* fallthrough */
+ case Tdup:
t = redir();
- tt = cmd(prectab[Kbang]);
+ tt = cmd(prectab[Tbang]);
t = hang2(t, t->child[0], tt);
return t;
}
@@ -391,7 +450,7 @@ cmd(int prec)
p = node;
advance();
r = cmd(np+1);
- if (tok == Apipe)
+ if (tok == Tpipe)
l = hang2(p, l, r);
else
l = tree2(tok, l, r);
@@ -420,11 +479,16 @@ loop:
tt = cmd(1);
t = tree2(';', t, tt);
goto loop;
- case '\n': case EOF:
- pfmt(errio, "%t", t);
+ case '\n':
+ advance();
+ case EOF:
+ pfmt(errio, "%t\n", t);
break;
default:
- rcerror("unrecognized token: %d", tok);
+ if (tok > 0x20)
+ rcerror("unrecognized token: %c[%d]", tok, tok);
+ else
+ rcerror("unrecognized token: %d", tok, tok);
}
- return 0;
+ return tok != EOF;
}