Changeset View
Changeset View
Standalone View
Standalone View
bin/sh/parser.c
| Show First 20 Lines • Show All 474 Lines • ▼ Show 20 Lines | case TUNTIL: | ||||
| checkkwd = CHKKWD | CHKALIAS; | checkkwd = CHKKWD | CHKALIAS; | ||||
| break; | break; | ||||
| case TFOR: | case TFOR: | ||||
| if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) | if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) | ||||
| synerror("Bad for loop variable"); | synerror("Bad for loop variable"); | ||||
| n1 = (union node *)stalloc(sizeof (struct nfor)); | n1 = (union node *)stalloc(sizeof (struct nfor)); | ||||
| n1->type = NFOR; | n1->type = NFOR; | ||||
| n1->nfor.var = wordtext; | n1->nfor.var = wordtext; | ||||
| while (readtoken() == TNL) | checkkwd = CHKNL; | ||||
| ; | if (readtoken() == TWORD && !quoteflag && | ||||
| if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) { | equal(wordtext, "in")) { | ||||
bdrewery: dash also has `CHKKWD | CHKALIAS` here but I don't see how a keyword or alias is valid here. | |||||
Done Inline ActionsLike most shells, dash recognizes in as a keyword, resulting in a syntax error if it occurs unquoted as the first word of a command. zsh and FreeBSD sh only recognize in in the appropriate location in a case or for command, allowing it unquoted as a utility or function name. Recognizing aliases here is an extension shared by a few other shells. In older shells, this happened because keyword and alias recognition were tied together. For example, sh -c 'alias DO=do; eval "$1"' arg0 'for i in a b c; DO echo ".$i"; done' works with a variety of shells, and sh -c 'alias IN=in; eval "$1"' arg0 'for i IN a b c; do echo ".$i"; done' works a bit less commonly. Per POSIX, this is allowed because the syntax is otherwise invalid. Expanding an alias in in a for command would not be allowed, however. jilles: Like most shells, dash recognizes `in` as a keyword, resulting in a syntax error if it occurs… | |||||
| app = ≈ | app = ≈ | ||||
| while (readtoken() == TWORD) { | while (readtoken() == TWORD) { | ||||
| n2 = makename(); | n2 = makename(); | ||||
| *app = n2; | *app = n2; | ||||
| app = &n2->narg.next; | app = &n2->narg.next; | ||||
| } | } | ||||
| *app = NULL; | *app = NULL; | ||||
| n1->nfor.args = ap; | n1->nfor.args = ap; | ||||
| if (lasttoken != TNL && lasttoken != TSEMI) | if (lasttoken == TNL) | ||||
| tokpushback++; | |||||
| else if (lasttoken != TSEMI) | |||||
| synexpect(-1); | synexpect(-1); | ||||
| } else { | } else { | ||||
| static char argvars[5] = { | static char argvars[5] = { | ||||
| CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' | CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' | ||||
| }; | }; | ||||
| n2 = (union node *)stalloc(sizeof (struct narg)); | n2 = (union node *)stalloc(sizeof (struct narg)); | ||||
| n2->type = NARG; | n2->type = NARG; | ||||
| n2->narg.text = argvars; | n2->narg.text = argvars; | ||||
| n2->narg.backquote = NULL; | n2->narg.backquote = NULL; | ||||
| n2->narg.next = NULL; | n2->narg.next = NULL; | ||||
| n1->nfor.args = n2; | n1->nfor.args = n2; | ||||
| /* | /* | ||||
| * Newline or semicolon here is optional (but note | * Newline or semicolon here is optional (but note | ||||
| * that the original Bourne shell only allowed NL). | * that the original Bourne shell only allowed NL). | ||||
| */ | */ | ||||
| if (lasttoken != TNL && lasttoken != TSEMI) | if (lasttoken != TSEMI) | ||||
| tokpushback++; | tokpushback++; | ||||
| } | } | ||||
| checkkwd = CHKNL | CHKKWD | CHKALIAS; | checkkwd = CHKNL | CHKKWD | CHKALIAS; | ||||
| if ((t = readtoken()) == TDO) | if ((t = readtoken()) == TDO) | ||||
| t = TDONE; | t = TDONE; | ||||
| else if (t == TBEGIN) | else if (t == TBEGIN) | ||||
| t = TEND; | t = TEND; | ||||
| else | else | ||||
| synexpect(-1); | synexpect(-1); | ||||
| n1->nfor.body = list(0); | n1->nfor.body = list(0); | ||||
| consumetoken(t); | consumetoken(t); | ||||
| checkkwd = CHKKWD | CHKALIAS; | checkkwd = CHKKWD | CHKALIAS; | ||||
| break; | break; | ||||
| case TCASE: | case TCASE: | ||||
| n1 = (union node *)stalloc(sizeof (struct ncase)); | n1 = (union node *)stalloc(sizeof (struct ncase)); | ||||
| n1->type = NCASE; | n1->type = NCASE; | ||||
| consumetoken(TWORD); | consumetoken(TWORD); | ||||
| n1->ncase.expr = makename(); | n1->ncase.expr = makename(); | ||||
| while (readtoken() == TNL); | checkkwd = CHKNL; | ||||
| if (lasttoken != TWORD || ! equal(wordtext, "in")) | if (readtoken() != TWORD || ! equal(wordtext, "in")) | ||||
Not Done Inline ActionsAnd dash checks for CHKKWD here too but seems wrong. bdrewery: And dash checks for `CHKKWD` here too but seems wrong. | |||||
| synerror("expecting \"in\""); | synerror("expecting \"in\""); | ||||
| cpp = &n1->ncase.cases; | cpp = &n1->ncase.cases; | ||||
| checkkwd = CHKNL | CHKKWD, readtoken(); | checkkwd = CHKNL | CHKKWD, readtoken(); | ||||
| while (lasttoken != TESAC) { | while (lasttoken != TESAC) { | ||||
| *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); | *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); | ||||
| cp->type = NCLIST; | cp->type = NCLIST; | ||||
| app = &cp->nclist.pattern; | app = &cp->nclist.pattern; | ||||
| if (lasttoken == TLP) | if (lasttoken == TLP) | ||||
| ▲ Show 20 Lines • Show All 1,663 Lines • Show Last 20 Lines | |||||
dash also has CHKKWD | CHKALIAS here but I don't see how a keyword or alias is valid here.