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