15155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*	$OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
5c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser *		 2011, 2012
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
26c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.88 2012/12/28 02:28:39 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);
565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *block(int, struct op *, struct op *, char **);
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)
1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				t = tl = block(TPIPE, t, p, NOWORDS);
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else
1135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
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);
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
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)
1605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = block(c == '&' ? TASYNC : TCOPROC,
1615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    p, NOBLOCK, NOWORDS);
1625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (c != ';')
16303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			have_sep = false;
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!t)
1655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = p;
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (!tl)
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = tl = block(TLIST, t, p, NOWORDS);
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!have_sep)
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	REJECT;
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct ioword *
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusynio(int cf)
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword *iop;
18103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	static struct ioword *nextiop;
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool ishere;
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (nextiop != NULL) {
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop = nextiop;
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop = NULL;
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (iop);
1885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (tpeek(cf) != REDIR)
1915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
1925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ACCEPT;
1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	iop = yylval.iop;
19403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (iop->flag & IONDELIM)
19503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto gotnulldelim;
19603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ishere = (iop->flag & IOTYPE) == IOHERE;
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	musthave(LWORD, ishere ? HEREDELIM : 0);
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ishere) {
1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop->delim = yylval.cp;
20003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (*ident != 0)
20103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* unquoted */
20203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra gotnulldelim:
2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			iop->flag |= IOEVAL;
2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (herep > &heres[HERES - 1])
20503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("too many %ss\n", "<<");
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*herep++ = iop;
2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop->name = yylval.cp;
2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (iop->flag & IOBASH) {
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *cp;
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop = alloc(sizeof(*iop), ATEMP);
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->name = cp = alloc(5, ATEMP);
2155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (iop->unit > 9) {
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cp++ = CHAR;
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cp++ = '0' + (iop->unit / 10);
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cp++ = CHAR;
2215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cp++ = '0' + (iop->unit % 10);
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cp = EOS;
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iop->flag &= ~IOBASH;
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->unit = 2;
2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->flag = IODUP;
2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->delim = NULL;
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nextiop->heredoc = NULL;
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (iop);
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunested(int type, int smark, int emark)
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct nesting_state old_nesting;
2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting_push(&old_nesting, smark);
2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = c_list(true);
241c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(emark, KEYWORD|sALIAS);
2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting_pop(&old_nesting);
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (block(type, t, NOBLOCK, NOWORDS));
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
246c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char let_cmd[] = {
247c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	CHAR, 'l', CHAR, 'e', CHAR, 't', EOS
248c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
249c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char setA_cmd0[] = {
250c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	CHAR, 's', CHAR, 'e', CHAR, 't', EOS
251c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
252c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char setA_cmd1[] = {
253c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	CHAR, '-', CHAR, 'A', EOS
254c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
255c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char setA_cmd2[] = {
256c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	CHAR, '-', CHAR, '-', EOS
257c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser};
258c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruget_command(int cf)
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
263c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int c, iopn = 0, syniocf, lno;
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct ioword *iop, **iops;
2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV args, vars;
266c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	char *tcp;
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct nesting_state old_nesting;
2685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* NUFILE is small enough to leave this addition unchecked */
27003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	iops = alloc2((NUFILE + 1), sizeof(struct ioword *), ATEMP);
2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(args, 16);
2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(vars, 16);
2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
274c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	syniocf = KEYWORD|sALIAS;
275c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	switch (c = token(cf|KEYWORD|sALIAS|VARASN)) {
2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(iops, ATEMP);
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(args);
2805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(vars);
28103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* empty line */
28203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (NULL);
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case LWORD:
2855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case REDIR:
2865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
287c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		syniocf &= ~(KEYWORD|sALIAS);
2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TCOM);
2895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->lineno = source->line;
29003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (/* CONSTCOND */ 1) {
2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cf = (t->u.evalflags ? ARRAYVAR : 0) |
292c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    (XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD);
2935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			switch (tpeek(cf)) {
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case REDIR:
2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				while ((iop = synio(cf)) != NULL) {
2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (iopn >= NUFILE)
29703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						yyerror("too many %ss\n",
29803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						    "redirection");
2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					iops[iopn++] = iop;
3005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			case LWORD:
3045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				ACCEPT;
30503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
30603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * the iopn == 0 and XPsize(vars) == 0 are
3075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * dubious but AT&T ksh acts this way
3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 */
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (iopn == 0 && XPsize(vars) == 0 &&
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    XPsize(args) == 0 &&
3115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    assign_command(ident))
3125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					t->u.evalflags = DOVACHECK;
3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    is_wdvarassign(yylval.cp))
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					XPput(vars, yylval.cp);
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					XPput(args, yylval.cp);
3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
320c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			case '(' /*)*/:
321c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (XPsize(args) == 0 && XPsize(vars) == 1 &&
322c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    is_wdvarassign(yylval.cp)) {
323c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* wdarrassign: foo=(bar) */
3245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					ACCEPT;
32503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
326c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* manipulate the vars string */
327c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					tcp = XPptrv(vars)[(vars.len = 0)];
328c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* 'varname=' -> 'varname' */
329c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
330c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
331c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* construct new args strings */
332c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, wdcopy(setA_cmd0, ATEMP));
333c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, wdcopy(setA_cmd1, ATEMP));
334c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, tcp);
335c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					XPput(args, wdcopy(setA_cmd2, ATEMP));
336c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
337c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* slurp in words till closing paren */
338c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					while (token(CONTIN) == LWORD)
339c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						XPput(args, yylval.cp);
340c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					if (symbol != /*(*/ ')')
341c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						syntaxerr(NULL);
342c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				} else {
343c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/*
344c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 * Check for "> foo (echo hi)"
345c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 * which AT&T ksh allows (not
346c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 * POSIX, but not disallowed)
347c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					 */
348c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					afree(t, ATEMP);
349c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					if (XPsize(args) == 0 &&
350c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					    XPsize(vars) == 0) {
351c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						ACCEPT;
352c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						goto Subshell;
353c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					}
354c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
355c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					/* must be a function */
356c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					if (iopn != 0 || XPsize(args) != 1 ||
357c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					    XPsize(vars) != 0)
358c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser						syntaxerr(NULL);
359c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					ACCEPT;
360c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					musthave(/*(*/')', 0);
361c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					t = function_body(XPptrv(args)[0], false);
362c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				}
36303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				goto Leave;
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			default:
3665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				goto Leave;
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Leave:
3705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
372c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case '(': /*)*/ {
373c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		int subshell_nesting_type_saved;
3745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Subshell:
375c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		subshell_nesting_type_saved = subshell_nesting_type;
376c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		subshell_nesting_type = ')';
3775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = nested(TPAREN, '(', ')');
378c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		subshell_nesting_type = subshell_nesting_type_saved;
3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
380c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    }
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '{': /*}*/
3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = nested(TBRACE, '{', '}');
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
386c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case MDPAREN:
38703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
3885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		lno = source->line;
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ACCEPT;
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (token(LETEXPR)) {
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case LWORD:
3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
39303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case '(': /*)*/
3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto Subshell;
3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
3965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			syntaxerr(NULL);
3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TCOM);
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->lineno = lno;
4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, wdcopy(let_cmd, ATEMP));
4015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, yylval.cp);
4025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case DBRACKET: /* [[ .. ]] */
40503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TDBRACKET);
4075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ACCEPT;
4085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		{
4095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			Test_env te;
4105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.flags = TEF_DBRACKET;
4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.pos.av = &args;
4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.isa = dbtestp_isa;
4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.getopnd = dbtestp_getopnd;
4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.eval = dbtestp_eval;
4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			te.error = dbtestp_error;
4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			test_parse(&te);
4195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case FOR:
4235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case SELECT:
4245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp((c == FOR) ? TFOR : TSELECT);
4255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		musthave(LWORD, ARRAYVAR);
4265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!is_wdvarname(yylval.cp, true))
42703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("%s: %s\n", c == FOR ? "for" : Tselect,
42803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "bad identifier");
4295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strdupx(t->str, ident, ATEMP);
4305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->vars = wordlist();
4325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = dogroup();
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case WHILE:
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case UNTIL:
4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp((c == WHILE) ? TWHILE : TUNTIL);
4405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = c_list(true);
4415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->right = dogroup();
4425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case CASE:
4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TCASE);
4475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		musthave(LWORD, 0);
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->str = yylval.cp;
4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = caselist();
4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case IF:
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_push(&old_nesting, c);
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TIF);
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = c_list(true);
4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->right = thenpart();
459c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		musthave(FI, KEYWORD|sALIAS);
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nesting_pop(&old_nesting);
4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case BANG:
464c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		syniocf &= ~(KEYWORD|sALIAS);
4655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = pipeline(0);
4665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (t == NULL)
4675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			syntaxerr(NULL);
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = block(TBANG, NOBLOCK, t, NOWORDS);
4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case TIME:
472c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		syniocf &= ~(KEYWORD|sALIAS);
4735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = pipeline(0);
474c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (t && t->type == TCOM) {
4755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t->str = alloc(2, ATEMP);
47603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* TF_* flags */
47703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			t->str[0] = '\0';
4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t->str[1] = '\0';
4795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = block(TTIME, t, NOBLOCK, NOWORDS);
4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case FUNCTION:
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		musthave(LWORD, 0);
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = function_body(yylval.cp, true);
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
4875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((iop = synio(syniocf)) != NULL) {
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (iopn >= NUFILE)
49103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("too many %ss\n", "redirection");
4925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iops[iopn++] = iop;
4935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (iopn == 0) {
4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(iops, ATEMP);
4975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->ioact = NULL;
4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
4995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		iops[iopn++] = NULL;
50003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		iops = aresize2(iops, iopn, sizeof(struct ioword *), ATEMP);
5015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->ioact = iops;
5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->type == TCOM || t->type == TDBRACKET) {
5055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, NULL);
5065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->args = (const char **)XPclose(args);
5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(vars, NULL);
5085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->vars = (char **) XPclose(vars);
5095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(args);
5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(vars);
5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
5155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudogroup(void)
5195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
5215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *list;
5225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
523c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	c = token(CONTIN|KEYWORD|sALIAS);
52403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
52503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * A {...} can be used instead of do...done for for/select loops
5265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * but not for while/until loops - we don't need to check if it
5275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * is a while loop because it would have been parsed as part of
5285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * the conditional command list...
5295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
5305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == DO)
5315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = DONE;
5325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (c == '{')
5335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = '}';
5345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
5355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
5365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	list = c_list(true);
537c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(c, KEYWORD|sALIAS);
5385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (list);
5395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruthenpart(void)
5435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
5455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
546c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(THEN, KEYWORD|sALIAS);
5475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(0);
5485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = c_list(true);
5495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t->left == NULL)
5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
5515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->right = elsepart();
5525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
5535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruelsepart(void)
5575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
560c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	switch (token(KEYWORD|sALIAS|VARASN)) {
5615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case ELSE:
5625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((t = c_list(true)) == NULL)
5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			syntaxerr(NULL);
5645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (t);
5655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case ELIF:
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t = newtp(TELIF);
5685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = c_list(true);
5695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->right = thenpart();
5705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (t);
5715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (NULL);
5765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querucaselist(void)
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t, *tl;
5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
5835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
584c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	c = token(CONTIN|KEYWORD|sALIAS);
5855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* A {...} can be used instead of in...esac for case statements */
5865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == IN)
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = ESAC;
5885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (c == '{')
5895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = '}';
5905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
5915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
5925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = tl = NULL;
59303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* no ALIAS here */
59403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) {
5955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct op *tc = casepart(c);
5965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tl == NULL)
5975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t = tl = tc, tl->right = NULL;
5985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
5995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tl->right = tc, tl = tc;
6005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
601c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	musthave(c, KEYWORD|sALIAS);
6025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
6035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
6065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querucasepart(int endtok)
6075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
6095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV ptns;
6105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(ptns, 16);
6125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(TPAT);
6135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* no ALIAS here */
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (token(CONTIN | KEYWORD) != '(')
6155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	do {
617c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		switch (token(0)) {
618c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case LWORD:
619c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			break;
620c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case '}':
621c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case ESAC:
622c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (symbol != endtok) {
623c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				strdupx(yylval.cp,
624c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				    symbol == '}' ? Tcbrace : Tesac, ATEMP);
625c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				break;
626c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
627c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* FALLTHROUGH */
628c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		default:
629c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			syntaxerr(NULL);
630c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
6315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(ptns, yylval.cp);
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} while (token(0) == '|');
6335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	REJECT;
6345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPput(ptns, NULL);
6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->vars = (char **) XPclose(ptns);
6365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	musthave(')', 0);
6375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = c_list(true);
639c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
640c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* initialise to default for ;; or omitted */
641c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	t->u.charflag = ';';
642c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* SUSv4 requires the ;; except in the last casepart */
643c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if ((tpeek(CONTIN|KEYWORD|sALIAS)) != endtok)
64403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		switch (symbol) {
64503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		default:
64603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			syntaxerr(NULL);
64703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case BRKEV:
648c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			t->u.charflag = '|';
649c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			if (0)
650c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				/* FALLTHROUGH */
65103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case BRKFT:
652c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			t->u.charflag = '&';
653c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* FALLTHROUGH */
654c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		case BREAK:
655c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* initialised above, but we need to eat the token */
65603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ACCEPT;
65703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
6585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
6595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
6625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querufunction_body(char *name,
66303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* function foo { ... } vs foo() { .. } */
66403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    bool ksh_func)
6655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *sname, *p;
6675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
6685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
66903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	sname = wdstrip(name, 0);
67003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*-
67103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Check for valid characters in name. POSIX and AT&T ksh93 say
67203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * only allow [a-zA-Z_0-9] but this allows more as old pdkshs
67303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * have allowed more; the following were never allowed:
6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *	NUL TAB NL SP " $ & ' ( ) ; < = > \ ` |
6755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * C_QUOTE covers all but adds # * ? [ ]
6765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = sname; *p; p++)
6785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ctype(*p, C_QUOTE))
67903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			yyerror("%s: %s\n", sname, "invalid function name");
6805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
68103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
68203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Note that POSIX allows only compound statements after foo(),
68303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * sh and AT&T ksh allow any command, go with the later since it
68403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * shouldn't break anything. However, for function foo, AT&T ksh
68503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * only accepts an open-brace.
6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
6875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ksh_func) {
688c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (tpeek(CONTIN|KEYWORD|sALIAS) == '(' /*)*/) {
689c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* function foo () { //}*/
6905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ACCEPT;
6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			musthave(')', 0);
6925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* degrade to POSIX function */
6935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ksh_func = false;
6945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
695c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		musthave('{' /*}*/, CONTIN|KEYWORD|sALIAS);
6965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
6975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(TFUNCT);
7005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->str = sname;
70103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	t->u.ksh_func = tobool(ksh_func);
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->lineno = source->line;
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((t->left = get_command(CONTIN)) == NULL) {
7055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *tv;
7065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
70703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Probably something like foo() followed by EOF or ';'.
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * This is accepted by sh and ksh88.
7095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * To make "typeset -f foo" work reliably (so its output can
7105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * be used as input), we pretend there is a colon here.
7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left = newtp(TCOM);
71303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* (2 * sizeof(char *)) is small enough */
7145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->args = alloc(2 * sizeof(char *), ATEMP);
7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->args[0] = tv = alloc(3, ATEMP);
7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tv[0] = CHAR;
7175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tv[1] = ':';
7185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tv[2] = EOS;
7195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->args[1] = NULL;
7205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->vars = alloc(sizeof(char *), ATEMP);
7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->vars[0] = NULL;
7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		t->left->lineno = 1;
7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
7265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char **
7295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruwordlist(void)
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV args;
7335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(args, 16);
7355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* POSIX does not do alias expansion here... */
736c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if ((c = token(CONTIN|KEYWORD|sALIAS)) != IN) {
73703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (c != ';')
73803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* non-POSIX, but AT&T ksh accepts a ; here */
7395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			REJECT;
7405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
7415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((c = token(0)) == LWORD)
7435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, yylval.cp);
7445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c != '\n' && c != ';')
7455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		syntaxerr(NULL);
7465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (XPsize(args) == 0) {
7475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPfree(args);
7485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
7495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
7505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		XPput(args, NULL);
7515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return ((char **)XPclose(args));
7525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
7565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * supporting functions
7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
7585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querublock(int type, struct op *t1, struct op *t2, char **wp)
7615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
7635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = newtp(type);
7655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = t1;
7665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->right = t2;
7675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->vars = wp;
7685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
7695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
771c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const struct tokeninfo {
7725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *name;
7735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	short val;
7745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	short reserved;
7755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} tokentab[] = {
7765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Reserved words */
7775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "if",		IF,	true },
7785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "then",	THEN,	true },
7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "else",	ELSE,	true },
7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "elif",	ELIF,	true },
7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "fi",		FI,	true },
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "case",	CASE,	true },
783c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	{ Tesac,	ESAC,	true },
7845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "for",	FOR,	true },
78503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ Tselect,	SELECT,	true },
7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "while",	WHILE,	true },
7875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "until",	UNTIL,	true },
7885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "do",		DO,	true },
7895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "done",	DONE,	true },
7905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "in",		IN,	true },
79103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ Tfunction,	FUNCTION, true },
7925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "time",	TIME,	true },
7935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "{",		'{',	true },
794c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	{ Tcbrace,	'}',	true },
7955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "!",		BANG,	true },
7965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "[[",		DBRACKET, true },
7975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
7985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "&&",		LOGAND,	false },
7995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "||",		LOGOR,	false },
8005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ ";;",		BREAK,	false },
80103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ ";|",		BRKEV,	false },
80203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{ ";&",		BRKFT,	false },
8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "((",		MDPAREN, false },
8045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "|&",		COPROC,	false },
8055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* and some special cases... */
8065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ "newline",	'\n',	false },
8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	{ NULL,		0,	false }
8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
8095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
8115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinitkeywords(void)
8125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tokeninfo const *tt;
8145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *p;
8155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
81603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ktinit(APERM, &keywords,
817c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    /* currently 28 keywords: 75% of 64 = 2^6 */
81803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    6);
8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (tt = tokentab; tt->name; tt++) {
8205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tt->reserved) {
8215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p = ktenter(&keywords, tt->name, hash(tt->name));
8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->flag |= DEFINED|ISSET;
8235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->type = CKEYWD;
8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			p->val.i = tt->val;
8255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusyntaxerr(const char *what)
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
83203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* 2<<- is the longest redirection, I think */
83303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char redir[6];
8345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *s;
8355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tokeninfo const *tt;
8365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
8375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!what)
8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		what = "unexpected";
8405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	REJECT;
8415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	c = token(0);
8425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru Again:
8435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (c) {
8445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 0:
8455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (nesting.start_token) {
8465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = nesting.start_token;
8475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			source->errline = nesting.start_line;
8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			what = "unmatched";
8495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto Again;
8505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* don't quote the EOF */
85203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		yyerror("%s: %s %s\n", Tsynerr, "unexpected", "EOF");
8535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* NOTREACHED */
8545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case LWORD:
8565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = snptreef(NULL, 32, "%S", yylval.cp);
8575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
8585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case REDIR:
8605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
8615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
8625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
8645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (tt = tokentab; tt->name; tt++)
8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tt->val == c)
8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    break;
8675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tt->name)
8685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = tt->name;
8695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else {
8705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (c > 0 && c < 256) {
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				redir[0] = c;
8725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				redir[1] = '\0';
8735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
8745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_snprintf(redir, sizeof(redir),
8755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					"?%d", c);
8765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = redir;
8775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
87903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	yyerror("%s: '%s' %s\n", Tsynerr, s, what);
8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunesting_push(struct nesting_state *save, int tok)
8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*save = nesting;
8865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_token = tok;
8875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_line = source->line;
8885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
8915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunesting_pop(struct nesting_state *saved)
8925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting = *saved;
8945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct op *
8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunewtp(int type)
8985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct op *t;
9005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t = alloc(sizeof(struct op), ATEMP);
9025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->type = type;
9035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->u.evalflags = 0;
9045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->args = NULL;
9055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->vars = NULL;
9065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->ioact = NULL;
9075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->left = t->right = NULL;
9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	t->str = NULL;
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (t);
9105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct op *
91303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condracompile(Source *s, bool skiputf8bom)
9145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_token = 0;
9165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nesting.start_line = 0;
9175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	herep = heres;
9185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	source = s;
91903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (skiputf8bom)
92003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		yyskiputf8bom();
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	yyparse();
9225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (outtree);
9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
92503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*-
92603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * This kludge exists to take care of sh/AT&T ksh oddity in which
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the arguments of alias/export/readonly/typeset have no field
9285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * splitting, file globbing, or (normal) tilde expansion done.
9295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * AT&T ksh seems to do something similar to this since
9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	$ touch a=a; typeset a=[ab]; echo "$a"
9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	a=[ab]
9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	$ x=typeset; $x a=[ab]; echo "$a"
9335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	a=a
9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	$
9355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
937c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserassign_command(const char *s)
9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!*s)
9405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
94103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return ((strcmp(s, Talias) == 0) ||
942c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    (strcmp(s, Texport) == 0) ||
943c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    (strcmp(s, Treadonly) == 0) ||
94403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    (strcmp(s, Ttypeset) == 0));
9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Check if we are in the middle of reading an alias */
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
9495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinalias(struct source *s)
9505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (; s && s->type == SALIAS; s = s->next)
9525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(s->flags & SF_ALIASEND))
9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (1);
9545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
9555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
95803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
95903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Order important - indexed by Test_meta values
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Note that ||, &&, ( and ) can't appear in as unquoted strings
9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * in normal shell input, so these can be interpreted unambiguously
9625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * in the evaluation pass.
9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
9655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
9665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_not[] = { CHAR, '!', EOS };
9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_oparen[] = { CHAR, '(', EOS };
9685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char dbtest_cparen[] = { CHAR, ')', EOS };
969c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserconst char * const dbtest_tokens[] = {
9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	dbtest_or, dbtest_and, dbtest_not,
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	dbtest_oparen, dbtest_cparen
9725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
973c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
974c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char db_lthan[] = { CHAR, '<', EOS };
975c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstatic const char db_gthan[] = { CHAR, '>', EOS };
9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
9785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Test if the current token is a whatever. Accepts the current token if
9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * it is. Returns 0 if it is not, non-zero if it is (in the case of
9805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * TM_UNOP and TM_BINOP, the returned value is a Test_op).
9815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic Test_op
9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_isa(Test_env *te, Test_meta meta)
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
9865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int uqword;
9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *save = NULL;
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Test_op ret = TO_NONOP;
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* unquoted word? */
9915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uqword = c == LWORD && *ident;
9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (meta == TM_OR)
9945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == LOGOR ? TO_NONNULL : TO_NONOP;
9955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_AND)
9965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == LOGAND ? TO_NONNULL : TO_NONOP;
9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_NOT)
9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = (uqword && !strcmp(yylval.cp,
9995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    dbtest_tokens[(int)TM_NOT])) ? TO_NONNULL : TO_NONOP;
10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_OPAREN)
10015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == '(' /*)*/ ? TO_NONNULL : TO_NONOP;
10025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_CPAREN)
10035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP;
10045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else if (meta == TM_UNOP || meta == TM_BINOP) {
10055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (meta == TM_BINOP && c == REDIR &&
10065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) {
10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			ret = TO_NONNULL;
10085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			save = wdcopy(yylval.iop->flag == IOREAD ?
10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    db_lthan : db_gthan, ATEMP);
10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (uqword && (ret = test_isop(meta, ident)))
10115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			save = yylval.cp;
101203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else
101303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* meta == TM_END */
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ret = (uqword && !strcmp(yylval.cp,
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    db_close)) ? TO_NONNULL : TO_NONOP;
10165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (ret != TO_NONOP) {
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ACCEPT;
1018c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if ((unsigned int)meta < NELEM(dbtest_tokens))
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			save = wdcopy(dbtest_tokens[(int)meta], ATEMP);
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (save)
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XPput(*te->pos.av, save);
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
10275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
10285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    bool do_eval MKSH_A_UNUSED)
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c = tpeek(ARRAYVAR);
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c != LWORD)
10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ACCEPT;
10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPput(*te->pos.av, yylval.cp);
10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (null);
10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_eval(Test_env *te MKSH_A_UNUSED, Test_op op MKSH_A_UNUSED,
10435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    const char *opnd1 MKSH_A_UNUSED, const char *opnd2 MKSH_A_UNUSED,
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    bool do_eval MKSH_A_UNUSED)
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (1);
10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudbtestp_error(Test_env *te, int offset, const char *msg)
10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	te->flags |= TEF_ERROR;
10535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (offset < 0) {
10555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		REJECT;
10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Kludgy to say the least... */
10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		symbol = LWORD;
10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) +
10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    offset);
10605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	syntaxerr(msg);
10625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
106303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
106403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#if HAVE_SELECT
106503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
106603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef EOVERFLOW
106703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifdef ERANGE
106803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define EOVERFLOW	ERANGE
106903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#else
107003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define EOVERFLOW	EINVAL
107103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
107203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
107303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
107403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrabool
107503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraparse_usec(const char *s, struct timeval *tv)
107603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
107703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct timeval tt;
107803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int i;
107903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
108003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	tv->tv_sec = 0;
108103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* parse integral part */
108203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (ksh_isdigit(*s)) {
108303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tt.tv_sec = tv->tv_sec * 10 + (*s++ - '0');
108403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (tt.tv_sec / 10 != tv->tv_sec) {
108503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errno = EOVERFLOW;
108603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (true);
108703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
108803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tv->tv_sec = tt.tv_sec;
108903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
109003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
109103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	tv->tv_usec = 0;
109203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (!*s)
109303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* no decimal fraction */
109403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (false);
109503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	else if (*s++ != '.') {
109603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* junk after integral part */
109703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errno = EINVAL;
109803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (true);
109903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
110003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
110103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* parse decimal fraction */
110203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	i = 100000;
110303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (ksh_isdigit(*s)) {
110403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tv->tv_usec += i * (*s++ - '0');
110503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (i == 1)
110603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
110703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i /= 10;
110803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
110903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* check for junk after fractional part */
111003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (ksh_isdigit(*s))
111103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		++s;
111203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (*s) {
111303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errno = EINVAL;
111403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (true);
111503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
111603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
111703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* end of input string reached, no errors */
111803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (false);
111903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
112003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
112103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
112203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
112303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Helper function called from within lex.c:yylex() to parse
112403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * a COMSUB recursively using the main shell parser and lexer
112503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra */
112603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrachar *
1127c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaseryyrecursive(int subtype MKSH_A_UNUSED)
112803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
112903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct op *t;
113003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *cp;
1131c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct yyrecursive_state *ys;
1132c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	int stok, etok;
1133c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1134c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (subtype == FUNSUB) {
1135c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		stok = '{';
1136c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		etok = '}';
1137c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	} else {
1138c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		stok = '(';
1139c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		etok = ')';
1140c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
1141c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1142c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys = alloc(sizeof(struct yyrecursive_state), ATEMP);
114303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
114403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* tell the lexer to accept a closing parenthesis as EOD */
1145c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_nesting_type = subshell_nesting_type;
1146c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	subshell_nesting_type = etok;
114703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
114803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* push reject state, parse recursively, pop reject state */
1149c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_reject = reject;
1150c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_symbol = symbol;
115103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ACCEPT;
1152c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_herep = herep;
1153c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->old_salias = sALIAS;
1154c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	sALIAS = 0;
1155c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	ys->next = e->yyrecursive_statep;
1156c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	e->yyrecursive_statep = ys;
115703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* we use TPAREN as a helper container here */
1158c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	t = nested(TPAREN, stok, etok);
1159c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	yyrecursive_pop(false);
116003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
116103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* t->left because nested(TPAREN, ...) hides our goodies there */
116203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	cp = snptreef(NULL, 0, "%T", t->left);
116303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	tfree(t, ATEMP);
116403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
116503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (cp);
116603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
1167c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1168c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaservoid
1169c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaseryyrecursive_pop(bool popall)
1170c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1171c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct yyrecursive_state *ys;
1172c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1173c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser popnext:
1174c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (!(ys = e->yyrecursive_statep))
1175c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return;
1176c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	e->yyrecursive_statep = ys->next;
1177c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1178c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	sALIAS = ys->old_salias;
1179c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	herep = ys->old_herep;
1180c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	reject = ys->old_reject;
1181c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	symbol = ys->old_symbol;
1182c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1183c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	subshell_nesting_type = ys->old_nesting_type;
1184c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1185c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	afree(ys, ATEMP);
1186c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (popall)
1187c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		goto popnext;
1188c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1189