xref: /onnv-gate/usr/src/cmd/csh/sh.parse.c (revision 559:4933e3c7324c)
10Sstevel@tonic-gate /*
2356Smuffin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate 
60Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
70Sstevel@tonic-gate /*	  All Rights Reserved  	*/
80Sstevel@tonic-gate 
90Sstevel@tonic-gate /*
100Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
110Sstevel@tonic-gate  * All rights reserved. The Berkeley Software License Agreement
120Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
130Sstevel@tonic-gate  */
140Sstevel@tonic-gate 
150Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
160Sstevel@tonic-gate 
170Sstevel@tonic-gate #include "sh.h"
180Sstevel@tonic-gate #include "sh.tconst.h"
190Sstevel@tonic-gate 
200Sstevel@tonic-gate /*
210Sstevel@tonic-gate  * C shell
220Sstevel@tonic-gate  */
230Sstevel@tonic-gate 
24356Smuffin void	asyntax(struct wordent *, struct wordent *);
25356Smuffin void	asyn0(struct wordent *, struct wordent *);
26356Smuffin void	asyn3(struct wordent *, struct wordent *);
27356Smuffin void	chr_blkfree(char **);
28356Smuffin struct command	*syn0(struct wordent *, struct wordent *, int);
29356Smuffin struct command	*syn1(struct wordent *, struct wordent *, int);
30356Smuffin struct command	*syn1a(struct wordent *, struct wordent *, int);
31356Smuffin struct command	*syn1b(struct wordent *, struct wordent *, int);
32356Smuffin struct command	*syn2(struct wordent *, struct wordent *, int);
33356Smuffin struct command	*syn3(struct wordent *, struct wordent *, int);
34356Smuffin struct wordent	*freenod(struct wordent *, struct wordent *);
35356Smuffin 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * Perform aliasing on the word list lex
380Sstevel@tonic-gate  * Do a (very rudimentary) parse to separate into commands.
390Sstevel@tonic-gate  * If word 0 of a command has an alias, do it.
400Sstevel@tonic-gate  * Repeat a maximum of 20 times.
410Sstevel@tonic-gate  */
42356Smuffin void
alias(struct wordent * lex)43356Smuffin alias(struct wordent *lex)
440Sstevel@tonic-gate {
450Sstevel@tonic-gate 	int aleft = 21;
460Sstevel@tonic-gate 	jmp_buf osetexit;
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #ifdef TRACE
490Sstevel@tonic-gate 	tprintf("TRACE- alias()\n");
500Sstevel@tonic-gate #endif
510Sstevel@tonic-gate 	getexit(osetexit);
520Sstevel@tonic-gate 	setexit();
530Sstevel@tonic-gate 	if (haderr) {
540Sstevel@tonic-gate 		resexit(osetexit);
550Sstevel@tonic-gate 		reset();
560Sstevel@tonic-gate 	}
570Sstevel@tonic-gate 	if (--aleft == 0)
580Sstevel@tonic-gate 		error("Alias loop");
590Sstevel@tonic-gate 	asyntax(lex->next, lex);
600Sstevel@tonic-gate 	resexit(osetexit);
610Sstevel@tonic-gate }
620Sstevel@tonic-gate 
63356Smuffin void
asyntax(struct wordent * p1,struct wordent * p2)64356Smuffin asyntax(struct wordent *p1, struct wordent *p2)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate #ifdef TRACE
670Sstevel@tonic-gate 	tprintf("TRACE- asyntax()\n");
680Sstevel@tonic-gate #endif
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	while (p1 != p2)
710Sstevel@tonic-gate 		/* if (any(p1->word[0], ";&\n")) */  /* For char -> tchar */
720Sstevel@tonic-gate 		if (p1->word[0] == ';' ||
730Sstevel@tonic-gate 		    p1->word[0] == '&' ||
740Sstevel@tonic-gate 		    p1->word[0] == '\n')
750Sstevel@tonic-gate 			p1 = p1->next;
760Sstevel@tonic-gate 		else {
770Sstevel@tonic-gate 			asyn0(p1, p2);
780Sstevel@tonic-gate 			return;
790Sstevel@tonic-gate 		}
800Sstevel@tonic-gate }
810Sstevel@tonic-gate 
82356Smuffin void
asyn0(struct wordent * p1,struct wordent * p2)83356Smuffin asyn0(struct wordent *p1, struct wordent *p2)
840Sstevel@tonic-gate {
85356Smuffin 	struct wordent *p;
86356Smuffin 	int l = 0;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate #ifdef TRACE
890Sstevel@tonic-gate 	tprintf("TRACE- asyn0()\n");
900Sstevel@tonic-gate #endif
910Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next)
920Sstevel@tonic-gate 		switch (p->word[0]) {
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 		case '(':
950Sstevel@tonic-gate 			l++;
960Sstevel@tonic-gate 			continue;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 		case ')':
990Sstevel@tonic-gate 			l--;
1000Sstevel@tonic-gate 			if (l < 0)
1010Sstevel@tonic-gate 				error("Too many )'s");
1020Sstevel@tonic-gate 			continue;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 		case '>':
1050Sstevel@tonic-gate 			if (p->next != p2 && eq(p->next->word, S_AND /* "&"*/))
1060Sstevel@tonic-gate 				p = p->next;
1070Sstevel@tonic-gate 			continue;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 		case '&':
1100Sstevel@tonic-gate 		case '|':
1110Sstevel@tonic-gate 		case ';':
1120Sstevel@tonic-gate 		case '\n':
1130Sstevel@tonic-gate 			if (l != 0)
1140Sstevel@tonic-gate 				continue;
1150Sstevel@tonic-gate 			asyn3(p1, p);
1160Sstevel@tonic-gate 			asyntax(p->next, p2);
1170Sstevel@tonic-gate 			return;
1180Sstevel@tonic-gate 		}
1190Sstevel@tonic-gate 	if (l == 0)
1200Sstevel@tonic-gate 		asyn3(p1, p2);
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate 
123356Smuffin void
asyn3(struct wordent * p1,struct wordent * p2)124356Smuffin asyn3(struct wordent *p1, struct wordent *p2)
1250Sstevel@tonic-gate {
126356Smuffin 	struct varent *ap;
1270Sstevel@tonic-gate 	struct wordent alout;
128356Smuffin 	bool redid;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate #ifdef TRACE
1310Sstevel@tonic-gate 	tprintf("TRACE- asyn3()\n");
1320Sstevel@tonic-gate #endif
1330Sstevel@tonic-gate 	if (p1 == p2)
1340Sstevel@tonic-gate 		return;
1350Sstevel@tonic-gate 	if (p1->word[0] == '(') {
1360Sstevel@tonic-gate 		for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
1370Sstevel@tonic-gate 			if (p2 == p1)
1380Sstevel@tonic-gate 				return;
1390Sstevel@tonic-gate 		if (p2 == p1->next)
1400Sstevel@tonic-gate 			return;
1410Sstevel@tonic-gate 		asyn0(p1->next, p2);
1420Sstevel@tonic-gate 		return;
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 	ap = adrof1(p1->word, &aliases);
1450Sstevel@tonic-gate 	if (ap == 0)
1460Sstevel@tonic-gate 		return;
1470Sstevel@tonic-gate 	alhistp = p1->prev;
1480Sstevel@tonic-gate 	alhistt = p2;
1490Sstevel@tonic-gate 	alvec = ap->vec;
1500Sstevel@tonic-gate 	redid = lex(&alout);
1510Sstevel@tonic-gate 	alhistp = alhistt = 0;
1520Sstevel@tonic-gate 	alvec = 0;
1530Sstevel@tonic-gate 	if (err) {
1540Sstevel@tonic-gate 		freelex(&alout);
1550Sstevel@tonic-gate 		error("%s", gettext(err));
1560Sstevel@tonic-gate 	}
1570Sstevel@tonic-gate 	if (p1->word[0] && eq(p1->word, alout.next->word)) {
1580Sstevel@tonic-gate 		tchar *cp = alout.next->word;
1590Sstevel@tonic-gate 
160*559Snakanon 		alout.next->word = strspl(S_TOPBIT /* "\200" */, cp);
161*559Snakanon 		xfree(cp);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	p1 = freenod(p1, redid ? p2 : p1->next);
1640Sstevel@tonic-gate 	if (alout.next != &alout) {
1650Sstevel@tonic-gate 		p1->next->prev = alout.prev->prev;
1660Sstevel@tonic-gate 		alout.prev->prev->next = p1->next;
1670Sstevel@tonic-gate 		alout.next->prev = p1;
1680Sstevel@tonic-gate 		p1->next = alout.next;
169*559Snakanon 		xfree(alout.prev->word);
170*559Snakanon 		xfree(alout.prev);
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 	reset();		/* throw! */
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate struct wordent *
freenod(struct wordent * p1,struct wordent * p2)176356Smuffin freenod(struct wordent *p1, struct wordent *p2)
1770Sstevel@tonic-gate {
178356Smuffin 	struct wordent *retp = p1->prev;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate #ifdef TRACE
1810Sstevel@tonic-gate 	tprintf("TRACE- freenod()\n");
1820Sstevel@tonic-gate #endif
1830Sstevel@tonic-gate 	while (p1 != p2) {
184*559Snakanon 		xfree(p1->word);
1850Sstevel@tonic-gate 		p1 = p1->next;
186*559Snakanon 		xfree(p1->prev);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 	retp->next = p2;
1890Sstevel@tonic-gate 	p2->prev = retp;
1900Sstevel@tonic-gate 	return (retp);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate #define	PHERE	1
1940Sstevel@tonic-gate #define	PIN	2
1950Sstevel@tonic-gate #define	POUT	4
1960Sstevel@tonic-gate #define	PDIAG	8
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate  * syntax
2000Sstevel@tonic-gate  *	empty
2010Sstevel@tonic-gate  *	syn0
2020Sstevel@tonic-gate  */
2030Sstevel@tonic-gate struct command *
syntax(struct wordent * p1,struct wordent * p2,int flags)204356Smuffin syntax(struct wordent *p1, struct wordent *p2, int flags)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate #ifdef TRACE
2070Sstevel@tonic-gate 	tprintf("TRACE- syntax()\n");
2080Sstevel@tonic-gate #endif
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	while (p1 != p2)
2110Sstevel@tonic-gate 		/* if (any(p1->word[0], ";&\n")) */ /* for char -> tchar */
2120Sstevel@tonic-gate 		if (p1->word[0] == ';' ||
2130Sstevel@tonic-gate 		    p1->word[0] == '&' ||
2140Sstevel@tonic-gate 		    p1->word[0] == '\n')
2150Sstevel@tonic-gate 			p1 = p1->next;
2160Sstevel@tonic-gate 		else
2170Sstevel@tonic-gate 			return (syn0(p1, p2, flags));
2180Sstevel@tonic-gate 	return (0);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate /*
2220Sstevel@tonic-gate  * syn0
2230Sstevel@tonic-gate  *	syn1
2240Sstevel@tonic-gate  *	syn1 & syntax
2250Sstevel@tonic-gate  */
2260Sstevel@tonic-gate struct command *
syn0(struct wordent * p1,struct wordent * p2,int flags)227356Smuffin syn0(struct wordent *p1, struct wordent *p2, int flags)
2280Sstevel@tonic-gate {
229356Smuffin 	struct wordent *p;
230356Smuffin 	struct command *t, *t1;
2310Sstevel@tonic-gate 	int l;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate #ifdef TRACE
2340Sstevel@tonic-gate 	tprintf("TRACE- syn0()\n");
2350Sstevel@tonic-gate #endif
2360Sstevel@tonic-gate 	l = 0;
2370Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next)
2380Sstevel@tonic-gate 		switch (p->word[0]) {
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 		case '(':
2410Sstevel@tonic-gate 			l++;
2420Sstevel@tonic-gate 			continue;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		case ')':
2450Sstevel@tonic-gate 			l--;
2460Sstevel@tonic-gate 			if (l < 0)
2470Sstevel@tonic-gate 				seterr("Too many )'s");
2480Sstevel@tonic-gate 			continue;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 		case '|':
2510Sstevel@tonic-gate 			if (p->word[1] == '|')
2520Sstevel@tonic-gate 				continue;
2530Sstevel@tonic-gate 			/* fall into ... */
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 		case '>':
256*559Snakanon 			if (p->next != p2 && eq(p->next->word, S_AND /* "&" */))
2570Sstevel@tonic-gate 				p = p->next;
2580Sstevel@tonic-gate 			continue;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		case '&':
2610Sstevel@tonic-gate 			if (l != 0)
2620Sstevel@tonic-gate 				break;
2630Sstevel@tonic-gate 			if (p->word[1] == '&')
2640Sstevel@tonic-gate 				continue;
2650Sstevel@tonic-gate 			t1 = syn1(p1, p, flags);
2660Sstevel@tonic-gate 			if (t1->t_dtyp == TLST ||
267*559Snakanon 			    t1->t_dtyp == TAND ||
268*559Snakanon 			    t1->t_dtyp == TOR) {
269*559Snakanon 				t = (struct command *)xcalloc(1, sizeof (*t));
2700Sstevel@tonic-gate 				t->t_dtyp = TPAR;
2710Sstevel@tonic-gate 				t->t_dflg = FAND|FINT;
2720Sstevel@tonic-gate 				t->t_dspr = t1;
2730Sstevel@tonic-gate 				t1 = t;
2740Sstevel@tonic-gate 			} else
2750Sstevel@tonic-gate 				t1->t_dflg |= FAND|FINT;
276*559Snakanon 			t = (struct command *)xcalloc(1, sizeof (*t));
2770Sstevel@tonic-gate 			t->t_dtyp = TLST;
2780Sstevel@tonic-gate 			t->t_dflg = 0;
2790Sstevel@tonic-gate 			t->t_dcar = t1;
2800Sstevel@tonic-gate 			t->t_dcdr = syntax(p, p2, flags);
281*559Snakanon 			return (t);
2820Sstevel@tonic-gate 		}
2830Sstevel@tonic-gate 	if (l == 0)
2840Sstevel@tonic-gate 		return (syn1(p1, p2, flags));
2850Sstevel@tonic-gate 	seterr("Too many ('s");
2860Sstevel@tonic-gate 	return (0);
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate  * syn1
2910Sstevel@tonic-gate  *	syn1a
2920Sstevel@tonic-gate  *	syn1a ; syntax
2930Sstevel@tonic-gate  */
2940Sstevel@tonic-gate struct command *
syn1(struct wordent * p1,struct wordent * p2,int flags)295356Smuffin syn1(struct wordent *p1, struct wordent *p2, int flags)
2960Sstevel@tonic-gate {
297356Smuffin 	struct wordent *p;
298356Smuffin 	struct command *t;
2990Sstevel@tonic-gate 	int l;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate #ifdef TRACE
3020Sstevel@tonic-gate 	tprintf("TRACE- syn1()\n");
3030Sstevel@tonic-gate #endif
3040Sstevel@tonic-gate 	l = 0;
3050Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next)
3060Sstevel@tonic-gate 		switch (p->word[0]) {
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 		case '(':
3090Sstevel@tonic-gate 			l++;
3100Sstevel@tonic-gate 			continue;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 		case ')':
3130Sstevel@tonic-gate 			l--;
3140Sstevel@tonic-gate 			continue;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 		case ';':
3170Sstevel@tonic-gate 		case '\n':
3180Sstevel@tonic-gate 			if (l != 0)
3190Sstevel@tonic-gate 				break;
320*559Snakanon 			t = (struct command *)xcalloc(1, sizeof (*t));
3210Sstevel@tonic-gate 			t->t_dtyp = TLST;
3220Sstevel@tonic-gate 			t->t_dcar = syn1a(p1, p, flags);
3230Sstevel@tonic-gate 			t->t_dcdr = syntax(p->next, p2, flags);
3240Sstevel@tonic-gate 			if (t->t_dcdr == 0)
3250Sstevel@tonic-gate 				t->t_dcdr = t->t_dcar, t->t_dcar = 0;
3260Sstevel@tonic-gate 			return (t);
3270Sstevel@tonic-gate 		}
3280Sstevel@tonic-gate 	return (syn1a(p1, p2, flags));
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate /*
3320Sstevel@tonic-gate  * syn1a
3330Sstevel@tonic-gate  *	syn1b
3340Sstevel@tonic-gate  *	syn1b || syn1a
3350Sstevel@tonic-gate  */
3360Sstevel@tonic-gate struct command *
syn1a(struct wordent * p1,struct wordent * p2,int flags)337356Smuffin syn1a(struct wordent *p1, struct wordent *p2, int flags)
3380Sstevel@tonic-gate {
339356Smuffin 	struct wordent *p;
340356Smuffin 	struct command *t;
341356Smuffin 	int l = 0;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate #ifdef TRACE
3440Sstevel@tonic-gate 	tprintf("TRACE- syn1a()\n");
3450Sstevel@tonic-gate #endif
3460Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next)
3470Sstevel@tonic-gate 		switch (p->word[0]) {
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		case '(':
3500Sstevel@tonic-gate 			l++;
3510Sstevel@tonic-gate 			continue;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 		case ')':
3540Sstevel@tonic-gate 			l--;
3550Sstevel@tonic-gate 			continue;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 		case '|':
3580Sstevel@tonic-gate 			if (p->word[1] != '|')
3590Sstevel@tonic-gate 				continue;
3600Sstevel@tonic-gate 			if (l == 0) {
361*559Snakanon 				t = (struct command *)xcalloc(1, sizeof (*t));
3620Sstevel@tonic-gate 				t->t_dtyp = TOR;
3630Sstevel@tonic-gate 				t->t_dcar = syn1b(p1, p, flags);
3640Sstevel@tonic-gate 				t->t_dcdr = syn1a(p->next, p2, flags);
3650Sstevel@tonic-gate 				t->t_dflg = 0;
3660Sstevel@tonic-gate 				return (t);
3670Sstevel@tonic-gate 			}
3680Sstevel@tonic-gate 			continue;
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 	return (syn1b(p1, p2, flags));
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate  * syn1b
3750Sstevel@tonic-gate  *	syn2
3760Sstevel@tonic-gate  *	syn2 && syn1b
3770Sstevel@tonic-gate  */
3780Sstevel@tonic-gate struct command *
syn1b(struct wordent * p1,struct wordent * p2,int flags)379356Smuffin syn1b(struct wordent *p1, struct wordent *p2, int flags)
3800Sstevel@tonic-gate {
381356Smuffin 	struct wordent *p;
382356Smuffin 	struct command *t;
383356Smuffin 	int l = 0;
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate #ifdef TRACE
3860Sstevel@tonic-gate 	tprintf("TRACE- syn1b()\n");
3870Sstevel@tonic-gate #endif
3880Sstevel@tonic-gate 	l = 0;
3890Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next)
3900Sstevel@tonic-gate 		switch (p->word[0]) {
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 		case '(':
3930Sstevel@tonic-gate 			l++;
3940Sstevel@tonic-gate 			continue;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		case ')':
3970Sstevel@tonic-gate 			l--;
3980Sstevel@tonic-gate 			continue;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		case '&':
4010Sstevel@tonic-gate 			if (p->word[1] == '&' && l == 0) {
402*559Snakanon 				t = (struct command *)xcalloc(1, sizeof (*t));
4030Sstevel@tonic-gate 				t->t_dtyp = TAND;
4040Sstevel@tonic-gate 				t->t_dcar = syn2(p1, p, flags);
4050Sstevel@tonic-gate 				t->t_dcdr = syn1b(p->next, p2, flags);
4060Sstevel@tonic-gate 				t->t_dflg = 0;
4070Sstevel@tonic-gate 				return (t);
4080Sstevel@tonic-gate 			}
4090Sstevel@tonic-gate 			continue;
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 	return (syn2(p1, p2, flags));
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate /*
4150Sstevel@tonic-gate  * syn2
4160Sstevel@tonic-gate  *	syn3
4170Sstevel@tonic-gate  *	syn3 | syn2
4180Sstevel@tonic-gate  *	syn3 |& syn2
4190Sstevel@tonic-gate  */
4200Sstevel@tonic-gate struct command *
syn2(struct wordent * p1,struct wordent * p2,int flags)421356Smuffin syn2(struct wordent *p1, struct wordent *p2, int flags)
4220Sstevel@tonic-gate {
423356Smuffin 	struct wordent *p, *pn;
424356Smuffin 	struct command *t;
425356Smuffin 	int l = 0;
4260Sstevel@tonic-gate 	int f;
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate #ifdef TRACE
4290Sstevel@tonic-gate 	tprintf("TRACE- syn2()\n");
4300Sstevel@tonic-gate #endif
4310Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next)
4320Sstevel@tonic-gate 		switch (p->word[0]) {
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 		case '(':
4350Sstevel@tonic-gate 			l++;
4360Sstevel@tonic-gate 			continue;
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		case ')':
4390Sstevel@tonic-gate 			l--;
4400Sstevel@tonic-gate 			continue;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 		case '|':
4430Sstevel@tonic-gate 			if (l != 0)
4440Sstevel@tonic-gate 				continue;
445*559Snakanon 			t = (struct command *)xcalloc(1, sizeof (*t));
4460Sstevel@tonic-gate 			f = flags | POUT;
4470Sstevel@tonic-gate 			pn = p->next;
4480Sstevel@tonic-gate 			if (pn != p2 && pn->word[0] == '&') {
4490Sstevel@tonic-gate 				f |= PDIAG;
4500Sstevel@tonic-gate 				t->t_dflg |= FDIAG;
4510Sstevel@tonic-gate 			}
4520Sstevel@tonic-gate 			t->t_dtyp = TFIL;
4530Sstevel@tonic-gate 			t->t_dcar = syn3(p1, p, f);
4540Sstevel@tonic-gate 			if (pn != p2 && pn->word[0] == '&')
4550Sstevel@tonic-gate 				p = pn;
4560Sstevel@tonic-gate 			t->t_dcdr = syn2(p->next, p2, flags | PIN);
4570Sstevel@tonic-gate 			return (t);
4580Sstevel@tonic-gate 		}
4590Sstevel@tonic-gate 	return (syn3(p1, p2, flags));
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate tchar RELPAR[] = {'<', '>', '(', ')', 0};	/* "<>()" */
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate  * syn3
4660Sstevel@tonic-gate  *	( syn0 ) [ < in  ] [ > out ]
4670Sstevel@tonic-gate  *	word word* [ < in ] [ > out ]
4680Sstevel@tonic-gate  *	KEYWORD ( word* ) word* [ < in ] [ > out ]
4690Sstevel@tonic-gate  *
4700Sstevel@tonic-gate  *	KEYWORD = (@ exit foreach if set switch test while)
4710Sstevel@tonic-gate  */
4720Sstevel@tonic-gate struct command *
syn3(struct wordent * p1,struct wordent * p2,int flags)473356Smuffin syn3(struct wordent *p1, struct wordent *p2, int flags)
4740Sstevel@tonic-gate {
475356Smuffin 	struct wordent *p;
4760Sstevel@tonic-gate 	struct wordent *lp, *rp;
477356Smuffin 	struct command *t;
478356Smuffin 	int l;
4790Sstevel@tonic-gate 	tchar **av;
4800Sstevel@tonic-gate 	int n, c;
4810Sstevel@tonic-gate 	bool specp = 0;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate #ifdef TRACE
4840Sstevel@tonic-gate 	tprintf("TRACE- syn3()\n");
4850Sstevel@tonic-gate #endif
4860Sstevel@tonic-gate 	if (p1 != p2) {
4870Sstevel@tonic-gate 		p = p1;
4880Sstevel@tonic-gate again:
4890Sstevel@tonic-gate 		switch (srchx(p->word)) {
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 		case ZELSE:
4920Sstevel@tonic-gate 			p = p->next;
4930Sstevel@tonic-gate 			if (p != p2)
4940Sstevel@tonic-gate 				goto again;
4950Sstevel@tonic-gate 			break;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 		case ZEXIT:
4980Sstevel@tonic-gate 		case ZFOREACH:
4990Sstevel@tonic-gate 		case ZIF:
5000Sstevel@tonic-gate 		case ZLET:
5010Sstevel@tonic-gate 		case ZSET:
5020Sstevel@tonic-gate 		case ZSWITCH:
5030Sstevel@tonic-gate 		case ZWHILE:
5040Sstevel@tonic-gate 			specp = 1;
5050Sstevel@tonic-gate 			break;
5060Sstevel@tonic-gate 		}
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 	n = 0;
5090Sstevel@tonic-gate 	l = 0;
5100Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next)
5110Sstevel@tonic-gate 		switch (p->word[0]) {
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		case '(':
5140Sstevel@tonic-gate 			if (specp)
5150Sstevel@tonic-gate 				n++;
5160Sstevel@tonic-gate 			l++;
5170Sstevel@tonic-gate 			continue;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		case ')':
5200Sstevel@tonic-gate 			if (specp)
5210Sstevel@tonic-gate 				n++;
5220Sstevel@tonic-gate 			l--;
5230Sstevel@tonic-gate 			continue;
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		case '>':
5260Sstevel@tonic-gate 		case '<':
5270Sstevel@tonic-gate 			if (l != 0) {
5280Sstevel@tonic-gate 				if (specp)
5290Sstevel@tonic-gate 					n++;
5300Sstevel@tonic-gate 				continue;
5310Sstevel@tonic-gate 			}
5320Sstevel@tonic-gate 			if (p->next == p2)
5330Sstevel@tonic-gate 				continue;
5340Sstevel@tonic-gate 			if (any(p->next->word[0], RELPAR))
5350Sstevel@tonic-gate 				continue;
5360Sstevel@tonic-gate 			n--;
5370Sstevel@tonic-gate 			continue;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 		default:
5400Sstevel@tonic-gate 			if (!specp && l != 0)
5410Sstevel@tonic-gate 				continue;
5420Sstevel@tonic-gate 			n++;
5430Sstevel@tonic-gate 			continue;
5440Sstevel@tonic-gate 		}
5450Sstevel@tonic-gate 	if (n < 0)
5460Sstevel@tonic-gate 		n = 0;
547*559Snakanon 	t = (struct command *)xcalloc(1, sizeof (*t));
548*559Snakanon 	av =  (tchar **)xcalloc((unsigned)(n + 1), sizeof (tchar **));
5490Sstevel@tonic-gate 	t->t_dcom = av;
5500Sstevel@tonic-gate 	n = 0;
5510Sstevel@tonic-gate 	if (p2->word[0] == ')')
5520Sstevel@tonic-gate 		t->t_dflg = FPAR;
5530Sstevel@tonic-gate 	lp = 0;
5540Sstevel@tonic-gate 	rp = 0;
5550Sstevel@tonic-gate 	l = 0;
5560Sstevel@tonic-gate 	for (p = p1; p != p2; p = p->next) {
5570Sstevel@tonic-gate 		c = p->word[0];
5580Sstevel@tonic-gate 		switch (c) {
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 		case '(':
5610Sstevel@tonic-gate 			if (l == 0) {
5620Sstevel@tonic-gate 				if (lp != 0 && !specp)
5630Sstevel@tonic-gate 					seterr("Badly placed (");
5640Sstevel@tonic-gate 				lp = p->next;
5650Sstevel@tonic-gate 			}
5660Sstevel@tonic-gate 			l++;
5670Sstevel@tonic-gate 			goto savep;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 		case ')':
5700Sstevel@tonic-gate 			l--;
5710Sstevel@tonic-gate 			if (l == 0)
5720Sstevel@tonic-gate 				rp = p;
5730Sstevel@tonic-gate 			goto savep;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 		case '>':
5760Sstevel@tonic-gate 			if (l != 0)
5770Sstevel@tonic-gate 				goto savep;
5780Sstevel@tonic-gate 			if (p->word[1] == '>')
5790Sstevel@tonic-gate 				t->t_dflg |= FCAT;
580*559Snakanon 			if (p->next != p2 && eq(p->next->word, S_AND /* "&" */)) {
5810Sstevel@tonic-gate 				t->t_dflg |= FDIAG, p = p->next;
5820Sstevel@tonic-gate 				if (flags & (POUT|PDIAG))
5830Sstevel@tonic-gate 					goto badout;
5840Sstevel@tonic-gate 			}
585*559Snakanon 			if (p->next != p2 && eq(p->next->word, S_EXAS /* "!" */))
5860Sstevel@tonic-gate 				t->t_dflg |= FANY, p = p->next;
5870Sstevel@tonic-gate 			if (p->next == p2) {
5880Sstevel@tonic-gate missfile:
5890Sstevel@tonic-gate 				seterr("Missing name for redirect");
5900Sstevel@tonic-gate 				continue;
5910Sstevel@tonic-gate 			}
5920Sstevel@tonic-gate 			p = p->next;
5930Sstevel@tonic-gate 			if (any(p->word[0], RELPAR))
5940Sstevel@tonic-gate 				goto missfile;
5950Sstevel@tonic-gate 			if ((flags & POUT) && (flags & PDIAG) == 0 || t->t_drit)
5960Sstevel@tonic-gate badout:
5970Sstevel@tonic-gate 				seterr("Ambiguous output redirect");
5980Sstevel@tonic-gate 			else
5990Sstevel@tonic-gate 				t->t_drit = savestr(p->word);
6000Sstevel@tonic-gate 			continue;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 		case '<':
6030Sstevel@tonic-gate 			if (l != 0)
6040Sstevel@tonic-gate 				goto savep;
6050Sstevel@tonic-gate 			if (p->word[1] == '<')
6060Sstevel@tonic-gate 				t->t_dflg |= FHERE;
6070Sstevel@tonic-gate 			if (p->next == p2)
6080Sstevel@tonic-gate 				goto missfile;
6090Sstevel@tonic-gate 			p = p->next;
6100Sstevel@tonic-gate 			if (any(p->word[0], RELPAR))
6110Sstevel@tonic-gate 				goto missfile;
6120Sstevel@tonic-gate 			if ((flags & PHERE) && (t->t_dflg & FHERE))
6130Sstevel@tonic-gate 				seterr("Can't << within ()'s");
6140Sstevel@tonic-gate 			else if ((flags & PIN) || t->t_dlef)
6150Sstevel@tonic-gate 				seterr("Ambiguous input redirect");
6160Sstevel@tonic-gate 			else
6170Sstevel@tonic-gate 				t->t_dlef = savestr(p->word);
6180Sstevel@tonic-gate 			continue;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate savep:
6210Sstevel@tonic-gate 			if (!specp)
6220Sstevel@tonic-gate 				continue;
6230Sstevel@tonic-gate 		default:
6240Sstevel@tonic-gate 			if (l != 0 && !specp)
6250Sstevel@tonic-gate 				continue;
6260Sstevel@tonic-gate 			if (err == 0)
6270Sstevel@tonic-gate 				av[n] = savestr(p->word);
6280Sstevel@tonic-gate 			n++;
6290Sstevel@tonic-gate 			continue;
6300Sstevel@tonic-gate 		}
6310Sstevel@tonic-gate 	}
6320Sstevel@tonic-gate 	if (lp != 0 && !specp) {
6330Sstevel@tonic-gate 		if (n != 0)
6340Sstevel@tonic-gate 			seterr("Badly placed ()'s");
6350Sstevel@tonic-gate 		t->t_dtyp = TPAR;
6360Sstevel@tonic-gate 		t->t_dspr = syn0(lp, rp, PHERE);
6370Sstevel@tonic-gate 	} else {
6380Sstevel@tonic-gate 		if (n == 0)
6390Sstevel@tonic-gate 			seterr("Invalid null command");
6400Sstevel@tonic-gate 		t->t_dtyp = TCOM;
6410Sstevel@tonic-gate 	}
6420Sstevel@tonic-gate 	return (t);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
645356Smuffin void
freesyn(struct command * t)646356Smuffin freesyn(struct command *t)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate #ifdef TRACE
6490Sstevel@tonic-gate 	tprintf("TRACE- freesyn()\n");
6500Sstevel@tonic-gate #endif
6510Sstevel@tonic-gate 	if (t == 0)
6520Sstevel@tonic-gate 		return;
6530Sstevel@tonic-gate 	switch (t->t_dtyp) {
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	case TCOM:
6560Sstevel@tonic-gate 		blkfree(t->t_dcom);
6570Sstevel@tonic-gate 		if (t->cfname)
6580Sstevel@tonic-gate 			xfree(t->cfname);
6590Sstevel@tonic-gate 		if (t->cargs)
6600Sstevel@tonic-gate 			chr_blkfree(t->cargs);
6610Sstevel@tonic-gate 		goto lr;
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	case TPAR:
6640Sstevel@tonic-gate 		freesyn(t->t_dspr);
6650Sstevel@tonic-gate 		/* fall into ... */
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate lr:
668*559Snakanon 		xfree(t->t_dlef);
669*559Snakanon 		xfree(t->t_drit);
6700Sstevel@tonic-gate 		break;
6710Sstevel@tonic-gate 
6720Sstevel@tonic-gate 	case TAND:
6730Sstevel@tonic-gate 	case TOR:
6740Sstevel@tonic-gate 	case TFIL:
6750Sstevel@tonic-gate 	case TLST:
6760Sstevel@tonic-gate 		freesyn(t->t_dcar), freesyn(t->t_dcdr);
6770Sstevel@tonic-gate 		break;
6780Sstevel@tonic-gate 	}
679*559Snakanon 	xfree(t);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 
683356Smuffin void
chr_blkfree(char ** vec)684356Smuffin chr_blkfree(char **vec)
6850Sstevel@tonic-gate {
686356Smuffin 	char **av;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	for (av = vec; *av; av++)
6890Sstevel@tonic-gate 		xfree(*av);
6900Sstevel@tonic-gate 	xfree(vec);
6910Sstevel@tonic-gate }
692