1/*	$OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $	*/
2
3/*-
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
5 *		 2011, 2012
6 *	Thorsten Glaser <tg@mirbsd.org>
7 *
8 * Provided that these terms and disclaimer and all copyright notices
9 * are retained or reproduced in an accompanying document, permission
10 * is granted to deal in this work without restriction, including un-
11 * limited rights to use, publicly perform, distribute, sell, modify,
12 * merge, give away, or sublicence.
13 *
14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15 * the utmost extent permitted by applicable law, neither express nor
16 * implied; without malicious intent or gross negligence. In no event
17 * may a licensor, author or contributor be held liable for indirect,
18 * direct, other damage, loss, or other issues arising in any way out
19 * of dealing in the work, even if advised of the possibility of such
20 * damage or existence of a defect, except proven that it results out
21 * of said person's immediate fault when using the work as intended.
22 */
23
24#include "sh.h"
25
26__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.88 2012/12/28 02:28:39 tg Exp $");
27
28struct nesting_state {
29	int start_token;	/* token than began nesting (eg, FOR) */
30	int start_line;		/* line nesting began on */
31};
32
33struct yyrecursive_state {
34	struct yyrecursive_state *next;
35	struct ioword **old_herep;
36	int old_symbol;
37	int old_salias;
38	int old_nesting_type;
39	bool old_reject;
40};
41
42static void yyparse(void);
43static struct op *pipeline(int);
44static struct op *andor(void);
45static struct op *c_list(bool);
46static struct ioword *synio(int);
47static struct op *nested(int, int, int);
48static struct op *get_command(int);
49static struct op *dogroup(void);
50static struct op *thenpart(void);
51static struct op *elsepart(void);
52static struct op *caselist(void);
53static struct op *casepart(int);
54static struct op *function_body(char *, bool);
55static char **wordlist(void);
56static struct op *block(int, struct op *, struct op *, char **);
57static struct op *newtp(int);
58static void syntaxerr(const char *) MKSH_A_NORETURN;
59static void nesting_push(struct nesting_state *, int);
60static void nesting_pop(struct nesting_state *);
61static int assign_command(const char *);
62static int inalias(struct source *);
63static Test_op dbtestp_isa(Test_env *, Test_meta);
64static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
65static int dbtestp_eval(Test_env *, Test_op, const char *,
66    const char *, bool);
67static void dbtestp_error(Test_env *, int, const char *) MKSH_A_NORETURN;
68
69static struct op *outtree;		/* yyparse output */
70static struct nesting_state nesting;	/* \n changed to ; */
71
72static bool reject;			/* token(cf) gets symbol again */
73static int symbol;			/* yylex value */
74static int sALIAS = ALIAS;		/* 0 in yyrecursive */
75
76#define REJECT		(reject = true)
77#define ACCEPT		(reject = false)
78#define token(cf)	((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
79#define tpeek(cf)	((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
80#define musthave(c,cf)	do { if (token(cf) != (c)) syntaxerr(NULL); } while (/* CONSTCOND */ 0)
81
82static const char Tcbrace[] = "}";
83static const char Tesac[] = "esac";
84
85static void
86yyparse(void)
87{
88	int c;
89
90	ACCEPT;
91
92	outtree = c_list(source->type == SSTRING);
93	c = tpeek(0);
94	if (c == 0 && !outtree)
95		outtree = newtp(TEOF);
96	else if (c != '\n' && c != 0)
97		syntaxerr(NULL);
98}
99
100static struct op *
101pipeline(int cf)
102{
103	struct op *t, *p, *tl = NULL;
104
105	t = get_command(cf);
106	if (t != NULL) {
107		while (token(0) == '|') {
108			if ((p = get_command(CONTIN)) == NULL)
109				syntaxerr(NULL);
110			if (tl == NULL)
111				t = tl = block(TPIPE, t, p, NOWORDS);
112			else
113				tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
114		}
115		REJECT;
116	}
117	return (t);
118}
119
120static struct op *
121andor(void)
122{
123	struct op *t, *p;
124	int c;
125
126	t = pipeline(0);
127	if (t != NULL) {
128		while ((c = token(0)) == LOGAND || c == LOGOR) {
129			if ((p = pipeline(CONTIN)) == NULL)
130				syntaxerr(NULL);
131			t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
132		}
133		REJECT;
134	}
135	return (t);
136}
137
138static struct op *
139c_list(bool multi)
140{
141	struct op *t = NULL, *p, *tl = NULL;
142	int c;
143	bool have_sep;
144
145	while (/* CONSTCOND */ 1) {
146		p = andor();
147		/*
148		 * Token has always been read/rejected at this point, so
149		 * we don't worry about what flags to pass token()
150		 */
151		c = token(0);
152		have_sep = true;
153		if (c == '\n' && (multi || inalias(source))) {
154			if (!p)
155				/* ignore blank lines */
156				continue;
157		} else if (!p)
158			break;
159		else if (c == '&' || c == COPROC)
160			p = block(c == '&' ? TASYNC : TCOPROC,
161			    p, NOBLOCK, NOWORDS);
162		else if (c != ';')
163			have_sep = false;
164		if (!t)
165			t = p;
166		else if (!tl)
167			t = tl = block(TLIST, t, p, NOWORDS);
168		else
169			tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
170		if (!have_sep)
171			break;
172	}
173	REJECT;
174	return (t);
175}
176
177static struct ioword *
178synio(int cf)
179{
180	struct ioword *iop;
181	static struct ioword *nextiop;
182	bool ishere;
183
184	if (nextiop != NULL) {
185		iop = nextiop;
186		nextiop = NULL;
187		return (iop);
188	}
189
190	if (tpeek(cf) != REDIR)
191		return (NULL);
192	ACCEPT;
193	iop = yylval.iop;
194	if (iop->flag & IONDELIM)
195		goto gotnulldelim;
196	ishere = (iop->flag & IOTYPE) == IOHERE;
197	musthave(LWORD, ishere ? HEREDELIM : 0);
198	if (ishere) {
199		iop->delim = yylval.cp;
200		if (*ident != 0)
201			/* unquoted */
202 gotnulldelim:
203			iop->flag |= IOEVAL;
204		if (herep > &heres[HERES - 1])
205			yyerror("too many %ss\n", "<<");
206		*herep++ = iop;
207	} else
208		iop->name = yylval.cp;
209
210	if (iop->flag & IOBASH) {
211		char *cp;
212
213		nextiop = alloc(sizeof(*iop), ATEMP);
214		nextiop->name = cp = alloc(5, ATEMP);
215
216		if (iop->unit > 9) {
217			*cp++ = CHAR;
218			*cp++ = '0' + (iop->unit / 10);
219		}
220		*cp++ = CHAR;
221		*cp++ = '0' + (iop->unit % 10);
222		*cp = EOS;
223
224		iop->flag &= ~IOBASH;
225		nextiop->unit = 2;
226		nextiop->flag = IODUP;
227		nextiop->delim = NULL;
228		nextiop->heredoc = NULL;
229	}
230	return (iop);
231}
232
233static struct op *
234nested(int type, int smark, int emark)
235{
236	struct op *t;
237	struct nesting_state old_nesting;
238
239	nesting_push(&old_nesting, smark);
240	t = c_list(true);
241	musthave(emark, KEYWORD|sALIAS);
242	nesting_pop(&old_nesting);
243	return (block(type, t, NOBLOCK, NOWORDS));
244}
245
246static const char let_cmd[] = {
247	CHAR, 'l', CHAR, 'e', CHAR, 't', EOS
248};
249static const char setA_cmd0[] = {
250	CHAR, 's', CHAR, 'e', CHAR, 't', EOS
251};
252static const char setA_cmd1[] = {
253	CHAR, '-', CHAR, 'A', EOS
254};
255static const char setA_cmd2[] = {
256	CHAR, '-', CHAR, '-', EOS
257};
258
259static struct op *
260get_command(int cf)
261{
262	struct op *t;
263	int c, iopn = 0, syniocf, lno;
264	struct ioword *iop, **iops;
265	XPtrV args, vars;
266	char *tcp;
267	struct nesting_state old_nesting;
268
269	/* NUFILE is small enough to leave this addition unchecked */
270	iops = alloc2((NUFILE + 1), sizeof(struct ioword *), ATEMP);
271	XPinit(args, 16);
272	XPinit(vars, 16);
273
274	syniocf = KEYWORD|sALIAS;
275	switch (c = token(cf|KEYWORD|sALIAS|VARASN)) {
276	default:
277		REJECT;
278		afree(iops, ATEMP);
279		XPfree(args);
280		XPfree(vars);
281		/* empty line */
282		return (NULL);
283
284	case LWORD:
285	case REDIR:
286		REJECT;
287		syniocf &= ~(KEYWORD|sALIAS);
288		t = newtp(TCOM);
289		t->lineno = source->line;
290		while (/* CONSTCOND */ 1) {
291			cf = (t->u.evalflags ? ARRAYVAR : 0) |
292			    (XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD);
293			switch (tpeek(cf)) {
294			case REDIR:
295				while ((iop = synio(cf)) != NULL) {
296					if (iopn >= NUFILE)
297						yyerror("too many %ss\n",
298						    "redirection");
299					iops[iopn++] = iop;
300				}
301				break;
302
303			case LWORD:
304				ACCEPT;
305				/*
306				 * the iopn == 0 and XPsize(vars) == 0 are
307				 * dubious but AT&T ksh acts this way
308				 */
309				if (iopn == 0 && XPsize(vars) == 0 &&
310				    XPsize(args) == 0 &&
311				    assign_command(ident))
312					t->u.evalflags = DOVACHECK;
313				if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
314				    is_wdvarassign(yylval.cp))
315					XPput(vars, yylval.cp);
316				else
317					XPput(args, yylval.cp);
318				break;
319
320			case '(' /*)*/:
321				if (XPsize(args) == 0 && XPsize(vars) == 1 &&
322				    is_wdvarassign(yylval.cp)) {
323					/* wdarrassign: foo=(bar) */
324					ACCEPT;
325
326					/* manipulate the vars string */
327					tcp = XPptrv(vars)[(vars.len = 0)];
328					/* 'varname=' -> 'varname' */
329					tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
330
331					/* construct new args strings */
332					XPput(args, wdcopy(setA_cmd0, ATEMP));
333					XPput(args, wdcopy(setA_cmd1, ATEMP));
334					XPput(args, tcp);
335					XPput(args, wdcopy(setA_cmd2, ATEMP));
336
337					/* slurp in words till closing paren */
338					while (token(CONTIN) == LWORD)
339						XPput(args, yylval.cp);
340					if (symbol != /*(*/ ')')
341						syntaxerr(NULL);
342				} else {
343					/*
344					 * Check for "> foo (echo hi)"
345					 * which AT&T ksh allows (not
346					 * POSIX, but not disallowed)
347					 */
348					afree(t, ATEMP);
349					if (XPsize(args) == 0 &&
350					    XPsize(vars) == 0) {
351						ACCEPT;
352						goto Subshell;
353					}
354
355					/* must be a function */
356					if (iopn != 0 || XPsize(args) != 1 ||
357					    XPsize(vars) != 0)
358						syntaxerr(NULL);
359					ACCEPT;
360					musthave(/*(*/')', 0);
361					t = function_body(XPptrv(args)[0], false);
362				}
363				goto Leave;
364
365			default:
366				goto Leave;
367			}
368		}
369 Leave:
370		break;
371
372	case '(': /*)*/ {
373		int subshell_nesting_type_saved;
374 Subshell:
375		subshell_nesting_type_saved = subshell_nesting_type;
376		subshell_nesting_type = ')';
377		t = nested(TPAREN, '(', ')');
378		subshell_nesting_type = subshell_nesting_type_saved;
379		break;
380	    }
381
382	case '{': /*}*/
383		t = nested(TBRACE, '{', '}');
384		break;
385
386	case MDPAREN:
387		/* leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
388		lno = source->line;
389		ACCEPT;
390		switch (token(LETEXPR)) {
391		case LWORD:
392			break;
393		case '(': /*)*/
394			goto Subshell;
395		default:
396			syntaxerr(NULL);
397		}
398		t = newtp(TCOM);
399		t->lineno = lno;
400		XPput(args, wdcopy(let_cmd, ATEMP));
401		XPput(args, yylval.cp);
402		break;
403
404	case DBRACKET: /* [[ .. ]] */
405		/* leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
406		t = newtp(TDBRACKET);
407		ACCEPT;
408		{
409			Test_env te;
410
411			te.flags = TEF_DBRACKET;
412			te.pos.av = &args;
413			te.isa = dbtestp_isa;
414			te.getopnd = dbtestp_getopnd;
415			te.eval = dbtestp_eval;
416			te.error = dbtestp_error;
417
418			test_parse(&te);
419		}
420		break;
421
422	case FOR:
423	case SELECT:
424		t = newtp((c == FOR) ? TFOR : TSELECT);
425		musthave(LWORD, ARRAYVAR);
426		if (!is_wdvarname(yylval.cp, true))
427			yyerror("%s: %s\n", c == FOR ? "for" : Tselect,
428			    "bad identifier");
429		strdupx(t->str, ident, ATEMP);
430		nesting_push(&old_nesting, c);
431		t->vars = wordlist();
432		t->left = dogroup();
433		nesting_pop(&old_nesting);
434		break;
435
436	case WHILE:
437	case UNTIL:
438		nesting_push(&old_nesting, c);
439		t = newtp((c == WHILE) ? TWHILE : TUNTIL);
440		t->left = c_list(true);
441		t->right = dogroup();
442		nesting_pop(&old_nesting);
443		break;
444
445	case CASE:
446		t = newtp(TCASE);
447		musthave(LWORD, 0);
448		t->str = yylval.cp;
449		nesting_push(&old_nesting, c);
450		t->left = caselist();
451		nesting_pop(&old_nesting);
452		break;
453
454	case IF:
455		nesting_push(&old_nesting, c);
456		t = newtp(TIF);
457		t->left = c_list(true);
458		t->right = thenpart();
459		musthave(FI, KEYWORD|sALIAS);
460		nesting_pop(&old_nesting);
461		break;
462
463	case BANG:
464		syniocf &= ~(KEYWORD|sALIAS);
465		t = pipeline(0);
466		if (t == NULL)
467			syntaxerr(NULL);
468		t = block(TBANG, NOBLOCK, t, NOWORDS);
469		break;
470
471	case TIME:
472		syniocf &= ~(KEYWORD|sALIAS);
473		t = pipeline(0);
474		if (t && t->type == TCOM) {
475			t->str = alloc(2, ATEMP);
476			/* TF_* flags */
477			t->str[0] = '\0';
478			t->str[1] = '\0';
479		}
480		t = block(TTIME, t, NOBLOCK, NOWORDS);
481		break;
482
483	case FUNCTION:
484		musthave(LWORD, 0);
485		t = function_body(yylval.cp, true);
486		break;
487	}
488
489	while ((iop = synio(syniocf)) != NULL) {
490		if (iopn >= NUFILE)
491			yyerror("too many %ss\n", "redirection");
492		iops[iopn++] = iop;
493	}
494
495	if (iopn == 0) {
496		afree(iops, ATEMP);
497		t->ioact = NULL;
498	} else {
499		iops[iopn++] = NULL;
500		iops = aresize2(iops, iopn, sizeof(struct ioword *), ATEMP);
501		t->ioact = iops;
502	}
503
504	if (t->type == TCOM || t->type == TDBRACKET) {
505		XPput(args, NULL);
506		t->args = (const char **)XPclose(args);
507		XPput(vars, NULL);
508		t->vars = (char **) XPclose(vars);
509	} else {
510		XPfree(args);
511		XPfree(vars);
512	}
513
514	return (t);
515}
516
517static struct op *
518dogroup(void)
519{
520	int c;
521	struct op *list;
522
523	c = token(CONTIN|KEYWORD|sALIAS);
524	/*
525	 * A {...} can be used instead of do...done for for/select loops
526	 * but not for while/until loops - we don't need to check if it
527	 * is a while loop because it would have been parsed as part of
528	 * the conditional command list...
529	 */
530	if (c == DO)
531		c = DONE;
532	else if (c == '{')
533		c = '}';
534	else
535		syntaxerr(NULL);
536	list = c_list(true);
537	musthave(c, KEYWORD|sALIAS);
538	return (list);
539}
540
541static struct op *
542thenpart(void)
543{
544	struct op *t;
545
546	musthave(THEN, KEYWORD|sALIAS);
547	t = newtp(0);
548	t->left = c_list(true);
549	if (t->left == NULL)
550		syntaxerr(NULL);
551	t->right = elsepart();
552	return (t);
553}
554
555static struct op *
556elsepart(void)
557{
558	struct op *t;
559
560	switch (token(KEYWORD|sALIAS|VARASN)) {
561	case ELSE:
562		if ((t = c_list(true)) == NULL)
563			syntaxerr(NULL);
564		return (t);
565
566	case ELIF:
567		t = newtp(TELIF);
568		t->left = c_list(true);
569		t->right = thenpart();
570		return (t);
571
572	default:
573		REJECT;
574	}
575	return (NULL);
576}
577
578static struct op *
579caselist(void)
580{
581	struct op *t, *tl;
582	int c;
583
584	c = token(CONTIN|KEYWORD|sALIAS);
585	/* A {...} can be used instead of in...esac for case statements */
586	if (c == IN)
587		c = ESAC;
588	else if (c == '{')
589		c = '}';
590	else
591		syntaxerr(NULL);
592	t = tl = NULL;
593	/* no ALIAS here */
594	while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) {
595		struct op *tc = casepart(c);
596		if (tl == NULL)
597			t = tl = tc, tl->right = NULL;
598		else
599			tl->right = tc, tl = tc;
600	}
601	musthave(c, KEYWORD|sALIAS);
602	return (t);
603}
604
605static struct op *
606casepart(int endtok)
607{
608	struct op *t;
609	XPtrV ptns;
610
611	XPinit(ptns, 16);
612	t = newtp(TPAT);
613	/* no ALIAS here */
614	if (token(CONTIN | KEYWORD) != '(')
615		REJECT;
616	do {
617		switch (token(0)) {
618		case LWORD:
619			break;
620		case '}':
621		case ESAC:
622			if (symbol != endtok) {
623				strdupx(yylval.cp,
624				    symbol == '}' ? Tcbrace : Tesac, ATEMP);
625				break;
626			}
627			/* FALLTHROUGH */
628		default:
629			syntaxerr(NULL);
630		}
631		XPput(ptns, yylval.cp);
632	} while (token(0) == '|');
633	REJECT;
634	XPput(ptns, NULL);
635	t->vars = (char **) XPclose(ptns);
636	musthave(')', 0);
637
638	t->left = c_list(true);
639
640	/* initialise to default for ;; or omitted */
641	t->u.charflag = ';';
642	/* SUSv4 requires the ;; except in the last casepart */
643	if ((tpeek(CONTIN|KEYWORD|sALIAS)) != endtok)
644		switch (symbol) {
645		default:
646			syntaxerr(NULL);
647		case BRKEV:
648			t->u.charflag = '|';
649			if (0)
650				/* FALLTHROUGH */
651		case BRKFT:
652			t->u.charflag = '&';
653			/* FALLTHROUGH */
654		case BREAK:
655			/* initialised above, but we need to eat the token */
656			ACCEPT;
657		}
658	return (t);
659}
660
661static struct op *
662function_body(char *name,
663    /* function foo { ... } vs foo() { .. } */
664    bool ksh_func)
665{
666	char *sname, *p;
667	struct op *t;
668
669	sname = wdstrip(name, 0);
670	/*-
671	 * Check for valid characters in name. POSIX and AT&T ksh93 say
672	 * only allow [a-zA-Z_0-9] but this allows more as old pdkshs
673	 * have allowed more; the following were never allowed:
674	 *	NUL TAB NL SP " $ & ' ( ) ; < = > \ ` |
675	 * C_QUOTE covers all but adds # * ? [ ]
676	 */
677	for (p = sname; *p; p++)
678		if (ctype(*p, C_QUOTE))
679			yyerror("%s: %s\n", sname, "invalid function name");
680
681	/*
682	 * Note that POSIX allows only compound statements after foo(),
683	 * sh and AT&T ksh allow any command, go with the later since it
684	 * shouldn't break anything. However, for function foo, AT&T ksh
685	 * only accepts an open-brace.
686	 */
687	if (ksh_func) {
688		if (tpeek(CONTIN|KEYWORD|sALIAS) == '(' /*)*/) {
689			/* function foo () { //}*/
690			ACCEPT;
691			musthave(')', 0);
692			/* degrade to POSIX function */
693			ksh_func = false;
694		}
695		musthave('{' /*}*/, CONTIN|KEYWORD|sALIAS);
696		REJECT;
697	}
698
699	t = newtp(TFUNCT);
700	t->str = sname;
701	t->u.ksh_func = tobool(ksh_func);
702	t->lineno = source->line;
703
704	if ((t->left = get_command(CONTIN)) == NULL) {
705		char *tv;
706		/*
707		 * Probably something like foo() followed by EOF or ';'.
708		 * This is accepted by sh and ksh88.
709		 * To make "typeset -f foo" work reliably (so its output can
710		 * be used as input), we pretend there is a colon here.
711		 */
712		t->left = newtp(TCOM);
713		/* (2 * sizeof(char *)) is small enough */
714		t->left->args = alloc(2 * sizeof(char *), ATEMP);
715		t->left->args[0] = tv = alloc(3, ATEMP);
716		tv[0] = CHAR;
717		tv[1] = ':';
718		tv[2] = EOS;
719		t->left->args[1] = NULL;
720		t->left->vars = alloc(sizeof(char *), ATEMP);
721		t->left->vars[0] = NULL;
722		t->left->lineno = 1;
723	}
724
725	return (t);
726}
727
728static char **
729wordlist(void)
730{
731	int c;
732	XPtrV args;
733
734	XPinit(args, 16);
735	/* POSIX does not do alias expansion here... */
736	if ((c = token(CONTIN|KEYWORD|sALIAS)) != IN) {
737		if (c != ';')
738			/* non-POSIX, but AT&T ksh accepts a ; here */
739			REJECT;
740		return (NULL);
741	}
742	while ((c = token(0)) == LWORD)
743		XPput(args, yylval.cp);
744	if (c != '\n' && c != ';')
745		syntaxerr(NULL);
746	if (XPsize(args) == 0) {
747		XPfree(args);
748		return (NULL);
749	} else {
750		XPput(args, NULL);
751		return ((char **)XPclose(args));
752	}
753}
754
755/*
756 * supporting functions
757 */
758
759static struct op *
760block(int type, struct op *t1, struct op *t2, char **wp)
761{
762	struct op *t;
763
764	t = newtp(type);
765	t->left = t1;
766	t->right = t2;
767	t->vars = wp;
768	return (t);
769}
770
771static const struct tokeninfo {
772	const char *name;
773	short val;
774	short reserved;
775} tokentab[] = {
776	/* Reserved words */
777	{ "if",		IF,	true },
778	{ "then",	THEN,	true },
779	{ "else",	ELSE,	true },
780	{ "elif",	ELIF,	true },
781	{ "fi",		FI,	true },
782	{ "case",	CASE,	true },
783	{ Tesac,	ESAC,	true },
784	{ "for",	FOR,	true },
785	{ Tselect,	SELECT,	true },
786	{ "while",	WHILE,	true },
787	{ "until",	UNTIL,	true },
788	{ "do",		DO,	true },
789	{ "done",	DONE,	true },
790	{ "in",		IN,	true },
791	{ Tfunction,	FUNCTION, true },
792	{ "time",	TIME,	true },
793	{ "{",		'{',	true },
794	{ Tcbrace,	'}',	true },
795	{ "!",		BANG,	true },
796	{ "[[",		DBRACKET, true },
797	/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
798	{ "&&",		LOGAND,	false },
799	{ "||",		LOGOR,	false },
800	{ ";;",		BREAK,	false },
801	{ ";|",		BRKEV,	false },
802	{ ";&",		BRKFT,	false },
803	{ "((",		MDPAREN, false },
804	{ "|&",		COPROC,	false },
805	/* and some special cases... */
806	{ "newline",	'\n',	false },
807	{ NULL,		0,	false }
808};
809
810void
811initkeywords(void)
812{
813	struct tokeninfo const *tt;
814	struct tbl *p;
815
816	ktinit(APERM, &keywords,
817	    /* currently 28 keywords: 75% of 64 = 2^6 */
818	    6);
819	for (tt = tokentab; tt->name; tt++) {
820		if (tt->reserved) {
821			p = ktenter(&keywords, tt->name, hash(tt->name));
822			p->flag |= DEFINED|ISSET;
823			p->type = CKEYWD;
824			p->val.i = tt->val;
825		}
826	}
827}
828
829static void
830syntaxerr(const char *what)
831{
832	/* 2<<- is the longest redirection, I think */
833	char redir[6];
834	const char *s;
835	struct tokeninfo const *tt;
836	int c;
837
838	if (!what)
839		what = "unexpected";
840	REJECT;
841	c = token(0);
842 Again:
843	switch (c) {
844	case 0:
845		if (nesting.start_token) {
846			c = nesting.start_token;
847			source->errline = nesting.start_line;
848			what = "unmatched";
849			goto Again;
850		}
851		/* don't quote the EOF */
852		yyerror("%s: %s %s\n", Tsynerr, "unexpected", "EOF");
853		/* NOTREACHED */
854
855	case LWORD:
856		s = snptreef(NULL, 32, "%S", yylval.cp);
857		break;
858
859	case REDIR:
860		s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
861		break;
862
863	default:
864		for (tt = tokentab; tt->name; tt++)
865			if (tt->val == c)
866			    break;
867		if (tt->name)
868			s = tt->name;
869		else {
870			if (c > 0 && c < 256) {
871				redir[0] = c;
872				redir[1] = '\0';
873			} else
874				shf_snprintf(redir, sizeof(redir),
875					"?%d", c);
876			s = redir;
877		}
878	}
879	yyerror("%s: '%s' %s\n", Tsynerr, s, what);
880}
881
882static void
883nesting_push(struct nesting_state *save, int tok)
884{
885	*save = nesting;
886	nesting.start_token = tok;
887	nesting.start_line = source->line;
888}
889
890static void
891nesting_pop(struct nesting_state *saved)
892{
893	nesting = *saved;
894}
895
896static struct op *
897newtp(int type)
898{
899	struct op *t;
900
901	t = alloc(sizeof(struct op), ATEMP);
902	t->type = type;
903	t->u.evalflags = 0;
904	t->args = NULL;
905	t->vars = NULL;
906	t->ioact = NULL;
907	t->left = t->right = NULL;
908	t->str = NULL;
909	return (t);
910}
911
912struct op *
913compile(Source *s, bool skiputf8bom)
914{
915	nesting.start_token = 0;
916	nesting.start_line = 0;
917	herep = heres;
918	source = s;
919	if (skiputf8bom)
920		yyskiputf8bom();
921	yyparse();
922	return (outtree);
923}
924
925/*-
926 * This kludge exists to take care of sh/AT&T ksh oddity in which
927 * the arguments of alias/export/readonly/typeset have no field
928 * splitting, file globbing, or (normal) tilde expansion done.
929 * AT&T ksh seems to do something similar to this since
930 *	$ touch a=a; typeset a=[ab]; echo "$a"
931 *	a=[ab]
932 *	$ x=typeset; $x a=[ab]; echo "$a"
933 *	a=a
934 *	$
935 */
936static int
937assign_command(const char *s)
938{
939	if (!*s)
940		return (0);
941	return ((strcmp(s, Talias) == 0) ||
942	    (strcmp(s, Texport) == 0) ||
943	    (strcmp(s, Treadonly) == 0) ||
944	    (strcmp(s, Ttypeset) == 0));
945}
946
947/* Check if we are in the middle of reading an alias */
948static int
949inalias(struct source *s)
950{
951	for (; s && s->type == SALIAS; s = s->next)
952		if (!(s->flags & SF_ALIASEND))
953			return (1);
954	return (0);
955}
956
957
958/*
959 * Order important - indexed by Test_meta values
960 * Note that ||, &&, ( and ) can't appear in as unquoted strings
961 * in normal shell input, so these can be interpreted unambiguously
962 * in the evaluation pass.
963 */
964static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
965static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
966static const char dbtest_not[] = { CHAR, '!', EOS };
967static const char dbtest_oparen[] = { CHAR, '(', EOS };
968static const char dbtest_cparen[] = { CHAR, ')', EOS };
969const char * const dbtest_tokens[] = {
970	dbtest_or, dbtest_and, dbtest_not,
971	dbtest_oparen, dbtest_cparen
972};
973static const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
974static const char db_lthan[] = { CHAR, '<', EOS };
975static const char db_gthan[] = { CHAR, '>', EOS };
976
977/*
978 * Test if the current token is a whatever. Accepts the current token if
979 * it is. Returns 0 if it is not, non-zero if it is (in the case of
980 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
981 */
982static Test_op
983dbtestp_isa(Test_env *te, Test_meta meta)
984{
985	int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
986	int uqword;
987	char *save = NULL;
988	Test_op ret = TO_NONOP;
989
990	/* unquoted word? */
991	uqword = c == LWORD && *ident;
992
993	if (meta == TM_OR)
994		ret = c == LOGOR ? TO_NONNULL : TO_NONOP;
995	else if (meta == TM_AND)
996		ret = c == LOGAND ? TO_NONNULL : TO_NONOP;
997	else if (meta == TM_NOT)
998		ret = (uqword && !strcmp(yylval.cp,
999		    dbtest_tokens[(int)TM_NOT])) ? TO_NONNULL : TO_NONOP;
1000	else if (meta == TM_OPAREN)
1001		ret = c == '(' /*)*/ ? TO_NONNULL : TO_NONOP;
1002	else if (meta == TM_CPAREN)
1003		ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP;
1004	else if (meta == TM_UNOP || meta == TM_BINOP) {
1005		if (meta == TM_BINOP && c == REDIR &&
1006		    (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) {
1007			ret = TO_NONNULL;
1008			save = wdcopy(yylval.iop->flag == IOREAD ?
1009			    db_lthan : db_gthan, ATEMP);
1010		} else if (uqword && (ret = test_isop(meta, ident)))
1011			save = yylval.cp;
1012	} else
1013		/* meta == TM_END */
1014		ret = (uqword && !strcmp(yylval.cp,
1015		    db_close)) ? TO_NONNULL : TO_NONOP;
1016	if (ret != TO_NONOP) {
1017		ACCEPT;
1018		if ((unsigned int)meta < NELEM(dbtest_tokens))
1019			save = wdcopy(dbtest_tokens[(int)meta], ATEMP);
1020		if (save)
1021			XPput(*te->pos.av, save);
1022	}
1023	return (ret);
1024}
1025
1026static const char *
1027dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
1028    bool do_eval MKSH_A_UNUSED)
1029{
1030	int c = tpeek(ARRAYVAR);
1031
1032	if (c != LWORD)
1033		return (NULL);
1034
1035	ACCEPT;
1036	XPput(*te->pos.av, yylval.cp);
1037
1038	return (null);
1039}
1040
1041static int
1042dbtestp_eval(Test_env *te MKSH_A_UNUSED, Test_op op MKSH_A_UNUSED,
1043    const char *opnd1 MKSH_A_UNUSED, const char *opnd2 MKSH_A_UNUSED,
1044    bool do_eval MKSH_A_UNUSED)
1045{
1046	return (1);
1047}
1048
1049static void
1050dbtestp_error(Test_env *te, int offset, const char *msg)
1051{
1052	te->flags |= TEF_ERROR;
1053
1054	if (offset < 0) {
1055		REJECT;
1056		/* Kludgy to say the least... */
1057		symbol = LWORD;
1058		yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) +
1059		    offset);
1060	}
1061	syntaxerr(msg);
1062}
1063
1064#if HAVE_SELECT
1065
1066#ifndef EOVERFLOW
1067#ifdef ERANGE
1068#define EOVERFLOW	ERANGE
1069#else
1070#define EOVERFLOW	EINVAL
1071#endif
1072#endif
1073
1074bool
1075parse_usec(const char *s, struct timeval *tv)
1076{
1077	struct timeval tt;
1078	int i;
1079
1080	tv->tv_sec = 0;
1081	/* parse integral part */
1082	while (ksh_isdigit(*s)) {
1083		tt.tv_sec = tv->tv_sec * 10 + (*s++ - '0');
1084		if (tt.tv_sec / 10 != tv->tv_sec) {
1085			errno = EOVERFLOW;
1086			return (true);
1087		}
1088		tv->tv_sec = tt.tv_sec;
1089	}
1090
1091	tv->tv_usec = 0;
1092	if (!*s)
1093		/* no decimal fraction */
1094		return (false);
1095	else if (*s++ != '.') {
1096		/* junk after integral part */
1097		errno = EINVAL;
1098		return (true);
1099	}
1100
1101	/* parse decimal fraction */
1102	i = 100000;
1103	while (ksh_isdigit(*s)) {
1104		tv->tv_usec += i * (*s++ - '0');
1105		if (i == 1)
1106			break;
1107		i /= 10;
1108	}
1109	/* check for junk after fractional part */
1110	while (ksh_isdigit(*s))
1111		++s;
1112	if (*s) {
1113		errno = EINVAL;
1114		return (true);
1115	}
1116
1117	/* end of input string reached, no errors */
1118	return (false);
1119}
1120#endif
1121
1122/*
1123 * Helper function called from within lex.c:yylex() to parse
1124 * a COMSUB recursively using the main shell parser and lexer
1125 */
1126char *
1127yyrecursive(int subtype MKSH_A_UNUSED)
1128{
1129	struct op *t;
1130	char *cp;
1131	struct yyrecursive_state *ys;
1132	int stok, etok;
1133
1134	if (subtype == FUNSUB) {
1135		stok = '{';
1136		etok = '}';
1137	} else {
1138		stok = '(';
1139		etok = ')';
1140	}
1141
1142	ys = alloc(sizeof(struct yyrecursive_state), ATEMP);
1143
1144	/* tell the lexer to accept a closing parenthesis as EOD */
1145	ys->old_nesting_type = subshell_nesting_type;
1146	subshell_nesting_type = etok;
1147
1148	/* push reject state, parse recursively, pop reject state */
1149	ys->old_reject = reject;
1150	ys->old_symbol = symbol;
1151	ACCEPT;
1152	ys->old_herep = herep;
1153	ys->old_salias = sALIAS;
1154	sALIAS = 0;
1155	ys->next = e->yyrecursive_statep;
1156	e->yyrecursive_statep = ys;
1157	/* we use TPAREN as a helper container here */
1158	t = nested(TPAREN, stok, etok);
1159	yyrecursive_pop(false);
1160
1161	/* t->left because nested(TPAREN, ...) hides our goodies there */
1162	cp = snptreef(NULL, 0, "%T", t->left);
1163	tfree(t, ATEMP);
1164
1165	return (cp);
1166}
1167
1168void
1169yyrecursive_pop(bool popall)
1170{
1171	struct yyrecursive_state *ys;
1172
1173 popnext:
1174	if (!(ys = e->yyrecursive_statep))
1175		return;
1176	e->yyrecursive_statep = ys->next;
1177
1178	sALIAS = ys->old_salias;
1179	herep = ys->old_herep;
1180	reject = ys->old_reject;
1181	symbol = ys->old_symbol;
1182
1183	subshell_nesting_type = ys->old_nesting_type;
1184
1185	afree(ys, ATEMP);
1186	if (popall)
1187		goto popnext;
1188}
1189