parser.c revision 18202
1193323Sed/*-
2193323Sed * Copyright (c) 1991, 1993
3193323Sed *	The Regents of the University of California.  All rights reserved.
4193323Sed *
5193323Sed * This code is derived from software contributed to Berkeley by
6193323Sed * Kenneth Almquist.
7193323Sed *
8193323Sed * Redistribution and use in source and binary forms, with or without
9193323Sed * modification, are permitted provided that the following conditions
10193323Sed * are met:
11193323Sed * 1. Redistributions of source code must retain the above copyright
12193323Sed *    notice, this list of conditions and the following disclaimer.
13193323Sed * 2. Redistributions in binary form must reproduce the above copyright
14193323Sed *    notice, this list of conditions and the following disclaimer in the
15193323Sed *    documentation and/or other materials provided with the distribution.
16193323Sed * 3. All advertising materials mentioning features or use of this software
17193323Sed *    must display the following acknowledgement:
18193323Sed *	This product includes software developed by the University of
19193323Sed *	California, Berkeley and its contributors.
20193323Sed * 4. Neither the name of the University nor the names of its contributors
21193323Sed *    may be used to endorse or promote products derived from this software
22198090Srdivacky *    without specific prior written permission.
23193323Sed *
24193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34193323Sed * SUCH DAMAGE.
35193323Sed *
36193323Sed *	$Id$
37198090Srdivacky */
38193323Sed
39198090Srdivacky#ifndef lint
40193323Sedstatic char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
41193323Sed#endif /* not lint */
42193323Sed
43193323Sed#include <stdlib.h>
44193323Sed
45193323Sed#include "shell.h"
46193323Sed#include "parser.h"
47193323Sed#include "nodes.h"
48193323Sed#include "expand.h"	/* defines rmescapes() */
49193323Sed#include "redir.h"	/* defines copyfd() */
50193323Sed#include "syntax.h"
51193323Sed#include "options.h"
52193323Sed#include "input.h"
53193323Sed#include "output.h"
54193323Sed#include "var.h"
55193323Sed#include "error.h"
56193323Sed#include "memalloc.h"
57193323Sed#include "mystring.h"
58193323Sed#include "alias.h"
59193323Sed#include "show.h"
60193323Sed#ifndef NO_HISTORY
61193323Sed#include "myhistedit.h"
62193323Sed#endif
63193323Sed
64193323Sed/*
65193323Sed * Shell command parser.
66193323Sed */
67193323Sed
68193323Sed#define EOFMARKLEN 79
69193323Sed
70193323Sed/* values returned by readtoken */
71193323Sed#include "token.h"
72193323Sed
73193323Sed
74193323Sed
75193323Sedstruct heredoc {
76193323Sed	struct heredoc *next;	/* next here document in list */
77193323Sed	union node *here;		/* redirection node */
78193323Sed	char *eofmark;		/* string indicating end of input */
79193323Sed	int striptabs;		/* if set, strip leading tabs */
80193323Sed};
81193323Sed
82193323Sed
83193323Sed
84193323Sedstruct heredoc *heredoclist;	/* list of here documents to read */
85193323Sedint parsebackquote;		/* nonzero if we are inside backquotes */
86193323Sedint doprompt;			/* if set, prompt the user */
87193323Sedint needprompt;			/* true if interactive and at start of line */
88193323Sedint lasttoken;			/* last token read */
89193323SedMKINIT int tokpushback;		/* last token pushed back */
90193323Sedchar *wordtext;			/* text of last word returned by readtoken */
91193323SedMKINIT int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
92193323Sedstruct nodelist *backquotelist;
93193323Sedunion node *redirnode;
94193323Sedstruct heredoc *heredoc;
95193323Sedint quoteflag;			/* set if (part of) last token was quoted */
96193323Sedint startlinno;			/* line # where last token started */
97193323Sed
98193323Sed/* XXX When 'noaliases' is set to one, no alias expansion takes place. */
99193323Sedstatic int noaliases = 0;
100193323Sed
101193323Sed#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
102193323Sed#ifdef GDB_HACK
103193323Sedstatic const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
104193323Sedstatic const char types[] = "}-+?=";
105193323Sed#endif
106193323Sed
107193323Sed
108193323SedSTATIC union node *list __P((int));
109193323SedSTATIC union node *andor __P((void));
110193323SedSTATIC union node *pipeline __P((void));
111193323SedSTATIC union node *command __P((void));
112193323SedSTATIC union node *simplecmd __P((union node **, union node *));
113193323SedSTATIC union node *makename __P((void));
114193323SedSTATIC void parsefname __P((void));
115193323SedSTATIC void parseheredoc __P((void));
116193323SedSTATIC int peektoken __P((void));
117193323SedSTATIC int readtoken __P((void));
118193323SedSTATIC int xxreadtoken __P((void));
119193323SedSTATIC int readtoken1 __P((int, char const *, char *, int));
120193323SedSTATIC int noexpand __P((char *));
121193323SedSTATIC void synexpect __P((int));
122193323SedSTATIC void synerror __P((char *));
123193323SedSTATIC void setprompt __P((int));
124193323Sed
125193323Sed
126193323Sed/*
127193323Sed * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
128193323Sed * valid parse tree indicating a blank line.)
129193323Sed */
130193323Sed
131193323Sedunion node *
132193323Sedparsecmd(interact)
133193323Sed	int interact;
134193323Sed{
135193323Sed	int t;
136193323Sed
137193323Sed	doprompt = interact;
138193323Sed	if (doprompt)
139193323Sed		setprompt(1);
140193323Sed	else
141193323Sed		setprompt(0);
142193323Sed	needprompt = 0;
143193323Sed	t = readtoken();
144193323Sed	if (t == TEOF)
145193323Sed		return NEOF;
146193323Sed	if (t == TNL)
147193323Sed		return NULL;
148193323Sed	tokpushback++;
149193323Sed	return list(1);
150193323Sed}
151193323Sed
152193323Sed
153193323SedSTATIC union node *
154193323Sedlist(nlflag)
155193323Sed	int nlflag;
156193323Sed{
157193323Sed	union node *n1, *n2, *n3;
158193323Sed	int tok;
159193323Sed
160193323Sed	checkkwd = 2;
161193323Sed	if (nlflag == 0 && tokendlist[peektoken()])
162193323Sed		return NULL;
163193323Sed	n1 = NULL;
164193323Sed	for (;;) {
165193323Sed		n2 = andor();
166193323Sed		tok = readtoken();
167193323Sed		if (tok == TBACKGND) {
168193323Sed			if (n2->type == NCMD || n2->type == NPIPE) {
169193323Sed				n2->ncmd.backgnd = 1;
170193323Sed			} else if (n2->type == NREDIR) {
171193323Sed				n2->type = NBACKGND;
172193323Sed			} else {
173193323Sed				n3 = (union node *)stalloc(sizeof (struct nredir));
174193323Sed				n3->type = NBACKGND;
175193323Sed				n3->nredir.n = n2;
176193323Sed				n3->nredir.redirect = NULL;
177193323Sed				n2 = n3;
178193323Sed			}
179193323Sed		}
180193323Sed		if (n1 == NULL) {
181193323Sed			n1 = n2;
182193323Sed		}
183193323Sed		else {
184193323Sed			n3 = (union node *)stalloc(sizeof (struct nbinary));
185193323Sed			n3->type = NSEMI;
186193323Sed			n3->nbinary.ch1 = n1;
187193323Sed			n3->nbinary.ch2 = n2;
188193323Sed			n1 = n3;
189193323Sed		}
190193323Sed		switch (tok) {
191193323Sed		case TBACKGND:
192193323Sed		case TSEMI:
193193323Sed			tok = readtoken();
194193323Sed			/* fall through */
195193323Sed		case TNL:
196193323Sed			if (tok == TNL) {
197193323Sed				parseheredoc();
198193323Sed				if (nlflag)
199193323Sed					return n1;
200193323Sed			} else {
201193323Sed				tokpushback++;
202193323Sed			}
203193323Sed			checkkwd = 2;
204193323Sed			if (tokendlist[peektoken()])
205193323Sed				return n1;
206193323Sed			break;
207193323Sed		case TEOF:
208193323Sed			if (heredoclist)
209193323Sed				parseheredoc();
210193323Sed			else
211193323Sed				pungetc();		/* push back EOF on input */
212193323Sed			return n1;
213193323Sed		default:
214193323Sed			if (nlflag)
215193323Sed				synexpect(-1);
216193323Sed			tokpushback++;
217193323Sed			return n1;
218193323Sed		}
219198090Srdivacky	}
220193323Sed}
221193323Sed
222193323Sed
223198090Srdivacky
224198090SrdivackySTATIC union node *
225193323Sedandor() {
226193323Sed	union node *n1, *n2, *n3;
227193323Sed	int t;
228193323Sed
229193323Sed	n1 = pipeline();
230193323Sed	for (;;) {
231193323Sed		if ((t = readtoken()) == TAND) {
232193323Sed			t = NAND;
233193323Sed		} else if (t == TOR) {
234193323Sed			t = NOR;
235193323Sed		} else {
236193323Sed			tokpushback++;
237193323Sed			return n1;
238193323Sed		}
239193323Sed		n2 = pipeline();
240193323Sed		n3 = (union node *)stalloc(sizeof (struct nbinary));
241193323Sed		n3->type = t;
242198090Srdivacky		n3->nbinary.ch1 = n1;
243193323Sed		n3->nbinary.ch2 = n2;
244198090Srdivacky		n1 = n3;
245198090Srdivacky	}
246193323Sed}
247193323Sed
248193323Sed
249193323Sed
250193323SedSTATIC union node *
251198090Srdivackypipeline() {
252198090Srdivacky	union node *n1, *pipenode, *notnode;
253193323Sed	struct nodelist *lp, *prev;
254193323Sed	int negate = 0;
255193323Sed
256193323Sed	TRACE(("pipeline: entered\n"));
257193323Sed	while (readtoken() == TNOT) {
258193323Sed		TRACE(("pipeline: TNOT recognized\n"));
259193323Sed		negate = !negate;
260198090Srdivacky	}
261193323Sed	tokpushback++;
262193323Sed	n1 = command();
263193323Sed	if (readtoken() == TPIPE) {
264193323Sed		pipenode = (union node *)stalloc(sizeof (struct npipe));
265193323Sed		pipenode->type = NPIPE;
266193323Sed		pipenode->npipe.backgnd = 0;
267193323Sed		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
268193323Sed		pipenode->npipe.cmdlist = lp;
269193323Sed		lp->n = n1;
270193323Sed		do {
271193323Sed			prev = lp;
272193323Sed			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
273193323Sed			lp->n = command();
274193323Sed			prev->next = lp;
275193323Sed		} while (readtoken() == TPIPE);
276193323Sed		lp->next = NULL;
277193323Sed		n1 = pipenode;
278193323Sed	}
279193323Sed	tokpushback++;
280193323Sed	if (negate) {
281193323Sed		notnode = (union node *)stalloc(sizeof (struct nnot));
282193323Sed		notnode->type = NNOT;
283193323Sed		notnode->nnot.com = n1;
284193323Sed		n1 = notnode;
285193323Sed	}
286193323Sed	return n1;
287193323Sed}
288193323Sed
289193323Sed
290193323Sed
291193323SedSTATIC union node *
292193323Sedcommand() {
293193323Sed	union node *n1, *n2;
294193323Sed	union node *ap, **app;
295193323Sed	union node *cp, **cpp;
296193323Sed	union node *redir, **rpp;
297193323Sed	int t;
298193323Sed
299193323Sed	checkkwd = 2;
300193323Sed	redir = NULL;
301193323Sed	n1 = NULL;
302193323Sed	rpp = &redir;
303193323Sed	/* Check for redirection which may precede command */
304193323Sed	while (readtoken() == TREDIR) {
305193323Sed		*rpp = n2 = redirnode;
306193323Sed		rpp = &n2->nfile.next;
307193323Sed		parsefname();
308193323Sed	}
309193323Sed	tokpushback++;
310193323Sed
311193323Sed	switch (readtoken()) {
312193323Sed	case TIF:
313193323Sed		n1 = (union node *)stalloc(sizeof (struct nif));
314193323Sed		n1->type = NIF;
315193323Sed		n1->nif.test = list(0);
316193323Sed		if (readtoken() != TTHEN)
317193323Sed			synexpect(TTHEN);
318193323Sed		n1->nif.ifpart = list(0);
319193323Sed		n2 = n1;
320193323Sed		while (readtoken() == TELIF) {
321193323Sed			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
322193323Sed			n2 = n2->nif.elsepart;
323193323Sed			n2->type = NIF;
324193323Sed			n2->nif.test = list(0);
325193323Sed			if (readtoken() != TTHEN)
326193323Sed				synexpect(TTHEN);
327193323Sed			n2->nif.ifpart = list(0);
328193323Sed		}
329193323Sed		if (lasttoken == TELSE)
330193323Sed			n2->nif.elsepart = list(0);
331193323Sed		else {
332193323Sed			n2->nif.elsepart = NULL;
333193323Sed			tokpushback++;
334193323Sed		}
335193323Sed		if (readtoken() != TFI)
336193323Sed			synexpect(TFI);
337193323Sed		checkkwd = 1;
338193323Sed		break;
339193323Sed	case TWHILE:
340193323Sed	case TUNTIL: {
341193323Sed		int got;
342193323Sed		n1 = (union node *)stalloc(sizeof (struct nbinary));
343193323Sed		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
344193323Sed		n1->nbinary.ch1 = list(0);
345193323Sed		if ((got=readtoken()) != TDO) {
346193323SedTRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
347193323Sed			synexpect(TDO);
348193323Sed		}
349193323Sed		n1->nbinary.ch2 = list(0);
350193323Sed		if (readtoken() != TDONE)
351193323Sed			synexpect(TDONE);
352193323Sed		checkkwd = 1;
353193323Sed		break;
354193323Sed	}
355193323Sed	case TFOR:
356193323Sed		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
357193323Sed			synerror("Bad for loop variable");
358193323Sed		n1 = (union node *)stalloc(sizeof (struct nfor));
359193323Sed		n1->type = NFOR;
360193323Sed		n1->nfor.var = wordtext;
361193323Sed		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
362193323Sed			app = &ap;
363193323Sed			while (readtoken() == TWORD) {
364193323Sed				n2 = (union node *)stalloc(sizeof (struct narg));
365193323Sed				n2->type = NARG;
366193323Sed				n2->narg.text = wordtext;
367193323Sed				n2->narg.backquote = backquotelist;
368193323Sed				*app = n2;
369193323Sed				app = &n2->narg.next;
370193323Sed			}
371193323Sed			*app = NULL;
372193323Sed			n1->nfor.args = ap;
373193323Sed			if (lasttoken != TNL && lasttoken != TSEMI)
374193323Sed				synexpect(-1);
375193323Sed		} else {
376193323Sed#ifndef GDB_HACK
377193323Sed			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
378193323Sed								   '@', '=', '\0'};
379193323Sed#endif
380193323Sed			n2 = (union node *)stalloc(sizeof (struct narg));
381193323Sed			n2->type = NARG;
382193323Sed			n2->narg.text = (char *)argvars;
383193323Sed			n2->narg.backquote = NULL;
384193323Sed			n2->narg.next = NULL;
385193323Sed			n1->nfor.args = n2;
386193323Sed			/*
387193323Sed			 * Newline or semicolon here is optional (but note
388193323Sed			 * that the original Bourne shell only allowed NL).
389193323Sed			 */
390193323Sed			if (lasttoken != TNL && lasttoken != TSEMI)
391193323Sed				tokpushback++;
392193323Sed		}
393193323Sed		checkkwd = 2;
394193323Sed		if ((t = readtoken()) == TDO)
395193323Sed			t = TDONE;
396193323Sed		else if (t == TBEGIN)
397193323Sed			t = TEND;
398193323Sed		else
399193323Sed			synexpect(-1);
400193323Sed		n1->nfor.body = list(0);
401198090Srdivacky		if (readtoken() != t)
402193323Sed			synexpect(t);
403193323Sed		checkkwd = 1;
404193323Sed		break;
405193323Sed	case TCASE:
406193323Sed		n1 = (union node *)stalloc(sizeof (struct ncase));
407193323Sed		n1->type = NCASE;
408193323Sed		if (readtoken() != TWORD)
409193323Sed			synexpect(TWORD);
410193323Sed		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
411193323Sed		n2->type = NARG;
412193323Sed		n2->narg.text = wordtext;
413193323Sed		n2->narg.backquote = backquotelist;
414193323Sed		n2->narg.next = NULL;
415193323Sed		while (readtoken() == TNL);
416193323Sed		if (lasttoken != TWORD || ! equal(wordtext, "in"))
417193323Sed			synerror("expecting \"in\"");
418193323Sed		cpp = &n1->ncase.cases;
419193323Sed		noaliases = 1;	/* turn off alias expansion */
420193323Sed		checkkwd = 2, readtoken();
421193323Sed		do {
422193323Sed			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));
423193323Sed			cp->type = NCLIST;
424193323Sed			app = &cp->nclist.pattern;
425193323Sed			for (;;) {
426193323Sed				*app = ap = (union node *)stalloc(sizeof (struct narg));
427193323Sed				ap->type = NARG;
428193323Sed				ap->narg.text = wordtext;
429193323Sed				ap->narg.backquote = backquotelist;
430193323Sed				if (checkkwd = 2, readtoken() != TPIPE)
431193323Sed					break;
432193323Sed				app = &ap->narg.next;
433193323Sed				readtoken();
434193323Sed			}
435193323Sed			ap->narg.next = NULL;
436193323Sed			if (lasttoken != TRP)
437193323Sed				noaliases = 0, synexpect(TRP);
438193323Sed			cp->nclist.body = list(0);
439193323Sed
440193323Sed			checkkwd = 2;
441193323Sed			if ((t = readtoken()) != TESAC) {
442193323Sed				if (t != TENDCASE)
443193323Sed					noaliases = 0, synexpect(TENDCASE);
444193323Sed				else
445193323Sed					checkkwd = 2, readtoken();
446193323Sed			}
447193323Sed			cpp = &cp->nclist.next;
448193323Sed		} while(lasttoken != TESAC);
449193323Sed		noaliases = 0;	/* reset alias expansion */
450193323Sed		*cpp = NULL;
451193323Sed		checkkwd = 1;
452193323Sed		break;
453193323Sed	case TLP:
454193323Sed		n1 = (union node *)stalloc(sizeof (struct nredir));
455193323Sed		n1->type = NSUBSHELL;
456193323Sed		n1->nredir.n = list(0);
457193323Sed		n1->nredir.redirect = NULL;
458193323Sed		if (readtoken() != TRP)
459193323Sed			synexpect(TRP);
460193323Sed		checkkwd = 1;
461193323Sed		break;
462193323Sed	case TBEGIN:
463193323Sed		n1 = list(0);
464193323Sed		if (readtoken() != TEND)
465193323Sed			synexpect(TEND);
466193323Sed		checkkwd = 1;
467193323Sed		break;
468193323Sed	/* Handle an empty command like other simple commands.  */
469193323Sed	case TSEMI:
470193323Sed		/*
471193323Sed		 * An empty command before a ; doesn't make much sense, and
472193323Sed		 * should certainly be disallowed in the case of `if ;'.
473193323Sed		 */
474193323Sed		if (!redir)
475193323Sed			synexpect(-1);
476193323Sed	case TAND:	/* XXX merge query! */
477193323Sed	case TOR:	/* XXX merge query! */
478193323Sed	case TNL:
479193323Sed	case TEOF:
480193323Sed	case TWORD:
481193323Sed	case TRP:
482193323Sed		tokpushback++;
483193323Sed		return simplecmd(rpp, redir);
484193323Sed	default:
485193323Sed		synexpect(-1);
486193323Sed	}
487193323Sed
488193323Sed	/* Now check for redirection which may follow command */
489193323Sed	while (readtoken() == TREDIR) {
490193323Sed		*rpp = n2 = redirnode;
491193323Sed		rpp = &n2->nfile.next;
492193323Sed		parsefname();
493193323Sed	}
494193323Sed	tokpushback++;
495193323Sed	*rpp = NULL;
496193323Sed	if (redir) {
497193323Sed		if (n1->type != NSUBSHELL) {
498193323Sed			n2 = (union node *)stalloc(sizeof (struct nredir));
499193323Sed			n2->type = NREDIR;
500193323Sed			n2->nredir.n = n1;
501193323Sed			n1 = n2;
502193323Sed		}
503193323Sed		n1->nredir.redirect = redir;
504198090Srdivacky	}
505193323Sed	return n1;
506193323Sed}
507193323Sed
508193323Sed
509193323SedSTATIC union node *
510193323Sedsimplecmd(rpp, redir)
511193323Sed	union node **rpp, *redir;
512193323Sed	{
513193323Sed	union node *args, **app;
514193323Sed	union node **orig_rpp = rpp;
515193323Sed	union node *n = NULL;
516193323Sed
517193323Sed	/* If we don't have any redirections already, then we must reset */
518193323Sed	/* rpp to be the address of the local redir variable.  */
519193323Sed	if (redir == 0)
520193323Sed		rpp = &redir;
521193323Sed
522193323Sed	args = NULL;
523193323Sed	app = &args;
524193323Sed	/*
525193323Sed	 * We save the incoming value, because we need this for shell
526193323Sed	 * functions.  There can not be a redirect or an argument between
527193323Sed	 * the function name and the open parenthesis.
528193323Sed	 */
529193323Sed	orig_rpp = rpp;
530193323Sed
531193323Sed	for (;;) {
532193323Sed		if (readtoken() == TWORD) {
533193323Sed			n = (union node *)stalloc(sizeof (struct narg));
534193323Sed			n->type = NARG;
535193323Sed			n->narg.text = wordtext;
536193323Sed			n->narg.backquote = backquotelist;
537193323Sed			*app = n;
538193323Sed			app = &n->narg.next;
539193323Sed		} else if (lasttoken == TREDIR) {
540193323Sed			*rpp = n = redirnode;
541193323Sed			rpp = &n->nfile.next;
542193323Sed			parsefname();	/* read name of redirection file */
543193323Sed		} else if (lasttoken == TLP && app == &args->narg.next
544193323Sed					    && rpp == orig_rpp) {
545193323Sed			/* We have a function */
546198090Srdivacky			if (readtoken() != TRP)
547198090Srdivacky				synexpect(TRP);
548198090Srdivacky#ifdef notdef
549198090Srdivacky			if (! goodname(n->narg.text))
550198090Srdivacky				synerror("Bad function name");
551198090Srdivacky#endif
552193323Sed			n->type = NDEFUN;
553193323Sed			n->narg.next = command();
554193323Sed			return n;
555193323Sed		} else {
556193323Sed			tokpushback++;
557193323Sed			break;
558193323Sed		}
559193323Sed	}
560193323Sed	*app = NULL;
561193323Sed	*rpp = NULL;
562193323Sed	n = (union node *)stalloc(sizeof (struct ncmd));
563193323Sed	n->type = NCMD;
564193323Sed	n->ncmd.backgnd = 0;
565193323Sed	n->ncmd.args = args;
566193323Sed	n->ncmd.redirect = redir;
567193323Sed	return n;
568193323Sed}
569193323Sed
570193323SedSTATIC union node *
571193323Sedmakename() {
572193323Sed	union node *n;
573193323Sed
574193323Sed	n = (union node *)stalloc(sizeof (struct narg));
575193323Sed	n->type = NARG;
576193323Sed	n->narg.next = NULL;
577193323Sed	n->narg.text = wordtext;
578193323Sed	n->narg.backquote = backquotelist;
579193323Sed	return n;
580193323Sed}
581193323Sed
582193323Sedvoid fixredir(n, text, err)
583193323Sed	union node *n;
584193323Sed	const char *text;
585193323Sed	int err;
586193323Sed	{
587193323Sed	TRACE(("Fix redir %s %d\n", text, err));
588193323Sed	if (!err)
589193323Sed		n->ndup.vname = NULL;
590193323Sed
591193323Sed	if (is_digit(text[0]) && text[1] == '\0')
592193323Sed		n->ndup.dupfd = digit_val(text[0]);
593193323Sed	else if (text[0] == '-' && text[1] == '\0')
594193323Sed		n->ndup.dupfd = -1;
595193323Sed	else {
596193323Sed
597193323Sed		if (err)
598193323Sed			synerror("Bad fd number");
599193323Sed		else
600193323Sed			n->ndup.vname = makename();
601193323Sed	}
602193323Sed}
603193323Sed
604193323Sed
605193323SedSTATIC void
606193323Sedparsefname() {
607193323Sed	union node *n = redirnode;
608193323Sed
609193323Sed	if (readtoken() != TWORD)
610193323Sed		synexpect(-1);
611193323Sed	if (n->type == NHERE) {
612193323Sed		struct heredoc *here = heredoc;
613193323Sed		struct heredoc *p;
614193323Sed		int i;
615193323Sed
616193323Sed		if (quoteflag == 0)
617193323Sed			n->type = NXHERE;
618193323Sed		TRACE(("Here document %d\n", n->type));
619193323Sed		if (here->striptabs) {
620193323Sed			while (*wordtext == '\t')
621193323Sed				wordtext++;
622193323Sed		}
623198090Srdivacky		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
624198090Srdivacky			synerror("Illegal eof marker for << redirection");
625198090Srdivacky		rmescapes(wordtext);
626198090Srdivacky		here->eofmark = wordtext;
627198090Srdivacky		here->next = NULL;
628193323Sed		if (heredoclist == NULL)
629193323Sed			heredoclist = here;
630193323Sed		else {
631193323Sed			for (p = heredoclist ; p->next ; p = p->next);
632193323Sed			p->next = here;
633193323Sed		}
634193323Sed	} else if (n->type == NTOFD || n->type == NFROMFD) {
635193323Sed		fixredir(n, wordtext, 0);
636193323Sed	} else {
637193323Sed		n->nfile.fname = makename();
638193323Sed	}
639193323Sed}
640193323Sed
641193323Sed
642193323Sed/*
643193323Sed * Input any here documents.
644193323Sed */
645193323Sed
646193323SedSTATIC void
647193323Sedparseheredoc() {
648193323Sed	struct heredoc *here;
649193323Sed	union node *n;
650193323Sed
651193323Sed	while (heredoclist) {
652193323Sed		here = heredoclist;
653193323Sed		heredoclist = here->next;
654193323Sed		if (needprompt) {
655193323Sed			setprompt(2);
656193323Sed			needprompt = 0;
657193323Sed		}
658193323Sed		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
659193323Sed				here->eofmark, here->striptabs);
660193323Sed		n = (union node *)stalloc(sizeof (struct narg));
661193323Sed		n->narg.type = NARG;
662193323Sed		n->narg.next = NULL;
663193323Sed		n->narg.text = wordtext;
664193323Sed		n->narg.backquote = backquotelist;
665193323Sed		here->here->nhere.doc = n;
666193323Sed	}
667193323Sed}
668193323Sed
669193323SedSTATIC int
670193323Sedpeektoken() {
671193323Sed	int t;
672193323Sed
673193323Sed	t = readtoken();
674193323Sed	tokpushback++;
675193323Sed	return (t);
676193323Sed}
677193323Sed
678193323SedSTATIC int xxreadtoken();
679193323Sed
680193323SedSTATIC int
681193323Sedreadtoken() {
682193323Sed	int t;
683193323Sed	int savecheckkwd = checkkwd;
684193323Sed	struct alias *ap;
685193323Sed#ifdef DEBUG
686193323Sed	int alreadyseen = tokpushback;
687193323Sed#endif
688193323Sed
689193323Sed	top:
690193323Sed	t = xxreadtoken();
691193323Sed
692193323Sed	if (checkkwd) {
693198090Srdivacky		/*
694198090Srdivacky		 * eat newlines
695198090Srdivacky		 */
696198090Srdivacky		if (checkkwd == 2) {
697198090Srdivacky			checkkwd = 0;
698193323Sed			while (t == TNL) {
699193323Sed				parseheredoc();
700193323Sed				t = xxreadtoken();
701193323Sed			}
702193323Sed		} else
703193323Sed			checkkwd = 0;
704193323Sed		/*
705193323Sed		 * check for keywords and aliases
706193323Sed		 */
707193323Sed		if (t == TWORD && !quoteflag)
708193323Sed		{
709193323Sed			register char * const *pp;
710193323Sed
711193323Sed			for (pp = (char **)parsekwd; *pp; pp++) {
712193323Sed				if (**pp == *wordtext && equal(*pp, wordtext))
713193323Sed				{
714193323Sed					lasttoken = t = pp - parsekwd + KWDOFFSET;
715193323Sed					TRACE(("keyword %s recognized\n", tokname[t]));
716193323Sed					goto out;
717193323Sed				}
718193323Sed			}
719193323Sed			if (noaliases == 0 &&
720193323Sed			    (ap = lookupalias(wordtext, 1)) != NULL) {
721193323Sed				pushstring(ap->val, strlen(ap->val), ap);
722193323Sed				checkkwd = savecheckkwd;
723193323Sed				goto top;
724193323Sed			}
725193323Sed		}
726193323Sedout:
727193323Sed		checkkwd = 0;
728193323Sed	}
729193323Sed#ifdef DEBUG
730193323Sed	if (!alreadyseen)
731193323Sed	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
732193323Sed	else
733193323Sed	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
734193323Sed#endif
735193323Sed	return (t);
736193323Sed}
737193323Sed
738193323Sed
739193323Sed/*
740193323Sed * Read the next input token.
741193323Sed * If the token is a word, we set backquotelist to the list of cmds in
742193323Sed *	backquotes.  We set quoteflag to true if any part of the word was
743193323Sed *	quoted.
744193323Sed * If the token is TREDIR, then we set redirnode to a structure containing
745193323Sed *	the redirection.
746193323Sed * In all cases, the variable startlinno is set to the number of the line
747193323Sed *	on which the token starts.
748193323Sed *
749193323Sed * [Change comment:  here documents and internal procedures]
750193323Sed * [Readtoken shouldn't have any arguments.  Perhaps we should make the
751193323Sed *  word parsing code into a separate routine.  In this case, readtoken
752193323Sed *  doesn't need to have any internal procedures, but parseword does.
753193323Sed *  We could also make parseoperator in essence the main routine, and
754193323Sed *  have parseword (readtoken1?) handle both words and redirection.]
755193323Sed */
756193323Sed
757193323Sed#define RETURN(token)	return lasttoken = token
758193323Sed
759193323SedSTATIC int
760193323Sedxxreadtoken() {
761193323Sed	register c;
762193323Sed
763193323Sed	if (tokpushback) {
764193323Sed		tokpushback = 0;
765193323Sed		return lasttoken;
766193323Sed	}
767193323Sed	if (needprompt) {
768193323Sed		setprompt(2);
769193323Sed		needprompt = 0;
770193323Sed	}
771193323Sed	startlinno = plinno;
772193323Sed	for (;;) {	/* until token or start of word found */
773193323Sed		c = pgetc_macro();
774193323Sed		if (c == ' ' || c == '\t')
775193323Sed			continue;		/* quick check for white space first */
776193323Sed		switch (c) {
777193323Sed		case ' ': case '\t':
778193323Sed			continue;
779193323Sed		case '#':
780193323Sed			while ((c = pgetc()) != '\n' && c != PEOF);
781193323Sed			pungetc();
782193323Sed			continue;
783193323Sed		case '\\':
784193323Sed			if (pgetc() == '\n') {
785193323Sed				startlinno = ++plinno;
786193323Sed				if (doprompt)
787193323Sed					setprompt(2);
788193323Sed				else
789193323Sed					setprompt(0);
790193323Sed				continue;
791193323Sed			}
792193323Sed			pungetc();
793193323Sed			goto breakloop;
794193323Sed		case '\n':
795193323Sed			plinno++;
796193323Sed			needprompt = doprompt;
797193323Sed			RETURN(TNL);
798193323Sed		case PEOF:
799193323Sed			RETURN(TEOF);
800193323Sed		case '&':
801193323Sed			if (pgetc() == '&')
802193323Sed				RETURN(TAND);
803193323Sed			pungetc();
804193323Sed			RETURN(TBACKGND);
805193323Sed		case '|':
806193323Sed			if (pgetc() == '|')
807193323Sed				RETURN(TOR);
808193323Sed			pungetc();
809193323Sed			RETURN(TPIPE);
810193323Sed		case ';':
811193323Sed			if (pgetc() == ';')
812193323Sed				RETURN(TENDCASE);
813193323Sed			pungetc();
814193323Sed			RETURN(TSEMI);
815198090Srdivacky		case '(':
816193323Sed			RETURN(TLP);
817193323Sed		case ')':
818193323Sed			RETURN(TRP);
819193323Sed		default:
820193323Sed			goto breakloop;
821193323Sed		}
822193323Sed	}
823193323Sedbreakloop:
824193323Sed	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
825193323Sed#undef RETURN
826193323Sed}
827193323Sed
828193323Sed
829193323Sed
830193323Sed/*
831193323Sed * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
832193323Sed * is not NULL, read a here document.  In the latter case, eofmark is the
833193323Sed * word which marks the end of the document and striptabs is true if
834193323Sed * leading tabs should be stripped from the document.  The argument firstc
835193323Sed * is the first character of the input token or document.
836193323Sed *
837193323Sed * Because C does not have internal subroutines, I have simulated them
838193323Sed * using goto's to implement the subroutine linkage.  The following macros
839193323Sed * will run code that appears at the end of readtoken1.
840193323Sed */
841193323Sed
842193323Sed#define CHECKEND()	{goto checkend; checkend_return:;}
843193323Sed#define PARSEREDIR()	{goto parseredir; parseredir_return:;}
844193323Sed#define PARSESUB()	{goto parsesub; parsesub_return:;}
845193323Sed#define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
846193323Sed#define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
847193323Sed#define	PARSEARITH()	{goto parsearith; parsearith_return:;}
848193323Sed
849193323SedSTATIC int
850193323Sedreadtoken1(firstc, syntax, eofmark, striptabs)
851193323Sed	int firstc;
852193323Sed	char const *syntax;
853193323Sed	char *eofmark;
854193323Sed	int striptabs;
855193323Sed	{
856193323Sed	int c = firstc;
857193323Sed	char *out;
858193323Sed	int len;
859193323Sed	char line[EOFMARKLEN + 1];
860193323Sed	struct nodelist *bqlist;
861193323Sed	int quotef;
862193323Sed	int dblquote;
863193323Sed	int varnest;	/* levels of variables expansion */
864193323Sed	int arinest;	/* levels of arithmetic expansion */
865193323Sed	int parenlevel;	/* levels of parens in arithmetic */
866193323Sed	int oldstyle;
867193323Sed	char const *prevsyntax;	/* syntax before arithmetic */
868193323Sed#if __GNUC__
869193323Sed	/* Avoid longjmp clobbering */
870193323Sed	(void) &out;
871193323Sed	(void) &quotef;
872193323Sed	(void) &dblquote;
873193323Sed	(void) &varnest;
874193323Sed	(void) &arinest;
875193323Sed	(void) &parenlevel;
876193323Sed	(void) &oldstyle;
877193323Sed	(void) &prevsyntax;
878193323Sed	(void) &syntax;
879193323Sed#endif
880193323Sed
881193323Sed	startlinno = plinno;
882193323Sed	dblquote = 0;
883193323Sed	if (syntax == DQSYNTAX)
884193323Sed		dblquote = 1;
885193323Sed	quotef = 0;
886193323Sed	bqlist = NULL;
887193323Sed	varnest = 0;
888193323Sed	arinest = 0;
889193323Sed	parenlevel = 0;
890193323Sed
891193323Sed	STARTSTACKSTR(out);
892198090Srdivacky	loop: {	/* for each line, until end of word */
893193323Sed#if ATTY
894193323Sed		if (c == '\034' && doprompt
895193323Sed		 && attyset() && ! equal(termval(), "emacs")) {
896193323Sed			attyline();
897193323Sed			if (syntax == BASESYNTAX)
898193323Sed				return readtoken();
899193323Sed			c = pgetc();
900193323Sed			goto loop;
901193323Sed		}
902193323Sed#endif
903193323Sed		CHECKEND();	/* set c to PEOF if at end of here document */
904193323Sed		for (;;) {	/* until end of line or end of word */
905193323Sed			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */
906193323Sed			switch(syntax[c]) {
907193323Sed			case CNL:	/* '\n' */
908193323Sed				if (syntax == BASESYNTAX)
909193323Sed					goto endword;	/* exit outer loop */
910193323Sed				USTPUTC(c, out);
911193323Sed				plinno++;
912193323Sed				if (doprompt)
913198090Srdivacky					setprompt(2);
914193323Sed				else
915193323Sed					setprompt(0);
916193323Sed				c = pgetc();
917193323Sed				goto loop;		/* continue outer loop */
918193323Sed			case CWORD:
919193323Sed				USTPUTC(c, out);
920193323Sed				break;
921193323Sed			case CCTL:
922193323Sed				if (eofmark == NULL || dblquote)
923193323Sed					USTPUTC(CTLESC, out);
924193323Sed				USTPUTC(c, out);
925193323Sed				break;
926193323Sed			case CBACK:	/* backslash */
927193323Sed				c = pgetc();
928193323Sed				if (c == PEOF) {
929193323Sed					USTPUTC('\\', out);
930193323Sed					pungetc();
931193323Sed				} else if (c == '\n') {
932193323Sed					if (doprompt)
933193323Sed						setprompt(2);
934193323Sed					else
935193323Sed						setprompt(0);
936193323Sed				} else {
937198090Srdivacky					if (dblquote && c != '\\' && c != '`' && c != '$'
938198090Srdivacky							 && (c != '"' || eofmark != NULL))
939198090Srdivacky						USTPUTC('\\', out);
940198090Srdivacky					if (SQSYNTAX[c] == CCTL)
941198090Srdivacky						USTPUTC(CTLESC, out);
942198090Srdivacky					USTPUTC(c, out);
943198090Srdivacky					quotef++;
944198090Srdivacky				}
945193323Sed				break;
946193323Sed			case CSQUOTE:
947193323Sed				syntax = SQSYNTAX;
948193323Sed				break;
949193323Sed			case CDQUOTE:
950193323Sed				syntax = DQSYNTAX;
951193323Sed				dblquote = 1;
952193323Sed				break;
953198090Srdivacky			case CENDQUOTE:
954193323Sed				if (eofmark) {
955193323Sed					USTPUTC(c, out);
956193323Sed				} else {
957193323Sed					if (arinest)
958193323Sed						syntax = ARISYNTAX;
959193323Sed					else
960193323Sed						syntax = BASESYNTAX;
961193323Sed					quotef++;
962193323Sed					dblquote = 0;
963193323Sed				}
964193323Sed				break;
965193323Sed			case CVAR:	/* '$' */
966193323Sed				PARSESUB();		/* parse substitution */
967193323Sed				break;
968193323Sed			case CENDVAR:	/* '}' */
969193323Sed				if (varnest > 0) {
970193323Sed					varnest--;
971193323Sed					USTPUTC(CTLENDVAR, out);
972193323Sed				} else {
973193323Sed					USTPUTC(c, out);
974193323Sed				}
975193323Sed				break;
976193323Sed			case CLP:	/* '(' in arithmetic */
977198090Srdivacky				parenlevel++;
978193323Sed				USTPUTC(c, out);
979193323Sed				break;
980193323Sed			case CRP:	/* ')' in arithmetic */
981193323Sed				if (parenlevel > 0) {
982193323Sed					USTPUTC(c, out);
983193323Sed					--parenlevel;
984193323Sed				} else {
985193323Sed					if (pgetc() == ')') {
986193323Sed						if (--arinest == 0) {
987193323Sed							USTPUTC(CTLENDARI, out);
988193323Sed							syntax = prevsyntax;
989193323Sed						} else
990193323Sed							USTPUTC(')', out);
991193323Sed					} else {
992193323Sed						/*
993193323Sed						 * unbalanced parens
994193323Sed						 *  (don't 2nd guess - no error)
995193323Sed						 */
996193323Sed						pungetc();
997193323Sed						USTPUTC(')', out);
998193323Sed					}
999193323Sed				}
1000193323Sed				break;
1001193323Sed			case CBQUOTE:	/* '`' */
1002193323Sed				PARSEBACKQOLD();
1003193323Sed				break;
1004193323Sed			case CEOF:
1005193323Sed				goto endword;		/* exit outer loop */
1006193323Sed			default:
1007193323Sed				if (varnest == 0)
1008193323Sed					goto endword;	/* exit outer loop */
1009193323Sed				USTPUTC(c, out);
1010193323Sed			}
1011193323Sed			c = pgetc_macro();
1012193323Sed		}
1013193323Sed	}
1014193323Sedendword:
1015193323Sed	if (syntax == ARISYNTAX)
1016193323Sed		synerror("Missing '))'");
1017193323Sed	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
1018193323Sed		synerror("Unterminated quoted string");
1019193323Sed	if (varnest != 0) {
1020193323Sed		startlinno = plinno;
1021193323Sed		synerror("Missing '}'");
1022193323Sed	}
1023193323Sed	USTPUTC('\0', out);
1024193323Sed	len = out - stackblock();
1025193323Sed	out = stackblock();
1026193323Sed	if (eofmark == NULL) {
1027193323Sed		if ((c == '>' || c == '<')
1028193323Sed		 && quotef == 0
1029193323Sed		 && len <= 2
1030193323Sed		 && (*out == '\0' || is_digit(*out))) {
1031193323Sed			PARSEREDIR();
1032193323Sed			return lasttoken = TREDIR;
1033193323Sed		} else {
1034193323Sed			pungetc();
1035193323Sed		}
1036193323Sed	}
1037193323Sed	quoteflag = quotef;
1038193323Sed	backquotelist = bqlist;
1039193323Sed	grabstackblock(len);
1040193323Sed	wordtext = out;
1041193323Sed	return lasttoken = TWORD;
1042193323Sed/* end of readtoken routine */
1043193323Sed
1044193323Sed
1045193323Sed
1046193323Sed/*
1047193323Sed * Check to see whether we are at the end of the here document.  When this
1048193323Sed * is called, c is set to the first character of the next input line.  If
1049193323Sed * we are at the end of the here document, this routine sets the c to PEOF.
1050193323Sed */
1051193323Sed
1052193323Sedcheckend: {
1053193323Sed	if (eofmark) {
1054193323Sed		if (striptabs) {
1055193323Sed			while (c == '\t')
1056193323Sed				c = pgetc();
1057193323Sed		}
1058193323Sed		if (c == *eofmark) {
1059193323Sed			if (pfgets(line, sizeof line) != NULL) {
1060193323Sed				register char *p, *q;
1061193323Sed
1062193323Sed				p = line;
1063193323Sed				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
1064193323Sed				if (*p == '\n' && *q == '\0') {
1065193323Sed					c = PEOF;
1066193323Sed					plinno++;
1067193323Sed					needprompt = doprompt;
1068193323Sed				} else {
1069193323Sed					pushstring(line, strlen(line), NULL);
1070193323Sed				}
1071193323Sed			}
1072193323Sed		}
1073193323Sed	}
1074193323Sed	goto checkend_return;
1075193323Sed}
1076193323Sed
1077193323Sed
1078193323Sed/*
1079193323Sed * Parse a redirection operator.  The variable "out" points to a string
1080193323Sed * specifying the fd to be redirected.  The variable "c" contains the
1081193323Sed * first character of the redirection operator.
1082193323Sed */
1083193323Sed
1084193323Sedparseredir: {
1085193323Sed	char fd = *out;
1086193323Sed	union node *np;
1087193323Sed
1088193323Sed	np = (union node *)stalloc(sizeof (struct nfile));
1089193323Sed	if (c == '>') {
1090193323Sed		np->nfile.fd = 1;
1091193323Sed		c = pgetc();
1092193323Sed		if (c == '>')
1093193323Sed			np->type = NAPPEND;
1094193323Sed		else if (c == '&')
1095193323Sed			np->type = NTOFD;
1096193323Sed		else {
1097193323Sed			np->type = NTO;
1098193323Sed			pungetc();
1099193323Sed		}
1100198090Srdivacky	} else {	/* c == '<' */
1101193323Sed		np->nfile.fd = 0;
1102193323Sed		c = pgetc();
1103193323Sed		if (c == '<') {
1104193323Sed			if (sizeof (struct nfile) != sizeof (struct nhere)) {
1105193323Sed				np = (union node *)stalloc(sizeof (struct nhere));
1106193323Sed				np->nfile.fd = 0;
1107193323Sed			}
1108193323Sed			np->type = NHERE;
1109193323Sed			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
1110193323Sed			heredoc->here = np;
1111193323Sed			if ((c = pgetc()) == '-') {
1112193323Sed				heredoc->striptabs = 1;
1113193323Sed			} else {
1114193323Sed				heredoc->striptabs = 0;
1115193323Sed				pungetc();
1116193323Sed			}
1117193323Sed		} else if (c == '&')
1118193323Sed			np->type = NFROMFD;
1119193323Sed		else {
1120193323Sed			np->type = NFROM;
1121193323Sed			pungetc();
1122193323Sed		}
1123193323Sed	}
1124193323Sed	if (fd != '\0')
1125193323Sed		np->nfile.fd = digit_val(fd);
1126193323Sed	redirnode = np;
1127193323Sed	goto parseredir_return;
1128193323Sed}
1129193323Sed
1130193323Sed
1131193323Sed/*
1132193323Sed * Parse a substitution.  At this point, we have read the dollar sign
1133193323Sed * and nothing else.
1134193323Sed */
1135193323Sed
1136193323Sedparsesub: {
1137193323Sed	int subtype;
1138193323Sed	int typeloc;
1139193323Sed	int flags;
1140193323Sed	char *p;
1141193323Sed#ifndef GDB_HACK
1142193323Sed	static const char types[] = "}-+?=";
1143193323Sed#endif
1144193323Sed       int bracketed_name = 0; /* used to handle ${[0-9]*} variables */
1145193323Sed
1146193323Sed	c = pgetc();
1147193323Sed	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
1148193323Sed		USTPUTC('$', out);
1149193323Sed		pungetc();
1150193323Sed	} else if (c == '(') {	/* $(command) or $((arith)) */
1151193323Sed		if (pgetc() == '(') {
1152193323Sed			PARSEARITH();
1153193323Sed		} else {
1154193323Sed			pungetc();
1155193323Sed			PARSEBACKQNEW();
1156193323Sed		}
1157193323Sed	} else {
1158193323Sed		USTPUTC(CTLVAR, out);
1159193323Sed		typeloc = out - stackblock();
1160193323Sed		USTPUTC(VSNORMAL, out);
1161193323Sed		subtype = VSNORMAL;
1162198090Srdivacky		if (c == '{') {
1163193323Sed			bracketed_name = 1;
1164193323Sed			c = pgetc();
1165193323Sed			if (c == '#') {
1166193323Sed				if ((c = pgetc()) == '}')
1167193323Sed					c = '#';
1168193323Sed				else
1169193323Sed					subtype = VSLENGTH;
1170193323Sed			}
1171193323Sed			else
1172193323Sed				subtype = 0;
1173193323Sed		}
1174193323Sed		if (is_name(c)) {
1175193323Sed			do {
1176193323Sed				STPUTC(c, out);
1177193323Sed				c = pgetc();
1178193323Sed			} while (is_in_name(c));
1179193323Sed		} else if (is_digit(c)) {
1180193323Sed			if (bracketed_name) {
1181193323Sed				do {
1182193323Sed					STPUTC(c, out);
1183193323Sed					c = pgetc();
1184193323Sed				} while (is_digit(c));
1185193323Sed			} else {
1186193323Sed				STPUTC(c, out);
1187193323Sed				c = pgetc();
1188193323Sed			}
1189193323Sed		} else {
1190193323Sed			if (! is_special(c))
1191193323Sedbadsub:				synerror("Bad substitution");
1192193323Sed			USTPUTC(c, out);
1193193323Sed			c = pgetc();
1194193323Sed		}
1195193323Sed		STPUTC('=', out);
1196193323Sed		flags = 0;
1197193323Sed		if (subtype == 0) {
1198193323Sed			switch (c) {
1199193323Sed			case ':':
1200193323Sed				flags = VSNUL;
1201193323Sed				c = pgetc();
1202193323Sed				/*FALLTHROUGH*/
1203193323Sed			default:
1204193323Sed				p = strchr(types, c);
1205193323Sed				if (p == NULL)
1206193323Sed					goto badsub;
1207193323Sed				subtype = p - types + VSNORMAL;
1208193323Sed				break;
1209193323Sed			case '%':
1210193323Sed			case '#':
1211193323Sed				{
1212193323Sed					int cc = c;
1213193323Sed					subtype = c == '#' ? VSTRIMLEFT :
1214193323Sed							     VSTRIMRIGHT;
1215193323Sed					c = pgetc();
1216193323Sed					if (c == cc)
1217193323Sed						subtype++;
1218193323Sed					else
1219193323Sed						pungetc();
1220193323Sed					break;
1221193323Sed				}
1222193323Sed			}
1223193323Sed		} else {
1224193323Sed			pungetc();
1225193323Sed		}
1226193323Sed		if (dblquote || arinest)
1227193323Sed			flags |= VSQUOTE;
1228193323Sed		*(stackblock() + typeloc) = subtype | flags;
1229193323Sed		if (subtype != VSNORMAL)
1230193323Sed			varnest++;
1231193323Sed	}
1232193323Sed	goto parsesub_return;
1233193323Sed}
1234193323Sed
1235198090Srdivacky
1236193323Sed/*
1237193323Sed * Called to parse command substitutions.  Newstyle is set if the command
1238193323Sed * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1239193323Sed * list of commands (passed by reference), and savelen is the number of
1240193323Sed * characters on the top of the stack which must be preserved.
1241193323Sed */
1242193323Sed
1243193323Sedparsebackq: {
1244193323Sed	struct nodelist **nlpp;
1245193323Sed	int savepbq;
1246193323Sed	union node *n;
1247193323Sed	char *volatile str;
1248193323Sed	struct jmploc jmploc;
1249193323Sed	struct jmploc *volatile savehandler;
1250193323Sed	int savelen;
1251193323Sed
1252193323Sed	savepbq = parsebackquote;
1253193323Sed	if (setjmp(jmploc.loc)) {
1254193323Sed		if (str)
1255193323Sed			ckfree(str);
1256193323Sed		parsebackquote = 0;
1257193323Sed		handler = savehandler;
1258193323Sed		longjmp(handler->loc, 1);
1259193323Sed	}
1260193323Sed	INTOFF;
1261193323Sed	str = NULL;
1262193323Sed	savelen = out - stackblock();
1263193323Sed	if (savelen > 0) {
1264193323Sed		str = ckmalloc(savelen);
1265193323Sed		memcpy(str, stackblock(), savelen);
1266193323Sed	}
1267193323Sed	savehandler = handler;
1268193323Sed	handler = &jmploc;
1269193323Sed	INTON;
1270193323Sed        if (oldstyle) {
1271193323Sed                /* We must read until the closing backquote, giving special
1272193323Sed                   treatment to some slashes, and then push the string and
1273193323Sed                   reread it as input, interpreting it normally.  */
1274193323Sed                register char *out;
1275193323Sed                register c;
1276193323Sed                int savelen;
1277193323Sed                char *str;
1278193323Sed
1279193323Sed                STARTSTACKSTR(out);
1280193323Sed                while ((c = pgetc ()) != '`') {
1281193323Sed                       if (c == PEOF) {
1282193323Sed                                startlinno = plinno;
1283193323Sed                                synerror("EOF in backquote substitution");
1284193323Sed                       }
1285193323Sed                       if (c == '\\') {
1286193323Sed                                c = pgetc ();
1287193323Sed                                if (c != '\\' && c != '`' && c != '$'
1288193323Sed                                    && (!dblquote || c != '"'))
1289193323Sed                                        STPUTC('\\', out);
1290193323Sed                       }
1291193323Sed                       STPUTC(c, out);
1292193323Sed                }
1293193323Sed                STPUTC('\0', out);
1294193323Sed                savelen = out - stackblock();
1295193323Sed                if (savelen > 0) {
1296193323Sed                        str = ckmalloc(savelen);
1297193323Sed                        memcpy(str, stackblock(), savelen);
1298193323Sed			setinputstring(str, 1);
1299193323Sed                }
1300193323Sed        }
1301193323Sed	nlpp = &bqlist;
1302193323Sed	while (*nlpp)
1303193323Sed		nlpp = &(*nlpp)->next;
1304193323Sed	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1305193323Sed	(*nlpp)->next = NULL;
1306193323Sed	parsebackquote = oldstyle;
1307193323Sed	n = list(0);
1308193323Sed        if (!oldstyle && (readtoken() != TRP))
1309193323Sed                synexpect(TRP);
1310193323Sed	(*nlpp)->n = n;
1311193323Sed        /* Start reading from old file again.  */
1312193323Sed        if (oldstyle)
1313193323Sed                popfile();
1314193323Sed	while (stackblocksize() <= savelen)
1315193323Sed		growstackblock();
1316193323Sed	STARTSTACKSTR(out);
1317193323Sed	if (str) {
1318193323Sed		memcpy(out, str, savelen);
1319193323Sed		STADJUST(savelen, out);
1320193323Sed		INTOFF;
1321193323Sed		ckfree(str);
1322193323Sed		str = NULL;
1323193323Sed		INTON;
1324193323Sed	}
1325193323Sed	parsebackquote = savepbq;
1326193323Sed	handler = savehandler;
1327193323Sed	if (arinest || dblquote)
1328198090Srdivacky		USTPUTC(CTLBACKQ | CTLQUOTE, out);
1329193323Sed	else
1330193323Sed		USTPUTC(CTLBACKQ, out);
1331193323Sed	if (oldstyle)
1332193323Sed		goto parsebackq_oldreturn;
1333193323Sed	else
1334193323Sed		goto parsebackq_newreturn;
1335193323Sed}
1336193323Sed
1337193323Sed/*
1338193323Sed * Parse an arithmetic expansion (indicate start of one and set state)
1339193323Sed */
1340193323Sedparsearith: {
1341193323Sed
1342193323Sed	if (++arinest == 1) {
1343193323Sed		prevsyntax = syntax;
1344193323Sed		syntax = ARISYNTAX;
1345193323Sed		USTPUTC(CTLARI, out);
1346193323Sed	} else {
1347193323Sed		/*
1348193323Sed		 * we collapse embedded arithmetic expansion to
1349193323Sed		 * parenthesis, which should be equivalent
1350193323Sed		 */
1351193323Sed		USTPUTC('(', out);
1352193323Sed	}
1353193323Sed	goto parsearith_return;
1354193323Sed}
1355193323Sed
1356193323Sed} /* end of readtoken */
1357193323Sed
1358193323Sed
1359193323Sed
1360193323Sed#ifdef mkinit
1361193323SedRESET {
1362193323Sed	tokpushback = 0;
1363193323Sed	checkkwd = 0;
1364193323Sed}
1365193323Sed#endif
1366193323Sed
1367193323Sed/*
1368193323Sed * Returns true if the text contains nothing to expand (no dollar signs
1369193323Sed * or backquotes).
1370193323Sed */
1371193323Sed
1372193323SedSTATIC int
1373193323Sednoexpand(text)
1374193323Sed	char *text;
1375193323Sed	{
1376193323Sed	register char *p;
1377193323Sed	register char c;
1378193323Sed
1379193323Sed	p = text;
1380193323Sed	while ((c = *p++) != '\0') {
1381193323Sed		if (c == CTLESC)
1382193323Sed			p++;
1383193323Sed		else if (BASESYNTAX[c] == CCTL)
1384193323Sed			return 0;
1385193323Sed	}
1386193323Sed	return 1;
1387193323Sed}
1388193323Sed
1389193323Sed
1390193323Sed/*
1391193323Sed * Return true if the argument is a legal variable name (a letter or
1392193323Sed * underscore followed by zero or more letters, underscores, and digits).
1393193323Sed */
1394193323Sed
1395193323Sedint
1396193323Sedgoodname(name)
1397193323Sed	char *name;
1398193323Sed	{
1399193323Sed	register char *p;
1400193323Sed
1401193323Sed	p = name;
1402193323Sed	if (! is_name(*p))
1403193323Sed		return 0;
1404193323Sed	while (*++p) {
1405193323Sed		if (! is_in_name(*p))
1406193323Sed			return 0;
1407193323Sed	}
1408193323Sed	return 1;
1409193323Sed}
1410193323Sed
1411193323Sed
1412193323Sed/*
1413193323Sed * Called when an unexpected token is read during the parse.  The argument
1414193323Sed * is the token that is expected, or -1 if more than one type of token can
1415198090Srdivacky * occur at this point.
1416193323Sed */
1417193323Sed
1418193323SedSTATIC void
1419193323Sedsynexpect(token)
1420193323Sed	int token;
1421193323Sed{
1422193323Sed	char msg[64];
1423193323Sed
1424193323Sed	if (token >= 0) {
1425193323Sed		fmtstr(msg, 64, "%s unexpected (expecting %s)",
1426193323Sed			tokname[lasttoken], tokname[token]);
1427193323Sed	} else {
1428193323Sed		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1429193323Sed	}
1430193323Sed	synerror(msg);
1431193323Sed}
1432193323Sed
1433193323Sed
1434193323SedSTATIC void
1435198090Srdivackysynerror(msg)
1436193323Sed	char *msg;
1437193323Sed	{
1438193323Sed	if (commandname)
1439193323Sed		outfmt(&errout, "%s: %d: ", commandname, startlinno);
1440193323Sed	outfmt(&errout, "Syntax error: %s\n", msg);
1441193323Sed	error((char *)NULL);
1442193323Sed}
1443193323Sed
1444193323SedSTATIC void
1445193323Sedsetprompt(which)
1446193323Sed	int which;
1447193323Sed	{
1448193323Sed	whichprompt = which;
1449193323Sed
1450193323Sed#ifndef NO_HISTORY
1451193323Sed	if (!el)
1452193323Sed#endif
1453193323Sed		out2str(getprompt(NULL));
1454193323Sed}
1455193323Sed
1456193323Sed/*
1457193323Sed * called by editline -- any expansions to the prompt
1458193323Sed *    should be added here.
1459193323Sed */
1460193323Sedchar *
1461193323Sedgetprompt(unused)
1462193323Sed	void *unused;
1463193323Sed	{
1464193323Sed	switch (whichprompt) {
1465193323Sed	case 0:
1466193323Sed		return "";
1467198090Srdivacky	case 1:
1468193323Sed		return ps1val();
1469193323Sed	case 2:
1470193323Sed		return ps2val();
1471193323Sed	default:
1472193323Sed		return "<internal prompt error>";
1473193323Sed	}
1474193323Sed}
1475193323Sed