xref: /netbsd-src/bin/csh/parse.c (revision 7f63690a47eaa06b516ad488da1060889c503b5a)
1*7f63690aSdholland /* $NetBSD: parse.c,v 1.21 2020/08/09 00:34:21 dholland Exp $ */
249f0ad86Scgd 
361f28255Scgd /*-
4cee2bad8Smycroft  * Copyright (c) 1980, 1991, 1993
5cee2bad8Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
328ea378c6Schristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3449f0ad86Scgd #if 0
3549f0ad86Scgd static char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 5/31/93";
3649f0ad86Scgd #else
37*7f63690aSdholland __RCSID("$NetBSD: parse.c,v 1.21 2020/08/09 00:34:21 dholland Exp $");
3849f0ad86Scgd #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
4161f28255Scgd #include <sys/types.h>
42b771e65bSwiz 
4318158540Swiz #include <stdarg.h>
4461f28255Scgd #include <stdlib.h>
4561f28255Scgd #include <string.h>
46b771e65bSwiz 
4761f28255Scgd #include "csh.h"
4861f28255Scgd #include "extern.h"
4961f28255Scgd 
50b771e65bSwiz static void asyntax(struct wordent *, struct wordent *);
51b771e65bSwiz static void asyn0(struct wordent *, struct wordent *);
52b771e65bSwiz static void asyn3(struct wordent *, struct wordent *);
53b771e65bSwiz static struct wordent *freenod(struct wordent *, struct wordent *);
54b771e65bSwiz static struct command *syn0(struct wordent *, struct wordent *, int);
55b771e65bSwiz static struct command *syn1(struct wordent *, struct wordent *, int);
56b771e65bSwiz static struct command *syn1a(struct wordent *, struct wordent *, int);
57b771e65bSwiz static struct command *syn1b(struct wordent *, struct wordent *, int);
58b771e65bSwiz static struct command *syn2(struct wordent *, struct wordent *, int);
59b771e65bSwiz static struct command *syn3(struct wordent *, struct wordent *, int);
6061f28255Scgd 
6161f28255Scgd #define ALEFT 21		/* max of 20 alias expansions	 */
6261f28255Scgd #define HLEFT 11		/* max of 10 history expansions	 */
6361f28255Scgd /*
6461f28255Scgd  * Perform aliasing on the word list lex
6561f28255Scgd  * Do a (very rudimentary) parse to separate into commands.
6661f28255Scgd  * If word 0 of a command has an alias, do it.
6761f28255Scgd  * Repeat a maximum of 20 times.
6861f28255Scgd  */
6961f28255Scgd static int aleft;
7061f28255Scgd extern int hleft;
71b771e65bSwiz 
7261f28255Scgd void
alias(struct wordent * lexp)73537f55c6Slukem alias(struct wordent *lexp)
7461f28255Scgd {
7561f28255Scgd     jmp_buf osetexit;
7661f28255Scgd 
7761f28255Scgd     aleft = ALEFT;
7861f28255Scgd     hleft = HLEFT;
7961f28255Scgd     getexit(osetexit);
8061f28255Scgd     (void)setexit();
8161f28255Scgd     if (haderr) {
8261f28255Scgd 	resexit(osetexit);
8361f28255Scgd 	reset();
8461f28255Scgd     }
85ee9e50eaSmycroft     if (--aleft == 0)
8661f28255Scgd 	stderror(ERR_ALIASLOOP);
87537f55c6Slukem     asyntax(lexp->next, lexp);
8861f28255Scgd     resexit(osetexit);
8961f28255Scgd }
9061f28255Scgd 
9161f28255Scgd static void
asyntax(struct wordent * p1,struct wordent * p2)92b771e65bSwiz asyntax(struct wordent *p1, struct wordent *p2)
9361f28255Scgd {
9461f28255Scgd     while (p1 != p2)
9561f28255Scgd 	if (any(";&\n", p1->word[0]))
9661f28255Scgd 	    p1 = p1->next;
9761f28255Scgd 	else {
9861f28255Scgd 	    asyn0(p1, p2);
9961f28255Scgd 	    return;
10061f28255Scgd 	}
10161f28255Scgd }
10261f28255Scgd 
10361f28255Scgd static void
asyn0(struct wordent * p1,struct wordent * p2)104b771e65bSwiz asyn0(struct wordent *p1, struct wordent *p2)
10561f28255Scgd {
10676adbe2bStls     struct wordent *p;
107b771e65bSwiz     int l;
10861f28255Scgd 
109b771e65bSwiz     l = 0;
11061f28255Scgd     for (p = p1; p != p2; p = p->next)
11161f28255Scgd 	switch (p->word[0]) {
11261f28255Scgd 	case '(':
11361f28255Scgd 	    l++;
11461f28255Scgd 	    continue;
11561f28255Scgd 	case ')':
11661f28255Scgd 	    l--;
117ee9e50eaSmycroft 	    if (l < 0)
11861f28255Scgd 		stderror(ERR_TOOMANYRP);
11961f28255Scgd 	    continue;
12061f28255Scgd 	case '>':
12161f28255Scgd 	    if (p->next != p2 && eq(p->next->word, STRand))
12261f28255Scgd 		p = p->next;
12361f28255Scgd 	    continue;
12461f28255Scgd 	case '&':
12561f28255Scgd 	case '|':
12661f28255Scgd 	case ';':
12761f28255Scgd 	case '\n':
12861f28255Scgd 	    if (l != 0)
12961f28255Scgd 		continue;
13061f28255Scgd 	    asyn3(p1, p);
13161f28255Scgd 	    asyntax(p->next, p2);
13261f28255Scgd 	    return;
13361f28255Scgd 	}
13461f28255Scgd     if (l == 0)
13561f28255Scgd 	asyn3(p1, p2);
13661f28255Scgd }
13761f28255Scgd 
13861f28255Scgd static void
asyn3(struct wordent * p1,struct wordent * p2)139b771e65bSwiz asyn3(struct wordent *p1, struct wordent *p2)
14061f28255Scgd {
14176adbe2bStls     struct varent *ap;
14261f28255Scgd     struct wordent alout;
143b79c2ef2Schristos     int redid;
14461f28255Scgd 
14561f28255Scgd     if (p1 == p2)
14661f28255Scgd 	return;
14761f28255Scgd     if (p1->word[0] == '(') {
14861f28255Scgd 	for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
14961f28255Scgd 	    if (p2 == p1)
15061f28255Scgd 		return;
15161f28255Scgd 	if (p2 == p1->next)
15261f28255Scgd 	    return;
15361f28255Scgd 	asyn0(p1->next, p2);
15461f28255Scgd 	return;
15561f28255Scgd     }
15661f28255Scgd     ap = adrof1(p1->word, &aliases);
15761f28255Scgd     if (ap == 0)
15861f28255Scgd 	return;
15961f28255Scgd     alhistp = p1->prev;
16061f28255Scgd     alhistt = p2;
16161f28255Scgd     alvec = ap->vec;
16261f28255Scgd     redid = lex(&alout);
16361f28255Scgd     alhistp = alhistt = 0;
16461f28255Scgd     alvec = 0;
16561f28255Scgd     if (seterr) {
16661f28255Scgd 	freelex(&alout);
16761f28255Scgd 	stderror(ERR_OLD);
16861f28255Scgd     }
16961f28255Scgd     if (p1->word[0] && eq(p1->word, alout.next->word)) {
170b771e65bSwiz 	Char *cp;
17161f28255Scgd 
172b771e65bSwiz 	cp = alout.next->word;
17361f28255Scgd 	alout.next->word = Strspl(STRQNULL, cp);
1741767ce60Schristos 	free(cp);
17561f28255Scgd     }
17661f28255Scgd     p1 = freenod(p1, redid ? p2 : p1->next);
17761f28255Scgd     if (alout.next != &alout) {
17861f28255Scgd 	p1->next->prev = alout.prev->prev;
17961f28255Scgd 	alout.prev->prev->next = p1->next;
18061f28255Scgd 	alout.next->prev = p1;
18161f28255Scgd 	p1->next = alout.next;
1821767ce60Schristos 	free(alout.prev->word);
1831767ce60Schristos 	free(alout.prev);
18461f28255Scgd     }
18561f28255Scgd     reset();			/* throw! */
18661f28255Scgd }
18761f28255Scgd 
18861f28255Scgd static struct wordent *
freenod(struct wordent * p1,struct wordent * p2)189b771e65bSwiz freenod(struct wordent *p1, struct wordent *p2)
19061f28255Scgd {
191b771e65bSwiz     struct wordent *retp;
19261f28255Scgd 
193b771e65bSwiz     retp = p1->prev;
19461f28255Scgd     while (p1 != p2) {
1951767ce60Schristos 	free(p1->word);
19661f28255Scgd 	p1 = p1->next;
1971767ce60Schristos 	free(p1->prev);
19861f28255Scgd     }
19961f28255Scgd     retp->next = p2;
20061f28255Scgd     p2->prev = retp;
20161f28255Scgd     return (retp);
20261f28255Scgd }
20361f28255Scgd 
20461f28255Scgd #define	PHERE	1
20561f28255Scgd #define	PIN	2
20661f28255Scgd #define	POUT	4
207cee2bad8Smycroft #define	PERR	8
20861f28255Scgd 
20961f28255Scgd /*
21061f28255Scgd  * syntax
21161f28255Scgd  *	empty
21261f28255Scgd  *	syn0
21361f28255Scgd  */
21461f28255Scgd struct command *
syntax(struct wordent * p1,struct wordent * p2,int flags)215b771e65bSwiz syntax(struct wordent *p1, struct wordent *p2, int flags)
21661f28255Scgd {
21761f28255Scgd     while (p1 != p2)
21861f28255Scgd 	if (any(";&\n", p1->word[0]))
21961f28255Scgd 	    p1 = p1->next;
22061f28255Scgd 	else
22161f28255Scgd 	    return (syn0(p1, p2, flags));
22261f28255Scgd     return (0);
22361f28255Scgd }
22461f28255Scgd 
22561f28255Scgd /*
22661f28255Scgd  * syn0
22761f28255Scgd  *	syn1
22861f28255Scgd  *	syn1 & syntax
22961f28255Scgd  */
23061f28255Scgd static struct command *
syn0(struct wordent * p1,struct wordent * p2,int flags)231b771e65bSwiz syn0(struct wordent *p1, struct wordent *p2, int flags)
23261f28255Scgd {
23376adbe2bStls     struct wordent *p;
23476adbe2bStls     struct command *t, *t1;
23561f28255Scgd     int l;
23661f28255Scgd 
23761f28255Scgd     l = 0;
23861f28255Scgd     for (p = p1; p != p2; p = p->next)
23961f28255Scgd 	switch (p->word[0]) {
24061f28255Scgd 	case '(':
24161f28255Scgd 	    l++;
24261f28255Scgd 	    continue;
24361f28255Scgd 	case ')':
24461f28255Scgd 	    l--;
24561f28255Scgd 	    if (l < 0)
24661f28255Scgd 		seterror(ERR_TOOMANYRP);
24761f28255Scgd 	    continue;
24861f28255Scgd 	case '|':
24961f28255Scgd 	    if (p->word[1] == '|')
25061f28255Scgd 		continue;
251cdbd74daSmycroft 	    /* FALLTHROUGH */
25261f28255Scgd 	case '>':
25361f28255Scgd 	    if (p->next != p2 && eq(p->next->word, STRand))
25461f28255Scgd 		p = p->next;
25561f28255Scgd 	    continue;
25661f28255Scgd 	case '&':
25761f28255Scgd 	    if (l != 0)
25861f28255Scgd 		break;
25961f28255Scgd 	    if (p->word[1] == '&')
26061f28255Scgd 		continue;
26161f28255Scgd 	    t1 = syn1(p1, p, flags);
26261f28255Scgd 	    if (t1->t_dtyp == NODE_LIST ||
26361f28255Scgd 		t1->t_dtyp == NODE_AND ||
26461f28255Scgd 		t1->t_dtyp == NODE_OR) {
26585bd10cbSdholland 		t = xcalloc(1, sizeof(*t));
26661f28255Scgd 		t->t_dtyp = NODE_PAREN;
26761f28255Scgd 		t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
26861f28255Scgd 		t->t_dspr = t1;
26961f28255Scgd 		t1 = t;
27061f28255Scgd 	    }
27161f28255Scgd 	    else
27261f28255Scgd 		t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
27385bd10cbSdholland 	    t = xcalloc(1, sizeof(*t));
27461f28255Scgd 	    t->t_dtyp = NODE_LIST;
27561f28255Scgd 	    t->t_dflg = 0;
27661f28255Scgd 	    t->t_dcar = t1;
27761f28255Scgd 	    t->t_dcdr = syntax(p, p2, flags);
27861f28255Scgd 	    return (t);
27961f28255Scgd 	}
28061f28255Scgd     if (l == 0)
28161f28255Scgd 	return (syn1(p1, p2, flags));
28261f28255Scgd     seterror(ERR_TOOMANYLP);
28361f28255Scgd     return (0);
28461f28255Scgd }
28561f28255Scgd 
28661f28255Scgd /*
28761f28255Scgd  * syn1
28861f28255Scgd  *	syn1a
28961f28255Scgd  *	syn1a ; syntax
29061f28255Scgd  */
29161f28255Scgd static struct command *
syn1(struct wordent * p1,struct wordent * p2,int flags)292b771e65bSwiz syn1(struct wordent *p1, struct wordent *p2, int flags)
29361f28255Scgd {
29476adbe2bStls     struct wordent *p;
29576adbe2bStls     struct command *t;
29661f28255Scgd     int l;
29761f28255Scgd 
29861f28255Scgd     l = 0;
29961f28255Scgd     for (p = p1; p != p2; p = p->next)
30061f28255Scgd 	switch (p->word[0]) {
30161f28255Scgd 	case '(':
30261f28255Scgd 	    l++;
30361f28255Scgd 	    continue;
30461f28255Scgd 	case ')':
30561f28255Scgd 	    l--;
30661f28255Scgd 	    continue;
30761f28255Scgd 	case ';':
30861f28255Scgd 	case '\n':
30961f28255Scgd 	    if (l != 0)
31061f28255Scgd 		break;
31185bd10cbSdholland 	    t = xcalloc(1, sizeof(*t));
31261f28255Scgd 	    t->t_dtyp = NODE_LIST;
31361f28255Scgd 	    t->t_dcar = syn1a(p1, p, flags);
31461f28255Scgd 	    t->t_dcdr = syntax(p->next, p2, flags);
31561f28255Scgd 	    if (t->t_dcdr == 0)
31661f28255Scgd 		t->t_dcdr = t->t_dcar, t->t_dcar = 0;
31761f28255Scgd 	    return (t);
31861f28255Scgd 	}
31961f28255Scgd     return (syn1a(p1, p2, flags));
32061f28255Scgd }
32161f28255Scgd 
32261f28255Scgd /*
32361f28255Scgd  * syn1a
32461f28255Scgd  *	syn1b
32561f28255Scgd  *	syn1b || syn1a
32661f28255Scgd  */
32761f28255Scgd static struct command *
syn1a(struct wordent * p1,struct wordent * p2,int flags)328b771e65bSwiz syn1a(struct wordent *p1, struct wordent *p2, int flags)
32961f28255Scgd {
33076adbe2bStls     struct wordent *p;
33176adbe2bStls     struct command *t;
332b771e65bSwiz     int l;
33361f28255Scgd 
334b771e65bSwiz     l = 0;
33561f28255Scgd     for (p = p1; p != p2; p = p->next)
33661f28255Scgd 	switch (p->word[0]) {
33761f28255Scgd 	case '(':
33861f28255Scgd 	    l++;
33961f28255Scgd 	    continue;
34061f28255Scgd 	case ')':
34161f28255Scgd 	    l--;
34261f28255Scgd 	    continue;
34361f28255Scgd 	case '|':
34461f28255Scgd 	    if (p->word[1] != '|')
34561f28255Scgd 		continue;
34661f28255Scgd 	    if (l == 0) {
34785bd10cbSdholland 		t = xcalloc(1, sizeof(*t));
34861f28255Scgd 		t->t_dtyp = NODE_OR;
34961f28255Scgd 		t->t_dcar = syn1b(p1, p, flags);
35061f28255Scgd 		t->t_dcdr = syn1a(p->next, p2, flags);
35161f28255Scgd 		t->t_dflg = 0;
35261f28255Scgd 		return (t);
35361f28255Scgd 	    }
35461f28255Scgd 	    continue;
35561f28255Scgd 	}
35661f28255Scgd     return (syn1b(p1, p2, flags));
35761f28255Scgd }
35861f28255Scgd 
35961f28255Scgd /*
36061f28255Scgd  * syn1b
36161f28255Scgd  *	syn2
36261f28255Scgd  *	syn2 && syn1b
36361f28255Scgd  */
36461f28255Scgd static struct command *
syn1b(struct wordent * p1,struct wordent * p2,int flags)365b771e65bSwiz syn1b(struct wordent *p1, struct wordent *p2, int flags)
36661f28255Scgd {
36776adbe2bStls     struct wordent *p;
36876adbe2bStls     struct command *t;
369b771e65bSwiz     int l;
37061f28255Scgd 
371b771e65bSwiz     l = 0;
37261f28255Scgd     for (p = p1; p != p2; p = p->next)
37361f28255Scgd 	switch (p->word[0]) {
37461f28255Scgd 	case '(':
37561f28255Scgd 	    l++;
37661f28255Scgd 	    continue;
37761f28255Scgd 	case ')':
37861f28255Scgd 	    l--;
37961f28255Scgd 	    continue;
38061f28255Scgd 	case '&':
38161f28255Scgd 	    if (p->word[1] == '&' && l == 0) {
38285bd10cbSdholland 		t = xcalloc(1, sizeof(*t));
38361f28255Scgd 		t->t_dtyp = NODE_AND;
38461f28255Scgd 		t->t_dcar = syn2(p1, p, flags);
38561f28255Scgd 		t->t_dcdr = syn1b(p->next, p2, flags);
38661f28255Scgd 		t->t_dflg = 0;
38761f28255Scgd 		return (t);
38861f28255Scgd 	    }
38961f28255Scgd 	    continue;
39061f28255Scgd 	}
39161f28255Scgd     return (syn2(p1, p2, flags));
39261f28255Scgd }
39361f28255Scgd 
39461f28255Scgd /*
39561f28255Scgd  * syn2
39661f28255Scgd  *	syn3
39761f28255Scgd  *	syn3 | syn2
39861f28255Scgd  *	syn3 |& syn2
39961f28255Scgd  */
40061f28255Scgd static struct command *
syn2(struct wordent * p1,struct wordent * p2,int flags)401b771e65bSwiz syn2(struct wordent *p1, struct wordent *p2, int flags)
40261f28255Scgd {
40376adbe2bStls     struct wordent *p, *pn;
40476adbe2bStls     struct command *t;
405b771e65bSwiz     int f, l;
40661f28255Scgd 
407b771e65bSwiz     l = 0;
40861f28255Scgd     for (p = p1; p != p2; p = p->next)
40961f28255Scgd 	switch (p->word[0]) {
41061f28255Scgd 	case '(':
41161f28255Scgd 	    l++;
41261f28255Scgd 	    continue;
41361f28255Scgd 	case ')':
41461f28255Scgd 	    l--;
41561f28255Scgd 	    continue;
41661f28255Scgd 	case '|':
41761f28255Scgd 	    if (l != 0)
41861f28255Scgd 		continue;
41985bd10cbSdholland 	    t = xcalloc(1, sizeof(*t));
42061f28255Scgd 	    f = flags | POUT;
42161f28255Scgd 	    pn = p->next;
42261f28255Scgd 	    if (pn != p2 && pn->word[0] == '&') {
423cee2bad8Smycroft 		f |= PERR;
42461f28255Scgd 		t->t_dflg |= F_STDERR;
42561f28255Scgd 	    }
42661f28255Scgd 	    t->t_dtyp = NODE_PIPE;
42761f28255Scgd 	    t->t_dcar = syn3(p1, p, f);
42861f28255Scgd 	    if (pn != p2 && pn->word[0] == '&')
42961f28255Scgd 		p = pn;
43061f28255Scgd 	    t->t_dcdr = syn2(p->next, p2, flags | PIN);
43161f28255Scgd 	    return (t);
43261f28255Scgd 	}
43361f28255Scgd     return (syn3(p1, p2, flags));
43461f28255Scgd }
43561f28255Scgd 
43661f28255Scgd static char RELPAR[] = {'<', '>', '(', ')', '\0'};
43761f28255Scgd 
43861f28255Scgd /*
43961f28255Scgd  * syn3
44061f28255Scgd  *	( syn0 ) [ < in  ] [ > out ]
44161f28255Scgd  *	word word* [ < in ] [ > out ]
44261f28255Scgd  *	KEYWORD ( word* ) word* [ < in ] [ > out ]
44361f28255Scgd  *
44461f28255Scgd  *	KEYWORD = (@ exit foreach if set switch test while)
44561f28255Scgd  */
44661f28255Scgd static struct command *
syn3(struct wordent * p1,struct wordent * p2,int flags)447b771e65bSwiz syn3(struct wordent *p1, struct wordent *p2, int flags)
44861f28255Scgd {
449b771e65bSwiz     struct wordent *lp, *p, *rp;
45076adbe2bStls     struct command *t;
45161f28255Scgd     Char **av;
452b771e65bSwiz     int c, l, n;
453b79c2ef2Schristos     int specp;
45461f28255Scgd 
455b771e65bSwiz     specp = 0;
45661f28255Scgd     if (p1 != p2) {
45761f28255Scgd 	p = p1;
45861f28255Scgd again:
45961f28255Scgd 	switch (srchx(p->word)) {
46061f28255Scgd 	case T_ELSE:
46161f28255Scgd 	    p = p->next;
46261f28255Scgd 	    if (p != p2)
46361f28255Scgd 		goto again;
46461f28255Scgd 	    break;
46561f28255Scgd 	case T_EXIT:
46661f28255Scgd 	case T_FOREACH:
46761f28255Scgd 	case T_IF:
46861f28255Scgd 	case T_LET:
46961f28255Scgd 	case T_SET:
47061f28255Scgd 	case T_SWITCH:
47161f28255Scgd 	case T_WHILE:
47261f28255Scgd 	    specp = 1;
47361f28255Scgd 	    break;
47461f28255Scgd 	}
47561f28255Scgd     }
47661f28255Scgd     n = 0;
47761f28255Scgd     l = 0;
47861f28255Scgd     for (p = p1; p != p2; p = p->next)
47961f28255Scgd 	switch (p->word[0]) {
48061f28255Scgd 	case '(':
48161f28255Scgd 	    if (specp)
48261f28255Scgd 		n++;
48361f28255Scgd 	    l++;
48461f28255Scgd 	    continue;
48561f28255Scgd 	case ')':
48661f28255Scgd 	    if (specp)
48761f28255Scgd 		n++;
48861f28255Scgd 	    l--;
48961f28255Scgd 	    continue;
49061f28255Scgd 	case '>':
49161f28255Scgd 	case '<':
49261f28255Scgd 	    if (l != 0) {
49361f28255Scgd 		if (specp)
49461f28255Scgd 		    n++;
49561f28255Scgd 		continue;
49661f28255Scgd 	    }
49761f28255Scgd 	    if (p->next == p2)
49861f28255Scgd 		continue;
49961f28255Scgd 	    if (any(RELPAR, p->next->word[0]))
50061f28255Scgd 		continue;
50161f28255Scgd 	    n--;
50261f28255Scgd 	    continue;
50361f28255Scgd 	default:
50461f28255Scgd 	    if (!specp && l != 0)
50561f28255Scgd 		continue;
50661f28255Scgd 	    n++;
50761f28255Scgd 	    continue;
50861f28255Scgd 	}
50961f28255Scgd     if (n < 0)
51061f28255Scgd 	n = 0;
51185bd10cbSdholland     t = xcalloc(1, sizeof(*t));
512*7f63690aSdholland     /* XXX the cast is needed because n is signed */
513*7f63690aSdholland     av = xcalloc((size_t)(n + 1), sizeof(*av));
51461f28255Scgd     t->t_dcom = av;
51561f28255Scgd     n = 0;
51661f28255Scgd     if (p2->word[0] == ')')
51761f28255Scgd 	t->t_dflg = F_NOFORK;
51861f28255Scgd     lp = 0;
51961f28255Scgd     rp = 0;
52061f28255Scgd     l = 0;
52161f28255Scgd     for (p = p1; p != p2; p = p->next) {
52261f28255Scgd 	c = p->word[0];
52361f28255Scgd 	switch (c) {
52461f28255Scgd 	case '(':
52561f28255Scgd 	    if (l == 0) {
52661f28255Scgd 		if (lp != 0 && !specp)
52761f28255Scgd 		    seterror(ERR_BADPLP);
52861f28255Scgd 		lp = p->next;
52961f28255Scgd 	    }
53061f28255Scgd 	    l++;
53161f28255Scgd 	    goto savep;
53261f28255Scgd 	case ')':
53361f28255Scgd 	    l--;
53461f28255Scgd 	    if (l == 0)
53561f28255Scgd 		rp = p;
53661f28255Scgd 	    goto savep;
53761f28255Scgd 	case '>':
53861f28255Scgd 	    if (l != 0)
53961f28255Scgd 		goto savep;
54061f28255Scgd 	    if (p->word[1] == '>')
54161f28255Scgd 		t->t_dflg |= F_APPEND;
54261f28255Scgd 	    if (p->next != p2 && eq(p->next->word, STRand)) {
54361f28255Scgd 		t->t_dflg |= F_STDERR, p = p->next;
544cee2bad8Smycroft 		if (flags & (POUT | PERR)) {
54561f28255Scgd 		    seterror(ERR_OUTRED);
54661f28255Scgd 		    continue;
54761f28255Scgd 		}
54861f28255Scgd 	    }
54961f28255Scgd 	    if (p->next != p2 && eq(p->next->word, STRbang))
55061f28255Scgd 		t->t_dflg |= F_OVERWRITE, p = p->next;
55161f28255Scgd 	    if (p->next == p2) {
55261f28255Scgd 		seterror(ERR_MISRED);
55361f28255Scgd 		continue;
55461f28255Scgd 	    }
55561f28255Scgd 	    p = p->next;
55661f28255Scgd 	    if (any(RELPAR, p->word[0])) {
55761f28255Scgd 		seterror(ERR_MISRED);
55861f28255Scgd 		continue;
55961f28255Scgd 	    }
560cee2bad8Smycroft 	    if ((flags & POUT) && ((flags & PERR) == 0 || t->t_drit))
56161f28255Scgd 		seterror(ERR_OUTRED);
56261f28255Scgd 	    else
56361f28255Scgd 		t->t_drit = Strsave(p->word);
56461f28255Scgd 	    continue;
56561f28255Scgd 	case '<':
56661f28255Scgd 	    if (l != 0)
56761f28255Scgd 		goto savep;
56861f28255Scgd 	    if (p->word[1] == '<')
56961f28255Scgd 		t->t_dflg |= F_READ;
57061f28255Scgd 	    if (p->next == p2) {
57161f28255Scgd 		seterror(ERR_MISRED);
57261f28255Scgd 		continue;
57361f28255Scgd 	    }
57461f28255Scgd 	    p = p->next;
57561f28255Scgd 	    if (any(RELPAR, p->word[0])) {
57661f28255Scgd 		seterror(ERR_MISRED);
57761f28255Scgd 		continue;
57861f28255Scgd 	    }
57961f28255Scgd 	    if ((flags & PHERE) && (t->t_dflg & F_READ))
58061f28255Scgd 		seterror(ERR_REDPAR);
58161f28255Scgd 	    else if ((flags & PIN) || t->t_dlef)
58261f28255Scgd 		seterror(ERR_INRED);
58361f28255Scgd 	    else
58461f28255Scgd 		t->t_dlef = Strsave(p->word);
58561f28255Scgd 	    continue;
58661f28255Scgd 	savep:
58761f28255Scgd 	    if (!specp)
58861f28255Scgd 		continue;
589cdbd74daSmycroft 	    /* FALLTHROUGH */
59061f28255Scgd 	default:
59161f28255Scgd 	    if (l != 0 && !specp)
59261f28255Scgd 		continue;
59361f28255Scgd 	    if (seterr == 0)
59461f28255Scgd 		av[n] = Strsave(p->word);
59561f28255Scgd 	    n++;
59661f28255Scgd 	    continue;
59761f28255Scgd 	}
59861f28255Scgd     }
59961f28255Scgd     if (lp != 0 && !specp) {
60061f28255Scgd 	if (n != 0)
60161f28255Scgd 	    seterror(ERR_BADPLPS);
60261f28255Scgd 	t->t_dtyp = NODE_PAREN;
60361f28255Scgd 	t->t_dspr = syn0(lp, rp, PHERE);
60461f28255Scgd     }
60561f28255Scgd     else {
60661f28255Scgd 	if (n == 0)
60761f28255Scgd 	    seterror(ERR_NULLCOM);
60861f28255Scgd 	t->t_dtyp = NODE_COMMAND;
60961f28255Scgd     }
61061f28255Scgd     return (t);
61161f28255Scgd }
61261f28255Scgd 
61361f28255Scgd void
freesyn(struct command * t)614b771e65bSwiz freesyn(struct command *t)
61561f28255Scgd {
61676adbe2bStls     Char **v;
61761f28255Scgd 
61861f28255Scgd     if (t == 0)
61961f28255Scgd 	return;
62061f28255Scgd     switch (t->t_dtyp) {
62161f28255Scgd     case NODE_COMMAND:
62261f28255Scgd 	for (v = t->t_dcom; *v; v++)
6231767ce60Schristos 	    free(* v);
6241767ce60Schristos 	free(t->t_dcom);
6251767ce60Schristos 	free(t->t_dlef);
6261767ce60Schristos 	free(t->t_drit);
62761f28255Scgd 	break;
62861f28255Scgd     case NODE_PAREN:
62961f28255Scgd 	freesyn(t->t_dspr);
6301767ce60Schristos 	free(t->t_dlef);
6311767ce60Schristos 	free(t->t_drit);
63261f28255Scgd 	break;
63361f28255Scgd     case NODE_AND:
63461f28255Scgd     case NODE_OR:
63561f28255Scgd     case NODE_PIPE:
63661f28255Scgd     case NODE_LIST:
63761f28255Scgd 	freesyn(t->t_dcar), freesyn(t->t_dcdr);
63861f28255Scgd 	break;
63961f28255Scgd     }
6401767ce60Schristos     free(t);
64161f28255Scgd }
642