From 91c673b37782d4cd90e5cf9a8e4491723e6c04bf Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Fri, 19 Jun 2020 14:44:54 -0700 Subject: fix: many small bug fixes with parser and lexer --- sys/cmd/rc/parse.c | 226 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 145 insertions(+), 81 deletions(-) (limited to 'sys/cmd/rc/parse.c') 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; } -- cgit v1.2.1