return n;
checkneg: if (negate) { n2 = (union node *)stalloc(sizeof (struct nnot)); n2->type = NNOT; n2->nnot.com = n; return n2; } else return n;
STATIC union node *makename __P((void));STATIC void parsefname __P((void));STATIC void parseheredoc __P((void));STATIC int peektoken __P((void));STATIC int readtoken __P((void));STATIC int xxreadtoken __P((void));STATIC int readtoken1 __P((int, char const *, char *, int));STATIC int noexpand __P((char *));STATIC void synexpect __P((int));STATIC void synerror __P((char *));STATIC void setprompt __P((int)); /* * Read and parse a command.  Returns NEOF on end of file.  (NULL is a * valid parse tree indicating a blank line.) */union node *parsecmd(interact) 	int interact;{	int t;	doprompt = interact;	if (doprompt)		setprompt(1);	else		setprompt(0);	needprompt = 0;	t = readtoken();	if (t == TEOF)		return NEOF;	if (t == TNL)		return NULL;	tokpushback++;	return list(1);}STATIC union node *list(nlflag) 	int nlflag;{	union node *n1, *n2, *n3;	int tok;	checkkwd = 2;	if (nlflag == 0 && tokendlist[peektoken()])		return NULL;	n1 = NULL;	for (;;) {		n2 = andor();		tok = readtoken();		if (tok == TBACKGND) {			if (n2->type == NCMD || n2->type == NPIPE) {				n2->ncmd.backgnd = 1;			} else if (n2->type == NREDIR) {				n2->type = NBACKGND;			} else {				n3 = (union node *)stalloc(sizeof (struct nredir));				n3->type = NBACKGND;				n3->nredir.n = n2;				n3->nredir.redirect = NULL;				n2 = n3;			}		}		if (n1 == NULL) {			n1 = n2;		}		else {			n3 = (union node *)stalloc(sizeof (struct nbinary));			n3->type = NSEMI;			n3->nbinary.ch1 = n1;			n3->nbinary.ch2 = n2;			n1 = n3;		}		switch (tok) {		case TBACKGND:		case TSEMI:			tok = readtoken();			/* fall through */		case TNL:			if (tok == TNL) {				parseheredoc();				if (nlflag)					return n1;			} else {				tokpushback++;			}			checkkwd = 2;			if (tokendlist[peektoken()])				return n1;			break;		case TEOF:			if (heredoclist)				parseheredoc();			else				pungetc();		/* push back EOF on input */			return n1;		default:			if (nlflag)				synexpect(-1);			tokpushback++;			return n1;		}	}}STATIC union node *andor() {	union node *n1, *n2, *n3;	int t;	n1 = pipeline();	for (;;) {		if ((t = readtoken()) == TAND) {			t = NAND;		} else if (t == TOR) {			t = NOR;		} else {			tokpushback++;			return n1;		}		n2 = pipeline();		n3 = (union node *)stalloc(sizeof (struct nbinary));		n3->type = t;		n3->nbinary.ch1 = n1;		n3->nbinary.ch2 = n2;		n1 = n3;	}}STATIC union node *pipeline() {	union node *n1, *pipenode, *notnode;	struct nodelist *lp, *prev;	int negate = 0;	TRACE(("pipeline: entered\n"));	while (readtoken() == TNOT) {		TRACE(("pipeline: TNOT recognized\n"));		negate = !negate;	}	tokpushback++;	n1 = command();	if (readtoken() == TPIPE) {		pipenode = (union node *)stalloc(sizeof (struct npipe));		pipenode->type = NPIPE;		pipenode->npipe.backgnd = 0;		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));		pipenode->npipe.cmdlist = lp;		lp->n = n1;		do {			prev = lp;			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));			lp->n = command();			prev->next = lp;		} while (readtoken() == TPIPE);		lp->next = NULL;		n1 = pipenode;	}	tokpushback++;	if (negate) {		notnode = (union node *)stalloc(sizeof (struct nnot));		notnode->type = NNOT;		notnode->nnot.com = n1;		n1 = notnode;	}	return n1;}STATIC union node *command() {	union node *n1, *n2;	union node *ap, **app;	union node *cp, **cpp;	union node *redir, **rpp;	int t;	checkkwd = 2;	redir = NULL;	n1 = NULL;	rpp = &redir;	/* Check for redirection which may precede command */	while (readtoken() == TREDIR) {		*rpp = n2 = redirnode;		rpp = &n2->nfile.next;		parsefname();	}	tokpushback++;	switch (readtoken()) {	case TIF:		n1 = (union node *)stalloc(sizeof (struct nif));		n1->type = NIF;		n1->nif.test = list(0);		if (readtoken() != TTHEN)			synexpect(TTHEN);		n1->nif.ifpart = list(0);		n2 = n1;		while (readtoken() == TELIF) {			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));			n2 = n2->nif.elsepart;			n2->type = NIF;			n2->nif.test = list(0);			if (readtoken() != TTHEN)				synexpect(TTHEN);			n2->nif.ifpart = list(0);		}		if (lasttoken == TELSE)			n2->nif.elsepart = list(0);		else {			n2->nif.elsepart = NULL;			tokpushback++;		}		if (readtoken() != TFI)			synexpect(TFI);		checkkwd = 1;		break;	case TWHILE:	case TUNTIL: {		int got;		n1 = (union node *)stalloc(sizeof (struct nbinary));		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;		n1->nbinary.ch1 = list(0);		if ((got=readtoken()) != TDO) {TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));			synexpect(TDO);		}		n1->nbinary.ch2 = list(0);		if (readtoken() != TDONE)			synexpect(TDONE);		checkkwd = 1;		break;	}	case TFOR:		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))			synerror("Bad for loop variable");		n1 = (union node *)stalloc(sizeof (struct nfor));		n1->type = NFOR;		n1->nfor.var = wordtext;		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {			app = &ap;			while (readtoken() == TWORD) {				n2 = (union node *)stalloc(sizeof (struct narg));				n2->type = NARG;				n2->narg.text = wordtext;				n2->narg.backquote = backquotelist;				*app = n2;				app = &n2->narg.next;			}			*app = NULL;			n1->nfor.args = ap;			if (lasttoken != TNL && lasttoken != TSEMI)				synexpect(-1);		} else {#ifndef GDB_HACK			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,								   '@', '=', '\0'};#endif			n2 = (union node *)stalloc(sizeof (struct narg));			n2->type = NARG;			n2->narg.text = (char *)argvars;			n2->narg.backquote = NULL;			n2->narg.next = NULL;			n1->nfor.args = n2;			/*			 * Newline or semicolon here is optional (but note			 * that the original Bourne shell only allowed NL).			 */			if (lasttoken != TNL && lasttoken != TSEMI)				tokpushback++;		}		checkkwd = 2;		if ((t = readtoken()) == TDO)			t = TDONE;		else if (t == TBEGIN)			t = TEND;		else			synexpect(-1);		n1->nfor.body = list(0);		if (readtoken() != t)			synexpect(t);		checkkwd = 1;		break;	case TCASE:		n1 = (union node *)stalloc(sizeof (struct ncase));		n1->type = NCASE;		if (readtoken() != TWORD)			synexpect(TWORD);		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));		n2->type = NARG;		n2->narg.text = wordtext;		n2->narg.backquote = backquotelist;		n2->narg.next = NULL;		while (readtoken() == TNL);		if (lasttoken != TWORD || ! equal(wordtext, "in"))			synerror("expecting \"in\"");		cpp = &n1->ncase.cases;		checkkwd = 2, readtoken();		do {			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));			cp->type = NCLIST;			app = &cp->nclist.pattern;			for (;;) {				*app = ap = (union node *)stalloc(sizeof (struct narg));				ap->type = NARG;				ap->narg.text = wordtext;				ap->narg.backquote = backquotelist;				if (checkkwd = 2, readtoken() != TPIPE)					break;				app = &ap->narg.next;				readtoken();			}			ap->narg.next = NULL;			if (lasttoken != TRP)				synexpect(TRP);			cp->nclist.body = list(0);			checkkwd = 2;			if ((t = readtoken()) != TESAC) {				if (t != TENDCASE)					synexpect(TENDCASE);				else					checkkwd = 2, readtoken();			}			cpp = &cp->nclist.next;		} while(lasttoken != TESAC);		*cpp = NULL;		checkkwd = 1;		break;	case TLP:		n1 = (union node *)stalloc(sizeof (struct nredir));		n1->type = NSUBSHELL;		n1->nredir.n = list(0);		n1->nredir.redirect = NULL;		if (readtoken() != TRP)			synexpect(TRP);		checkkwd = 1;		break;	case TBEGIN:		n1 = list(0);		if (readtoken() != TEND)			synexpect(TEND);		checkkwd = 1;		break;	/* Handle an empty command like other simple commands.  */	case TSEMI:		/*		 * An empty command before a ; doesn't make much sense, and		 * should certainly be disallowed in the case of `if ;'.		 */		if (!redir)			synexpect(-1);	case TAND:	case TOR:	case TNL:	case TEOF:	case TWORD:	case TRP:		tokpushback++;		return simplecmd(rpp, redir);	default:		synexpect(-1);	}	/* Now check for redirection which may follow command */	while (readtoken() == TREDIR) {		*rpp = n2 = redirnode;		rpp = &n2->nfile.next;		parsefname();	}	tokpushback++;	*rpp = NULL;	if (redir) {		if (n1->type != NSUBSHELL) {			n2 = (union node *)stalloc(sizeof (struct nredir));			n2->type = NREDIR;			n2->nredir.n = n1;			n1 = n2;		}		n1->nredir.redirect = redir;	}	return n1;}STATIC union node *simplecmd(rpp, redir) 	union node **rpp, *redir;	{	union node *args, **app;	union node **orig_rpp = rpp;	union node *n = NULL;	/* If we don't have any redirections already, then we must reset */	/* rpp to be the address of the local redir variable.  */	if (redir == 0)		rpp = &redir;	args = NULL;	app = &args;	/* 	 * We save the incoming value, because we need this for shell	 * functions.  There can not be a redirect or an argument between	 * the function name and the open parenthesis.  	 */	orig_rpp = rpp;	for (;;) {		if (readtoken() == TWORD) {			n = (union node *)stalloc(sizeof (struct narg));			n->type = NARG;			n->narg.text = wordtext;			n->narg.backquote = backquotelist;			*app = n;			app = &n->narg.next;		} else if (lasttoken == TREDIR) {			*rpp = n = redirnode;			rpp = &n->nfile.next;			parsefname();	/* read name of redirection file */		} else if (lasttoken == TLP && app == &args->narg.next					    && rpp == orig_rpp) {			/* We have a function */			if (readtoken() != TRP)				synexpect(TRP);#ifdef notdef			if (! goodname(n->narg.text))				synerror("Bad function name");#endif			n->type = NDEFUN;			n->narg.next = command();			return n;		} else {			tokpushback++;			break;		}	}	*app = NULL;	*rpp = NULL;	n = (union node *)stalloc(sizeof (struct ncmd));	n->type = NCMD;	n->ncmd.backgnd = 0;	n->ncmd.args = args;	n->ncmd.redirect = redir;	return n;}STATIC union node *makename() {	union node *n;	n = (union node *)stalloc(sizeof (struct narg));	n->type = NARG;	n->narg.next = NULL;	n->narg.text = wordtext;	n->narg.backquote = backquotelist;	return n;}