1232633Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.parse.c,v 3.19 2011/03/30 16:21:37 christos Exp $ */
259243Sobrien/*
359243Sobrien * sh.parse.c: Interpret a list of tokens
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien
35232633SmpRCSID("$tcsh: sh.parse.c,v 3.19 2011/03/30 16:21:37 christos Exp $")
3659243Sobrien
3759243Sobrien/*
3859243Sobrien * C shell
3959243Sobrien */
40167465Smpstatic	int		 asyntax (struct wordent *, struct wordent *);
41167465Smpstatic	int		 asyn0 	 (struct wordent *, struct wordent *);
42167465Smpstatic	int		 asyn3	 (struct wordent *, struct wordent *);
43167465Smpstatic	struct wordent	*freenod (struct wordent *, struct wordent *);
44167465Smpstatic	struct command	*syn0	 (const struct wordent *, const struct wordent *, int);
45167465Smpstatic	struct command	*syn1	 (const struct wordent *, const struct wordent *, int);
46167465Smpstatic	struct command	*syn1a	 (const struct wordent *, const struct wordent *, int);
47167465Smpstatic	struct command	*syn1b	 (const struct wordent *, const struct wordent *, int);
48167465Smpstatic	struct command	*syn2	 (const struct wordent *, const struct wordent *, int);
49167465Smpstatic	struct command	*syn3	 (const struct wordent *, const struct wordent *, int);
5059243Sobrien
5159243Sobrien#define ALEFT	51		/* max of 50 alias expansions	 */
5259243Sobrien#define HLEFT	11		/* max of 10 history expansions */
5359243Sobrien/*
5459243Sobrien * Perform aliasing on the word list lexp
5559243Sobrien * Do a (very rudimentary) parse to separate into commands.
5659243Sobrien * If word 0 of a command has an alias, do it.
5759243Sobrien * Repeat a maximum of 50 times.
5859243Sobrien */
5959243Sobrienextern int hleft;
6059243Sobrienvoid
61167465Smpalias(struct wordent *lexp)
6259243Sobrien{
63167465Smp    int aleft;
6459243Sobrien
6559243Sobrien    aleft = ALEFT;
6659243Sobrien    hleft = HLEFT;
67167465Smp    do {
68167465Smp	if (--aleft == 0)
69167465Smp	    stderror(ERR_ALIASLOOP);
70167465Smp    } while (asyntax(lexp->next, lexp) != 0);
7159243Sobrien}
7259243Sobrien
73167465Smpstatic int
74167465Smpasyntax(struct wordent *p1, struct wordent *p2)
7559243Sobrien{
76167465Smp    while (p1 != p2) {
77167465Smp	if (!any(";&\n", p1->word[0]))
78167465Smp	    return asyn0(p1, p2);
79167465Smp	p1 = p1->next;
80167465Smp    }
81167465Smp    return 0;
8259243Sobrien}
8359243Sobrien
84167465Smpstatic int
85167465Smpasyn0(struct wordent *p1, struct wordent *p2)
8659243Sobrien{
87145479Smp    struct wordent *p;
88145479Smp    int l = 0;
8959243Sobrien
9059243Sobrien    for (p = p1; p != p2; p = p->next)
9159243Sobrien	switch (p->word[0]) {
9259243Sobrien
9359243Sobrien	case '(':
9459243Sobrien	    l++;
9559243Sobrien	    continue;
9659243Sobrien
9759243Sobrien	case ')':
9859243Sobrien	    l--;
9959243Sobrien	    if (l < 0)
10059243Sobrien		stderror(ERR_TOOMANYRP);
10159243Sobrien	    continue;
10259243Sobrien
10359243Sobrien	case '>':
10459243Sobrien	    if (p->next != p2 && eq(p->next->word, STRand))
10559243Sobrien		p = p->next;
10659243Sobrien	    continue;
10759243Sobrien
10859243Sobrien	case '&':
10959243Sobrien	case '|':
11059243Sobrien	case ';':
11159243Sobrien	case '\n':
11259243Sobrien	    if (l != 0)
11359243Sobrien		continue;
114167465Smp	    if (asyn3(p1, p) != 0)
115167465Smp		return 1;
116167465Smp	    return asyntax(p->next, p2);
11759243Sobrien
11859243Sobrien	default:
11959243Sobrien	    break;
12059243Sobrien	}
12159243Sobrien    if (l == 0)
122167465Smp	return asyn3(p1, p2);
123167465Smp    return 0;
12459243Sobrien}
12559243Sobrien
12659243Sobrienstatic void
127167465Smpalvec_cleanup(void *dummy)
12859243Sobrien{
129167465Smp    USE(dummy);
130167465Smp    alhistp = NULL;
131167465Smp    alhistt = NULL;
132167465Smp    alvec = NULL;
133167465Smp}
134167465Smp
135167465Smpstatic int
136167465Smpasyn3(struct wordent *p1, struct wordent *p2)
137167465Smp{
138145479Smp    struct varent *ap;
13959243Sobrien    struct wordent alout;
140145479Smp    int redid;
14159243Sobrien
14259243Sobrien    if (p1 == p2)
143167465Smp	return 0;
14459243Sobrien    if (p1->word[0] == '(') {
14559243Sobrien	for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
14659243Sobrien	    if (p2 == p1)
147167465Smp		return 0;
14859243Sobrien	if (p2 == p1->next)
149167465Smp	    return 0;
150167465Smp	return asyn0(p1->next, p2);
15159243Sobrien    }
15259243Sobrien    ap = adrof1(p1->word, &aliases);
15359243Sobrien    if (ap == 0)
154167465Smp	return 0;
15559243Sobrien    alhistp = p1->prev;
15659243Sobrien    alhistt = p2;
15759243Sobrien    alvec = ap->vec;
158167465Smp    cleanup_push(&alvec, alvec_cleanup);
15959243Sobrien    redid = lex(&alout);
160167465Smp    cleanup_until(&alvec);
16159243Sobrien    if (seterr) {
16259243Sobrien	freelex(&alout);
16359243Sobrien	stderror(ERR_OLD);
16459243Sobrien    }
16559243Sobrien    if (p1->word[0] && eq(p1->word, alout.next->word)) {
16659243Sobrien	Char   *cp = alout.next->word;
16759243Sobrien
16859243Sobrien	alout.next->word = Strspl(STRQNULL, cp);
169167465Smp	xfree(cp);
17059243Sobrien    }
17159243Sobrien    p1 = freenod(p1, redid ? p2 : p1->next);
17259243Sobrien    if (alout.next != &alout) {
17359243Sobrien	p1->next->prev = alout.prev->prev;
17459243Sobrien	alout.prev->prev->next = p1->next;
17559243Sobrien	alout.next->prev = p1;
17659243Sobrien	p1->next = alout.next;
177167465Smp	xfree(alout.prev->word);
178167465Smp	xfree(alout.prev);
17959243Sobrien    }
180167465Smp    return 1;
18159243Sobrien}
18259243Sobrien
18359243Sobrienstatic struct wordent *
184167465Smpfreenod(struct wordent *p1, struct wordent *p2)
18559243Sobrien{
186145479Smp    struct wordent *retp = p1->prev;
18759243Sobrien
18859243Sobrien    while (p1 != p2) {
189167465Smp	xfree(p1->word);
19059243Sobrien	p1 = p1->next;
191167465Smp	xfree(p1->prev);
19259243Sobrien    }
19359243Sobrien    retp->next = p2;
19459243Sobrien    p2->prev = retp;
19559243Sobrien    return (retp);
19659243Sobrien}
19759243Sobrien
19859243Sobrien#define	P_HERE	1
19959243Sobrien#define	P_IN	2
20059243Sobrien#define	P_OUT	4
20159243Sobrien#define	P_DIAG	8
20259243Sobrien
20359243Sobrien/*
20459243Sobrien * syntax
20559243Sobrien *	empty
20659243Sobrien *	syn0
20759243Sobrien */
20859243Sobrienstruct command *
209167465Smpsyntax(const struct wordent *p1, const struct wordent *p2, int flags)
21059243Sobrien{
21159243Sobrien
21259243Sobrien    while (p1 != p2)
21359243Sobrien	if (any(";&\n", p1->word[0]))
21459243Sobrien	    p1 = p1->next;
21559243Sobrien	else
21659243Sobrien	    return (syn0(p1, p2, flags));
21759243Sobrien    return (0);
21859243Sobrien}
21959243Sobrien
22059243Sobrien/*
22159243Sobrien * syn0
22259243Sobrien *	syn1
22359243Sobrien *	syn1 & syntax
22459243Sobrien */
22559243Sobrienstatic struct command *
226167465Smpsyn0(const struct wordent *p1, const struct wordent *p2, int flags)
22759243Sobrien{
228167465Smp    const struct wordent *p;
229145479Smp    struct command *t, *t1;
23059243Sobrien    int     l;
23159243Sobrien
23259243Sobrien    l = 0;
23359243Sobrien    for (p = p1; p != p2; p = p->next)
23459243Sobrien	switch (p->word[0]) {
23559243Sobrien
23659243Sobrien	case '(':
23759243Sobrien	    l++;
23859243Sobrien	    continue;
23959243Sobrien
24059243Sobrien	case ')':
24159243Sobrien	    l--;
24259243Sobrien	    if (l < 0)
24359243Sobrien		seterror(ERR_TOOMANYRP);
24459243Sobrien	    continue;
24559243Sobrien
24659243Sobrien	case '|':
24759243Sobrien	    if (p->word[1] == '|')
24859243Sobrien		continue;
24959243Sobrien	    /*FALLTHROUGH*/
25059243Sobrien
25159243Sobrien	case '>':
25259243Sobrien	    if (p->next != p2 && eq(p->next->word, STRand))
25359243Sobrien		p = p->next;
25459243Sobrien	    continue;
25559243Sobrien
25659243Sobrien	case '&':
25759243Sobrien	    if (l != 0)
25859243Sobrien		break;
25959243Sobrien	    if (p->word[1] == '&')
26059243Sobrien		continue;
26159243Sobrien	    t1 = syn1(p1, p, flags);
26259243Sobrien	    if (t1->t_dtyp == NODE_LIST ||
26359243Sobrien		t1->t_dtyp == NODE_AND ||
26459243Sobrien		t1->t_dtyp == NODE_OR) {
265167465Smp		t = xcalloc(1, sizeof(*t));
26659243Sobrien		t->t_dtyp = NODE_PAREN;
26759243Sobrien		t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
26859243Sobrien		t->t_dspr = t1;
26959243Sobrien		t1 = t;
27059243Sobrien	    }
27159243Sobrien	    else
27259243Sobrien		t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
273167465Smp	    t = xcalloc(1, sizeof(*t));
27459243Sobrien	    t->t_dtyp = NODE_LIST;
27559243Sobrien	    t->t_dflg = 0;
27659243Sobrien	    t->t_dcar = t1;
27759243Sobrien	    t->t_dcdr = syntax(p, p2, flags);
27859243Sobrien	    return (t);
27959243Sobrien	default:
28059243Sobrien	    break;
28159243Sobrien	}
28259243Sobrien    if (l == 0)
28359243Sobrien	return (syn1(p1, p2, flags));
28459243Sobrien    seterror(ERR_TOOMANYLP);
28559243Sobrien    return (0);
28659243Sobrien}
28759243Sobrien
28859243Sobrien/*
28959243Sobrien * syn1
29059243Sobrien *	syn1a
29159243Sobrien *	syn1a ; syntax
29259243Sobrien */
29359243Sobrienstatic struct command *
294167465Smpsyn1(const struct wordent *p1, const struct wordent *p2, int flags)
29559243Sobrien{
296167465Smp    const struct wordent *p;
297145479Smp    struct command *t;
29859243Sobrien    int     l;
29959243Sobrien
30059243Sobrien    l = 0;
30159243Sobrien    for (p = p1; p != p2; p = p->next)
30259243Sobrien	switch (p->word[0]) {
30359243Sobrien
30459243Sobrien	case '(':
30559243Sobrien	    l++;
30659243Sobrien	    continue;
30759243Sobrien
30859243Sobrien	case ')':
30959243Sobrien	    l--;
31059243Sobrien	    continue;
31159243Sobrien
31259243Sobrien	case ';':
31359243Sobrien	case '\n':
31459243Sobrien	    if (l != 0)
31559243Sobrien		break;
316167465Smp	    t = xcalloc(1, sizeof(*t));
31759243Sobrien	    t->t_dtyp = NODE_LIST;
31859243Sobrien	    t->t_dcar = syn1a(p1, p, flags);
31959243Sobrien	    t->t_dcdr = syntax(p->next, p2, flags);
32059243Sobrien	    if (t->t_dcdr == 0)
32159243Sobrien		t->t_dcdr = t->t_dcar, t->t_dcar = 0;
32259243Sobrien	    return (t);
32359243Sobrien
32459243Sobrien	default:
32559243Sobrien	    break;
32659243Sobrien	}
32759243Sobrien    return (syn1a(p1, p2, flags));
32859243Sobrien}
32959243Sobrien
33059243Sobrien/*
33159243Sobrien * syn1a
33259243Sobrien *	syn1b
33359243Sobrien *	syn1b || syn1a
33459243Sobrien */
33559243Sobrienstatic struct command *
336167465Smpsyn1a(const struct wordent *p1, const struct wordent *p2, int flags)
33759243Sobrien{
338167465Smp    const struct wordent *p;
339145479Smp    struct command *t;
340145479Smp    int l = 0;
34159243Sobrien
34259243Sobrien    for (p = p1; p != p2; p = p->next)
34359243Sobrien	switch (p->word[0]) {
34459243Sobrien
34559243Sobrien	case '(':
34659243Sobrien	    l++;
34759243Sobrien	    continue;
34859243Sobrien
34959243Sobrien	case ')':
35059243Sobrien	    l--;
35159243Sobrien	    continue;
35259243Sobrien
35359243Sobrien	case '|':
35459243Sobrien	    if (p->word[1] != '|')
35559243Sobrien		continue;
35659243Sobrien	    if (l == 0) {
357167465Smp		t = xcalloc(1, sizeof(*t));
35859243Sobrien		t->t_dtyp = NODE_OR;
35959243Sobrien		t->t_dcar = syn1b(p1, p, flags);
36059243Sobrien		t->t_dcdr = syn1a(p->next, p2, flags);
36159243Sobrien		t->t_dflg = 0;
36259243Sobrien		return (t);
36359243Sobrien	    }
36459243Sobrien	    continue;
36559243Sobrien
36659243Sobrien	default:
36759243Sobrien	    break;
36859243Sobrien	}
36959243Sobrien    return (syn1b(p1, p2, flags));
37059243Sobrien}
37159243Sobrien
37259243Sobrien/*
37359243Sobrien * syn1b
37459243Sobrien *	syn2
37559243Sobrien *	syn2 && syn1b
37659243Sobrien */
37759243Sobrienstatic struct command *
378167465Smpsyn1b(const struct wordent *p1, const struct wordent *p2, int flags)
37959243Sobrien{
380167465Smp    const struct wordent *p;
381145479Smp    struct command *t;
382145479Smp    int l = 0;
38359243Sobrien
38459243Sobrien    for (p = p1; p != p2; p = p->next)
38559243Sobrien	switch (p->word[0]) {
38659243Sobrien
38759243Sobrien	case '(':
38859243Sobrien	    l++;
38959243Sobrien	    continue;
39059243Sobrien
39159243Sobrien	case ')':
39259243Sobrien	    l--;
39359243Sobrien	    continue;
39459243Sobrien
39559243Sobrien	case '&':
39659243Sobrien	    if (p->word[1] == '&' && l == 0) {
397167465Smp		t = xcalloc(1, sizeof(*t));
39859243Sobrien		t->t_dtyp = NODE_AND;
39959243Sobrien		t->t_dcar = syn2(p1, p, flags);
40059243Sobrien		t->t_dcdr = syn1b(p->next, p2, flags);
40159243Sobrien		t->t_dflg = 0;
40259243Sobrien		return (t);
40359243Sobrien	    }
40459243Sobrien	    continue;
40559243Sobrien
40659243Sobrien	default:
40759243Sobrien	    break;
40859243Sobrien	}
40959243Sobrien    return (syn2(p1, p2, flags));
41059243Sobrien}
41159243Sobrien
41259243Sobrien/*
41359243Sobrien * syn2
41459243Sobrien *	syn3
41559243Sobrien *	syn3 | syn2
41659243Sobrien *	syn3 |& syn2
41759243Sobrien */
41859243Sobrienstatic struct command *
419167465Smpsyn2(const struct wordent *p1, const struct wordent *p2, int flags)
42059243Sobrien{
421167465Smp    const struct wordent *p, *pn;
422145479Smp    struct command *t;
423145479Smp    int l = 0;
42459243Sobrien    int     f;
42559243Sobrien
42659243Sobrien    for (p = p1; p != p2; p = p->next)
42759243Sobrien	switch (p->word[0]) {
42859243Sobrien
42959243Sobrien	case '(':
43059243Sobrien	    l++;
43159243Sobrien	    continue;
43259243Sobrien
43359243Sobrien	case ')':
43459243Sobrien	    l--;
43559243Sobrien	    continue;
43659243Sobrien
43759243Sobrien	case '|':
43859243Sobrien	    if (l != 0)
43959243Sobrien		continue;
440167465Smp	    t = xcalloc(1, sizeof(*t));
44159243Sobrien	    f = flags | P_OUT;
44259243Sobrien	    pn = p->next;
44359243Sobrien	    if (pn != p2 && pn->word[0] == '&') {
44459243Sobrien		f |= P_DIAG;
44559243Sobrien		t->t_dflg |= F_STDERR;
44659243Sobrien	    }
44759243Sobrien	    t->t_dtyp = NODE_PIPE;
44859243Sobrien	    t->t_dcar = syn3(p1, p, f);
44959243Sobrien	    if (pn != p2 && pn->word[0] == '&')
45059243Sobrien		p = pn;
45159243Sobrien	    t->t_dcdr = syn2(p->next, p2, flags | P_IN);
45259243Sobrien	    return (t);
45359243Sobrien
45459243Sobrien	default:
45559243Sobrien	    break;
45659243Sobrien	}
45759243Sobrien    return (syn3(p1, p2, flags));
45859243Sobrien}
45959243Sobrien
460167465Smpstatic const char RELPAR[] = {'<', '>', '(', ')', '\0'};
46159243Sobrien
46259243Sobrien/*
46359243Sobrien * syn3
46459243Sobrien *	( syn0 ) [ < in  ] [ > out ]
46559243Sobrien *	word word* [ < in ] [ > out ]
46659243Sobrien *	KEYWORD ( word* ) word* [ < in ] [ > out ]
46759243Sobrien *
46859243Sobrien *	KEYWORD = (@ exit foreach if set switch test while)
46959243Sobrien */
47059243Sobrienstatic struct command *
471167465Smpsyn3(const struct wordent *p1, const struct wordent *p2, int flags)
47259243Sobrien{
473167465Smp    const struct wordent *p;
474167465Smp    const struct wordent *lp, *rp;
475145479Smp    struct command *t;
476145479Smp    int l;
47759243Sobrien    Char  **av;
47859243Sobrien    int     n, c;
479145479Smp    int    specp = 0;
48059243Sobrien
48159243Sobrien    if (p1 != p2) {
48259243Sobrien	p = p1;
48359243Sobrienagain:
48459243Sobrien	switch (srchx(p->word)) {
48559243Sobrien
48659243Sobrien	case TC_ELSE:
48759243Sobrien	    p = p->next;
48859243Sobrien	    if (p != p2)
48959243Sobrien		goto again;
49059243Sobrien	    break;
49159243Sobrien
49259243Sobrien	case TC_EXIT:
49359243Sobrien	case TC_FOREACH:
49459243Sobrien	case TC_IF:
49559243Sobrien	case TC_LET:
49659243Sobrien	case TC_SET:
49759243Sobrien	case TC_SWITCH:
49859243Sobrien	case TC_WHILE:
49959243Sobrien	    specp = 1;
50059243Sobrien	    break;
50159243Sobrien	default:
50259243Sobrien	    break;
50359243Sobrien	}
50459243Sobrien    }
50559243Sobrien    n = 0;
50659243Sobrien    l = 0;
50759243Sobrien    for (p = p1; p != p2; p = p->next)
50859243Sobrien	switch (p->word[0]) {
50959243Sobrien
51059243Sobrien	case '(':
51159243Sobrien	    if (specp)
51259243Sobrien		n++;
51359243Sobrien	    l++;
51459243Sobrien	    continue;
51559243Sobrien
51659243Sobrien	case ')':
51759243Sobrien	    if (specp)
51859243Sobrien		n++;
51959243Sobrien	    l--;
52059243Sobrien	    continue;
52159243Sobrien
52259243Sobrien	case '>':
52359243Sobrien	case '<':
52459243Sobrien	    if (l != 0) {
52559243Sobrien		if (specp)
52659243Sobrien		    n++;
52759243Sobrien		continue;
52859243Sobrien	    }
52959243Sobrien	    if (p->next == p2)
53059243Sobrien		continue;
53159243Sobrien	    if (any(RELPAR, p->next->word[0]))
53259243Sobrien		continue;
53359243Sobrien	    n--;
53459243Sobrien	    continue;
53559243Sobrien
53659243Sobrien	default:
53759243Sobrien	    if (!specp && l != 0)
53859243Sobrien		continue;
53959243Sobrien	    n++;
54059243Sobrien	    continue;
54159243Sobrien	}
54259243Sobrien    if (n < 0)
54359243Sobrien	n = 0;
544167465Smp    t = xcalloc(1, sizeof(*t));
545167465Smp    av = xcalloc(n + 1, sizeof(Char **));
54659243Sobrien    t->t_dcom = av;
54759243Sobrien    n = 0;
54859243Sobrien    if (p2->word[0] == ')')
54959243Sobrien	t->t_dflg = F_NOFORK;
55059243Sobrien    lp = 0;
55159243Sobrien    rp = 0;
55259243Sobrien    l = 0;
55359243Sobrien    for (p = p1; p != p2; p = p->next) {
55459243Sobrien	c = p->word[0];
55559243Sobrien	switch (c) {
55659243Sobrien
55759243Sobrien	case '(':
55859243Sobrien	    if (l == 0) {
55959243Sobrien		if (lp != 0 && !specp)
56059243Sobrien		    seterror(ERR_BADPLP);
56159243Sobrien		lp = p->next;
56259243Sobrien	    }
56359243Sobrien	    l++;
56459243Sobrien	    goto savep;
56559243Sobrien
56659243Sobrien	case ')':
56759243Sobrien	    l--;
56859243Sobrien	    if (l == 0)
56959243Sobrien		rp = p;
57059243Sobrien	    goto savep;
57159243Sobrien
57259243Sobrien	case '>':
57359243Sobrien	    if (l != 0)
57459243Sobrien		goto savep;
57559243Sobrien	    if (p->word[1] == '>')
57659243Sobrien		t->t_dflg |= F_APPEND;
57759243Sobrien	    if (p->next != p2 && eq(p->next->word, STRand)) {
57859243Sobrien		t->t_dflg |= F_STDERR, p = p->next;
57959243Sobrien		if (flags & (P_OUT | P_DIAG)) {
58059243Sobrien		    seterror(ERR_OUTRED);
58159243Sobrien		    continue;
58259243Sobrien		}
58359243Sobrien	    }
58459243Sobrien	    if (p->next != p2 && eq(p->next->word, STRbang))
58559243Sobrien		t->t_dflg |= F_OVERWRITE, p = p->next;
58659243Sobrien	    if (p->next == p2) {
58759243Sobrien		seterror(ERR_MISRED);
58859243Sobrien		continue;
58959243Sobrien	    }
59059243Sobrien	    p = p->next;
59159243Sobrien	    if (any(RELPAR, p->word[0])) {
59259243Sobrien		seterror(ERR_MISRED);
59359243Sobrien		continue;
59459243Sobrien	    }
59559243Sobrien	    if (((flags & P_OUT) && (flags & P_DIAG) == 0) || t->t_drit)
59659243Sobrien		seterror(ERR_OUTRED);
59759243Sobrien	    else
59859243Sobrien		t->t_drit = Strsave(p->word);
59959243Sobrien	    continue;
60059243Sobrien
60159243Sobrien	case '<':
60259243Sobrien	    if (l != 0)
60359243Sobrien		goto savep;
60459243Sobrien	    if (p->word[1] == '<')
60559243Sobrien		t->t_dflg |= F_READ;
60659243Sobrien	    if (p->next == p2) {
60759243Sobrien		seterror(ERR_MISRED);
60859243Sobrien		continue;
60959243Sobrien	    }
61059243Sobrien	    p = p->next;
61159243Sobrien	    if (any(RELPAR, p->word[0])) {
61259243Sobrien		seterror(ERR_MISRED);
61359243Sobrien		continue;
61459243Sobrien	    }
61559243Sobrien	    if ((flags & P_HERE) && (t->t_dflg & F_READ))
61659243Sobrien		seterror(ERR_REDPAR);
61759243Sobrien	    else if ((flags & P_IN) || t->t_dlef)
61859243Sobrien		seterror(ERR_INRED);
61959243Sobrien	    else
62059243Sobrien		t->t_dlef = Strsave(p->word);
62159243Sobrien	    continue;
62259243Sobrien
62359243Sobrien    savep:
62459243Sobrien	    if (!specp)
62559243Sobrien		continue;
62659243Sobrien	default:
62759243Sobrien	    if (l != 0 && !specp)
62859243Sobrien		continue;
62959243Sobrien	    if (seterr == 0)
63059243Sobrien		av[n] = Strsave(p->word);
63159243Sobrien	    n++;
63259243Sobrien	    continue;
63359243Sobrien	}
63459243Sobrien    }
63559243Sobrien    if (lp != 0 && !specp) {
63659243Sobrien	if (n != 0)
63759243Sobrien	    seterror(ERR_BADPLPS);
63859243Sobrien	t->t_dtyp = NODE_PAREN;
63959243Sobrien	t->t_dspr = syn0(lp, rp, P_HERE);
64059243Sobrien    }
64159243Sobrien    else {
64259243Sobrien	if (n == 0)
64359243Sobrien	    seterror(ERR_NULLCOM);
64459243Sobrien	t->t_dtyp = NODE_COMMAND;
64559243Sobrien    }
64659243Sobrien    return (t);
64759243Sobrien}
64859243Sobrien
64959243Sobrienvoid
650167465Smpfreesyn(struct command *t)
65159243Sobrien{
652145479Smp    Char **v;
65359243Sobrien
65459243Sobrien    if (t == 0)
65559243Sobrien	return;
65659243Sobrien    switch (t->t_dtyp) {
65759243Sobrien
65859243Sobrien    case NODE_COMMAND:
65959243Sobrien	for (v = t->t_dcom; *v; v++)
660167465Smp	    xfree(*v);
661167465Smp	xfree(t->t_dcom);
662167465Smp	xfree(t->t_dlef);
663167465Smp	xfree(t->t_drit);
66459243Sobrien	break;
66559243Sobrien    case NODE_PAREN:
66659243Sobrien	freesyn(t->t_dspr);
667167465Smp	xfree(t->t_dlef);
668167465Smp	xfree(t->t_drit);
66959243Sobrien	break;
67059243Sobrien
67159243Sobrien    case NODE_AND:
67259243Sobrien    case NODE_OR:
67359243Sobrien    case NODE_PIPE:
67459243Sobrien    case NODE_LIST:
67559243Sobrien	freesyn(t->t_dcar), freesyn(t->t_dcdr);
67659243Sobrien	break;
67759243Sobrien    default:
67859243Sobrien	break;
67959243Sobrien    }
680232633Smp#ifdef DEBUG
681232633Smp    memset(t, 0, sizeof(*t));
682232633Smp#endif
683167465Smp    xfree(t);
68459243Sobrien}
685167465Smp
686167465Smpvoid
687167465Smpsyntax_cleanup(void *xt)
688167465Smp{
689167465Smp    struct command *t;
690167465Smp
691167465Smp    t = xt;
692167465Smp    freesyn(t);
693167465Smp}
694