1811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser/*	$OpenBSD: syn.c,v 1.29 2013/06/03 18:40:05 jca Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
5811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser *		 2011, 2012, 2013
65155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	Thorsten Glaser <tg@mirbsd.org>
75155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
85155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices
95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission
105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un-
115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify,
125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence.
135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor
165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event
175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect,
185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out
195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such
205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out
215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended.
225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h"
255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.92 2013/06/03 22:28:17 tg Exp $");
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct nesting_state {
295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int start_token;	/* token than began nesting (eg, FOR) */
305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int start_line;		/* line nesting began on */
315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
33c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstruct yyrecursive_state {
34c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct yyrecursive_state *next;
35c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct ioword **old_herep;
36c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int old_symbol;
37c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int old_salias;
38c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int old_nesting_type;
39c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bool old_reject;
40c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
41c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void yyparse(void);
435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *pipeline(int);
445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *andor(void);
4503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic struct op *c_list(bool);
465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct ioword *synio(int);
475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *nested(int, int, int);
485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *get_command(int);
495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *dogroup(void);
505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *thenpart(void);
515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *elsepart(void);
525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *caselist(void);
535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *casepart(int);
545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *function_body(char *, bool);
555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char **wordlist(void);
56811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserstatic struct op *block(int, struct op *, struct op *);
575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *newtp(int);
585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void syntaxerr(const char *) MKSH_A_NORETURN;
595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void nesting_push(struct nesting_state *, int);
605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void nesting_pop(struct nesting_state *);
61c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int assign_command(const char *);
625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int inalias(struct source *);
635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic Test_op dbtestp_isa(Test_env *, Test_meta);
645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *dbtestp_getopnd(Test_env *, Test_op, bool);
655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int dbtestp_eval(Test_env *, Test_op, const char *,
665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    const char *, bool);
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void dbtestp_error(Test_env *, int, const char *) MKSH_A_NORETURN;
685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *outtree;		/* yyparse output */
705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct nesting_state nesting;	/* \n changed to ; */
715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic bool reject;			/* token(cf) gets symbol again */
7303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int symbol;			/* yylex value */
74c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic int sALIAS = ALIAS;		/* 0 in yyrecursive */
755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define REJECT		(reject = true)
7703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define ACCEPT		(reject = false)
785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define token(cf)	((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define tpeek(cf)	((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
8003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define musthave(c,cf)	do { if (token(cf) != (c)) syntaxerr(NULL); } while (/* CONSTCOND */ 0)
815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
82c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char Tcbrace[] = "}";
83c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char Tesac[] = "esac";
84c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruyyparse(void)
875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ACCEPT;
915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	outtree = c_list(source->type == SSTRING);
935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	c = tpeek(0);
945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == 0 && !outtree)
955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		outtree = newtp(TEOF);
965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (c != '\n' && c != 0)
975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
1015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querupipeline(int cf)
1025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t, *p, *tl = NULL;
1045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = get_command(cf);
1065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t != NULL) {
1075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (token(0) == '|') {
1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((p = get_command(CONTIN)) == NULL)
1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				syntaxerr(NULL);
1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tl == NULL)
111811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				t = tl = block(TPIPE, t, p);
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else
113811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				tl = tl->right = block(TPIPE, tl->right, p);
1145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
1185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
1215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruandor(void)
1225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t, *p;
1245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
1255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = pipeline(0);
1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t != NULL) {
1285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while ((c = token(0)) == LOGAND || c == LOGOR) {
1295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((p = pipeline(CONTIN)) == NULL)
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				syntaxerr(NULL);
131811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			t = block(c == LOGAND? TAND: TOR, t, p);
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
13903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrac_list(bool multi)
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t = NULL, *p, *tl = NULL;
14203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int c;
14303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool have_sep;
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (/* CONSTCOND */ 1) {
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p = andor();
14703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
14803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Token has always been read/rejected at this point, so
1495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * we don't worry about what flags to pass token()
1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = token(0);
15203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		have_sep = true;
1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c == '\n' && (multi || inalias(source))) {
15403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!p)
15503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* ignore blank lines */
1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
1575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (!p)
1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
1595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (c == '&' || c == COPROC)
160811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			p = block(c == '&' ? TASYNC : TCOPROC, p, NULL);
1615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (c != ';')
16203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			have_sep = false;
1635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!t)
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = p;
1655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (!tl)
166811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			t = tl = block(TLIST, t, p);
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
168811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			tl = tl->right = block(TLIST, tl->right, p);
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!have_sep)
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	REJECT;
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct ioword *
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusynio(int cf)
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword *iop;
18003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	static struct ioword *nextiop;
1815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool ishere;
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (nextiop != NULL) {
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop = nextiop;
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop = NULL;
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (iop);
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (tpeek(cf) != REDIR)
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
1915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ACCEPT;
1925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	iop = yylval.iop;
19303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (iop->flag & IONDELIM)
19403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto gotnulldelim;
19503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ishere = (iop->flag & IOTYPE) == IOHERE;
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	musthave(LWORD, ishere ? HEREDELIM : 0);
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ishere) {
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop->delim = yylval.cp;
19903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (*ident != 0)
20003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* unquoted */
20103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra gotnulldelim:
2025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			iop->flag |= IOEVAL;
2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (herep > &heres[HERES - 1])
20403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("too many %ss\n", "<<");
2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*herep++ = iop;
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop->name = yylval.cp;
2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (iop->flag & IOBASH) {
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *cp;
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop = alloc(sizeof(*iop), ATEMP);
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->name = cp = alloc(5, ATEMP);
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (iop->unit > 9) {
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cp++ = CHAR;
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cp++ = '0' + (iop->unit / 10);
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cp++ = CHAR;
2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cp++ = '0' + (iop->unit % 10);
2215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cp = EOS;
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop->flag &= ~IOBASH;
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->unit = 2;
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->flag = IODUP;
2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->delim = NULL;
2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->heredoc = NULL;
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (iop);
2305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunested(int type, int smark, int emark)
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct nesting_state old_nesting;
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting_push(&old_nesting, smark);
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = c_list(true);
240c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(emark, KEYWORD|sALIAS);
2415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting_pop(&old_nesting);
242811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	return (block(type, t, NULL));
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
245c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char let_cmd[] = {
246811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	CHAR, 'l', CHAR, 'e', CHAR, 't', CHAR, ']', EOS
247c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
248c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char setA_cmd0[] = {
249c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	CHAR, 's', CHAR, 'e', CHAR, 't', EOS
250c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
251c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char setA_cmd1[] = {
252c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	CHAR, '-', CHAR, 'A', EOS
253c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
254c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char setA_cmd2[] = {
255c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	CHAR, '-', CHAR, '-', EOS
256c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
257c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruget_command(int cf)
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
262c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int c, iopn = 0, syniocf, lno;
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword *iop, **iops;
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV args, vars;
265c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	char *tcp;
2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct nesting_state old_nesting;
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* NUFILE is small enough to leave this addition unchecked */
26903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	iops = alloc2((NUFILE + 1), sizeof(struct ioword *), ATEMP);
2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(args, 16);
2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(vars, 16);
2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
273c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	syniocf = KEYWORD|sALIAS;
274c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	switch (c = token(cf|KEYWORD|sALIAS|VARASN)) {
2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(iops, ATEMP);
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(args);
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(vars);
28003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* empty line */
28103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (NULL);
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case LWORD:
2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case REDIR:
2855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
286c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		syniocf &= ~(KEYWORD|sALIAS);
2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TCOM);
2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->lineno = source->line;
28903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (/* CONSTCOND */ 1) {
2905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cf = (t->u.evalflags ? ARRAYVAR : 0) |
291c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    (XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD);
2925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			switch (tpeek(cf)) {
2935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case REDIR:
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				while ((iop = synio(cf)) != NULL) {
2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (iopn >= NUFILE)
29603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						yyerror("too many %ss\n",
29703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						    "redirection");
2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					iops[iopn++] = iop;
2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
3005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case LWORD:
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				ACCEPT;
30403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
30503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * the iopn == 0 and XPsize(vars) == 0 are
3065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * dubious but AT&T ksh acts this way
3075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 */
3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (iopn == 0 && XPsize(vars) == 0 &&
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    XPsize(args) == 0 &&
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    assign_command(ident))
3115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					t->u.evalflags = DOVACHECK;
3125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    is_wdvarassign(yylval.cp))
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					XPput(vars, yylval.cp);
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					XPput(args, yylval.cp);
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
319c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '(' /*)*/:
320c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (XPsize(args) == 0 && XPsize(vars) == 1 &&
321c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    is_wdvarassign(yylval.cp)) {
322c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* wdarrassign: foo=(bar) */
3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					ACCEPT;
32403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
325c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* manipulate the vars string */
326c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					tcp = XPptrv(vars)[(vars.len = 0)];
327c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* 'varname=' -> 'varname' */
328c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
329c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
330c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* construct new args strings */
331c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, wdcopy(setA_cmd0, ATEMP));
332c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, wdcopy(setA_cmd1, ATEMP));
333c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, tcp);
334c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, wdcopy(setA_cmd2, ATEMP));
335c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
336c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* slurp in words till closing paren */
337c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					while (token(CONTIN) == LWORD)
338c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						XPput(args, yylval.cp);
339c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					if (symbol != /*(*/ ')')
340c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						syntaxerr(NULL);
341c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				} else {
342c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/*
343c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 * Check for "> foo (echo hi)"
344c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 * which AT&T ksh allows (not
345c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 * POSIX, but not disallowed)
346c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 */
347c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					afree(t, ATEMP);
348c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					if (XPsize(args) == 0 &&
349c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					    XPsize(vars) == 0) {
350c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						ACCEPT;
351c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						goto Subshell;
352c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					}
353c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
354c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* must be a function */
355c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					if (iopn != 0 || XPsize(args) != 1 ||
356c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					    XPsize(vars) != 0)
357c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						syntaxerr(NULL);
358c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					ACCEPT;
359c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					musthave(/*(*/')', 0);
360c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					t = function_body(XPptrv(args)[0], false);
361c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				}
36203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				goto Leave;
3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			default:
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Leave;
3665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Leave:
3695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
371c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case '(': /*)*/ {
372c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		int subshell_nesting_type_saved;
3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Subshell:
374c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		subshell_nesting_type_saved = subshell_nesting_type;
375c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		subshell_nesting_type = ')';
3765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = nested(TPAREN, '(', ')');
377c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		subshell_nesting_type = subshell_nesting_type_saved;
3785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
379c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    }
3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '{': /*}*/
3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = nested(TBRACE, '{', '}');
3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
385c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case MDPAREN:
38603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
3875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		lno = source->line;
3885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ACCEPT;
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (token(LETEXPR)) {
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LWORD:
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
39203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case '(': /*)*/
3935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto Subshell;
3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			syntaxerr(NULL);
3965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TCOM);
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->lineno = lno;
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, wdcopy(let_cmd, ATEMP));
4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, yylval.cp);
4015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case DBRACKET: /* [[ .. ]] */
40403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
4055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TDBRACKET);
4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ACCEPT;
4075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		{
4085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			Test_env te;
4095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.flags = TEF_DBRACKET;
4115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.pos.av = &args;
4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.isa = dbtestp_isa;
4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.getopnd = dbtestp_getopnd;
4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.eval = dbtestp_eval;
4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.error = dbtestp_error;
4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			test_parse(&te);
4185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case FOR:
4225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case SELECT:
4235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp((c == FOR) ? TFOR : TSELECT);
4245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		musthave(LWORD, ARRAYVAR);
4255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!is_wdvarname(yylval.cp, true))
42603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("%s: %s\n", c == FOR ? "for" : Tselect,
42703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "bad identifier");
4285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strdupx(t->str, ident, ATEMP);
4295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->vars = wordlist();
4315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = dogroup();
4325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case WHILE:
4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case UNTIL:
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp((c == WHILE) ? TWHILE : TUNTIL);
4395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = c_list(true);
4405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->right = dogroup();
4415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case CASE:
4455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TCASE);
4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		musthave(LWORD, 0);
4475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->str = yylval.cp;
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = caselist();
4505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IF:
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TIF);
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = c_list(true);
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->right = thenpart();
458c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		musthave(FI, KEYWORD|sALIAS);
4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case BANG:
463c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		syniocf &= ~(KEYWORD|sALIAS);
4645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = pipeline(0);
4655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (t == NULL)
4665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			syntaxerr(NULL);
467811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		t = block(TBANG, NULL, t);
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TIME:
471c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		syniocf &= ~(KEYWORD|sALIAS);
4725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = pipeline(0);
473c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (t && t->type == TCOM) {
4745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t->str = alloc(2, ATEMP);
47503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* TF_* flags */
47603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			t->str[0] = '\0';
4775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t->str[1] = '\0';
4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
479811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		t = block(TTIME, t, NULL);
4805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case FUNCTION:
4835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		musthave(LWORD, 0);
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = function_body(yylval.cp, true);
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((iop = synio(syniocf)) != NULL) {
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (iopn >= NUFILE)
49003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("too many %ss\n", "redirection");
4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iops[iopn++] = iop;
4925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (iopn == 0) {
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(iops, ATEMP);
4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->ioact = NULL;
4975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iops[iopn++] = NULL;
49903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		iops = aresize2(iops, iopn, sizeof(struct ioword *), ATEMP);
5005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->ioact = iops;
5015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->type == TCOM || t->type == TDBRACKET) {
5045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, NULL);
5055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->args = (const char **)XPclose(args);
5065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(vars, NULL);
507811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		t->vars = (char **)XPclose(vars);
5085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
5095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(args);
5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(vars);
5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
5145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudogroup(void)
5185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
5205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *list;
5215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
522c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	c = token(CONTIN|KEYWORD|sALIAS);
52303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
52403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * A {...} can be used instead of do...done for for/select loops
5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * but not for while/until loops - we don't need to check if it
5265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * is a while loop because it would have been parsed as part of
5275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * the conditional command list...
5285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
5295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == DO)
5305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = DONE;
5315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (c == '{')
5325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = '}';
5335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
5345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
5355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	list = c_list(true);
536c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(c, KEYWORD|sALIAS);
5375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (list);
5385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruthenpart(void)
5425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
5445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
545c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(THEN, KEYWORD|sALIAS);
5465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(0);
5475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = c_list(true);
5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->left == NULL)
5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->right = elsepart();
5515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
5525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruelsepart(void)
5565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
5585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
559c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	switch (token(KEYWORD|sALIAS|VARASN)) {
5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case ELSE:
5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((t = c_list(true)) == NULL)
5625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			syntaxerr(NULL);
5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (t);
5645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case ELIF:
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TELIF);
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = c_list(true);
5685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->right = thenpart();
5695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (t);
5705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
5725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (NULL);
5755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querucaselist(void)
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t, *tl;
5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
583c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	c = token(CONTIN|KEYWORD|sALIAS);
5845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* A {...} can be used instead of in...esac for case statements */
5855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == IN)
5865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = ESAC;
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (c == '{')
5885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = '}';
5895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
5905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
5915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = tl = NULL;
59203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* no ALIAS here */
59303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) {
5945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct op *tc = casepart(c);
5955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tl == NULL)
5965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = tl = tc, tl->right = NULL;
5975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
5985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tl->right = tc, tl = tc;
5995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
600c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(c, KEYWORD|sALIAS);
6015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
6025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
6055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querucasepart(int endtok)
6065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV ptns;
6095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(ptns, 16);
6115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(TPAT);
6125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* no ALIAS here */
6135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (token(CONTIN | KEYWORD) != '(')
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
6155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	do {
616c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		switch (token(0)) {
617c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case LWORD:
618c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			break;
619c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case '}':
620c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case ESAC:
621c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (symbol != endtok) {
622c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				strdupx(yylval.cp,
623c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    symbol == '}' ? Tcbrace : Tesac, ATEMP);
624c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				break;
625c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
626c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* FALLTHROUGH */
627c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		default:
628c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			syntaxerr(NULL);
629c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
6305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(ptns, yylval.cp);
6315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} while (token(0) == '|');
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	REJECT;
6335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPput(ptns, NULL);
634811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	t->vars = (char **)XPclose(ptns);
6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	musthave(')', 0);
6365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = c_list(true);
638c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
639c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* initialise to default for ;; or omitted */
640c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	t->u.charflag = ';';
641c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* SUSv4 requires the ;; except in the last casepart */
642c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if ((tpeek(CONTIN|KEYWORD|sALIAS)) != endtok)
64303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		switch (symbol) {
64403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		default:
64503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			syntaxerr(NULL);
64603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case BRKEV:
647c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			t->u.charflag = '|';
648c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (0)
649c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/* FALLTHROUGH */
65003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case BRKFT:
651c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			t->u.charflag = '&';
652c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* FALLTHROUGH */
653c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case BREAK:
654c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* initialised above, but we need to eat the token */
65503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ACCEPT;
65603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
6585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
6615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querufunction_body(char *name,
66203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* function foo { ... } vs foo() { .. } */
66303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    bool ksh_func)
6645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *sname, *p;
6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
6675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
66803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	sname = wdstrip(name, 0);
66903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*-
67003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Check for valid characters in name. POSIX and AT&T ksh93 say
67103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * only allow [a-zA-Z_0-9] but this allows more as old pdkshs
67203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * have allowed more; the following were never allowed:
6735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	NUL TAB NL SP " $ & ' ( ) ; < = > \ ` |
6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * C_QUOTE covers all but adds # * ? [ ]
6755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
6765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = sname; *p; p++)
6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ctype(*p, C_QUOTE))
67803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("%s: %s\n", sname, "invalid function name");
6795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
68003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
68103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Note that POSIX allows only compound statements after foo(),
68203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * sh and AT&T ksh allow any command, go with the later since it
68303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * shouldn't break anything. However, for function foo, AT&T ksh
68403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * only accepts an open-brace.
6855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ksh_func) {
687c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (tpeek(CONTIN|KEYWORD|sALIAS) == '(' /*)*/) {
688c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* function foo () { //}*/
6895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ACCEPT;
6905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			musthave(')', 0);
6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* degrade to POSIX function */
6925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_func = false;
6935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
694c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		musthave('{' /*}*/, CONTIN|KEYWORD|sALIAS);
6955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
6965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(TFUNCT);
6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->str = sname;
70003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	t->u.ksh_func = tobool(ksh_func);
7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->lineno = source->line;
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((t->left = get_command(CONTIN)) == NULL) {
7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *tv;
7055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
70603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Probably something like foo() followed by EOF or ';'.
7075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * This is accepted by sh and ksh88.
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * To make "typeset -f foo" work reliably (so its output can
7095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * be used as input), we pretend there is a colon here.
7105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = newtp(TCOM);
71203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* (2 * sizeof(char *)) is small enough */
7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->args = alloc(2 * sizeof(char *), ATEMP);
7145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->args[0] = tv = alloc(3, ATEMP);
7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tv[0] = CHAR;
7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tv[1] = ':';
7175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tv[2] = EOS;
7185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->args[1] = NULL;
7195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->vars = alloc(sizeof(char *), ATEMP);
7205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->vars[0] = NULL;
7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->lineno = 1;
7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
7255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char **
7285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruwordlist(void)
7295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV args;
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(args, 16);
7345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* POSIX does not do alias expansion here... */
735c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if ((c = token(CONTIN|KEYWORD|sALIAS)) != IN) {
73603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (c != ';')
73703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* non-POSIX, but AT&T ksh accepts a ; here */
7385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			REJECT;
7395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
7405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((c = token(0)) == LWORD)
7425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, yylval.cp);
7435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c != '\n' && c != ';')
7445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
745811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	XPput(args, NULL);
746811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	return ((char **)XPclose(args));
7475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
7505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * supporting functions
7515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
7525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
754811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserblock(int type, struct op *t1, struct op *t2)
7555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(type);
7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = t1;
7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->right = t2;
7615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
7625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
764c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const struct tokeninfo {
7655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *name;
7665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	short val;
7675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	short reserved;
7685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} tokentab[] = {
7695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Reserved words */
7705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "if",		IF,	true },
7715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "then",	THEN,	true },
7725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "else",	ELSE,	true },
7735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "elif",	ELIF,	true },
7745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "fi",		FI,	true },
7755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "case",	CASE,	true },
776c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	{ Tesac,	ESAC,	true },
7775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "for",	FOR,	true },
77803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ Tselect,	SELECT,	true },
7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "while",	WHILE,	true },
7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "until",	UNTIL,	true },
7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "do",		DO,	true },
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "done",	DONE,	true },
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "in",		IN,	true },
78403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ Tfunction,	FUNCTION, true },
7855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "time",	TIME,	true },
7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "{",		'{',	true },
787c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	{ Tcbrace,	'}',	true },
7885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "!",		BANG,	true },
7895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "[[",		DBRACKET, true },
7905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
7915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "&&",		LOGAND,	false },
7925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "||",		LOGOR,	false },
7935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ ";;",		BREAK,	false },
79403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ ";|",		BRKEV,	false },
79503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ ";&",		BRKFT,	false },
7965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "((",		MDPAREN, false },
7975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "|&",		COPROC,	false },
7985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* and some special cases... */
7995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "newline",	'\n',	false },
8005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ NULL,		0,	false }
8015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
8025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
8045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinitkeywords(void)
8055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tokeninfo const *tt;
8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *p;
8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
80903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ktinit(APERM, &keywords,
810c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    /* currently 28 keywords: 75% of 64 = 2^6 */
81103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    6);
8125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (tt = tokentab; tt->name; tt++) {
8135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tt->reserved) {
8145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = ktenter(&keywords, tt->name, hash(tt->name));
8155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->flag |= DEFINED|ISSET;
8165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->type = CKEYWD;
8175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->val.i = tt->val;
8185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
8235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusyntaxerr(const char *what)
8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
82503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* 2<<- is the longest redirection, I think */
82603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char redir[6];
8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *s;
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tokeninfo const *tt;
8295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!what)
8325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		what = "unexpected";
8335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	REJECT;
8345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	c = token(0);
8355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Again:
8365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (c) {
8375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 0:
8385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (nesting.start_token) {
8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = nesting.start_token;
8405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			source->errline = nesting.start_line;
8415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			what = "unmatched";
8425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto Again;
8435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* don't quote the EOF */
84503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		yyerror("%s: %s %s\n", Tsynerr, "unexpected", "EOF");
8465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* NOTREACHED */
8475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case LWORD:
8495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = snptreef(NULL, 32, "%S", yylval.cp);
8505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
8515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case REDIR:
8535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
8545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
8555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
8575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (tt = tokentab; tt->name; tt++)
8585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tt->val == c)
8595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    break;
8605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tt->name)
8615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = tt->name;
8625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else {
8635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (c > 0 && c < 256) {
8645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				redir[0] = c;
8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				redir[1] = '\0';
8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
8675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_snprintf(redir, sizeof(redir),
8685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					"?%d", c);
8695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = redir;
8705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
87203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	yyerror("%s: '%s' %s\n", Tsynerr, s, what);
8735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
8765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunesting_push(struct nesting_state *save, int tok)
8775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*save = nesting;
8795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_token = tok;
8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_line = source->line;
8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunesting_pop(struct nesting_state *saved)
8855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting = *saved;
8875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
8905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunewtp(int type)
8915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
8935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = alloc(sizeof(struct op), ATEMP);
8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->type = type;
8965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->u.evalflags = 0;
8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->args = NULL;
8985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->vars = NULL;
8995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->ioact = NULL;
9005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = t->right = NULL;
9015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->str = NULL;
9025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
9035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct op *
90603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condracompile(Source *s, bool skiputf8bom)
9075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_token = 0;
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_line = 0;
9105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	herep = heres;
9115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	source = s;
91203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (skiputf8bom)
91303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		yyskiputf8bom();
9145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	yyparse();
9155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (outtree);
9165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
91803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*-
91903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * This kludge exists to take care of sh/AT&T ksh oddity in which
9205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the arguments of alias/export/readonly/typeset have no field
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * splitting, file globbing, or (normal) tilde expansion done.
9225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * AT&T ksh seems to do something similar to this since
9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	$ touch a=a; typeset a=[ab]; echo "$a"
9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	a=[ab]
9255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	$ x=typeset; $x a=[ab]; echo "$a"
9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	a=a
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	$
9285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
930c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserassign_command(const char *s)
9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!*s)
9335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
93403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return ((strcmp(s, Talias) == 0) ||
935c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    (strcmp(s, Texport) == 0) ||
936c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    (strcmp(s, Treadonly) == 0) ||
93703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    (strcmp(s, Ttypeset) == 0));
9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Check if we are in the middle of reading an alias */
9415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
9425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinalias(struct source *s)
9435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (; s && s->type == SALIAS; s = s->next)
9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(s->flags & SF_ALIASEND))
9465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
95103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
95203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Order important - indexed by Test_meta values
9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Note that ||, &&, ( and ) can't appear in as unquoted strings
9545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * in normal shell input, so these can be interpreted unambiguously
9555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * in the evaluation pass.
9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
9585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
9595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_not[] = { CHAR, '!', EOS };
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_oparen[] = { CHAR, '(', EOS };
9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_cparen[] = { CHAR, ')', EOS };
962c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserconst char * const dbtest_tokens[] = {
9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	dbtest_or, dbtest_and, dbtest_not,
9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	dbtest_oparen, dbtest_cparen
9655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
966c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
967c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char db_lthan[] = { CHAR, '<', EOS };
968c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char db_gthan[] = { CHAR, '>', EOS };
9695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Test if the current token is a whatever. Accepts the current token if
9725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * it is. Returns 0 if it is not, non-zero if it is (in the case of
9735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * TM_UNOP and TM_BINOP, the returned value is a Test_op).
9745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic Test_op
9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_isa(Test_env *te, Test_meta meta)
9775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int uqword;
9805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *save = NULL;
9815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Test_op ret = TO_NONOP;
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* unquoted word? */
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uqword = c == LWORD && *ident;
9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (meta == TM_OR)
9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == LOGOR ? TO_NONNULL : TO_NONOP;
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_AND)
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == LOGAND ? TO_NONNULL : TO_NONOP;
9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_NOT)
9915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = (uqword && !strcmp(yylval.cp,
9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    dbtest_tokens[(int)TM_NOT])) ? TO_NONNULL : TO_NONOP;
9935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_OPAREN)
9945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == '(' /*)*/ ? TO_NONNULL : TO_NONOP;
9955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_CPAREN)
9965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP;
9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_UNOP || meta == TM_BINOP) {
9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (meta == TM_BINOP && c == REDIR &&
9995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) {
10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ret = TO_NONNULL;
10015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			save = wdcopy(yylval.iop->flag == IOREAD ?
10025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    db_lthan : db_gthan, ATEMP);
10035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (uqword && (ret = test_isop(meta, ident)))
10045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			save = yylval.cp;
100503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else
100603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* meta == TM_END */
10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = (uqword && !strcmp(yylval.cp,
10085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    db_close)) ? TO_NONNULL : TO_NONOP;
10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ret != TO_NONOP) {
10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ACCEPT;
1011c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if ((unsigned int)meta < NELEM(dbtest_tokens))
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			save = wdcopy(dbtest_tokens[(int)meta], ATEMP);
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (save)
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XPput(*te->pos.av, save);
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    bool do_eval MKSH_A_UNUSED)
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c = tpeek(ARRAYVAR);
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c != LWORD)
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
10275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ACCEPT;
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPput(*te->pos.av, yylval.cp);
10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (null);
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_eval(Test_env *te MKSH_A_UNUSED, Test_op op MKSH_A_UNUSED,
10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    const char *opnd1 MKSH_A_UNUSED, const char *opnd2 MKSH_A_UNUSED,
10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    bool do_eval MKSH_A_UNUSED)
10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (1);
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
10435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_error(Test_env *te, int offset, const char *msg)
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	te->flags |= TEF_ERROR;
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (offset < 0) {
10485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Kludgy to say the least... */
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		symbol = LWORD;
10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) +
10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    offset);
10535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	syntaxerr(msg);
10555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
105603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
105703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#if HAVE_SELECT
105803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
105903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef EOVERFLOW
106003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifdef ERANGE
106103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define EOVERFLOW	ERANGE
106203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#else
106303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define EOVERFLOW	EINVAL
106403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
106503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
106603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
106703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrabool
106803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraparse_usec(const char *s, struct timeval *tv)
106903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
107003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct timeval tt;
107103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int i;
107203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
107303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	tv->tv_sec = 0;
107403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* parse integral part */
107503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (ksh_isdigit(*s)) {
107603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tt.tv_sec = tv->tv_sec * 10 + (*s++ - '0');
107703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (tt.tv_sec / 10 != tv->tv_sec) {
107803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errno = EOVERFLOW;
107903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (true);
108003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
108103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tv->tv_sec = tt.tv_sec;
108203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
108303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
108403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	tv->tv_usec = 0;
108503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (!*s)
108603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* no decimal fraction */
108703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (false);
108803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	else if (*s++ != '.') {
108903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* junk after integral part */
109003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errno = EINVAL;
109103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (true);
109203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
109303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
109403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* parse decimal fraction */
109503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	i = 100000;
109603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (ksh_isdigit(*s)) {
109703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tv->tv_usec += i * (*s++ - '0');
109803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (i == 1)
109903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
110003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i /= 10;
110103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
110203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* check for junk after fractional part */
110303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (ksh_isdigit(*s))
110403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		++s;
110503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (*s) {
110603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errno = EINVAL;
110703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (true);
110803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
110903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
111003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* end of input string reached, no errors */
111103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (false);
111203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
111303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
111403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
111503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
111603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Helper function called from within lex.c:yylex() to parse
111703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * a COMSUB recursively using the main shell parser and lexer
111803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra */
111903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrachar *
1120c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaseryyrecursive(int subtype MKSH_A_UNUSED)
112103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
112203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct op *t;
112303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *cp;
1124c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct yyrecursive_state *ys;
1125c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int stok, etok;
1126c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1127811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (subtype != COMSUB) {
1128c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		stok = '{';
1129c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		etok = '}';
1130c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else {
1131c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		stok = '(';
1132c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		etok = ')';
1133c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
1134c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1135c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys = alloc(sizeof(struct yyrecursive_state), ATEMP);
113603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
113703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* tell the lexer to accept a closing parenthesis as EOD */
1138c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_nesting_type = subshell_nesting_type;
1139c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	subshell_nesting_type = etok;
114003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
114103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* push reject state, parse recursively, pop reject state */
1142c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_reject = reject;
1143c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_symbol = symbol;
114403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ACCEPT;
1145c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_herep = herep;
1146c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_salias = sALIAS;
1147c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	sALIAS = 0;
1148c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->next = e->yyrecursive_statep;
1149c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	e->yyrecursive_statep = ys;
115003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* we use TPAREN as a helper container here */
1151c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	t = nested(TPAREN, stok, etok);
1152c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	yyrecursive_pop(false);
115303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
115403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* t->left because nested(TPAREN, ...) hides our goodies there */
115503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	cp = snptreef(NULL, 0, "%T", t->left);
115603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	tfree(t, ATEMP);
115703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
115803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (cp);
115903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
1160c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1161c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
1162c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaseryyrecursive_pop(bool popall)
1163c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1164c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct yyrecursive_state *ys;
1165c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1166c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser popnext:
1167c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (!(ys = e->yyrecursive_statep))
1168c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return;
1169c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	e->yyrecursive_statep = ys->next;
1170c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1171c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	sALIAS = ys->old_salias;
1172c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	herep = ys->old_herep;
1173c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	reject = ys->old_reject;
1174c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	symbol = ys->old_symbol;
1175c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1176c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	subshell_nesting_type = ys->old_nesting_type;
1177c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1178c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	afree(ys, ATEMP);
1179c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (popall)
1180c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		goto popnext;
1181c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1182