xref: /original-bsd/bin/sh/parser.c (revision cba8738a)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Kenneth Almquist.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)parser.c	5.3 (Berkeley) 04/12/91";
13 #endif /* not lint */
14 
15 #include "shell.h"
16 #include "parser.h"
17 #include "nodes.h"
18 #include "expand.h"	/* defines rmescapes() */
19 #include "redir.h"	/* defines copyfd() */
20 #include "syntax.h"
21 #include "options.h"
22 #include "input.h"
23 #include "output.h"
24 #include "var.h"
25 #include "error.h"
26 #include "memalloc.h"
27 #include "mystring.h"
28 
29 
30 /*
31  * Shell command parser.
32  */
33 
34 #define EOFMARKLEN 79
35 
36 /* values returned by readtoken */
37 #include "token.def"
38 
39 
40 
41 struct heredoc {
42 	struct heredoc *next;	/* next here document in list */
43 	union node *here;		/* redirection node */
44 	char *eofmark;		/* string indicating end of input */
45 	int striptabs;		/* if set, strip leading tabs */
46 };
47 
48 
49 
50 struct heredoc *heredoclist;	/* list of here documents to read */
51 int parsebackquote;		/* nonzero if we are inside backquotes */
52 int doprompt;			/* if set, prompt the user */
53 int needprompt;			/* true if interactive and at start of line */
54 int lasttoken;			/* last token read */
55 MKINIT int tokpushback;		/* last token pushed back */
56 char *wordtext;			/* text of last word returned by readtoken */
57 int checkkwd;               /* 1 == check for kwds, 2 == also eat newlines */
58 struct nodelist *backquotelist;
59 union node *redirnode;
60 struct heredoc *heredoc;
61 int quoteflag;			/* set if (part of) last token was quoted */
62 int startlinno;			/* line # where last token started */
63 
64 
65 #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
66 #ifdef GDB_HACK
67 static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
68 static const char types[] = "}-+?=";
69 #endif
70 
71 
72 STATIC union node *list __P((int));
73 STATIC union node *andor __P((void));
74 STATIC union node *pipeline __P((void));
75 STATIC union node *command __P((void));
76 STATIC union node *simplecmd __P((void));
77 STATIC void parsefname __P((void));
78 STATIC void parseheredoc __P((void));
79 STATIC int readtoken __P((void));
80 STATIC int readtoken1 __P((int, char const *, char *, int));
81 STATIC void attyline __P((void));
82 STATIC int noexpand __P((char *));
83 STATIC void synexpect __P((int));
84 STATIC void synerror __P((char *));
85 
86 #if ATTY
87 STATIC void putprompt __P((char *));
88 #else /* not ATTY */
89 #define putprompt(s)	out2str(s)
90 #endif
91 
92 
93 
94 
95 /*
96  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
97  * valid parse tree indicating a blank line.)
98  */
99 
100 union node *
101 parsecmd(interact) {
102 	int t;
103 
104 	doprompt = interact;
105 	if (doprompt)
106 		putprompt(ps1val());
107 	needprompt = 0;
108 	if ((t = readtoken()) == TEOF)
109 		return NEOF;
110 	if (t == TNL)
111 		return NULL;
112 	tokpushback++;
113 	return list(1);
114 }
115 
116 
117 STATIC union node *
118 list(nlflag) {
119 	union node *n1, *n2, *n3;
120 
121 	checkkwd = 2;
122 	if (nlflag == 0 && tokendlist[peektoken()])
123 		return NULL;
124 	n1 = andor();
125 	for (;;) {
126 		switch (readtoken()) {
127 		case TBACKGND:
128 			if (n1->type == NCMD || n1->type == NPIPE) {
129 				n1->ncmd.backgnd = 1;
130 			} else if (n1->type == NREDIR) {
131 				n1->type = NBACKGND;
132 			} else {
133 				n3 = (union node *)stalloc(sizeof (struct nredir));
134 				n3->type = NBACKGND;
135 				n3->nredir.n = n1;
136 				n3->nredir.redirect = NULL;
137 				n1 = n3;
138 			}
139 			goto tsemi;
140 		case TNL:
141 			tokpushback++;
142 			/* fall through */
143 tsemi:	    case TSEMI:
144 			if (readtoken() == TNL) {
145 				parseheredoc();
146 				if (nlflag)
147 					return n1;
148 			} else {
149 				tokpushback++;
150 			}
151 			checkkwd = 2;
152 			if (tokendlist[peektoken()])
153 				return n1;
154 			n2 = andor();
155 			n3 = (union node *)stalloc(sizeof (struct nbinary));
156 			n3->type = NSEMI;
157 			n3->nbinary.ch1 = n1;
158 			n3->nbinary.ch2 = n2;
159 			n1 = n3;
160 			break;
161 		case TEOF:
162 			if (heredoclist)
163 				parseheredoc();
164 			else
165 				pungetc();		/* push back EOF on input */
166 			return n1;
167 		default:
168 			if (nlflag)
169 				synexpect(-1);
170 			tokpushback++;
171 			return n1;
172 		}
173 	}
174 }
175 
176 
177 
178 STATIC union node *
179 andor() {
180 	union node *n1, *n2, *n3;
181 	int t;
182 
183 	n1 = pipeline();
184 	for (;;) {
185 		if ((t = readtoken()) == TAND) {
186 			t = NAND;
187 		} else if (t == TOR) {
188 			t = NOR;
189 		} else {
190 			tokpushback++;
191 			return n1;
192 		}
193 		n2 = pipeline();
194 		n3 = (union node *)stalloc(sizeof (struct nbinary));
195 		n3->type = t;
196 		n3->nbinary.ch1 = n1;
197 		n3->nbinary.ch2 = n2;
198 		n1 = n3;
199 	}
200 }
201 
202 
203 
204 STATIC union node *
205 pipeline() {
206 	union node *n1, *pipenode;
207 	struct nodelist *lp, *prev;
208 
209 	n1 = command();
210 	if (readtoken() == TPIPE) {
211 		pipenode = (union node *)stalloc(sizeof (struct npipe));
212 		pipenode->type = NPIPE;
213 		pipenode->npipe.backgnd = 0;
214 		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
215 		pipenode->npipe.cmdlist = lp;
216 		lp->n = n1;
217 		do {
218 			prev = lp;
219 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
220 			lp->n = command();
221 			prev->next = lp;
222 		} while (readtoken() == TPIPE);
223 		lp->next = NULL;
224 		n1 = pipenode;
225 	}
226 	tokpushback++;
227 	return n1;
228 }
229 
230 
231 
232 STATIC union node *
233 command() {
234 	union node *n1, *n2;
235 	union node *ap, **app;
236 	union node *cp, **cpp;
237 	union node *redir, **rpp;
238 	int t;
239 
240 	checkkwd = 2;
241 	switch (readtoken()) {
242 	case TIF:
243 		n1 = (union node *)stalloc(sizeof (struct nif));
244 		n1->type = NIF;
245 		n1->nif.test = list(0);
246 		if (readtoken() != TTHEN)
247 			synexpect(TTHEN);
248 		n1->nif.ifpart = list(0);
249 		n2 = n1;
250 		while (readtoken() == TELIF) {
251 			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
252 			n2 = n2->nif.elsepart;
253 			n2->type = NIF;
254 			n2->nif.test = list(0);
255 			if (readtoken() != TTHEN)
256 				synexpect(TTHEN);
257 			n2->nif.ifpart = list(0);
258 		}
259 		if (lasttoken == TELSE)
260 			n2->nif.elsepart = list(0);
261 		else {
262 			n2->nif.elsepart = NULL;
263 			tokpushback++;
264 		}
265 		if (readtoken() != TFI)
266 			synexpect(TFI);
267 		checkkwd = 1;
268 		break;
269 	case TWHILE:
270 	case TUNTIL: {
271 		int got;
272 		n1 = (union node *)stalloc(sizeof (struct nbinary));
273 		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
274 		n1->nbinary.ch1 = list(0);
275 		if ((got=readtoken()) != TDO) {
276 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
277 			synexpect(TDO);
278 		}
279 		n1->nbinary.ch2 = list(0);
280 		if (readtoken() != TDONE)
281 			synexpect(TDONE);
282 		checkkwd = 1;
283 		break;
284 	}
285 	case TFOR:
286 		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
287 			synerror("Bad for loop variable");
288 		n1 = (union node *)stalloc(sizeof (struct nfor));
289 		n1->type = NFOR;
290 		n1->nfor.var = wordtext;
291 		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
292 			app = ≈
293 			while (readtoken() == TWORD) {
294 				n2 = (union node *)stalloc(sizeof (struct narg));
295 				n2->type = NARG;
296 				n2->narg.text = wordtext;
297 				n2->narg.backquote = backquotelist;
298 				*app = n2;
299 				app = &n2->narg.next;
300 			}
301 			*app = NULL;
302 			n1->nfor.args = ap;
303 		} else {
304 #ifndef GDB_HACK
305 			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
306 								   '@', '=', '\0'};
307 #endif
308 			n2 = (union node *)stalloc(sizeof (struct narg));
309 			n2->type = NARG;
310 			n2->narg.text = (char *)argvars;
311 			n2->narg.backquote = NULL;
312 			n2->narg.next = NULL;
313 			n1->nfor.args = n2;
314 		}
315 		if (lasttoken != TNL && lasttoken != TSEMI)
316 			synexpect(-1);
317 		checkkwd = 2;
318 		if ((t = readtoken()) == TDO)
319 			t = TDONE;
320 		else if (t == TBEGIN)
321 			t = TEND;
322 		else
323 			synexpect(-1);
324 		n1->nfor.body = list(0);
325 		if (readtoken() != t)
326 			synexpect(t);
327 		checkkwd = 1;
328 		break;
329 	case TCASE:
330 		n1 = (union node *)stalloc(sizeof (struct ncase));
331 		n1->type = NCASE;
332 		if (readtoken() != TWORD)
333 			synexpect(TWORD);
334 		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
335 		n2->type = NARG;
336 		n2->narg.text = wordtext;
337 		n2->narg.backquote = backquotelist;
338 		n2->narg.next = NULL;
339 		while (readtoken() == TNL);
340 		if (lasttoken != TWORD || ! equal(wordtext, "in"))
341 			synerror("expecting \"in\"");
342 		cpp = &n1->ncase.cases;
343 		while (checkkwd = 2, readtoken() == TWORD) {
344 			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
345 			cp->type = NCLIST;
346 			app = &cp->nclist.pattern;
347 			for (;;) {
348 				*app = ap = (union node *)stalloc(sizeof (struct narg));
349 				ap->type = NARG;
350 				ap->narg.text = wordtext;
351 				ap->narg.backquote = backquotelist;
352 				if (readtoken() != TPIPE)
353 					break;
354 				app = &ap->narg.next;
355 				if (readtoken() != TWORD)
356 					synexpect(TWORD);
357 			}
358 			ap->narg.next = NULL;
359 			if (lasttoken != TRP)
360 				synexpect(TRP);
361 			cp->nclist.body = list(0);
362 			if ((t = readtoken()) == TESAC)
363 				tokpushback++;
364 			else if (t != TENDCASE)
365 				synexpect(TENDCASE);
366 			cpp = &cp->nclist.next;
367 		}
368 		*cpp = NULL;
369 		if (lasttoken != TESAC)
370 			synexpect(TESAC);
371 		checkkwd = 1;
372 		break;
373 	case TLP:
374 		n1 = (union node *)stalloc(sizeof (struct nredir));
375 		n1->type = NSUBSHELL;
376 		n1->nredir.n = list(0);
377 		n1->nredir.redirect = NULL;
378 		if (readtoken() != TRP)
379 			synexpect(TRP);
380 		checkkwd = 1;
381 		break;
382 	case TBEGIN:
383 		n1 = list(0);
384 		if (readtoken() != TEND)
385 			synexpect(TEND);
386 		checkkwd = 1;
387 		break;
388 	case TWORD:
389 	case TREDIR:
390 		tokpushback++;
391 		return simplecmd();
392 	default:
393 		synexpect(-1);
394 	}
395 
396 	/* Now check for redirection which may follow command */
397 	rpp = &redir;
398 	while (readtoken() == TREDIR) {
399 		*rpp = n2 = redirnode;
400 		rpp = &n2->nfile.next;
401 		parsefname();
402 	}
403 	tokpushback++;
404 	*rpp = NULL;
405 	if (redir) {
406 		if (n1->type != NSUBSHELL) {
407 			n2 = (union node *)stalloc(sizeof (struct nredir));
408 			n2->type = NREDIR;
409 			n2->nredir.n = n1;
410 			n1 = n2;
411 		}
412 		n1->nredir.redirect = redir;
413 	}
414 	return n1;
415 }
416 
417 
418 STATIC union node *
419 simplecmd() {
420 	union node *args, **app;
421 	union node *redir, **rpp;
422 	union node *n;
423 
424 	args = NULL;
425 	app = &args;
426 	rpp = &redir;
427 	for (;;) {
428 		if (readtoken() == TWORD) {
429 			n = (union node *)stalloc(sizeof (struct narg));
430 			n->type = NARG;
431 			n->narg.text = wordtext;
432 			n->narg.backquote = backquotelist;
433 			*app = n;
434 			app = &n->narg.next;
435 		} else if (lasttoken == TREDIR) {
436 			*rpp = n = redirnode;
437 			rpp = &n->nfile.next;
438 			parsefname();	/* read name of redirection file */
439 		} else if (lasttoken == TLP && app == &args->narg.next
440 					    && rpp == &redir) {
441 			/* We have a function */
442 			if (readtoken() != TRP)
443 				synexpect(TRP);
444 #ifdef notdef
445 			if (! goodname(n->narg.text))
446 				synerror("Bad function name");
447 #endif
448 			n->type = NDEFUN;
449 			n->narg.next = command();
450 			return n;
451 		} else {
452 			tokpushback++;
453 			break;
454 		}
455 	}
456 	*app = NULL;
457 	*rpp = NULL;
458 	n = (union node *)stalloc(sizeof (struct ncmd));
459 	n->type = NCMD;
460 	n->ncmd.backgnd = 0;
461 	n->ncmd.args = args;
462 	n->ncmd.redirect = redir;
463 	return n;
464 }
465 
466 
467 STATIC void
468 parsefname() {
469 	union node *n = redirnode;
470 
471 	if (readtoken() != TWORD)
472 		synexpect(-1);
473 	if (n->type == NHERE) {
474 		struct heredoc *here = heredoc;
475 		struct heredoc *p;
476 		int i;
477 
478 		if (quoteflag == 0)
479 			n->type = NXHERE;
480 		TRACE(("Here document %d\n", n->type));
481 		if (here->striptabs) {
482 			while (*wordtext == '\t')
483 				wordtext++;
484 		}
485 		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
486 			synerror("Illegal eof marker for << redirection");
487 		rmescapes(wordtext);
488 		here->eofmark = wordtext;
489 		here->next = NULL;
490 		if (heredoclist == NULL)
491 			heredoclist = here;
492 		else {
493 			for (p = heredoclist ; p->next ; p = p->next);
494 			p->next = here;
495 		}
496 	} else if (n->type == NTOFD || n->type == NFROMFD) {
497 		if (is_digit(wordtext[0]))
498 			n->ndup.dupfd = digit_val(wordtext[0]);
499 		else if (wordtext[0] == '-')
500 			n->ndup.dupfd = -1;
501 		else
502 			goto bad;
503 		if (wordtext[1] != '\0') {
504 bad:
505 			synerror("Bad fd number");
506 		}
507 	} else {
508 		n->nfile.fname = (union node *)stalloc(sizeof (struct narg));
509 		n = n->nfile.fname;
510 		n->type = NARG;
511 		n->narg.next = NULL;
512 		n->narg.text = wordtext;
513 		n->narg.backquote = backquotelist;
514 	}
515 }
516 
517 
518 /*
519  * Input any here documents.
520  */
521 
522 STATIC void
523 parseheredoc() {
524 	struct heredoc *here;
525 	union node *n;
526 
527 	while (heredoclist) {
528 		here = heredoclist;
529 		heredoclist = here->next;
530 		if (needprompt) {
531 			putprompt(ps2val());
532 			needprompt = 0;
533 		}
534 		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
535 				here->eofmark, here->striptabs);
536 		n = (union node *)stalloc(sizeof (struct narg));
537 		n->narg.type = NARG;
538 		n->narg.next = NULL;
539 		n->narg.text = wordtext;
540 		n->narg.backquote = backquotelist;
541 		here->here->nhere.doc = n;
542 	}
543 }
544 
545 STATIC int
546 peektoken() {
547 	int t;
548 
549 	t = readtoken();
550 	tokpushback++;
551 	return (t);
552 }
553 
554 STATIC int xxreadtoken();
555 
556 STATIC int
557 readtoken() {
558 	int t;
559 #ifdef DEBUG
560 	int alreadyseen = tokpushback;
561 #endif
562 
563 	t = xxreadtoken();
564 
565 	if (checkkwd) {
566 		/*
567 		 * eat newlines
568 		 */
569 		if (checkkwd == 2) {
570 			checkkwd = 0;
571 			while (t == TNL) {
572 				parseheredoc();
573 				t = xxreadtoken();
574 			}
575 		} else
576 			checkkwd = 0;
577 		/*
578 		 * check for keywords
579 		 */
580 		if (t == TWORD && !quoteflag) {
581 			register char **pp;
582 
583 			for (pp = parsekwd; *pp; pp++) {
584 				if (**pp == *wordtext && equal(*pp, wordtext)) {
585 					lasttoken = t = pp - parsekwd + KWDOFFSET;
586 					TRACE(("keyword %s recognized\n", tokname[t]));
587 					break;
588 				}
589 			}
590 		}
591 	}
592 #ifdef DEBUG
593 	if (!alreadyseen)
594 	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
595 	else
596 	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
597 #endif
598 	return (t);
599 }
600 
601 
602 /*
603  * Read the next input token.
604  * If the token is a word, we set backquotelist to the list of cmds in
605  *	backquotes.  We set quoteflag to true if any part of the word was
606  *	quoted.
607  * If the token is TREDIR, then we set redirnode to a structure containing
608  *	the redirection.
609  * In all cases, the variable startlinno is set to the number of the line
610  *	on which the token starts.
611  *
612  * [Change comment:  here documents and internal procedures]
613  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
614  *  word parsing code into a separate routine.  In this case, readtoken
615  *  doesn't need to have any internal procedures, but parseword does.
616  *  We could also make parseoperator in essence the main routine, and
617  *  have parseword (readtoken1?) handle both words and redirection.]
618  */
619 
620 #define RETURN(token)	return lasttoken = token
621 
622 STATIC int
623 xxreadtoken() {
624 	register c;
625 
626 	if (tokpushback) {
627 		tokpushback = 0;
628 		return lasttoken;
629 	}
630 	if (needprompt) {
631 		putprompt(ps2val());
632 		needprompt = 0;
633 	}
634 	startlinno = plinno;
635 	for (;;) {	/* until token or start of word found */
636 		c = pgetc_macro();
637 		if (c == ' ' || c == '\t')
638 			continue;		/* quick check for white space first */
639 		switch (c) {
640 		case ' ': case '\t':
641 			continue;
642 		case '#':
643 			while ((c = pgetc()) != '\n' && c != PEOF);
644 			pungetc();
645 			continue;
646 		case '\\':
647 			if (pgetc() == '\n') {
648 				startlinno = ++plinno;
649 				if (doprompt)
650 					putprompt(ps2val());
651 				continue;
652 			}
653 			pungetc();
654 			goto breakloop;
655 		case '\n':
656 			plinno++;
657 			needprompt = doprompt;
658 			RETURN(TNL);
659 		case PEOF:
660 			RETURN(TEOF);
661 		case '&':
662 			if (pgetc() == '&')
663 				RETURN(TAND);
664 			pungetc();
665 			RETURN(TBACKGND);
666 		case '|':
667 			if (pgetc() == '|')
668 				RETURN(TOR);
669 			pungetc();
670 			RETURN(TPIPE);
671 		case ';':
672 			if (pgetc() == ';')
673 				RETURN(TENDCASE);
674 			pungetc();
675 			RETURN(TSEMI);
676 		case '(':
677 			RETURN(TLP);
678 		case ')':
679 			RETURN(TRP);
680 		default:
681 			goto breakloop;
682 		}
683 	}
684 breakloop:
685 	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
686 #undef RETURN
687 }
688 
689 
690 
691 /*
692  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
693  * is not NULL, read a here document.  In the latter case, eofmark is the
694  * word which marks the end of the document and striptabs is true if
695  * leading tabs should be stripped from the document.  The argument firstc
696  * is the first character of the input token or document.
697  *
698  * Because C does not have internal subroutines, I have simulated them
699  * using goto's to implement the subroutine linkage.  The following macros
700  * will run code that appears at the end of readtoken1.
701  */
702 
703 #define CHECKEND()	{goto checkend; checkend_return:;}
704 #define PARSEREDIR()	{goto parseredir; parseredir_return:;}
705 #define PARSESUB()	{goto parsesub; parsesub_return:;}
706 #define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
707 #define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
708 
709 STATIC int
710 readtoken1(firstc, syntax, eofmark, striptabs)
711 	int firstc;
712 	char const *syntax;
713 	char *eofmark;
714 	int striptabs;
715 	{
716 	register c = firstc;
717 	register char *out;
718 	int len;
719 	char line[EOFMARKLEN + 1];
720 	struct nodelist *bqlist;
721 	int quotef;
722 	int dblquote;
723 	int varnest;
724 	int oldstyle;
725 
726 	startlinno = plinno;
727 	dblquote = 0;
728 	if (syntax == DQSYNTAX)
729 		dblquote = 1;
730 	quotef = 0;
731 	bqlist = NULL;
732 	varnest = 0;
733 	STARTSTACKSTR(out);
734 	loop: {	/* for each line, until end of word */
735 #if ATTY
736 		if (c == '\034' && doprompt
737 		 && attyset() && ! equal(termval(), "emacs")) {
738 			attyline();
739 			if (syntax == BASESYNTAX)
740 				return readtoken();
741 			c = pgetc();
742 			goto loop;
743 		}
744 #endif
745 		CHECKEND();	/* set c to PEOF if at end of here document */
746 		for (;;) {	/* until end of line or end of word */
747 			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
748 			switch(syntax[c]) {
749 			case CNL:	/* '\n' */
750 				if (syntax == BASESYNTAX)
751 					goto endword;	/* exit outer loop */
752 				USTPUTC(c, out);
753 				plinno++;
754 				if (doprompt) {
755 					putprompt(ps2val());
756 				}
757 				c = pgetc();
758 				goto loop;		/* continue outer loop */
759 			case CWORD:
760 				USTPUTC(c, out);
761 				break;
762 			case CCTL:
763 				if (eofmark == NULL || dblquote)
764 					USTPUTC(CTLESC, out);
765 				USTPUTC(c, out);
766 				break;
767 			case CBACK:	/* backslash */
768 				c = pgetc();
769 				if (c == PEOF) {
770 					USTPUTC('\\', out);
771 					pungetc();
772 				} else if (c == '\n') {
773 					if (doprompt)
774 						putprompt(ps2val());
775 				} else {
776 					if (dblquote && c != '\\' && c != '`' && c != '$'
777 							 && (c != '"' || eofmark != NULL))
778 						USTPUTC('\\', out);
779 					if (SQSYNTAX[c] == CCTL)
780 						USTPUTC(CTLESC, out);
781 					USTPUTC(c, out);
782 					quotef++;
783 				}
784 				break;
785 			case CSQUOTE:
786 				syntax = SQSYNTAX;
787 				break;
788 			case CDQUOTE:
789 				syntax = DQSYNTAX;
790 				dblquote = 1;
791 				break;
792 			case CENDQUOTE:
793 				if (eofmark) {
794 					USTPUTC(c, out);
795 				} else {
796 					syntax = BASESYNTAX;
797 					quotef++;
798 					dblquote = 0;
799 				}
800 				break;
801 			case CVAR:	/* '$' */
802 				PARSESUB();		/* parse substitution */
803 				break;
804 			case CENDVAR:	/* '}' */
805 				if (varnest > 0) {
806 					varnest--;
807 					USTPUTC(CTLENDVAR, out);
808 				} else {
809 					USTPUTC(c, out);
810 				}
811 				break;
812 			case CBQUOTE:	/* '`' */
813 				if (parsebackquote && syntax == BASESYNTAX) {
814 					if (out == stackblock())
815 						return lasttoken = TENDBQUOTE;
816 					else
817 						goto endword;	/* exit outer loop */
818 				}
819 				PARSEBACKQOLD();
820 				break;
821 			case CEOF:
822 				goto endword;		/* exit outer loop */
823 			default:
824 				if (varnest == 0)
825 					goto endword;	/* exit outer loop */
826 				USTPUTC(c, out);
827 			}
828 			c = pgetc_macro();
829 		}
830 	}
831 endword:
832 	if (syntax != BASESYNTAX && eofmark == NULL)
833 		synerror("Unterminated quoted string");
834 	if (varnest != 0) {
835 		startlinno = plinno;
836 		synerror("Missing '}'");
837 	}
838 	USTPUTC('\0', out);
839 	len = out - stackblock();
840 	out = stackblock();
841 	if (eofmark == NULL) {
842 		if ((c == '>' || c == '<')
843 		 && quotef == 0
844 		 && len <= 2
845 		 && (*out == '\0' || is_digit(*out))) {
846 			PARSEREDIR();
847 			return lasttoken = TREDIR;
848 		} else {
849 			pungetc();
850 		}
851 	}
852 	quoteflag = quotef;
853 	backquotelist = bqlist;
854 	grabstackblock(len);
855 	wordtext = out;
856 	return lasttoken = TWORD;
857 /* end of readtoken routine */
858 
859 
860 
861 /*
862  * Check to see whether we are at the end of the here document.  When this
863  * is called, c is set to the first character of the next input line.  If
864  * we are at the end of the here document, this routine sets the c to PEOF.
865  */
866 
867 checkend: {
868 	if (eofmark) {
869 		if (striptabs) {
870 			while (c == '\t')
871 				c = pgetc();
872 		}
873 		if (c == *eofmark) {
874 			if (pfgets(line, sizeof line) != NULL) {
875 				register char *p, *q;
876 
877 				p = line;
878 				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
879 				if (*p == '\n' && *q == '\0') {
880 					c = PEOF;
881 					plinno++;
882 					needprompt = doprompt;
883 				} else {
884 					ppushback(line, strlen(line));
885 				}
886 			}
887 		}
888 	}
889 	goto checkend_return;
890 }
891 
892 
893 /*
894  * Parse a redirection operator.  The variable "out" points to a string
895  * specifying the fd to be redirected.  The variable "c" contains the
896  * first character of the redirection operator.
897  */
898 
899 parseredir: {
900 	char fd = *out;
901 	union node *np;
902 
903 	np = (union node *)stalloc(sizeof (struct nfile));
904 	if (c == '>') {
905 		np->nfile.fd = 1;
906 		c = pgetc();
907 		if (c == '>')
908 			np->type = NAPPEND;
909 		else if (c == '&')
910 			np->type = NTOFD;
911 		else {
912 			np->type = NTO;
913 			pungetc();
914 		}
915 	} else {	/* c == '<' */
916 		np->nfile.fd = 0;
917 		c = pgetc();
918 		if (c == '<') {
919 			if (sizeof (struct nfile) != sizeof (struct nhere)) {
920 				np = (union node *)stalloc(sizeof (struct nhere));
921 				np->nfile.fd = 0;
922 			}
923 			np->type = NHERE;
924 			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
925 			heredoc->here = np;
926 			if ((c = pgetc()) == '-') {
927 				heredoc->striptabs = 1;
928 			} else {
929 				heredoc->striptabs = 0;
930 				pungetc();
931 			}
932 		} else if (c == '&')
933 			np->type = NFROMFD;
934 		else {
935 			np->type = NFROM;
936 			pungetc();
937 		}
938 	}
939 	if (fd != '\0')
940 		np->nfile.fd = digit_val(fd);
941 	redirnode = np;
942 	goto parseredir_return;
943 }
944 
945 
946 /*
947  * Parse a substitution.  At this point, we have read the dollar sign
948  * and nothing else.
949  */
950 
951 parsesub: {
952 	int subtype;
953 	int typeloc;
954 	int flags;
955 	char *p;
956 #ifndef GDB_HACK
957 	static const char types[] = "}-+?=";
958 #endif
959 
960 	c = pgetc();
961 	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
962 		USTPUTC('$', out);
963 		pungetc();
964 	} else if (c == '(') {	/* $(command) */
965 		PARSEBACKQNEW();
966 	} else {
967 		USTPUTC(CTLVAR, out);
968 		typeloc = out - stackblock();
969 		USTPUTC(VSNORMAL, out);
970 		subtype = VSNORMAL;
971 		if (c == '{') {
972 			c = pgetc();
973 			subtype = 0;
974 		}
975 		if (is_name(c)) {
976 			do {
977 				STPUTC(c, out);
978 				c = pgetc();
979 			} while (is_in_name(c));
980 		} else {
981 			if (! is_special(c))
982 badsub:				synerror("Bad substitution");
983 			USTPUTC(c, out);
984 			c = pgetc();
985 		}
986 		STPUTC('=', out);
987 		flags = 0;
988 		if (subtype == 0) {
989 			if (c == ':') {
990 				flags = VSNUL;
991 				c = pgetc();
992 			}
993 			p = strchr(types, c);
994 			if (p == NULL)
995 				goto badsub;
996 			subtype = p - types + VSNORMAL;
997 		} else {
998 			pungetc();
999 		}
1000 		if (dblquote)
1001 			flags |= VSQUOTE;
1002 		*(stackblock() + typeloc) = subtype | flags;
1003 		if (subtype != VSNORMAL)
1004 			varnest++;
1005 	}
1006 	goto parsesub_return;
1007 }
1008 
1009 
1010 /*
1011  * Called to parse command substitutions.  Newstyle is set if the command
1012  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1013  * list of commands (passed by reference), and savelen is the number of
1014  * characters on the top of the stack which must be preserved.
1015  */
1016 
1017 parsebackq: {
1018 	struct nodelist **nlpp;
1019 	int savepbq;
1020 	union node *n;
1021 	char *volatile str;
1022 	struct jmploc jmploc;
1023 	struct jmploc *volatile savehandler;
1024 	int savelen;
1025 	int t;
1026 
1027 	savepbq = parsebackquote;
1028 	if (setjmp(jmploc.loc)) {
1029 		if (str)
1030 			ckfree(str);
1031 		parsebackquote = 0;
1032 		handler = savehandler;
1033 		longjmp(handler, 1);
1034 	}
1035 	INTOFF;
1036 	str = NULL;
1037 	savelen = out - stackblock();
1038 	if (savelen > 0) {
1039 		str = ckmalloc(savelen);
1040 		bcopy(stackblock(), str, savelen);
1041 	}
1042 	savehandler = handler;
1043 	handler = &jmploc;
1044 	INTON;
1045 	nlpp = &bqlist;
1046 	while (*nlpp)
1047 		nlpp = &(*nlpp)->next;
1048 	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1049 	(*nlpp)->next = NULL;
1050 	parsebackquote = oldstyle;
1051 	n = list(0);
1052 	t = oldstyle? TENDBQUOTE : TRP;
1053 	if (readtoken() != t)
1054 		synexpect(t);
1055 	(*nlpp)->n = n;
1056 	while (stackblocksize() <= savelen)
1057 		growstackblock();
1058 	STARTSTACKSTR(out);
1059 	if (str) {
1060 		bcopy(str, out, savelen);
1061 		STADJUST(savelen, out);
1062 		INTOFF;
1063 		ckfree(str);
1064 		str = NULL;
1065 		INTON;
1066 	}
1067 	parsebackquote = savepbq;
1068 	handler = savehandler;
1069 	USTPUTC(CTLBACKQ + dblquote, out);
1070 	if (oldstyle)
1071 		goto parsebackq_oldreturn;
1072 	else
1073 		goto parsebackq_newreturn;
1074 }
1075 
1076 } /* end of readtoken */
1077 
1078 
1079 
1080 #ifdef mkinit
1081 RESET {
1082 	tokpushback = 0;
1083 }
1084 #endif
1085 
1086 
1087 #if ATTY
1088 /*
1089  * Called to process a command generated by atty.  We execute the line,
1090  * and catch any errors that occur so they don't propagate outside of
1091  * this routine.
1092  */
1093 
1094 STATIC void
1095 attyline() {
1096 	char line[256];
1097 	struct stackmark smark;
1098 	struct jmploc jmploc;
1099 	struct jmploc *volatile savehandler;
1100 
1101 	if (pfgets(line, sizeof line) == NULL)
1102 		return;				/* "can't happen" */
1103 	if (setjmp(jmploc.loc)) {
1104 		if (exception == EXERROR)
1105 			out2str("\033]D\n");
1106 		handler = savehandler;
1107 		longjmp(handler, 1);
1108 	}
1109 	savehandler = handler;
1110 	handler = &jmploc;
1111 	setstackmark(&smark);
1112 	evalstring(line);
1113 	popstackmark(&smark);
1114 	handler = savehandler;
1115 	doprompt = 1;
1116 }
1117 
1118 
1119 /*
1120  * Output a prompt for atty.  We output the prompt as part of the
1121  * appropriate escape sequence.
1122  */
1123 
1124 STATIC void
1125 putprompt(s)
1126 	char *s;
1127 	{
1128 	register char *p;
1129 
1130 	if (attyset() && ! equal(termval(), "emacs")) {
1131 		if (strchr(s, '\7'))
1132 			out2c('\7');
1133 		out2str("\033]P1;");
1134 		for (p = s ; *p ; p++) {
1135 			if ((unsigned)(*p - ' ') <= '~' - ' ')
1136 				out2c(*p);
1137 		}
1138 		out2c('\n');
1139 	} else {
1140 		out2str(s);
1141 	}
1142 }
1143 #endif
1144 
1145 
1146 
1147 /*
1148  * Returns true if the text contains nothing to expand (no dollar signs
1149  * or backquotes).
1150  */
1151 
1152 STATIC int
1153 noexpand(text)
1154 	char *text;
1155 	{
1156 	register char *p;
1157 	register char c;
1158 
1159 	p = text;
1160 	while ((c = *p++) != '\0') {
1161 		if (c == CTLESC)
1162 			p++;
1163 		else if (BASESYNTAX[c] == CCTL)
1164 			return 0;
1165 	}
1166 	return 1;
1167 }
1168 
1169 
1170 /*
1171  * Return true if the argument is a legal variable name (a letter or
1172  * underscore followed by zero or more letters, underscores, and digits).
1173  */
1174 
1175 int
1176 goodname(name)
1177 	char *name;
1178 	{
1179 	register char *p;
1180 
1181 	p = name;
1182 	if (! is_name(*p))
1183 		return 0;
1184 	while (*++p) {
1185 		if (! is_in_name(*p))
1186 			return 0;
1187 	}
1188 	return 1;
1189 }
1190 
1191 
1192 /*
1193  * Called when an unexpected token is read during the parse.  The argument
1194  * is the token that is expected, or -1 if more than one type of token can
1195  * occur at this point.
1196  */
1197 
1198 STATIC void
1199 synexpect(token) {
1200 	char msg[64];
1201 
1202 	if (token >= 0) {
1203 		fmtstr(msg, 64, "%s unexpected (expecting %s)",
1204 			tokname[lasttoken], tokname[token]);
1205 	} else {
1206 		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1207 	}
1208 	synerror(msg);
1209 }
1210 
1211 
1212 STATIC void
1213 synerror(msg)
1214 	char *msg;
1215 	{
1216 	if (commandname)
1217 		outfmt(&errout, "%s: %d: ", commandname, startlinno);
1218 	outfmt(&errout, "Syntax error: %s\n", msg);
1219 	error((char *)NULL);
1220 }
1221