xref: /freebsd/bin/sh/parser.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
1 /*-
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
40 #endif
41 #endif /* not lint */
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include <stdlib.h>
46 
47 #include "shell.h"
48 #include "parser.h"
49 #include "nodes.h"
50 #include "expand.h"	/* defines rmescapes() */
51 #include "redir.h"	/* defines copyfd() */
52 #include "syntax.h"
53 #include "options.h"
54 #include "input.h"
55 #include "output.h"
56 #include "var.h"
57 #include "error.h"
58 #include "memalloc.h"
59 #include "mystring.h"
60 #include "alias.h"
61 #include "show.h"
62 #include "eval.h"
63 #ifndef NO_HISTORY
64 #include "myhistedit.h"
65 #endif
66 
67 /*
68  * Shell command parser.
69  */
70 
71 #define EOFMARKLEN 79
72 
73 /* values returned by readtoken */
74 #include "token.h"
75 
76 
77 
78 struct heredoc {
79 	struct heredoc *next;	/* next here document in list */
80 	union node *here;		/* redirection node */
81 	char *eofmark;		/* string indicating end of input */
82 	int striptabs;		/* if set, strip leading tabs */
83 };
84 
85 
86 
87 STATIC struct heredoc *heredoclist;	/* list of here documents to read */
88 STATIC int parsebackquote;	/* nonzero if we are inside backquotes */
89 STATIC int doprompt;		/* if set, prompt the user */
90 STATIC int needprompt;		/* true if interactive and at start of line */
91 STATIC int lasttoken;		/* last token read */
92 MKINIT int tokpushback;		/* last token pushed back */
93 STATIC char *wordtext;		/* text of last word returned by readtoken */
94 MKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
95 STATIC struct nodelist *backquotelist;
96 STATIC union node *redirnode;
97 STATIC struct heredoc *heredoc;
98 STATIC int quoteflag;		/* set if (part of) last token was quoted */
99 STATIC int startlinno;		/* line # where last token started */
100 
101 /* XXX When 'noaliases' is set to one, no alias expansion takes place. */
102 static int noaliases = 0;
103 
104 #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
105 #ifdef GDB_HACK
106 static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
107 static const char types[] = "}-+?=";
108 #endif
109 
110 
111 STATIC union node *list(int);
112 STATIC union node *andor(void);
113 STATIC union node *pipeline(void);
114 STATIC union node *command(void);
115 STATIC union node *simplecmd(union node **, union node *);
116 STATIC union node *makename(void);
117 STATIC void parsefname(void);
118 STATIC void parseheredoc(void);
119 STATIC int peektoken(void);
120 STATIC int readtoken(void);
121 STATIC int xxreadtoken(void);
122 STATIC int readtoken1(int, char const *, char *, int);
123 STATIC int noexpand(char *);
124 STATIC void synexpect(int);
125 STATIC void synerror(char *);
126 STATIC void setprompt(int);
127 
128 
129 /*
130  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
131  * valid parse tree indicating a blank line.)
132  */
133 
134 union node *
135 parsecmd(int interact)
136 {
137 	int t;
138 
139 	tokpushback = 0;
140 	doprompt = interact;
141 	if (doprompt)
142 		setprompt(1);
143 	else
144 		setprompt(0);
145 	needprompt = 0;
146 	t = readtoken();
147 	if (t == TEOF)
148 		return NEOF;
149 	if (t == TNL)
150 		return NULL;
151 	tokpushback++;
152 	return list(1);
153 }
154 
155 
156 STATIC union node *
157 list(int nlflag)
158 {
159 	union node *n1, *n2, *n3;
160 	int tok;
161 
162 	checkkwd = 2;
163 	if (nlflag == 0 && tokendlist[peektoken()])
164 		return NULL;
165 	n1 = NULL;
166 	for (;;) {
167 		n2 = andor();
168 		tok = readtoken();
169 		if (tok == TBACKGND) {
170 			if (n2->type == NCMD || n2->type == NPIPE) {
171 				n2->ncmd.backgnd = 1;
172 			} else if (n2->type == NREDIR) {
173 				n2->type = NBACKGND;
174 			} else {
175 				n3 = (union node *)stalloc(sizeof (struct nredir));
176 				n3->type = NBACKGND;
177 				n3->nredir.n = n2;
178 				n3->nredir.redirect = NULL;
179 				n2 = n3;
180 			}
181 		}
182 		if (n1 == NULL) {
183 			n1 = n2;
184 		}
185 		else {
186 			n3 = (union node *)stalloc(sizeof (struct nbinary));
187 			n3->type = NSEMI;
188 			n3->nbinary.ch1 = n1;
189 			n3->nbinary.ch2 = n2;
190 			n1 = n3;
191 		}
192 		switch (tok) {
193 		case TBACKGND:
194 		case TSEMI:
195 			tok = readtoken();
196 			/* FALLTHROUGH */
197 		case TNL:
198 			if (tok == TNL) {
199 				parseheredoc();
200 				if (nlflag)
201 					return n1;
202 			} else {
203 				tokpushback++;
204 			}
205 			checkkwd = 2;
206 			if (tokendlist[peektoken()])
207 				return n1;
208 			break;
209 		case TEOF:
210 			if (heredoclist)
211 				parseheredoc();
212 			else
213 				pungetc();		/* push back EOF on input */
214 			return n1;
215 		default:
216 			if (nlflag)
217 				synexpect(-1);
218 			tokpushback++;
219 			return n1;
220 		}
221 	}
222 }
223 
224 
225 
226 STATIC union node *
227 andor(void)
228 {
229 	union node *n1, *n2, *n3;
230 	int t;
231 
232 	n1 = pipeline();
233 	for (;;) {
234 		if ((t = readtoken()) == TAND) {
235 			t = NAND;
236 		} else if (t == TOR) {
237 			t = NOR;
238 		} else {
239 			tokpushback++;
240 			return n1;
241 		}
242 		n2 = pipeline();
243 		n3 = (union node *)stalloc(sizeof (struct nbinary));
244 		n3->type = t;
245 		n3->nbinary.ch1 = n1;
246 		n3->nbinary.ch2 = n2;
247 		n1 = n3;
248 	}
249 }
250 
251 
252 
253 STATIC union node *
254 pipeline(void)
255 {
256 	union node *n1, *n2, *pipenode;
257 	struct nodelist *lp, *prev;
258 	int negate;
259 
260 	negate = 0;
261 	TRACE(("pipeline: entered\n"));
262 	while (readtoken() == TNOT)
263 		negate = !negate;
264 	tokpushback++;
265 	n1 = command();
266 	if (readtoken() == TPIPE) {
267 		pipenode = (union node *)stalloc(sizeof (struct npipe));
268 		pipenode->type = NPIPE;
269 		pipenode->npipe.backgnd = 0;
270 		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
271 		pipenode->npipe.cmdlist = lp;
272 		lp->n = n1;
273 		do {
274 			prev = lp;
275 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
276 			lp->n = command();
277 			prev->next = lp;
278 		} while (readtoken() == TPIPE);
279 		lp->next = NULL;
280 		n1 = pipenode;
281 	}
282 	tokpushback++;
283 	if (negate) {
284 		n2 = (union node *)stalloc(sizeof (struct nnot));
285 		n2->type = NNOT;
286 		n2->nnot.com = n1;
287 		return n2;
288 	} else
289 		return n1;
290 }
291 
292 
293 
294 STATIC union node *
295 command(void)
296 {
297 	union node *n1, *n2;
298 	union node *ap, **app;
299 	union node *cp, **cpp;
300 	union node *redir, **rpp;
301 	int t, negate = 0;
302 
303 	checkkwd = 2;
304 	redir = NULL;
305 	n1 = NULL;
306 	rpp = &redir;
307 
308 	/* Check for redirection which may precede command */
309 	while (readtoken() == TREDIR) {
310 		*rpp = n2 = redirnode;
311 		rpp = &n2->nfile.next;
312 		parsefname();
313 	}
314 	tokpushback++;
315 
316 	while (readtoken() == TNOT) {
317 		TRACE(("command: TNOT recognized\n"));
318 		negate = !negate;
319 	}
320 	tokpushback++;
321 
322 	switch (readtoken()) {
323 	case TIF:
324 		n1 = (union node *)stalloc(sizeof (struct nif));
325 		n1->type = NIF;
326 		if ((n1->nif.test = list(0)) == NULL)
327 			synexpect(-1);
328 		if (readtoken() != TTHEN)
329 			synexpect(TTHEN);
330 		n1->nif.ifpart = list(0);
331 		n2 = n1;
332 		while (readtoken() == TELIF) {
333 			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
334 			n2 = n2->nif.elsepart;
335 			n2->type = NIF;
336 			if ((n2->nif.test = list(0)) == NULL)
337 				synexpect(-1);
338 			if (readtoken() != TTHEN)
339 				synexpect(TTHEN);
340 			n2->nif.ifpart = list(0);
341 		}
342 		if (lasttoken == TELSE)
343 			n2->nif.elsepart = list(0);
344 		else {
345 			n2->nif.elsepart = NULL;
346 			tokpushback++;
347 		}
348 		if (readtoken() != TFI)
349 			synexpect(TFI);
350 		checkkwd = 1;
351 		break;
352 	case TWHILE:
353 	case TUNTIL: {
354 		int got;
355 		n1 = (union node *)stalloc(sizeof (struct nbinary));
356 		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
357 		if ((n1->nbinary.ch1 = list(0)) == NULL)
358 			synexpect(-1);
359 		if ((got=readtoken()) != TDO) {
360 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
361 			synexpect(TDO);
362 		}
363 		n1->nbinary.ch2 = list(0);
364 		if (readtoken() != TDONE)
365 			synexpect(TDONE);
366 		checkkwd = 1;
367 		break;
368 	}
369 	case TFOR:
370 		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
371 			synerror("Bad for loop variable");
372 		n1 = (union node *)stalloc(sizeof (struct nfor));
373 		n1->type = NFOR;
374 		n1->nfor.var = wordtext;
375 		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
376 			app = &ap;
377 			while (readtoken() == TWORD) {
378 				n2 = (union node *)stalloc(sizeof (struct narg));
379 				n2->type = NARG;
380 				n2->narg.text = wordtext;
381 				n2->narg.backquote = backquotelist;
382 				*app = n2;
383 				app = &n2->narg.next;
384 			}
385 			*app = NULL;
386 			n1->nfor.args = ap;
387 			if (lasttoken != TNL && lasttoken != TSEMI)
388 				synexpect(-1);
389 		} else {
390 #ifndef GDB_HACK
391 			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
392 								   '@', '=', '\0'};
393 #endif
394 			n2 = (union node *)stalloc(sizeof (struct narg));
395 			n2->type = NARG;
396 			n2->narg.text = (char *)argvars;
397 			n2->narg.backquote = NULL;
398 			n2->narg.next = NULL;
399 			n1->nfor.args = n2;
400 			/*
401 			 * Newline or semicolon here is optional (but note
402 			 * that the original Bourne shell only allowed NL).
403 			 */
404 			if (lasttoken != TNL && lasttoken != TSEMI)
405 				tokpushback++;
406 		}
407 		checkkwd = 2;
408 		if ((t = readtoken()) == TDO)
409 			t = TDONE;
410 		else if (t == TBEGIN)
411 			t = TEND;
412 		else
413 			synexpect(-1);
414 		n1->nfor.body = list(0);
415 		if (readtoken() != t)
416 			synexpect(t);
417 		checkkwd = 1;
418 		break;
419 	case TCASE:
420 		n1 = (union node *)stalloc(sizeof (struct ncase));
421 		n1->type = NCASE;
422 		if (readtoken() != TWORD)
423 			synexpect(TWORD);
424 		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
425 		n2->type = NARG;
426 		n2->narg.text = wordtext;
427 		n2->narg.backquote = backquotelist;
428 		n2->narg.next = NULL;
429 		while (readtoken() == TNL);
430 		if (lasttoken != TWORD || ! equal(wordtext, "in"))
431 			synerror("expecting \"in\"");
432 		cpp = &n1->ncase.cases;
433 		noaliases = 1;	/* turn off alias expansion */
434 		checkkwd = 2, readtoken();
435 		while (lasttoken != TESAC) {
436 			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
437 			cp->type = NCLIST;
438 			app = &cp->nclist.pattern;
439 			if (lasttoken == TLP)
440 				readtoken();
441 			for (;;) {
442 				*app = ap = (union node *)stalloc(sizeof (struct narg));
443 				ap->type = NARG;
444 				ap->narg.text = wordtext;
445 				ap->narg.backquote = backquotelist;
446 				if (checkkwd = 2, readtoken() != TPIPE)
447 					break;
448 				app = &ap->narg.next;
449 				readtoken();
450 			}
451 			ap->narg.next = NULL;
452 			if (lasttoken != TRP)
453 				noaliases = 0, synexpect(TRP);
454 			cp->nclist.body = list(0);
455 
456 			checkkwd = 2;
457 			if ((t = readtoken()) != TESAC) {
458 				if (t != TENDCASE)
459 					noaliases = 0, synexpect(TENDCASE);
460 				else
461 					checkkwd = 2, readtoken();
462 			}
463 			cpp = &cp->nclist.next;
464 		}
465 		noaliases = 0;	/* reset alias expansion */
466 		*cpp = NULL;
467 		checkkwd = 1;
468 		break;
469 	case TLP:
470 		n1 = (union node *)stalloc(sizeof (struct nredir));
471 		n1->type = NSUBSHELL;
472 		n1->nredir.n = list(0);
473 		n1->nredir.redirect = NULL;
474 		if (readtoken() != TRP)
475 			synexpect(TRP);
476 		checkkwd = 1;
477 		break;
478 	case TBEGIN:
479 		n1 = list(0);
480 		if (readtoken() != TEND)
481 			synexpect(TEND);
482 		checkkwd = 1;
483 		break;
484 	/* Handle an empty command like other simple commands.  */
485 	case TSEMI:
486 	case TAND:
487 	case TOR:
488 		/*
489 		 * An empty command before a ; doesn't make much sense, and
490 		 * should certainly be disallowed in the case of `if ;'.
491 		 */
492 		if (!redir)
493 			synexpect(-1);
494 	case TNL:
495 	case TEOF:
496 	case TWORD:
497 	case TRP:
498 		tokpushback++;
499 		n1 = simplecmd(rpp, redir);
500 		goto checkneg;
501 	default:
502 		synexpect(-1);
503 	}
504 
505 	/* Now check for redirection which may follow command */
506 	while (readtoken() == TREDIR) {
507 		*rpp = n2 = redirnode;
508 		rpp = &n2->nfile.next;
509 		parsefname();
510 	}
511 	tokpushback++;
512 	*rpp = NULL;
513 	if (redir) {
514 		if (n1->type != NSUBSHELL) {
515 			n2 = (union node *)stalloc(sizeof (struct nredir));
516 			n2->type = NREDIR;
517 			n2->nredir.n = n1;
518 			n1 = n2;
519 		}
520 		n1->nredir.redirect = redir;
521 	}
522 
523 checkneg:
524 	if (negate) {
525 		n2 = (union node *)stalloc(sizeof (struct nnot));
526 		n2->type = NNOT;
527 		n2->nnot.com = n1;
528 		return n2;
529 	}
530 	else
531 		return n1;
532 }
533 
534 
535 STATIC union node *
536 simplecmd(union node **rpp, union node *redir)
537 {
538 	union node *args, **app;
539 	union node **orig_rpp = rpp;
540 	union node *n = NULL, *n2;
541 	int negate = 0;
542 
543 	/* If we don't have any redirections already, then we must reset */
544 	/* rpp to be the address of the local redir variable.  */
545 	if (redir == 0)
546 		rpp = &redir;
547 
548 	args = NULL;
549 	app = &args;
550 	/*
551 	 * We save the incoming value, because we need this for shell
552 	 * functions.  There can not be a redirect or an argument between
553 	 * the function name and the open parenthesis.
554 	 */
555 	orig_rpp = rpp;
556 
557 	while (readtoken() == TNOT) {
558 		TRACE(("command: TNOT recognized\n"));
559 		negate = !negate;
560 	}
561 	tokpushback++;
562 
563 	for (;;) {
564 		if (readtoken() == TWORD) {
565 			n = (union node *)stalloc(sizeof (struct narg));
566 			n->type = NARG;
567 			n->narg.text = wordtext;
568 			n->narg.backquote = backquotelist;
569 			*app = n;
570 			app = &n->narg.next;
571 		} else if (lasttoken == TREDIR) {
572 			*rpp = n = redirnode;
573 			rpp = &n->nfile.next;
574 			parsefname();	/* read name of redirection file */
575 		} else if (lasttoken == TLP && app == &args->narg.next
576 					    && rpp == orig_rpp) {
577 			/* We have a function */
578 			if (readtoken() != TRP)
579 				synexpect(TRP);
580 #ifdef notdef
581 			if (! goodname(n->narg.text))
582 				synerror("Bad function name");
583 #endif
584 			n->type = NDEFUN;
585 			n->narg.next = command();
586 			goto checkneg;
587 		} else {
588 			tokpushback++;
589 			break;
590 		}
591 	}
592 	*app = NULL;
593 	*rpp = NULL;
594 	n = (union node *)stalloc(sizeof (struct ncmd));
595 	n->type = NCMD;
596 	n->ncmd.backgnd = 0;
597 	n->ncmd.args = args;
598 	n->ncmd.redirect = redir;
599 
600 checkneg:
601 	if (negate) {
602 		n2 = (union node *)stalloc(sizeof (struct nnot));
603 		n2->type = NNOT;
604 		n2->nnot.com = n;
605 		return n2;
606 	}
607 	else
608 		return n;
609 }
610 
611 STATIC union node *
612 makename(void)
613 {
614 	union node *n;
615 
616 	n = (union node *)stalloc(sizeof (struct narg));
617 	n->type = NARG;
618 	n->narg.next = NULL;
619 	n->narg.text = wordtext;
620 	n->narg.backquote = backquotelist;
621 	return n;
622 }
623 
624 void fixredir(union node *n, const char *text, int err)
625 {
626 	TRACE(("Fix redir %s %d\n", text, err));
627 	if (!err)
628 		n->ndup.vname = NULL;
629 
630 	if (is_digit(text[0]) && text[1] == '\0')
631 		n->ndup.dupfd = digit_val(text[0]);
632 	else if (text[0] == '-' && text[1] == '\0')
633 		n->ndup.dupfd = -1;
634 	else {
635 
636 		if (err)
637 			synerror("Bad fd number");
638 		else
639 			n->ndup.vname = makename();
640 	}
641 }
642 
643 
644 STATIC void
645 parsefname(void)
646 {
647 	union node *n = redirnode;
648 
649 	if (readtoken() != TWORD)
650 		synexpect(-1);
651 	if (n->type == NHERE) {
652 		struct heredoc *here = heredoc;
653 		struct heredoc *p;
654 		int i;
655 
656 		if (quoteflag == 0)
657 			n->type = NXHERE;
658 		TRACE(("Here document %d\n", n->type));
659 		if (here->striptabs) {
660 			while (*wordtext == '\t')
661 				wordtext++;
662 		}
663 		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
664 			synerror("Illegal eof marker for << redirection");
665 		rmescapes(wordtext);
666 		here->eofmark = wordtext;
667 		here->next = NULL;
668 		if (heredoclist == NULL)
669 			heredoclist = here;
670 		else {
671 			for (p = heredoclist ; p->next ; p = p->next);
672 			p->next = here;
673 		}
674 	} else if (n->type == NTOFD || n->type == NFROMFD) {
675 		fixredir(n, wordtext, 0);
676 	} else {
677 		n->nfile.fname = makename();
678 	}
679 }
680 
681 
682 /*
683  * Input any here documents.
684  */
685 
686 STATIC void
687 parseheredoc(void)
688 {
689 	struct heredoc *here;
690 	union node *n;
691 
692 	while (heredoclist) {
693 		here = heredoclist;
694 		heredoclist = here->next;
695 		if (needprompt) {
696 			setprompt(2);
697 			needprompt = 0;
698 		}
699 		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
700 				here->eofmark, here->striptabs);
701 		n = (union node *)stalloc(sizeof (struct narg));
702 		n->narg.type = NARG;
703 		n->narg.next = NULL;
704 		n->narg.text = wordtext;
705 		n->narg.backquote = backquotelist;
706 		here->here->nhere.doc = n;
707 	}
708 }
709 
710 STATIC int
711 peektoken(void)
712 {
713 	int t;
714 
715 	t = readtoken();
716 	tokpushback++;
717 	return (t);
718 }
719 
720 STATIC int
721 readtoken(void)
722 {
723 	int t;
724 	int savecheckkwd = checkkwd;
725 	struct alias *ap;
726 #ifdef DEBUG
727 	int alreadyseen = tokpushback;
728 #endif
729 
730 	top:
731 	t = xxreadtoken();
732 
733 	if (checkkwd) {
734 		/*
735 		 * eat newlines
736 		 */
737 		if (checkkwd == 2) {
738 			checkkwd = 0;
739 			while (t == TNL) {
740 				parseheredoc();
741 				t = xxreadtoken();
742 			}
743 		} else
744 			checkkwd = 0;
745 		/*
746 		 * check for keywords and aliases
747 		 */
748 		if (t == TWORD && !quoteflag)
749 		{
750 			const char * const *pp;
751 
752 			for (pp = parsekwd; *pp; pp++) {
753 				if (**pp == *wordtext && equal(*pp, wordtext))
754 				{
755 					lasttoken = t = pp - parsekwd + KWDOFFSET;
756 					TRACE(("keyword %s recognized\n", tokname[t]));
757 					goto out;
758 				}
759 			}
760 			if (noaliases == 0 &&
761 			    (ap = lookupalias(wordtext, 1)) != NULL) {
762 				pushstring(ap->val, strlen(ap->val), ap);
763 				checkkwd = savecheckkwd;
764 				goto top;
765 			}
766 		}
767 out:
768 		checkkwd = (t == TNOT) ? savecheckkwd : 0;
769 	}
770 #ifdef DEBUG
771 	if (!alreadyseen)
772 	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
773 	else
774 	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
775 #endif
776 	return (t);
777 }
778 
779 
780 /*
781  * Read the next input token.
782  * If the token is a word, we set backquotelist to the list of cmds in
783  *	backquotes.  We set quoteflag to true if any part of the word was
784  *	quoted.
785  * If the token is TREDIR, then we set redirnode to a structure containing
786  *	the redirection.
787  * In all cases, the variable startlinno is set to the number of the line
788  *	on which the token starts.
789  *
790  * [Change comment:  here documents and internal procedures]
791  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
792  *  word parsing code into a separate routine.  In this case, readtoken
793  *  doesn't need to have any internal procedures, but parseword does.
794  *  We could also make parseoperator in essence the main routine, and
795  *  have parseword (readtoken1?) handle both words and redirection.]
796  */
797 
798 #define RETURN(token)	return lasttoken = token
799 
800 STATIC int
801 xxreadtoken(void)
802 {
803 	int c;
804 
805 	if (tokpushback) {
806 		tokpushback = 0;
807 		return lasttoken;
808 	}
809 	if (needprompt) {
810 		setprompt(2);
811 		needprompt = 0;
812 	}
813 	startlinno = plinno;
814 	for (;;) {	/* until token or start of word found */
815 		c = pgetc_macro();
816 		if (c == ' ' || c == '\t')
817 			continue;		/* quick check for white space first */
818 		switch (c) {
819 		case ' ': case '\t':
820 			continue;
821 		case '#':
822 			while ((c = pgetc()) != '\n' && c != PEOF);
823 			pungetc();
824 			continue;
825 		case '\\':
826 			if (pgetc() == '\n') {
827 				startlinno = ++plinno;
828 				if (doprompt)
829 					setprompt(2);
830 				else
831 					setprompt(0);
832 				continue;
833 			}
834 			pungetc();
835 			goto breakloop;
836 		case '\n':
837 			plinno++;
838 			needprompt = doprompt;
839 			RETURN(TNL);
840 		case PEOF:
841 			RETURN(TEOF);
842 		case '&':
843 			if (pgetc() == '&')
844 				RETURN(TAND);
845 			pungetc();
846 			RETURN(TBACKGND);
847 		case '|':
848 			if (pgetc() == '|')
849 				RETURN(TOR);
850 			pungetc();
851 			RETURN(TPIPE);
852 		case ';':
853 			if (pgetc() == ';')
854 				RETURN(TENDCASE);
855 			pungetc();
856 			RETURN(TSEMI);
857 		case '(':
858 			RETURN(TLP);
859 		case ')':
860 			RETURN(TRP);
861 		default:
862 			goto breakloop;
863 		}
864 	}
865 breakloop:
866 	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
867 #undef RETURN
868 }
869 
870 
871 
872 /*
873  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
874  * is not NULL, read a here document.  In the latter case, eofmark is the
875  * word which marks the end of the document and striptabs is true if
876  * leading tabs should be stripped from the document.  The argument firstc
877  * is the first character of the input token or document.
878  *
879  * Because C does not have internal subroutines, I have simulated them
880  * using goto's to implement the subroutine linkage.  The following macros
881  * will run code that appears at the end of readtoken1.
882  */
883 
884 #define CHECKEND()	{goto checkend; checkend_return:;}
885 #define PARSEREDIR()	{goto parseredir; parseredir_return:;}
886 #define PARSESUB()	{goto parsesub; parsesub_return:;}
887 #define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
888 #define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
889 #define	PARSEARITH()	{goto parsearith; parsearith_return:;}
890 
891 STATIC int
892 readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
893 {
894 	int c = firstc;
895 	char *out;
896 	int len;
897 	char line[EOFMARKLEN + 1];
898 	struct nodelist *bqlist;
899 	int quotef;
900 	int dblquote;
901 	int varnest;	/* levels of variables expansion */
902 	int arinest;	/* levels of arithmetic expansion */
903 	int parenlevel;	/* levels of parens in arithmetic */
904 	int oldstyle;
905 	char const *prevsyntax;	/* syntax before arithmetic */
906 	int synentry;
907 #if __GNUC__
908 	/* Avoid longjmp clobbering */
909 	(void) &out;
910 	(void) &quotef;
911 	(void) &dblquote;
912 	(void) &varnest;
913 	(void) &arinest;
914 	(void) &parenlevel;
915 	(void) &oldstyle;
916 	(void) &prevsyntax;
917 	(void) &syntax;
918 	(void) &synentry;
919 #endif
920 
921 	startlinno = plinno;
922 	dblquote = 0;
923 	if (syntax == DQSYNTAX)
924 		dblquote = 1;
925 	quotef = 0;
926 	bqlist = NULL;
927 	varnest = 0;
928 	arinest = 0;
929 	parenlevel = 0;
930 
931 	STARTSTACKSTR(out);
932 	loop: {	/* for each line, until end of word */
933 		CHECKEND();	/* set c to PEOF if at end of here document */
934 		for (;;) {	/* until end of line or end of word */
935 			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
936 
937 			synentry = syntax[c];
938 
939 			switch(synentry) {
940 			case CNL:	/* '\n' */
941 				if (syntax == BASESYNTAX)
942 					goto endword;	/* exit outer loop */
943 				USTPUTC(c, out);
944 				plinno++;
945 				if (doprompt)
946 					setprompt(2);
947 				else
948 					setprompt(0);
949 				c = pgetc();
950 				goto loop;		/* continue outer loop */
951 			case CWORD:
952 				USTPUTC(c, out);
953 				break;
954 			case CCTL:
955 				if (eofmark == NULL || dblquote)
956 					USTPUTC(CTLESC, out);
957 				USTPUTC(c, out);
958 				break;
959 			case CBACK:	/* backslash */
960 				c = pgetc();
961 				if (c == PEOF) {
962 					USTPUTC('\\', out);
963 					pungetc();
964 				} else if (c == '\n') {
965 					if (doprompt)
966 						setprompt(2);
967 					else
968 						setprompt(0);
969 				} else {
970 					if (dblquote && c != '\\' &&
971 					    c != '`' && c != '$' &&
972 					    (c != '"' || eofmark != NULL))
973 						USTPUTC('\\', out);
974 					if (SQSYNTAX[c] == CCTL)
975 						USTPUTC(CTLESC, out);
976 					else if (eofmark == NULL)
977 						USTPUTC(CTLQUOTEMARK, out);
978 					USTPUTC(c, out);
979 					quotef++;
980 				}
981 				break;
982 			case CSQUOTE:
983 				if (eofmark == NULL)
984 					USTPUTC(CTLQUOTEMARK, out);
985 				syntax = SQSYNTAX;
986 				break;
987 			case CDQUOTE:
988 				if (eofmark == NULL)
989 					USTPUTC(CTLQUOTEMARK, out);
990 				syntax = DQSYNTAX;
991 				dblquote = 1;
992 				break;
993 			case CENDQUOTE:
994 				if (eofmark != NULL && arinest == 0 &&
995 				    varnest == 0) {
996 					USTPUTC(c, out);
997 				} else {
998 					if (arinest) {
999 						syntax = ARISYNTAX;
1000 						dblquote = 0;
1001 					} else if (eofmark == NULL) {
1002 						syntax = BASESYNTAX;
1003 						dblquote = 0;
1004 					}
1005 					quotef++;
1006 				}
1007 				break;
1008 			case CVAR:	/* '$' */
1009 				PARSESUB();		/* parse substitution */
1010 				break;
1011 			case CENDVAR:	/* '}' */
1012 				if (varnest > 0) {
1013 					varnest--;
1014 					USTPUTC(CTLENDVAR, out);
1015 				} else {
1016 					USTPUTC(c, out);
1017 				}
1018 				break;
1019 			case CLP:	/* '(' in arithmetic */
1020 				parenlevel++;
1021 				USTPUTC(c, out);
1022 				break;
1023 			case CRP:	/* ')' in arithmetic */
1024 				if (parenlevel > 0) {
1025 					USTPUTC(c, out);
1026 					--parenlevel;
1027 				} else {
1028 					if (pgetc() == ')') {
1029 						if (--arinest == 0) {
1030 							USTPUTC(CTLENDARI, out);
1031 							syntax = prevsyntax;
1032 							if (syntax == DQSYNTAX)
1033 								dblquote = 1;
1034 							else
1035 								dblquote = 0;
1036 						} else
1037 							USTPUTC(')', out);
1038 					} else {
1039 						/*
1040 						 * unbalanced parens
1041 						 *  (don't 2nd guess - no error)
1042 						 */
1043 						pungetc();
1044 						USTPUTC(')', out);
1045 					}
1046 				}
1047 				break;
1048 			case CBQUOTE:	/* '`' */
1049 				PARSEBACKQOLD();
1050 				break;
1051 			case CEOF:
1052 				goto endword;		/* exit outer loop */
1053 			default:
1054 				if (varnest == 0)
1055 					goto endword;	/* exit outer loop */
1056 				USTPUTC(c, out);
1057 			}
1058 			c = pgetc_macro();
1059 		}
1060 	}
1061 endword:
1062 	if (syntax == ARISYNTAX)
1063 		synerror("Missing '))'");
1064 	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
1065 		synerror("Unterminated quoted string");
1066 	if (varnest != 0) {
1067 		startlinno = plinno;
1068 		synerror("Missing '}'");
1069 	}
1070 	USTPUTC('\0', out);
1071 	len = out - stackblock();
1072 	out = stackblock();
1073 	if (eofmark == NULL) {
1074 		if ((c == '>' || c == '<')
1075 		 && quotef == 0
1076 		 && len <= 2
1077 		 && (*out == '\0' || is_digit(*out))) {
1078 			PARSEREDIR();
1079 			return lasttoken = TREDIR;
1080 		} else {
1081 			pungetc();
1082 		}
1083 	}
1084 	quoteflag = quotef;
1085 	backquotelist = bqlist;
1086 	grabstackblock(len);
1087 	wordtext = out;
1088 	return lasttoken = TWORD;
1089 /* end of readtoken routine */
1090 
1091 
1092 
1093 /*
1094  * Check to see whether we are at the end of the here document.  When this
1095  * is called, c is set to the first character of the next input line.  If
1096  * we are at the end of the here document, this routine sets the c to PEOF.
1097  */
1098 
1099 checkend: {
1100 	if (eofmark) {
1101 		if (striptabs) {
1102 			while (c == '\t')
1103 				c = pgetc();
1104 		}
1105 		if (c == *eofmark) {
1106 			if (pfgets(line, sizeof line) != NULL) {
1107 				char *p, *q;
1108 
1109 				p = line;
1110 				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1111 				if (*p == '\n' && *q == '\0') {
1112 					c = PEOF;
1113 					plinno++;
1114 					needprompt = doprompt;
1115 				} else {
1116 					pushstring(line, strlen(line), NULL);
1117 				}
1118 			}
1119 		}
1120 	}
1121 	goto checkend_return;
1122 }
1123 
1124 
1125 /*
1126  * Parse a redirection operator.  The variable "out" points to a string
1127  * specifying the fd to be redirected.  The variable "c" contains the
1128  * first character of the redirection operator.
1129  */
1130 
1131 parseredir: {
1132 	char fd = *out;
1133 	union node *np;
1134 
1135 	np = (union node *)stalloc(sizeof (struct nfile));
1136 	if (c == '>') {
1137 		np->nfile.fd = 1;
1138 		c = pgetc();
1139 		if (c == '>')
1140 			np->type = NAPPEND;
1141 		else if (c == '&')
1142 			np->type = NTOFD;
1143 		else if (c == '|')
1144 			np->type = NCLOBBER;
1145 		else {
1146 			np->type = NTO;
1147 			pungetc();
1148 		}
1149 	} else {	/* c == '<' */
1150 		np->nfile.fd = 0;
1151 		c = pgetc();
1152 		if (c == '<') {
1153 			if (sizeof (struct nfile) != sizeof (struct nhere)) {
1154 				np = (union node *)stalloc(sizeof (struct nhere));
1155 				np->nfile.fd = 0;
1156 			}
1157 			np->type = NHERE;
1158 			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1159 			heredoc->here = np;
1160 			if ((c = pgetc()) == '-') {
1161 				heredoc->striptabs = 1;
1162 			} else {
1163 				heredoc->striptabs = 0;
1164 				pungetc();
1165 			}
1166 		} else if (c == '&')
1167 			np->type = NFROMFD;
1168 		else if (c == '>')
1169 			np->type = NFROMTO;
1170 		else {
1171 			np->type = NFROM;
1172 			pungetc();
1173 		}
1174 	}
1175 	if (fd != '\0')
1176 		np->nfile.fd = digit_val(fd);
1177 	redirnode = np;
1178 	goto parseredir_return;
1179 }
1180 
1181 
1182 /*
1183  * Parse a substitution.  At this point, we have read the dollar sign
1184  * and nothing else.
1185  */
1186 
1187 parsesub: {
1188 	int subtype;
1189 	int typeloc;
1190 	int flags;
1191 	char *p;
1192 #ifndef GDB_HACK
1193 	static const char types[] = "}-+?=";
1194 #endif
1195        int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1196 
1197 	c = pgetc();
1198 	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
1199 		USTPUTC('$', out);
1200 		pungetc();
1201 	} else if (c == '(') {	/* $(command) or $((arith)) */
1202 		if (pgetc() == '(') {
1203 			PARSEARITH();
1204 		} else {
1205 			pungetc();
1206 			PARSEBACKQNEW();
1207 		}
1208 	} else {
1209 		USTPUTC(CTLVAR, out);
1210 		typeloc = out - stackblock();
1211 		USTPUTC(VSNORMAL, out);
1212 		subtype = VSNORMAL;
1213 		if (c == '{') {
1214 			bracketed_name = 1;
1215 			c = pgetc();
1216 			if (c == '#') {
1217 				if ((c = pgetc()) == '}')
1218 					c = '#';
1219 				else
1220 					subtype = VSLENGTH;
1221 			}
1222 			else
1223 				subtype = 0;
1224 		}
1225 		if (is_name(c)) {
1226 			do {
1227 				STPUTC(c, out);
1228 				c = pgetc();
1229 			} while (is_in_name(c));
1230 		} else if (is_digit(c)) {
1231 			if (bracketed_name) {
1232 				do {
1233 					STPUTC(c, out);
1234 					c = pgetc();
1235 				} while (is_digit(c));
1236 			} else {
1237 				STPUTC(c, out);
1238 				c = pgetc();
1239 			}
1240 		} else {
1241 			if (! is_special(c))
1242 badsub:				synerror("Bad substitution");
1243 			USTPUTC(c, out);
1244 			c = pgetc();
1245 		}
1246 		STPUTC('=', out);
1247 		flags = 0;
1248 		if (subtype == 0) {
1249 			switch (c) {
1250 			case ':':
1251 				flags = VSNUL;
1252 				c = pgetc();
1253 				/*FALLTHROUGH*/
1254 			default:
1255 				p = strchr(types, c);
1256 				if (p == NULL)
1257 					goto badsub;
1258 				subtype = p - types + VSNORMAL;
1259 				break;
1260 			case '%':
1261 			case '#':
1262 				{
1263 					int cc = c;
1264 					subtype = c == '#' ? VSTRIMLEFT :
1265 							     VSTRIMRIGHT;
1266 					c = pgetc();
1267 					if (c == cc)
1268 						subtype++;
1269 					else
1270 						pungetc();
1271 					break;
1272 				}
1273 			}
1274 		} else {
1275 			pungetc();
1276 		}
1277 		if (subtype != VSLENGTH && (dblquote || arinest))
1278 			flags |= VSQUOTE;
1279 		*(stackblock() + typeloc) = subtype | flags;
1280 		if (subtype != VSNORMAL)
1281 			varnest++;
1282 	}
1283 	goto parsesub_return;
1284 }
1285 
1286 
1287 /*
1288  * Called to parse command substitutions.  Newstyle is set if the command
1289  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1290  * list of commands (passed by reference), and savelen is the number of
1291  * characters on the top of the stack which must be preserved.
1292  */
1293 
1294 parsebackq: {
1295 	struct nodelist **nlpp;
1296 	int savepbq;
1297 	union node *n;
1298 	char *volatile str;
1299 	struct jmploc jmploc;
1300 	struct jmploc *volatile savehandler;
1301 	int savelen;
1302 	int saveprompt;
1303 #if __GNUC__
1304 	/* Avoid longjmp clobbering */
1305 	(void) &saveprompt;
1306 #endif
1307 
1308 	savepbq = parsebackquote;
1309 	if (setjmp(jmploc.loc)) {
1310 		if (str)
1311 			ckfree(str);
1312 		parsebackquote = 0;
1313 		handler = savehandler;
1314 		longjmp(handler->loc, 1);
1315 	}
1316 	INTOFF;
1317 	str = NULL;
1318 	savelen = out - stackblock();
1319 	if (savelen > 0) {
1320 		str = ckmalloc(savelen);
1321 		memcpy(str, stackblock(), savelen);
1322 	}
1323 	savehandler = handler;
1324 	handler = &jmploc;
1325 	INTON;
1326         if (oldstyle) {
1327                 /* We must read until the closing backquote, giving special
1328                    treatment to some slashes, and then push the string and
1329                    reread it as input, interpreting it normally.  */
1330                 char *out;
1331                 int c;
1332                 int savelen;
1333                 char *str;
1334 
1335 
1336                 STARTSTACKSTR(out);
1337 		for (;;) {
1338 			if (needprompt) {
1339 				setprompt(2);
1340 				needprompt = 0;
1341 			}
1342 			switch (c = pgetc()) {
1343 			case '`':
1344 				goto done;
1345 
1346 			case '\\':
1347                                 if ((c = pgetc()) == '\n') {
1348 					plinno++;
1349 					if (doprompt)
1350 						setprompt(2);
1351 					else
1352 						setprompt(0);
1353 					/*
1354 					 * If eating a newline, avoid putting
1355 					 * the newline into the new character
1356 					 * stream (via the STPUTC after the
1357 					 * switch).
1358 					 */
1359 					continue;
1360 				}
1361                                 if (c != '\\' && c != '`' && c != '$'
1362                                     && (!dblquote || c != '"'))
1363                                         STPUTC('\\', out);
1364 				break;
1365 
1366 			case '\n':
1367 				plinno++;
1368 				needprompt = doprompt;
1369 				break;
1370 
1371 			case PEOF:
1372 			        startlinno = plinno;
1373 				synerror("EOF in backquote substitution");
1374  				break;
1375 
1376 			default:
1377 				break;
1378 			}
1379 			STPUTC(c, out);
1380                 }
1381 done:
1382                 STPUTC('\0', out);
1383                 savelen = out - stackblock();
1384                 if (savelen > 0) {
1385                         str = ckmalloc(savelen);
1386                         memcpy(str, stackblock(), savelen);
1387 			setinputstring(str, 1);
1388                 }
1389         }
1390 	nlpp = &bqlist;
1391 	while (*nlpp)
1392 		nlpp = &(*nlpp)->next;
1393 	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1394 	(*nlpp)->next = NULL;
1395 	parsebackquote = oldstyle;
1396 
1397 	if (oldstyle) {
1398 		saveprompt = doprompt;
1399 		doprompt = 0;
1400 	}
1401 
1402 	n = list(0);
1403 
1404 	if (oldstyle)
1405 		doprompt = saveprompt;
1406 	else {
1407 		if (readtoken() != TRP)
1408 			synexpect(TRP);
1409 	}
1410 
1411 	(*nlpp)->n = n;
1412         if (oldstyle) {
1413 		/*
1414 		 * Start reading from old file again, ignoring any pushed back
1415 		 * tokens left from the backquote parsing
1416 		 */
1417                 popfile();
1418 		tokpushback = 0;
1419 	}
1420 	while (stackblocksize() <= savelen)
1421 		growstackblock();
1422 	STARTSTACKSTR(out);
1423 	if (str) {
1424 		memcpy(out, str, savelen);
1425 		STADJUST(savelen, out);
1426 		INTOFF;
1427 		ckfree(str);
1428 		str = NULL;
1429 		INTON;
1430 	}
1431 	parsebackquote = savepbq;
1432 	handler = savehandler;
1433 	if (arinest || dblquote)
1434 		USTPUTC(CTLBACKQ | CTLQUOTE, out);
1435 	else
1436 		USTPUTC(CTLBACKQ, out);
1437 	if (oldstyle)
1438 		goto parsebackq_oldreturn;
1439 	else
1440 		goto parsebackq_newreturn;
1441 }
1442 
1443 /*
1444  * Parse an arithmetic expansion (indicate start of one and set state)
1445  */
1446 parsearith: {
1447 
1448 	if (++arinest == 1) {
1449 		prevsyntax = syntax;
1450 		syntax = ARISYNTAX;
1451 		USTPUTC(CTLARI, out);
1452 		if (dblquote)
1453 			USTPUTC('"',out);
1454 		else
1455 			USTPUTC(' ',out);
1456 	} else {
1457 		/*
1458 		 * we collapse embedded arithmetic expansion to
1459 		 * parenthesis, which should be equivalent
1460 		 */
1461 		USTPUTC('(', out);
1462 	}
1463 	goto parsearith_return;
1464 }
1465 
1466 } /* end of readtoken */
1467 
1468 
1469 
1470 #ifdef mkinit
1471 RESET {
1472 	tokpushback = 0;
1473 	checkkwd = 0;
1474 }
1475 #endif
1476 
1477 /*
1478  * Returns true if the text contains nothing to expand (no dollar signs
1479  * or backquotes).
1480  */
1481 
1482 STATIC int
1483 noexpand(char *text)
1484 {
1485 	char *p;
1486 	char c;
1487 
1488 	p = text;
1489 	while ((c = *p++) != '\0') {
1490 		if ( c == CTLQUOTEMARK)
1491 			continue;
1492 		if (c == CTLESC)
1493 			p++;
1494 		else if (BASESYNTAX[(int)c] == CCTL)
1495 			return 0;
1496 	}
1497 	return 1;
1498 }
1499 
1500 
1501 /*
1502  * Return true if the argument is a legal variable name (a letter or
1503  * underscore followed by zero or more letters, underscores, and digits).
1504  */
1505 
1506 int
1507 goodname(char *name)
1508 {
1509 	char *p;
1510 
1511 	p = name;
1512 	if (! is_name(*p))
1513 		return 0;
1514 	while (*++p) {
1515 		if (! is_in_name(*p))
1516 			return 0;
1517 	}
1518 	return 1;
1519 }
1520 
1521 
1522 /*
1523  * Called when an unexpected token is read during the parse.  The argument
1524  * is the token that is expected, or -1 if more than one type of token can
1525  * occur at this point.
1526  */
1527 
1528 STATIC void
1529 synexpect(int token)
1530 {
1531 	char msg[64];
1532 
1533 	if (token >= 0) {
1534 		fmtstr(msg, 64, "%s unexpected (expecting %s)",
1535 			tokname[lasttoken], tokname[token]);
1536 	} else {
1537 		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1538 	}
1539 	synerror(msg);
1540 }
1541 
1542 
1543 STATIC void
1544 synerror(char *msg)
1545 {
1546 	if (commandname)
1547 		outfmt(&errout, "%s: %d: ", commandname, startlinno);
1548 	outfmt(&errout, "Syntax error: %s\n", msg);
1549 	error((char *)NULL);
1550 }
1551 
1552 STATIC void
1553 setprompt(int which)
1554 {
1555 	whichprompt = which;
1556 
1557 #ifndef NO_HISTORY
1558 	if (!el)
1559 #endif
1560 		out2str(getprompt(NULL));
1561 }
1562 
1563 /*
1564  * called by editline -- any expansions to the prompt
1565  *    should be added here.
1566  */
1567 char *
1568 getprompt(void *unused __unused)
1569 {
1570 	switch (whichprompt) {
1571 	case 0:
1572 		return "";
1573 	case 1:
1574 		return ps1val();
1575 	case 2:
1576 		return ps2val();
1577 	default:
1578 		return "<internal prompt error>";
1579 	}
1580 }
1581