14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * UNIX shell
234887Schin  *
244887Schin  * S. R. Bourne
254887Schin  * Rewritten by David Korn
264887Schin  * AT&T Labs
274887Schin  *
284887Schin  *  This is the parser for a shell language
294887Schin  */
304887Schin 
314887Schin #if KSHELL
324887Schin #include	"defs.h"
334887Schin #else
344887Schin #include	<shell.h>
354887Schin #endif
364887Schin #include	<ctype.h>
374887Schin #include	<fcin.h>
384887Schin #include	<error.h>
394887Schin #include	"shlex.h"
404887Schin #include	"history.h"
414887Schin #include	"builtins.h"
424887Schin #include	"test.h"
434887Schin #include	"history.h"
444887Schin 
454887Schin #define HERE_MEM	1024	/* size of here-docs kept in memory */
464887Schin 
474887Schin #define hash	nvlink.hl._hash
484887Schin 
494887Schin /* These routines are local to this module */
504887Schin 
51*8462SApril.Chin@Sun.COM static Shnode_t	*makeparent(Lex_t*, int, Shnode_t*);
52*8462SApril.Chin@Sun.COM static Shnode_t	*makelist(Lex_t*, int, Shnode_t*, Shnode_t*);
534887Schin static struct argnod	*qscan(struct comnod*, int);
54*8462SApril.Chin@Sun.COM static struct ionod	*inout(Lex_t*,struct ionod*, int);
55*8462SApril.Chin@Sun.COM static Shnode_t	*sh_cmd(Lex_t*,int,int);
56*8462SApril.Chin@Sun.COM static Shnode_t	*term(Lex_t*,int);
57*8462SApril.Chin@Sun.COM static Shnode_t	*list(Lex_t*,int);
58*8462SApril.Chin@Sun.COM static struct regnod	*syncase(Lex_t*,int);
59*8462SApril.Chin@Sun.COM static Shnode_t	*item(Lex_t*,int);
60*8462SApril.Chin@Sun.COM static Shnode_t	*simple(Lex_t*,int, struct ionod*);
61*8462SApril.Chin@Sun.COM static int	skipnl(Lex_t*,int);
62*8462SApril.Chin@Sun.COM static Shnode_t	*test_expr(Lex_t*,int);
63*8462SApril.Chin@Sun.COM static Shnode_t	*test_and(Lex_t*);
64*8462SApril.Chin@Sun.COM static Shnode_t	*test_or(Lex_t*);
65*8462SApril.Chin@Sun.COM static Shnode_t	*test_primary(Lex_t*);
664887Schin 
67*8462SApril.Chin@Sun.COM #define	sh_getlineno(lp)	(lp->lastline)
684887Schin 
694887Schin #ifndef NIL
704887Schin #   define NIL(type)	((type)0)
714887Schin #endif /* NIL */
724887Schin #define CNTL(x)		((x)&037)
734887Schin 
744887Schin 
754887Schin #if !KSHELL
764887Schin static struct stdata
774887Schin {
784887Schin 	struct slnod    *staklist;
794887Schin 	int	cmdline;
804887Schin } st;
814887Schin #endif
824887Schin 
83*8462SApril.Chin@Sun.COM static int		opt_get;
844887Schin static int		loop_level;
854887Schin static struct argnod	*label_list;
864887Schin static struct argnod	*label_last;
874887Schin 
884887Schin #define getnode(type)	((Shnode_t*)stakalloc(sizeof(struct type)))
894887Schin 
904887Schin #if SHOPT_KIA
914887Schin #include	"path.h"
924887Schin /*
934887Schin  * write out entities for each item in the list
944887Schin  * type=='V' for variable assignment lists
954887Schin  * Otherwise type is determined by the command */
96*8462SApril.Chin@Sun.COM static unsigned long writedefs(Lex_t *lexp,struct argnod *arglist, int line, int type, struct argnod *cmd)
974887Schin {
984887Schin 	register struct argnod *argp = arglist;
994887Schin 	register char *cp;
1004887Schin 	register int n,eline;
1014887Schin 	int width=0;
1024887Schin 	unsigned long r=0;
1034887Schin 	static char atbuff[20];
1044887Schin 	int  justify=0;
1054887Schin 	char *attribute = atbuff;
106*8462SApril.Chin@Sun.COM 	unsigned long parent=lexp->script;
1074887Schin 	if(type==0)
1084887Schin 	{
109*8462SApril.Chin@Sun.COM 		parent = lexp->current;
1104887Schin 		type = 'v';
1114887Schin 		switch(*argp->argval)
1124887Schin 		{
1134887Schin 		    case 'a':
1144887Schin 			type='p';
1154887Schin 			justify = 'a';
1164887Schin 			break;
1174887Schin 		    case 'e':
1184887Schin 			*attribute++ =  'x';
1194887Schin 			break;
1204887Schin 		    case 'r':
1214887Schin 			*attribute++ = 'r';
1224887Schin 			break;
1234887Schin 		    case 'l':
1244887Schin 			break;
1254887Schin 		}
1264887Schin 		while(argp = argp->argnxt.ap)
1274887Schin 		{
1284887Schin 			if((n= *(cp=argp->argval))!='-' && n!='+')
1294887Schin 				break;
1304887Schin 			if(cp[1]==n)
1314887Schin 				break;
1324887Schin 			while((n= *++cp))
1334887Schin 			{
1344887Schin 				if(isdigit(n))
1354887Schin 					width = 10*width + n-'0';
1364887Schin 				else if(n=='L' || n=='R' || n =='Z')
1374887Schin 					justify=n;
1384887Schin 				else
1394887Schin 					*attribute++ = n;
1404887Schin 			}
1414887Schin 		}
1424887Schin 	}
1434887Schin 	else if(cmd)
144*8462SApril.Chin@Sun.COM 		parent=kiaentity(lexp,sh_argstr(cmd),-1,'p',-1,-1,lexp->unknown,'b',0,"");
1454887Schin 	*attribute = 0;
1464887Schin 	while(argp)
1474887Schin 	{
1484887Schin 		if((cp=strchr(argp->argval,'='))||(cp=strchr(argp->argval,'?')))
1494887Schin 			n = cp-argp->argval;
1504887Schin 		else
1514887Schin 			n = strlen(argp->argval);
152*8462SApril.Chin@Sun.COM 		eline = lexp->sh->inlineno-(lexp->token==NL);
153*8462SApril.Chin@Sun.COM 		r=kiaentity(lexp,argp->argval,n,type,line,eline,parent,justify,width,atbuff);
154*8462SApril.Chin@Sun.COM 		sfprintf(lexp->kiatmp,"p;%..64d;v;%..64d;%d;%d;s;\n",lexp->current,r,line,eline);
1554887Schin 		argp = argp->argnxt.ap;
1564887Schin 	}
1574887Schin 	return(r);
1584887Schin }
1594887Schin #endif /* SHOPT_KIA */
160*8462SApril.Chin@Sun.COM 
161*8462SApril.Chin@Sun.COM static void typeset_order(const char *str,int line)
162*8462SApril.Chin@Sun.COM {
163*8462SApril.Chin@Sun.COM 	register int		c,n=0;
164*8462SApril.Chin@Sun.COM 	unsigned const char	*cp=(unsigned char*)str;
165*8462SApril.Chin@Sun.COM 	static unsigned char	*table;
166*8462SApril.Chin@Sun.COM 	if(*cp!='+' && *cp!='-')
167*8462SApril.Chin@Sun.COM 		return;
168*8462SApril.Chin@Sun.COM 	if(!table)
169*8462SApril.Chin@Sun.COM 	{
170*8462SApril.Chin@Sun.COM 		table = calloc(1,256);
171*8462SApril.Chin@Sun.COM 		for(cp=(unsigned char*)"bflmnprstuxACHS";c = *cp; cp++)
172*8462SApril.Chin@Sun.COM 			table[c] = 1;
173*8462SApril.Chin@Sun.COM 		for(cp=(unsigned char*)"aiEFLRXhTZ";c = *cp; cp++)
174*8462SApril.Chin@Sun.COM 			table[c] = 2;
175*8462SApril.Chin@Sun.COM 		for(c='0'; c <='9'; c++)
176*8462SApril.Chin@Sun.COM 			table[c] = 3;
177*8462SApril.Chin@Sun.COM 	}
178*8462SApril.Chin@Sun.COM 	for(cp=(unsigned char*)str; c= *cp++; n=table[c])
179*8462SApril.Chin@Sun.COM 	{
180*8462SApril.Chin@Sun.COM 		if(table[c] < n)
181*8462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_warn(0),e_lextypeset,line,str);
182*8462SApril.Chin@Sun.COM 	}
183*8462SApril.Chin@Sun.COM }
184*8462SApril.Chin@Sun.COM 
185*8462SApril.Chin@Sun.COM /*
186*8462SApril.Chin@Sun.COM  * add type definitions when compiling with -n
187*8462SApril.Chin@Sun.COM  */
188*8462SApril.Chin@Sun.COM static void check_typedef(struct comnod *tp)
189*8462SApril.Chin@Sun.COM {
190*8462SApril.Chin@Sun.COM 	char	*cp=0;
191*8462SApril.Chin@Sun.COM 	if(tp->comtyp&COMSCAN)
192*8462SApril.Chin@Sun.COM 	{
193*8462SApril.Chin@Sun.COM 		struct argnod *ap = tp->comarg;
194*8462SApril.Chin@Sun.COM 		while(ap = ap->argnxt.ap)
195*8462SApril.Chin@Sun.COM 		{
196*8462SApril.Chin@Sun.COM 			if(!(ap->argflag&ARG_RAW) || memcmp(ap->argval,"--",2))
197*8462SApril.Chin@Sun.COM 				break;
198*8462SApril.Chin@Sun.COM 			if(sh_isoption(SH_NOEXEC))
199*8462SApril.Chin@Sun.COM 				typeset_order(ap->argval,tp->comline);
200*8462SApril.Chin@Sun.COM 			if(memcmp(ap->argval,"-T",2)==0)
201*8462SApril.Chin@Sun.COM 			{
202*8462SApril.Chin@Sun.COM 				if(ap->argval[2])
203*8462SApril.Chin@Sun.COM 					cp = ap->argval+2;
204*8462SApril.Chin@Sun.COM 				else if((ap->argnxt.ap)->argflag&ARG_RAW)
205*8462SApril.Chin@Sun.COM 					cp = (ap->argnxt.ap)->argval;
206*8462SApril.Chin@Sun.COM 				if(cp)
207*8462SApril.Chin@Sun.COM 					break;
208*8462SApril.Chin@Sun.COM 			}
209*8462SApril.Chin@Sun.COM 		}
210*8462SApril.Chin@Sun.COM 	}
211*8462SApril.Chin@Sun.COM 	else
212*8462SApril.Chin@Sun.COM 	{
213*8462SApril.Chin@Sun.COM 		struct dolnod *dp = (struct dolnod*)tp->comarg;
214*8462SApril.Chin@Sun.COM 		char **argv = dp->dolval + dp->dolbot+1;
215*8462SApril.Chin@Sun.COM 		while((cp= *argv++) && memcmp(cp,"--",2))
216*8462SApril.Chin@Sun.COM 		{
217*8462SApril.Chin@Sun.COM 			if(sh_isoption(SH_NOEXEC))
218*8462SApril.Chin@Sun.COM 				typeset_order(cp,tp->comline);
219*8462SApril.Chin@Sun.COM 			if(memcmp(cp,"-T",2)==0)
220*8462SApril.Chin@Sun.COM 			{
221*8462SApril.Chin@Sun.COM 				if(cp[2])
222*8462SApril.Chin@Sun.COM 					cp = cp+2;
223*8462SApril.Chin@Sun.COM 				else
224*8462SApril.Chin@Sun.COM 					cp = *argv;
225*8462SApril.Chin@Sun.COM 				break;
226*8462SApril.Chin@Sun.COM 			}
227*8462SApril.Chin@Sun.COM 		}
228*8462SApril.Chin@Sun.COM 	}
229*8462SApril.Chin@Sun.COM 	if(cp)
230*8462SApril.Chin@Sun.COM 	{
231*8462SApril.Chin@Sun.COM 		Namval_t	*mp=(Namval_t*)tp->comnamp ,*bp;
232*8462SApril.Chin@Sun.COM 		bp = sh_addbuiltin(cp,mp->nvalue.bfp, (void*)0);
233*8462SApril.Chin@Sun.COM 		nv_onattr(bp,nv_isattr(mp,NV_PUBLIC));
234*8462SApril.Chin@Sun.COM 	}
235*8462SApril.Chin@Sun.COM }
236*8462SApril.Chin@Sun.COM 
2374887Schin /*
2384887Schin  * Make a parent node for fork() or io-redirection
2394887Schin  */
240*8462SApril.Chin@Sun.COM static Shnode_t	*makeparent(Lex_t *lp, int flag, Shnode_t *child)
2414887Schin {
2424887Schin 	register Shnode_t	*par = getnode(forknod);
2434887Schin 	par->fork.forktyp = flag;
2444887Schin 	par->fork.forktre = child;
2454887Schin 	par->fork.forkio = 0;
246*8462SApril.Chin@Sun.COM 	par->fork.forkline = sh_getlineno(lp)-1;
2474887Schin 	return(par);
2484887Schin }
2494887Schin 
250*8462SApril.Chin@Sun.COM static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
2514887Schin {
2524887Schin 	register Shnode_t *t = getnode(arithnod);
2534887Schin 	t->ar.artyp = TARITH;
254*8462SApril.Chin@Sun.COM 	t->ar.arline = sh_getlineno(lp);
2554887Schin 	t->ar.arexpr = ap;
2564887Schin 	if(ap->argflag&ARG_RAW)
2574887Schin 		t->ar.arcomp = sh_arithcomp(ap->argval);
2584887Schin 	else
2594887Schin 		t->ar.arcomp = 0;
2604887Schin 	return(t);
2614887Schin }
2624887Schin 
2634887Schin /*
2644887Schin  *  Make a node corresponding to a command list
2654887Schin  */
266*8462SApril.Chin@Sun.COM static Shnode_t	*makelist(Lex_t *lexp, int type, Shnode_t *l, Shnode_t *r)
2674887Schin {
2684887Schin 	register Shnode_t	*t;
2694887Schin 	if(!l || !r)
270*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
2714887Schin 	else
2724887Schin 	{
2734887Schin 		if((type&COMMSK) == TTST)
2744887Schin 			t = getnode(tstnod);
2754887Schin 		else
2764887Schin 			t = getnode(lstnod);
2774887Schin 		t->lst.lsttyp = type;
2784887Schin 		t->lst.lstlef = l;
2794887Schin 		t->lst.lstrit = r;
2804887Schin 	}
2814887Schin 	return(t);
2824887Schin }
2834887Schin 
2844887Schin /*
2854887Schin  * entry to shell parser
2864887Schin  * Flag can be the union of SH_EOF|SH_NL
2874887Schin  */
2884887Schin 
2894887Schin void	*sh_parse(Shell_t *shp, Sfio_t *iop, int flag)
2904887Schin {
2914887Schin 	register Shnode_t	*t;
292*8462SApril.Chin@Sun.COM 	Lex_t			*lexp = (Lex_t*)shp->lex_context;
2934887Schin 	Fcin_t	sav_input;
294*8462SApril.Chin@Sun.COM 	struct argnod *sav_arg = lexp->arg;
2954887Schin 	int	sav_prompt = shp->nextprompt;
2964887Schin 	if(shp->binscript && sffileno(iop)==shp->infd)
297*8462SApril.Chin@Sun.COM 		return((void*)sh_trestore(shp,iop));
2984887Schin 	fcsave(&sav_input);
2994887Schin 	shp->st.staklist = 0;
300*8462SApril.Chin@Sun.COM 	lexp->heredoc = 0;
301*8462SApril.Chin@Sun.COM 	lexp->inlineno = shp->inlineno;
302*8462SApril.Chin@Sun.COM 	lexp->firstline = shp->st.firstline;
3034887Schin 	shp->nextprompt = 1;
3044887Schin 	loop_level = 0;
3054887Schin 	label_list = label_last = 0;
3064887Schin 	if(sh_isoption(SH_INTERACTIVE))
3074887Schin 		sh_onstate(SH_INTERACTIVE);
3084887Schin 	if(sh_isoption(SH_VERBOSE))
3094887Schin 		sh_onstate(SH_VERBOSE);
310*8462SApril.Chin@Sun.COM 	sh_lexopen(lexp,shp,0);
3114887Schin 	if(fcfopen(iop) < 0)
3124887Schin 		return(NIL(void*));
3134887Schin 	if(fcfile())
3144887Schin 	{
3154887Schin 		char *cp = fcfirst();
3164887Schin 		if( cp[0]==CNTL('k') &&  cp[1]==CNTL('s') && cp[2]==CNTL('h') && cp[3]==0)
3174887Schin 		{
3184887Schin 			int version;
3194887Schin 			fcseek(4);
3204887Schin 			fcgetc(version);
3214887Schin 			fcclose();
3224887Schin 			fcrestore(&sav_input);
323*8462SApril.Chin@Sun.COM 			lexp->arg = sav_arg;
3244887Schin 			if(version > 3)
3254887Schin 				errormsg(SH_DICT,ERROR_exit(1),e_lexversion);
3264887Schin 			if(sffileno(iop)==shp->infd)
3274887Schin 				shp->binscript = 1;
3284887Schin 			sfgetc(iop);
329*8462SApril.Chin@Sun.COM 			return((void*)sh_trestore(shp,iop));
3304887Schin 		}
3314887Schin 	}
3324887Schin 	if((flag&SH_NL) && (shp->inlineno=error_info.line+shp->st.firstline)==0)
3334887Schin 		shp->inlineno=1;
3344887Schin #if KSHELL
3354887Schin 	shp->nextprompt = 2;
3364887Schin #endif
337*8462SApril.Chin@Sun.COM 	t = sh_cmd(lexp,(flag&SH_EOF)?EOFSYM:'\n',SH_SEMI|SH_EMPTY|(flag&SH_NL));
3384887Schin 	fcclose();
3394887Schin 	fcrestore(&sav_input);
340*8462SApril.Chin@Sun.COM 	lexp->arg = sav_arg;
3414887Schin 	/* unstack any completed alias expansions */
3424887Schin 	if((sfset(iop,0,0)&SF_STRING) && !sfreserve(iop,0,-1))
3434887Schin 	{
3444887Schin 		Sfio_t *sp = sfstack(iop,NULL);
3454887Schin 		if(sp)
3464887Schin 			sfclose(sp);
3474887Schin 	}
3484887Schin 	shp->nextprompt = sav_prompt;
3494887Schin 	if(flag&SH_NL)
3504887Schin 	{
351*8462SApril.Chin@Sun.COM 		shp->st.firstline = lexp->firstline;
352*8462SApril.Chin@Sun.COM 		shp->inlineno = lexp->inlineno;
3534887Schin 	}
354*8462SApril.Chin@Sun.COM 	stkseek(shp->stk,0);
3554887Schin 	return((void*)t);
3564887Schin }
3574887Schin 
3584887Schin /*
3594887Schin  * This routine parses up the matching right parenthesis and returns
3604887Schin  * the parse tree
3614887Schin  */
362*8462SApril.Chin@Sun.COM Shnode_t *sh_dolparen(Lex_t* lp)
3634887Schin {
3644887Schin 	register Shnode_t *t=0;
3654887Schin 	Sfio_t *sp = fcfile();
366*8462SApril.Chin@Sun.COM 	int line = lp->sh->inlineno;
367*8462SApril.Chin@Sun.COM 	lp->sh->inlineno = error_info.line+lp->sh->st.firstline;
368*8462SApril.Chin@Sun.COM 	sh_lexopen(lp,lp->sh,1);
369*8462SApril.Chin@Sun.COM 	lp->comsub = 1;
370*8462SApril.Chin@Sun.COM 	switch(sh_lex(lp))
3714887Schin 	{
3724887Schin 	    /* ((...)) arithmetic expression */
3734887Schin 	    case EXPRSYM:
374*8462SApril.Chin@Sun.COM 		t = getanode(lp,lp->arg);
3754887Schin 		break;
3764887Schin 	    case LPAREN:
377*8462SApril.Chin@Sun.COM 		t = sh_cmd(lp,RPAREN,SH_NL|SH_EMPTY);
378*8462SApril.Chin@Sun.COM 		break;
379*8462SApril.Chin@Sun.COM 	    case LBRACE:
380*8462SApril.Chin@Sun.COM 		t = sh_cmd(lp,RBRACE,SH_NL|SH_EMPTY);
3814887Schin 		break;
3824887Schin 	}
383*8462SApril.Chin@Sun.COM 	lp->comsub = 0;
3844887Schin 	if(!sp && (sp=fcfile()))
3854887Schin 	{
3864887Schin 		/*
3874887Schin 		 * This code handles the case where string has been converted
3884887Schin 		 * to a file by an alias setup
3894887Schin 		 */
3904887Schin 		register int c;
3914887Schin 		char *cp;
3924887Schin 		if(fcgetc(c) > 0)
3934887Schin 			fcseek(-1);
3944887Schin 		cp = fcseek(0);
3954887Schin 		fcclose();
3964887Schin 		fcsopen(cp);
3974887Schin 		sfclose(sp);
3984887Schin 	}
399*8462SApril.Chin@Sun.COM 	lp->sh->inlineno = line;
4004887Schin 	return(t);
4014887Schin }
4024887Schin 
4034887Schin /*
4044887Schin  * remove temporary files and stacks
4054887Schin  */
4064887Schin 
407*8462SApril.Chin@Sun.COM void	sh_freeup(Shell_t *shp)
4084887Schin {
409*8462SApril.Chin@Sun.COM 	if(shp->st.staklist)
410*8462SApril.Chin@Sun.COM 		sh_funstaks(shp->st.staklist,-1);
411*8462SApril.Chin@Sun.COM 	shp->st.staklist = 0;
4124887Schin }
4134887Schin 
4144887Schin /*
4154887Schin  * increase reference count for each stack in function list when flag>0
4164887Schin  * decrease reference count for each stack in function list when flag<=0
4174887Schin  * stack is freed when reference count is zero
4184887Schin  */
4194887Schin 
4204887Schin void sh_funstaks(register struct slnod *slp,int flag)
4214887Schin {
4224887Schin 	register struct slnod *slpold;
4234887Schin 	while(slpold=slp)
4244887Schin 	{
4254887Schin 		if(slp->slchild)
4264887Schin 			sh_funstaks(slp->slchild,flag);
4274887Schin 		slp = slp->slnext;
4284887Schin 		if(flag<=0)
4294887Schin 			stakdelete(slpold->slptr);
4304887Schin 		else
4314887Schin 			staklink(slpold->slptr);
4324887Schin 	}
4334887Schin }
4344887Schin /*
4354887Schin  * cmd
4364887Schin  *	empty
4374887Schin  *	list
4384887Schin  *	list & [ cmd ]
4394887Schin  *	list [ ; cmd ]
4404887Schin  */
4414887Schin 
442*8462SApril.Chin@Sun.COM static Shnode_t	*sh_cmd(Lex_t *lexp, register int sym, int flag)
4434887Schin {
4444887Schin 	register Shnode_t	*left, *right;
4454887Schin 	register int type = FINT|FAMP;
4464887Schin 	if(sym==NL)
447*8462SApril.Chin@Sun.COM 		lexp->lasttok = 0;
448*8462SApril.Chin@Sun.COM 	left = list(lexp,flag);
449*8462SApril.Chin@Sun.COM 	if(lexp->token==NL)
4504887Schin 	{
4514887Schin 		if(flag&SH_NL)
452*8462SApril.Chin@Sun.COM 			lexp->token=';';
4534887Schin 	}
4544887Schin 	else if(!left && !(flag&SH_EMPTY))
455*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
456*8462SApril.Chin@Sun.COM 	switch(lexp->token)
4574887Schin 	{
4584887Schin 	    case COOPSYM:		/* set up a cooperating process */
4594887Schin 		type |= (FPIN|FPOU|FPCL|FCOOP);
4604887Schin 		/* FALL THRU */
4614887Schin 	    case '&':
4624887Schin 		if(left)
4634887Schin 		{
4644887Schin 			/* (...)& -> {...;} & */
4654887Schin 			if(left->tre.tretyp==TPAR)
4664887Schin 				left = left->par.partre;
467*8462SApril.Chin@Sun.COM 			left = makeparent(lexp,TFORK|type, left);
4684887Schin 		}
4694887Schin 		/* FALL THRU */
4704887Schin 	    case ';':
4714887Schin 		if(!left)
472*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
473*8462SApril.Chin@Sun.COM 		if(right=sh_cmd(lexp,sym,flag|SH_EMPTY))
474*8462SApril.Chin@Sun.COM 			left=makelist(lexp,TLST, left, right);
4754887Schin 		break;
4764887Schin 	    case EOFSYM:
4774887Schin 		if(sym==NL)
4784887Schin 			break;
4794887Schin 	    default:
480*8462SApril.Chin@Sun.COM 		if(sym && sym!=lexp->token)
4814887Schin 		{
482*8462SApril.Chin@Sun.COM 			if(sym!=ELSESYM || (lexp->token!=ELIFSYM && lexp->token!=FISYM))
483*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
4844887Schin 		}
4854887Schin 	}
4864887Schin 	return(left);
4874887Schin }
4884887Schin 
4894887Schin /*
4904887Schin  * list
4914887Schin  *	term
4924887Schin  *	list && term
4934887Schin  *	list || term
4944887Schin  *      unfortunately, these are equal precedence
4954887Schin  */
496*8462SApril.Chin@Sun.COM static Shnode_t	*list(Lex_t *lexp, register int flag)
4974887Schin {
498*8462SApril.Chin@Sun.COM 	register Shnode_t	*t = term(lexp,flag);
4994887Schin 	register int 	token;
500*8462SApril.Chin@Sun.COM 	while(t && ((token=lexp->token)==ANDFSYM || token==ORFSYM))
501*8462SApril.Chin@Sun.COM 		t = makelist(lexp,(token==ANDFSYM?TAND:TORF), t, term(lexp,SH_NL|SH_SEMI));
5024887Schin 	return(t);
5034887Schin }
5044887Schin 
5054887Schin /*
5064887Schin  * term
5074887Schin  *	item
5084887Schin  *	item | term
5094887Schin  */
510*8462SApril.Chin@Sun.COM static Shnode_t	*term(Lex_t *lexp,register int flag)
5114887Schin {
5124887Schin 	register Shnode_t	*t;
5134887Schin 	register int token;
5144887Schin 	if(flag&SH_NL)
515*8462SApril.Chin@Sun.COM 		token = skipnl(lexp,flag);
5164887Schin 	else
517*8462SApril.Chin@Sun.COM 		token = sh_lex(lexp);
5184887Schin 	/* check to see if pipeline is to be timed */
5194887Schin 	if(token==TIMESYM || token==NOTSYM)
5204887Schin 	{
5214887Schin 		t = getnode(parnod);
5224887Schin 		t->par.partyp=TTIME;
523*8462SApril.Chin@Sun.COM 		if(lexp->token==NOTSYM)
5244887Schin 			t->par.partyp |= COMSCAN;
525*8462SApril.Chin@Sun.COM 		t->par.partre = term(lexp,0);
5264887Schin 	}
527*8462SApril.Chin@Sun.COM 	else if((t=item(lexp,SH_NL|SH_EMPTY|(flag&SH_SEMI))) && lexp->token=='|')
5284887Schin 	{
5294887Schin 		register Shnode_t	*tt;
5304887Schin 		int showme = t->tre.tretyp&FSHOWME;
531*8462SApril.Chin@Sun.COM 		t = makeparent(lexp,TFORK|FPOU,t);
532*8462SApril.Chin@Sun.COM 		if(tt=term(lexp,SH_NL))
5334887Schin 		{
5344887Schin 			switch(tt->tre.tretyp&COMMSK)
5354887Schin 			{
5364887Schin 			    case TFORK:
5374887Schin 				tt->tre.tretyp |= FPIN|FPCL;
5384887Schin 				break;
5394887Schin 			    case TFIL:
5404887Schin 				tt->lst.lstlef->tre.tretyp |= FPIN|FPCL;
5414887Schin 				break;
5424887Schin 			    default:
543*8462SApril.Chin@Sun.COM 				tt= makeparent(lexp,TSETIO|FPIN|FPCL,tt);
5444887Schin 			}
545*8462SApril.Chin@Sun.COM 			t=makelist(lexp,TFIL,t,tt);
5464887Schin 			t->tre.tretyp |= showme;
5474887Schin 		}
548*8462SApril.Chin@Sun.COM 		else if(lexp->token)
549*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5504887Schin 	}
5514887Schin 	return(t);
5524887Schin }
5534887Schin 
5544887Schin /*
5554887Schin  * case statement
5564887Schin  */
557*8462SApril.Chin@Sun.COM static struct regnod*	syncase(Lex_t *lexp,register int esym)
5584887Schin {
559*8462SApril.Chin@Sun.COM 	register int tok = skipnl(lexp,0);
5604887Schin 	register struct regnod	*r;
5614887Schin 	if(tok==esym)
5624887Schin 		return(NIL(struct regnod*));
5634887Schin 	r = (struct regnod*)stakalloc(sizeof(struct regnod));
5644887Schin 	r->regptr=0;
5654887Schin 	r->regflag=0;
5664887Schin 	if(tok==LPAREN)
567*8462SApril.Chin@Sun.COM 		skipnl(lexp,0);
5684887Schin 	while(1)
5694887Schin 	{
570*8462SApril.Chin@Sun.COM 		if(!lexp->arg)
571*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
572*8462SApril.Chin@Sun.COM 		lexp->arg->argnxt.ap=r->regptr;
573*8462SApril.Chin@Sun.COM 		r->regptr = lexp->arg;
574*8462SApril.Chin@Sun.COM 		if((tok=sh_lex(lexp))==RPAREN)
5754887Schin 			break;
5764887Schin 		else if(tok=='|')
577*8462SApril.Chin@Sun.COM 			sh_lex(lexp);
5784887Schin 		else
579*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5804887Schin 	}
581*8462SApril.Chin@Sun.COM 	r->regcom=sh_cmd(lexp,0,SH_NL|SH_EMPTY|SH_SEMI);
582*8462SApril.Chin@Sun.COM 	if((tok=lexp->token)==BREAKCASESYM)
583*8462SApril.Chin@Sun.COM 		r->regnxt=syncase(lexp,esym);
5844887Schin 	else if(tok==FALLTHRUSYM)
5854887Schin 	{
5864887Schin 		r->regflag++;
587*8462SApril.Chin@Sun.COM 		r->regnxt=syncase(lexp,esym);
5884887Schin 	}
5894887Schin 	else
5904887Schin 	{
5914887Schin 		if(tok!=esym && tok!=EOFSYM)
592*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
5934887Schin 		r->regnxt=0;
5944887Schin 	}
595*8462SApril.Chin@Sun.COM 	if(lexp->token==EOFSYM)
5964887Schin 		return(NIL(struct regnod*));
5974887Schin 	return(r);
5984887Schin }
5994887Schin 
6004887Schin /*
6014887Schin  * This routine creates the parse tree for the arithmetic for
6024887Schin  * When called, shlex.arg contains the string inside ((...))
6034887Schin  * When the first argument is missing, a while node is returned
6044887Schin  * Otherise a list containing an arithmetic command and a while
6054887Schin  * is returned.
6064887Schin  */
607*8462SApril.Chin@Sun.COM static Shnode_t	*arithfor(Lex_t *lexp,register Shnode_t *tf)
6084887Schin {
6094887Schin 	register Shnode_t	*t, *tw = tf;
6104887Schin 	register int	offset;
6114887Schin 	register struct argnod *argp;
6124887Schin 	register int n;
613*8462SApril.Chin@Sun.COM 	Stk_t		*stkp = lexp->sh->stk;
614*8462SApril.Chin@Sun.COM 	int argflag = lexp->arg->argflag;
6154887Schin 	/* save current input */
6164887Schin 	Fcin_t	sav_input;
6174887Schin 	fcsave(&sav_input);
618*8462SApril.Chin@Sun.COM 	fcsopen(lexp->arg->argval);
6194887Schin 	/* split ((...)) into three expressions */
6204887Schin 	for(n=0; ; n++)
6214887Schin 	{
6224887Schin 		register int c;
623*8462SApril.Chin@Sun.COM 		argp = (struct argnod*)stkseek(stkp,ARGVAL);
6244887Schin 		argp->argnxt.ap = 0;
6254887Schin 		argp->argchn.cp = 0;
6264887Schin 		argp->argflag = argflag;
6274887Schin 		if(n==2)
6284887Schin 			break;
6294887Schin 		/* copy up to ; onto the stack */
630*8462SApril.Chin@Sun.COM 		sh_lexskip(lexp,';',1,ST_NESTED);
631*8462SApril.Chin@Sun.COM 		offset = stktell(stkp)-1;
6324887Schin 		if((c=fcpeek(-1))!=';')
6334887Schin 			break;
6344887Schin 		/* remove trailing white space */
635*8462SApril.Chin@Sun.COM 		while(offset>ARGVAL && ((c= *stkptr(stkp,offset-1)),isspace(c)))
6364887Schin 			offset--;
6374887Schin 		/* check for empty initialization expression  */
6384887Schin 		if(offset==ARGVAL && n==0)
6394887Schin 			continue;
640*8462SApril.Chin@Sun.COM 		stkseek(stkp,offset);
6414887Schin 		/* check for empty condition and treat as while((1)) */
6424887Schin 		if(offset==ARGVAL)
643*8462SApril.Chin@Sun.COM 			sfputc(stkp,'1');
644*8462SApril.Chin@Sun.COM 		argp = (struct argnod*)stkfreeze(stkp,1);
645*8462SApril.Chin@Sun.COM 		t = getanode(lexp,argp);
6464887Schin 		if(n==0)
647*8462SApril.Chin@Sun.COM 			tf = makelist(lexp,TLST,t,tw);
6484887Schin 		else
6494887Schin 			tw->wh.whtre = t;
6504887Schin 	}
6514887Schin 	while((offset=fcpeek(0)) && isspace(offset))
6524887Schin 		fcseek(1);
6534887Schin 	stakputs(fcseek(0));
6544887Schin 	argp = (struct argnod*)stakfreeze(1);
6554887Schin 	fcrestore(&sav_input);
6564887Schin 	if(n<2)
6574887Schin 	{
658*8462SApril.Chin@Sun.COM 		lexp->token = RPAREN|SYMREP;
659*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
6604887Schin 	}
6614887Schin 	/* check whether the increment is present */
6624887Schin 	if(*argp->argval)
6634887Schin 	{
664*8462SApril.Chin@Sun.COM 		t = getanode(lexp,argp);
6654887Schin 		tw->wh.whinc = (struct arithnod*)t;
6664887Schin 	}
6674887Schin 	else
6684887Schin 		tw->wh.whinc = 0;
669*8462SApril.Chin@Sun.COM 	sh_lexopen(lexp, lexp->sh,1);
670*8462SApril.Chin@Sun.COM 	if((n=sh_lex(lexp))==NL)
671*8462SApril.Chin@Sun.COM 		n = skipnl(lexp,0);
6724887Schin 	else if(n==';')
673*8462SApril.Chin@Sun.COM 		n = sh_lex(lexp);
6744887Schin 	if(n!=DOSYM && n!=LBRACE)
675*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
676*8462SApril.Chin@Sun.COM 	tw->wh.dotre = sh_cmd(lexp,n==DOSYM?DONESYM:RBRACE,SH_NL);
6774887Schin 	tw->wh.whtyp = TWH;
6784887Schin 	return(tf);
6794887Schin 
6804887Schin }
6814887Schin 
682*8462SApril.Chin@Sun.COM static Shnode_t *funct(Lex_t *lexp)
6834887Schin {
684*8462SApril.Chin@Sun.COM 	Shell_t	*shp = lexp->sh;
6854887Schin 	register Shnode_t *t;
6864887Schin 	register int flag;
6874887Schin 	struct slnod *volatile slp=0;
6884887Schin 	Stak_t *savstak;
6894887Schin 	Sfoff_t	first, last;
690*8462SApril.Chin@Sun.COM 	struct functnod *volatile fp;
6914887Schin 	Sfio_t *iop;
6924887Schin #if SHOPT_KIA
693*8462SApril.Chin@Sun.COM 	unsigned long current = lexp->current;
6944887Schin #endif /* SHOPT_KIA */
6954887Schin 	int jmpval, saveloop=loop_level;
6964887Schin 	struct argnod *savelabel = label_last;
6974887Schin 	struct  checkpt buff;
698*8462SApril.Chin@Sun.COM 	int save_optget = opt_get;
699*8462SApril.Chin@Sun.COM 	void	*in_mktype = shp->mktype;
700*8462SApril.Chin@Sun.COM 	shp->mktype = 0;
701*8462SApril.Chin@Sun.COM 	opt_get = 0;
7024887Schin 	t = getnode(functnod);
703*8462SApril.Chin@Sun.COM 	t->funct.functline = shp->inlineno;
7044887Schin 	t->funct.functtyp=TFUN;
7054887Schin 	t->funct.functargs = 0;
706*8462SApril.Chin@Sun.COM 	if(!(flag = (lexp->token==FUNCTSYM)))
7074887Schin 		t->funct.functtyp |= FPOSIX;
708*8462SApril.Chin@Sun.COM 	else if(sh_lex(lexp))
709*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
7104887Schin 	if(!(iop=fcfile()))
7114887Schin 	{
7124887Schin 		iop = sfopen(NIL(Sfio_t*),fcseek(0),"s");
7134887Schin 		fcclose();
7144887Schin 		fcfopen(iop);
7154887Schin 	}
7164887Schin 	t->funct.functloc = first = fctell();
717*8462SApril.Chin@Sun.COM 	if(!shp->st.filename || sffileno(iop)<0)
7184887Schin 	{
7194887Schin 		if(fcfill() >= 0)
7204887Schin 			fcseek(-1);
7214887Schin 		if(sh_isstate(SH_HISTORY))
722*8462SApril.Chin@Sun.COM 			t->funct.functloc = sfseek(shp->hist_ptr->histfp,(off_t)0,SEEK_CUR);
7234887Schin 		else
7244887Schin 		{
7254887Schin 			/* copy source to temporary file */
7264887Schin 			t->funct.functloc = 0;
727*8462SApril.Chin@Sun.COM 			if(lexp->sh->heredocs)
728*8462SApril.Chin@Sun.COM 				t->funct.functloc = sfseek(lexp->sh->heredocs,(Sfoff_t)0, SEEK_END);
7294887Schin 			else
730*8462SApril.Chin@Sun.COM 				lexp->sh->heredocs = sftmp(HERE_MEM);
731*8462SApril.Chin@Sun.COM 			lexp->sh->funlog = lexp->sh->heredocs;
7324887Schin 			t->funct.functtyp |= FPIN;
7334887Schin 		}
7344887Schin 	}
735*8462SApril.Chin@Sun.COM 	t->funct.functnam= (char*)lexp->arg->argval;
7364887Schin #if SHOPT_KIA
737*8462SApril.Chin@Sun.COM 	if(lexp->kiafile)
738*8462SApril.Chin@Sun.COM 		lexp->current = kiaentity(lexp,t->funct.functnam,-1,'p',-1,-1,lexp->script,'p',0,"");
7394887Schin #endif /* SHOPT_KIA */
7404887Schin 	if(flag)
7414887Schin 	{
742*8462SApril.Chin@Sun.COM 		lexp->token = sh_lex(lexp);
7434887Schin #if SHOPT_BASH
744*8462SApril.Chin@Sun.COM 		if(lexp->token == LPAREN)
7454887Schin 		{
746*8462SApril.Chin@Sun.COM 			if((lexp->token = sh_lex(lexp)) == RPAREN)
7474887Schin 				t->funct.functtyp |= FPOSIX;
7484887Schin 			else
749*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
7504887Schin 		}
7514887Schin #endif
7524887Schin 	}
7534887Schin 	if(t->funct.functtyp&FPOSIX)
754*8462SApril.Chin@Sun.COM 		skipnl(lexp,0);
7554887Schin 	else
7564887Schin 	{
757*8462SApril.Chin@Sun.COM 		if(lexp->token==0)
758*8462SApril.Chin@Sun.COM 			t->funct.functargs = (struct comnod*)simple(lexp,SH_NOIO|SH_FUNDEF,NIL(struct ionod*));
759*8462SApril.Chin@Sun.COM 		while(lexp->token==NL)
760*8462SApril.Chin@Sun.COM 			lexp->token = sh_lex(lexp);
7614887Schin 	}
762*8462SApril.Chin@Sun.COM 	if((flag && lexp->token!=LBRACE) || lexp->token==EOFSYM)
763*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
7644887Schin 	sh_pushcontext(&buff,1);
7654887Schin 	jmpval = sigsetjmp(buff.buff,0);
7664887Schin 	if(jmpval == 0)
7674887Schin 	{
7684887Schin 		/* create a new stak frame to compile the command */
7694887Schin 		savstak = stakcreate(STAK_SMALL);
7704887Schin 		savstak = stakinstall(savstak, 0);
7714887Schin 		slp = (struct slnod*)stakalloc(sizeof(struct slnod)+sizeof(struct functnod));
7724887Schin 		slp->slchild = 0;
773*8462SApril.Chin@Sun.COM 		slp->slnext = shp->st.staklist;
774*8462SApril.Chin@Sun.COM 		shp->st.staklist = 0;
7754887Schin 		t->funct.functstak = (struct slnod*)slp;
7764887Schin 		/*
7774887Schin 		 * store the pathname of function definition file on stack
7784887Schin 		 * in name field of fake for node
7794887Schin 		 */
7804887Schin 		fp = (struct functnod*)(slp+1);
7814887Schin 		fp->functtyp = TFUN|FAMP;
7824887Schin 		fp->functnam = 0;
7834887Schin 		fp->functline = t->funct.functline;
784*8462SApril.Chin@Sun.COM 		if(shp->st.filename)
785*8462SApril.Chin@Sun.COM 			fp->functnam = stakcopy(shp->st.filename);
7864887Schin 		loop_level = 0;
7874887Schin 		label_last = label_list;
788*8462SApril.Chin@Sun.COM 		if(!flag && lexp->token==0)
7894887Schin 		{
7904887Schin 			/* copy current word token to current stak frame */
7914887Schin 			struct argnod *ap;
792*8462SApril.Chin@Sun.COM 			flag = ARGVAL + strlen(lexp->arg->argval);
7934887Schin 			ap = (struct argnod*)stakalloc(flag);
794*8462SApril.Chin@Sun.COM 			memcpy(ap,lexp->arg,flag);
795*8462SApril.Chin@Sun.COM 			lexp->arg = ap;
7964887Schin 		}
797*8462SApril.Chin@Sun.COM 		t->funct.functtre = item(lexp,SH_NOIO);
7984887Schin 	}
7994887Schin 	sh_popcontext(&buff);
8004887Schin 	loop_level = saveloop;
8014887Schin 	label_last = savelabel;
8024887Schin 	/* restore the old stack */
8034887Schin 	if(slp)
8044887Schin 	{
8054887Schin 		slp->slptr =  stakinstall(savstak,0);
806*8462SApril.Chin@Sun.COM 		slp->slchild = shp->st.staklist;
8074887Schin 	}
8084887Schin #if SHOPT_KIA
809*8462SApril.Chin@Sun.COM 	lexp->current = current;
8104887Schin #endif /* SHOPT_KIA */
8114887Schin 	if(jmpval)
8124887Schin 	{
8134887Schin 		if(slp && slp->slptr)
8144887Schin 		{
815*8462SApril.Chin@Sun.COM 			shp->st.staklist = slp->slnext;
8164887Schin 			stakdelete(slp->slptr);
8174887Schin 		}
818*8462SApril.Chin@Sun.COM 		siglongjmp(*shp->jmplist,jmpval);
8194887Schin 	}
820*8462SApril.Chin@Sun.COM 	shp->st.staklist = (struct slnod*)slp;
8214887Schin 	last = fctell();
8224887Schin 	fp->functline = (last-first);
8234887Schin 	fp->functtre = t;
824*8462SApril.Chin@Sun.COM 	shp->mktype = in_mktype;
825*8462SApril.Chin@Sun.COM 	if(lexp->sh->funlog)
8264887Schin 	{
8274887Schin 		if(fcfill()>0)
8284887Schin 			fcseek(-1);
829*8462SApril.Chin@Sun.COM 		lexp->sh->funlog = 0;
8304887Schin 	}
8314887Schin #if 	SHOPT_KIA
832*8462SApril.Chin@Sun.COM 	if(lexp->kiafile)
833*8462SApril.Chin@Sun.COM 		kiaentity(lexp,t->funct.functnam,-1,'p',t->funct.functline,shp->inlineno-1,lexp->current,'p',0,"");
8344887Schin #endif /* SHOPT_KIA */
835*8462SApril.Chin@Sun.COM 	t->funct.functtyp |= opt_get;
836*8462SApril.Chin@Sun.COM 	opt_get = save_optget;
8374887Schin 	return(t);
8384887Schin }
8394887Schin 
8404887Schin /*
8414887Schin  * Compound assignment
8424887Schin  */
843*8462SApril.Chin@Sun.COM static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int tdef)
8444887Schin {
8454887Schin 	register int n;
8464887Schin 	register Shnode_t *t, **tp;
8474887Schin 	register struct comnod *ac;
848*8462SApril.Chin@Sun.COM 	Stk_t	*stkp = lexp->sh->stk;
8494887Schin 	int array=0;
8504887Schin 	Namval_t *np;
8514887Schin 	n = strlen(ap->argval)-1;
8524887Schin 	if(ap->argval[n]!='=')
853*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
8544887Schin 	if(ap->argval[n-1]=='+')
8554887Schin 	{
8564887Schin 		ap->argval[n--]=0;
8574887Schin 		array = ARG_APPEND;
8584887Schin 	}
8594887Schin 	/* shift right */
8604887Schin 	while(n > 0)
8614887Schin 	{
8624887Schin 		ap->argval[n] = ap->argval[n-1];
8634887Schin 		n--;
8644887Schin 	}
8654887Schin 	*ap->argval=0;
8664887Schin 	t = getnode(fornod);
8674887Schin 	t->for_.fornam = (char*)(ap->argval+1);
868*8462SApril.Chin@Sun.COM 	t->for_.fortyp = sh_getlineno(lexp);
8694887Schin 	tp = &t->for_.fortre;
8704887Schin 	ap->argchn.ap = (struct argnod*)t;
8714887Schin 	ap->argflag &= ARG_QUOTED;
8724887Schin 	ap->argflag |= array;
873*8462SApril.Chin@Sun.COM 	lexp->assignok = SH_ASSIGN;
874*8462SApril.Chin@Sun.COM 	lexp->aliasok = 1;
8754887Schin 	array=0;
876*8462SApril.Chin@Sun.COM 	if((n=skipnl(lexp,0))==RPAREN || n==LPAREN)
8774887Schin 	{
8784887Schin 		int index= 0;
8794887Schin 		struct argnod **settail;
8804887Schin 		ac = (struct comnod*)getnode(comnod);
8814887Schin 		settail= &ac->comset;
8824887Schin 		memset((void*)ac,0,sizeof(*ac));
883*8462SApril.Chin@Sun.COM 		ac->comline = sh_getlineno(lexp);
8844887Schin 		while(n==LPAREN)
8854887Schin 		{
8864887Schin 			struct argnod *ap;
887*8462SApril.Chin@Sun.COM 			ap = (struct argnod*)stkseek(stkp,ARGVAL);
8884887Schin 			ap->argflag= ARG_ASSIGN;
889*8462SApril.Chin@Sun.COM 			sfprintf(stkp,"[%d]=",index++);
890*8462SApril.Chin@Sun.COM 			ap = (struct argnod*)stkfreeze(stkp,1);
8914887Schin 			ap->argnxt.ap = 0;
892*8462SApril.Chin@Sun.COM 			ap = assign(lexp,ap,0);
8934887Schin 			ap->argflag |= ARG_MESSAGE;
8944887Schin 			*settail = ap;
8954887Schin 			settail = &(ap->argnxt.ap);
896*8462SApril.Chin@Sun.COM 			while((n = skipnl(lexp,0))==0)
897*8462SApril.Chin@Sun.COM 			{
898*8462SApril.Chin@Sun.COM 				ap = (struct argnod*)stkseek(stkp,ARGVAL);
899*8462SApril.Chin@Sun.COM 				ap->argflag= ARG_ASSIGN;
900*8462SApril.Chin@Sun.COM 				sfprintf(stkp,"[%d]=",index++);
901*8462SApril.Chin@Sun.COM 				stakputs(lexp->arg->argval);
902*8462SApril.Chin@Sun.COM 				ap = (struct argnod*)stkfreeze(stkp,1);
903*8462SApril.Chin@Sun.COM 				ap->argnxt.ap = 0;
904*8462SApril.Chin@Sun.COM 				ap->argflag = lexp->arg->argflag;
905*8462SApril.Chin@Sun.COM 				*settail = ap;
906*8462SApril.Chin@Sun.COM 				settail = &(ap->argnxt.ap);
907*8462SApril.Chin@Sun.COM 			}
9084887Schin 		}
9094887Schin 	}
910*8462SApril.Chin@Sun.COM 	else if(n && n!=FUNCTSYM)
911*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
912*8462SApril.Chin@Sun.COM 	else if(n!=FUNCTSYM && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)|| np==SYSDOT)))
913*8462SApril.Chin@Sun.COM 	{
9144887Schin 		array=SH_ARRAY;
915*8462SApril.Chin@Sun.COM 		if(fcgetc(n)==LPAREN)
916*8462SApril.Chin@Sun.COM 		{
917*8462SApril.Chin@Sun.COM 			int c;
918*8462SApril.Chin@Sun.COM 			if(fcgetc(c)==RPAREN)
919*8462SApril.Chin@Sun.COM 			{
920*8462SApril.Chin@Sun.COM 				lexp->token =  SYMRES;
921*8462SApril.Chin@Sun.COM 				array = 0;
922*8462SApril.Chin@Sun.COM 			}
923*8462SApril.Chin@Sun.COM 			else
924*8462SApril.Chin@Sun.COM 				fcseek(-2);
925*8462SApril.Chin@Sun.COM 		}
926*8462SApril.Chin@Sun.COM 		else if(n>0)
927*8462SApril.Chin@Sun.COM 			fcseek(-1);
928*8462SApril.Chin@Sun.COM 		if(array && tdef)
929*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
930*8462SApril.Chin@Sun.COM 	}
9314887Schin 	while(1)
9324887Schin 	{
933*8462SApril.Chin@Sun.COM 		if((n=lexp->token)==RPAREN)
9344887Schin 			break;
9354887Schin 		if(n==FUNCTSYM || n==SYMRES)
936*8462SApril.Chin@Sun.COM 			ac = (struct comnod*)funct(lexp);
9374887Schin 		else
938*8462SApril.Chin@Sun.COM 			ac = (struct comnod*)simple(lexp,SH_NOIO|SH_ASSIGN|array,NIL(struct ionod*));
939*8462SApril.Chin@Sun.COM 		if((n=lexp->token)==RPAREN)
9404887Schin 			break;
9414887Schin 		if(n!=NL && n!=';')
942*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
943*8462SApril.Chin@Sun.COM 		lexp->assignok = SH_ASSIGN;
944*8462SApril.Chin@Sun.COM 		if((n=skipnl(lexp,0)) || array)
9454887Schin 		{
9464887Schin 			if(n==RPAREN)
9474887Schin 				break;
9484887Schin 			if(array ||  n!=FUNCTSYM)
949*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9504887Schin 		}
951*8462SApril.Chin@Sun.COM 		if((n!=FUNCTSYM) && !(lexp->arg->argflag&ARG_ASSIGN) && !((np=nv_search(lexp->arg->argval,lexp->sh->fun_tree,0)) && (nv_isattr(np,BLT_DCL)||np==SYSDOT)))
9524887Schin 		{
953*8462SApril.Chin@Sun.COM 			struct argnod *arg = lexp->arg;
9544887Schin 			if(n!=0)
955*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9564887Schin 			/* check for sys5 style function */
957*8462SApril.Chin@Sun.COM 			if(sh_lex(lexp)!=LPAREN || sh_lex(lexp)!=RPAREN)
9584887Schin 			{
959*8462SApril.Chin@Sun.COM 				lexp->arg = arg;
960*8462SApril.Chin@Sun.COM 				lexp->token = 0;
961*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
9624887Schin 			}
963*8462SApril.Chin@Sun.COM 			lexp->arg = arg;
964*8462SApril.Chin@Sun.COM 			lexp->token = SYMRES;
9654887Schin 		}
966*8462SApril.Chin@Sun.COM 		t = makelist(lexp,TLST,(Shnode_t*)ac,t);
9674887Schin 		*tp = t;
9684887Schin 		tp = &t->lst.lstrit;
9694887Schin 	}
9704887Schin 	*tp = (Shnode_t*)ac;
971*8462SApril.Chin@Sun.COM 	lexp->assignok = 0;
9724887Schin 	return(ap);
9734887Schin }
9744887Schin 
9754887Schin /*
9764887Schin  * item
9774887Schin  *
9784887Schin  *	( cmd ) [ < in ] [ > out ]
9794887Schin  *	word word* [ < in ] [ > out ]
9804887Schin  *	if ... then ... else ... fi
9814887Schin  *	for ... while ... do ... done
9824887Schin  *	case ... in ... esac
9834887Schin  *	begin ... end
9844887Schin  */
9854887Schin 
986*8462SApril.Chin@Sun.COM static Shnode_t	*item(Lex_t *lexp,int flag)
9874887Schin {
9884887Schin 	register Shnode_t	*t;
9894887Schin 	register struct ionod	*io;
990*8462SApril.Chin@Sun.COM 	register int tok = (lexp->token&0xff);
991*8462SApril.Chin@Sun.COM 	int savwdval = lexp->lasttok;
992*8462SApril.Chin@Sun.COM 	int savline = lexp->lastline;
993*8462SApril.Chin@Sun.COM 	int showme=0, comsub;
994*8462SApril.Chin@Sun.COM 	if(!(flag&SH_NOIO) && (tok=='<' || tok=='>' || lexp->token==IOVNAME))
995*8462SApril.Chin@Sun.COM 		io=inout(lexp,NIL(struct ionod*),1);
9964887Schin 	else
9974887Schin 		io=0;
998*8462SApril.Chin@Sun.COM 	if((tok=lexp->token) && tok!=EOFSYM && tok!=FUNCTSYM)
9994887Schin 	{
1000*8462SApril.Chin@Sun.COM 		lexp->lastline =  sh_getlineno(lexp);
1001*8462SApril.Chin@Sun.COM 		lexp->lasttok = lexp->token;
10024887Schin 	}
10034887Schin 	switch(tok)
10044887Schin 	{
10054887Schin 	    /* [[ ... ]] test expression */
10064887Schin 	    case BTESTSYM:
1007*8462SApril.Chin@Sun.COM 		t = test_expr(lexp,ETESTSYM);
10084887Schin 		t->tre.tretyp &= ~TTEST;
10094887Schin 		break;
10104887Schin 	    /* ((...)) arithmetic expression */
10114887Schin 	    case EXPRSYM:
1012*8462SApril.Chin@Sun.COM 		t = getanode(lexp,lexp->arg);
1013*8462SApril.Chin@Sun.COM 		sh_lex(lexp);
10144887Schin 		goto done;
10154887Schin 
10164887Schin 	    /* case statement */
10174887Schin 	    case CASESYM:
10184887Schin 	    {
1019*8462SApril.Chin@Sun.COM 		int savetok = lexp->lasttok;
1020*8462SApril.Chin@Sun.COM 		int saveline = lexp->lastline;
10214887Schin 		t = getnode(swnod);
1022*8462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
1023*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
1024*8462SApril.Chin@Sun.COM 		t->sw.swarg=lexp->arg;
10254887Schin 		t->sw.swtyp=TSW;
10264887Schin 		t->sw.swio = 0;
10274887Schin 		t->sw.swtyp |= FLINENO;
1028*8462SApril.Chin@Sun.COM 		t->sw.swline =  lexp->sh->inlineno;
1029*8462SApril.Chin@Sun.COM 		if((tok=skipnl(lexp,0))!=INSYM && tok!=LBRACE)
1030*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
1031*8462SApril.Chin@Sun.COM 		if(!(t->sw.swlst=syncase(lexp,tok==INSYM?ESACSYM:RBRACE)) && lexp->token==EOFSYM)
10324887Schin 		{
1033*8462SApril.Chin@Sun.COM 			lexp->lasttok = savetok;
1034*8462SApril.Chin@Sun.COM 			lexp->lastline = saveline;
1035*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
10364887Schin 		}
10374887Schin 		break;
10384887Schin 	    }
10394887Schin 
10404887Schin 	    /* if statement */
10414887Schin 	    case IFSYM:
10424887Schin 	    {
10434887Schin 		register Shnode_t	*tt;
10444887Schin 		t = getnode(ifnod);
10454887Schin 		t->if_.iftyp=TIF;
1046*8462SApril.Chin@Sun.COM 		t->if_.iftre=sh_cmd(lexp,THENSYM,SH_NL);
1047*8462SApril.Chin@Sun.COM 		t->if_.thtre=sh_cmd(lexp,ELSESYM,SH_NL|SH_SEMI);
1048*8462SApril.Chin@Sun.COM 		tok = lexp->token;
1049*8462SApril.Chin@Sun.COM 		t->if_.eltre=(tok==ELSESYM?sh_cmd(lexp,FISYM,SH_NL|SH_SEMI):
1050*8462SApril.Chin@Sun.COM 			(tok==ELIFSYM?(lexp->token=IFSYM, tt=item(lexp,SH_NOIO)):0));
10514887Schin 		if(tok==ELIFSYM)
10524887Schin 		{
10534887Schin 			if(!tt || tt->tre.tretyp!=TSETIO)
10544887Schin 				goto done;
10554887Schin 			t->if_.eltre = tt->fork.forktre;
10564887Schin 			tt->fork.forktre = t;
10574887Schin 			t = tt;
10584887Schin 			goto done;
10594887Schin 		}
10604887Schin 		break;
10614887Schin 	    }
10624887Schin 
10634887Schin 	    /* for and select statement */
10644887Schin 	    case FORSYM:
10654887Schin 	    case SELECTSYM:
10664887Schin 	    {
10674887Schin 		t = getnode(fornod);
1068*8462SApril.Chin@Sun.COM 		t->for_.fortyp=(lexp->token==FORSYM?TFOR:TSELECT);
10694887Schin 		t->for_.forlst=0;
1070*8462SApril.Chin@Sun.COM 		t->for_.forline =  lexp->sh->inlineno;
1071*8462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
10724887Schin 		{
1073*8462SApril.Chin@Sun.COM 			if(lexp->token!=EXPRSYM || t->for_.fortyp!=TFOR)
1074*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
10754887Schin 			/* arithmetic for */
1076*8462SApril.Chin@Sun.COM 			t = arithfor(lexp,t);
10774887Schin 			break;
10784887Schin 		}
1079*8462SApril.Chin@Sun.COM 		t->for_.fornam=(char*) lexp->arg->argval;
10804887Schin 		t->for_.fortyp |= FLINENO;
10814887Schin #if SHOPT_KIA
1082*8462SApril.Chin@Sun.COM 		if(lexp->kiafile)
1083*8462SApril.Chin@Sun.COM 			writedefs(lexp,lexp->arg,lexp->sh->inlineno,'v',NIL(struct argnod*));
10844887Schin #endif /* SHOPT_KIA */
1085*8462SApril.Chin@Sun.COM 		while((tok=sh_lex(lexp))==NL);
10864887Schin 		if(tok==INSYM)
10874887Schin 		{
1088*8462SApril.Chin@Sun.COM 			if(sh_lex(lexp))
10894887Schin 			{
1090*8462SApril.Chin@Sun.COM 				if(lexp->token != NL && lexp->token !=';')
1091*8462SApril.Chin@Sun.COM 					sh_syntax(lexp);
10924887Schin 				/* some Linux scripts assume this */
10934887Schin 				if(sh_isoption(SH_NOEXEC))
1094*8462SApril.Chin@Sun.COM 					errormsg(SH_DICT,ERROR_warn(0),e_lexemptyfor,lexp->sh->inlineno-(lexp->token=='\n'));
10954887Schin 				t->for_.forlst = (struct comnod*)getnode(comnod);
10964887Schin 				(t->for_.forlst)->comarg = 0;
10974887Schin 				(t->for_.forlst)->comset = 0;
10984887Schin 				(t->for_.forlst)->comnamp = 0;
10994887Schin 				(t->for_.forlst)->comnamq = 0;
11004887Schin 				(t->for_.forlst)->comstate = 0;
11014887Schin 				(t->for_.forlst)->comio = 0;
11024887Schin 				(t->for_.forlst)->comtyp = 0;
11034887Schin 			}
11044887Schin 			else
1105*8462SApril.Chin@Sun.COM 				t->for_.forlst=(struct comnod*)simple(lexp,SH_NOIO,NIL(struct ionod*));
1106*8462SApril.Chin@Sun.COM 			if(lexp->token != NL && lexp->token !=';')
1107*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
1108*8462SApril.Chin@Sun.COM 			tok = skipnl(lexp,0);
11094887Schin 		}
11104887Schin 		/* 'for i;do cmd' is valid syntax */
11114887Schin 		else if(tok==';')
1112*8462SApril.Chin@Sun.COM 			tok=sh_lex(lexp);
11134887Schin 		if(tok!=DOSYM && tok!=LBRACE)
1114*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11154887Schin 		loop_level++;
1116*8462SApril.Chin@Sun.COM 		t->for_.fortre=sh_cmd(lexp,tok==DOSYM?DONESYM:RBRACE,SH_NL|SH_SEMI);
11174887Schin 		if(--loop_level==0)
11184887Schin 			label_last = label_list;
11194887Schin 		break;
11204887Schin 	    }
11214887Schin 
11224887Schin 	    /* This is the code for parsing function definitions */
11234887Schin 	    case FUNCTSYM:
1124*8462SApril.Chin@Sun.COM 		return(funct(lexp));
11254887Schin 
11264887Schin #if SHOPT_NAMESPACE
11274887Schin 	    case NSPACESYM:
11284887Schin 		t = getnode(fornod);
11294887Schin 		t->for_.fortyp=TNSPACE;
11304887Schin 		t->for_.forlst=0;
1131*8462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
1132*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
1133*8462SApril.Chin@Sun.COM 		t->for_.fornam=(char*) lexp->arg->argval;
1134*8462SApril.Chin@Sun.COM 		while((tok=sh_lex(lexp))==NL);
11354887Schin 		if(tok!=LBRACE)
1136*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
1137*8462SApril.Chin@Sun.COM 		t->for_.fortre = sh_cmd(lexp,RBRACE,SH_NL);
11384887Schin 		break;
11394887Schin #endif /* SHOPT_NAMESPACE */
11404887Schin 
11414887Schin 	    /* while and until */
11424887Schin 	    case WHILESYM:
11434887Schin 	    case UNTILSYM:
11444887Schin 		t = getnode(whnod);
1145*8462SApril.Chin@Sun.COM 		t->wh.whtyp=(lexp->token==WHILESYM ? TWH : TUN);
11464887Schin 		loop_level++;
1147*8462SApril.Chin@Sun.COM 		t->wh.whtre = sh_cmd(lexp,DOSYM,SH_NL);
1148*8462SApril.Chin@Sun.COM 		t->wh.dotre = sh_cmd(lexp,DONESYM,SH_NL|SH_SEMI);
11494887Schin 		if(--loop_level==0)
11504887Schin 			label_last = label_list;
11514887Schin 		t->wh.whinc = 0;
11524887Schin 		break;
11534887Schin 
11544887Schin 	    case LABLSYM:
11554887Schin 	    {
11564887Schin 		register struct argnod *argp = label_list;
11574887Schin 		while(argp)
11584887Schin 		{
1159*8462SApril.Chin@Sun.COM 			if(strcmp(argp->argval,lexp->arg->argval)==0)
1160*8462SApril.Chin@Sun.COM 				errormsg(SH_DICT,ERROR_exit(3),e_lexsyntax3,lexp->sh->inlineno,argp->argval);
11614887Schin 			argp = argp->argnxt.ap;
11624887Schin 		}
1163*8462SApril.Chin@Sun.COM 		lexp->arg->argnxt.ap = label_list;
1164*8462SApril.Chin@Sun.COM 		label_list = lexp->arg;
1165*8462SApril.Chin@Sun.COM 		label_list->argchn.len = sh_getlineno(lexp);
11664887Schin 		label_list->argflag = loop_level;
1167*8462SApril.Chin@Sun.COM 		skipnl(lexp,flag);
1168*8462SApril.Chin@Sun.COM 		if(!(t = item(lexp,SH_NL)))
1169*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
11704887Schin 		tok = (t->tre.tretyp&(COMSCAN|COMSCAN-1));
11714887Schin 		if(sh_isoption(SH_NOEXEC) && tok!=TWH && tok!=TUN && tok!=TFOR && tok!=TSELECT)
11724887Schin 			errormsg(SH_DICT,ERROR_warn(0),e_lexlabignore,label_list->argchn.len,label_list->argval);
11734887Schin 		return(t);
11744887Schin 	    }
11754887Schin 
11764887Schin 	    /* command group with {...} */
11774887Schin 	    case LBRACE:
1178*8462SApril.Chin@Sun.COM 		comsub = lexp->comsub;
1179*8462SApril.Chin@Sun.COM 		lexp->comsub = 0;
1180*8462SApril.Chin@Sun.COM 		t = sh_cmd(lexp,RBRACE,SH_NL);
1181*8462SApril.Chin@Sun.COM 		lexp->comsub = comsub;
11824887Schin 		break;
11834887Schin 
11844887Schin 	    case LPAREN:
11854887Schin 		t = getnode(parnod);
1186*8462SApril.Chin@Sun.COM 		t->par.partre=sh_cmd(lexp,RPAREN,SH_NL);
11874887Schin 		t->par.partyp=TPAR;
11884887Schin 		break;
11894887Schin 
11904887Schin 	    default:
11914887Schin 		if(io==0)
11924887Schin 			return(0);
11934887Schin 
11944887Schin 	    case ';':
11954887Schin 		if(io==0)
11964887Schin 		{
11974887Schin 			if(!(flag&SH_SEMI))
11984887Schin 				return(0);
1199*8462SApril.Chin@Sun.COM 			if(sh_lex(lexp)==';')
1200*8462SApril.Chin@Sun.COM 				sh_syntax(lexp);
12014887Schin 			showme =  FSHOWME;
12024887Schin 		}
12034887Schin 	    /* simple command */
12044887Schin 	    case 0:
1205*8462SApril.Chin@Sun.COM 		t = (Shnode_t*)simple(lexp,flag,io);
1206*8462SApril.Chin@Sun.COM 		if(t->com.comarg && lexp->intypeset && (lexp->sh->shcomp || sh_isoption(SH_NOEXEC) || sh.dot_depth))
1207*8462SApril.Chin@Sun.COM 			check_typedef(&t->com);
1208*8462SApril.Chin@Sun.COM 		lexp->intypeset = 0;
1209*8462SApril.Chin@Sun.COM 		lexp->inexec = 0;
12104887Schin 		t->tre.tretyp |= showme;
12114887Schin 		return(t);
12124887Schin 	}
1213*8462SApril.Chin@Sun.COM 	sh_lex(lexp);
1214*8462SApril.Chin@Sun.COM 	if(io=inout(lexp,io,0))
12154887Schin 	{
12164887Schin 		if((tok=t->tre.tretyp&COMMSK) != TFORK)
12174887Schin 			tok = TSETIO;
1218*8462SApril.Chin@Sun.COM 		t=makeparent(lexp,tok,t);
12194887Schin 		t->tre.treio=io;
12204887Schin 	}
12214887Schin done:
1222*8462SApril.Chin@Sun.COM 	lexp->lasttok = savwdval;
1223*8462SApril.Chin@Sun.COM 	lexp->lastline = savline;
12244887Schin 	return(t);
12254887Schin }
12264887Schin 
12274887Schin /*
12284887Schin  * This is for a simple command, for list, or compound assignment
12294887Schin  */
1230*8462SApril.Chin@Sun.COM static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
12314887Schin {
12324887Schin 	register struct comnod *t;
12334887Schin 	register struct argnod	*argp;
12344887Schin 	register int tok;
1235*8462SApril.Chin@Sun.COM 	Stk_t		*stkp = lexp->sh->stk;
12364887Schin 	struct argnod	**argtail;
12374887Schin 	struct argnod	**settail;
1238*8462SApril.Chin@Sun.COM 	int	cmdarg=0;
1239*8462SApril.Chin@Sun.COM 	int	argno = 0, argmax=0;
12404887Schin 	int	assignment = 0;
12414887Schin 	int	key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
12424887Schin 	int	associative=0;
1243*8462SApril.Chin@Sun.COM 	if((argp=lexp->arg) && (argp->argflag&ARG_ASSIGN) && argp->argval[0]=='[')
12444887Schin 	{
12454887Schin 		flag |= SH_ARRAY;
12464887Schin 		associative = 1;
12474887Schin 	}
12484887Schin 	t = (struct comnod*)getnode(comnod);
12494887Schin 	t->comio=io; /*initial io chain*/
12504887Schin 	/* set command line number for error messages */
1251*8462SApril.Chin@Sun.COM 	t->comline = sh_getlineno(lexp);
12524887Schin 	argtail = &(t->comarg);
12534887Schin 	t->comset = 0;
12544887Schin 	t->comnamp = 0;
12554887Schin 	t->comnamq = 0;
12564887Schin 	t->comstate = 0;
12574887Schin 	settail = &(t->comset);
1258*8462SApril.Chin@Sun.COM 	while(lexp->token==0)
12594887Schin 	{
1260*8462SApril.Chin@Sun.COM 		argp = lexp->arg;
12614887Schin 		if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
12624887Schin 		{
1263*8462SApril.Chin@Sun.COM 			lexp->token = LBRACE;
12644887Schin 			break;
12654887Schin 		}
12664887Schin 		if(associative && argp->argval[0]!='[')
1267*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
12684887Schin 		/* check for assignment argument */
12694887Schin 		if((argp->argflag&ARG_ASSIGN) && assignment!=2)
12704887Schin 		{
12714887Schin 			*settail = argp;
12724887Schin 			settail = &(argp->argnxt.ap);
1273*8462SApril.Chin@Sun.COM 			lexp->assignok = (flag&SH_ASSIGN)?SH_ASSIGN:1;
12744887Schin 			if(assignment)
12754887Schin 			{
12764887Schin 				struct argnod *ap=argp;
12774887Schin 				char *last, *cp;
12784887Schin 				if(assignment==1)
12794887Schin 				{
12804887Schin 					last = strchr(argp->argval,'=');
12814887Schin 					if((cp=strchr(argp->argval,'[')) && (cp < last))
12824887Schin 						last = cp;
1283*8462SApril.Chin@Sun.COM 					stkseek(stkp,ARGVAL);
1284*8462SApril.Chin@Sun.COM 					sfwrite(stkp,argp->argval,last-argp->argval);
1285*8462SApril.Chin@Sun.COM 					ap=(struct argnod*)stkfreeze(stkp,1);
12864887Schin 					ap->argflag = ARG_RAW;
12874887Schin 					ap->argchn.ap = 0;
12884887Schin 				}
12894887Schin 				*argtail = ap;
12904887Schin 				argtail = &(ap->argnxt.ap);
12914887Schin 				if(argno>=0)
12924887Schin 					argno++;
12934887Schin 			}
12944887Schin 			else /* alias substitutions allowed */
1295*8462SApril.Chin@Sun.COM 				lexp->aliasok = 1;
12964887Schin 		}
12974887Schin 		else
12984887Schin 		{
12994887Schin 			if(!(argp->argflag&ARG_RAW))
1300*8462SApril.Chin@Sun.COM 			{
1301*8462SApril.Chin@Sun.COM 				if(argno>0)
1302*8462SApril.Chin@Sun.COM 					argmax = argno;
13034887Schin 				argno = -1;
1304*8462SApril.Chin@Sun.COM 			}
1305*8462SApril.Chin@Sun.COM 			if(argno>=0 && argno++==cmdarg && !(flag&SH_ARRAY) && *argp->argval!='/')
13064887Schin 			{
13074887Schin 				/* check for builtin command */
1308*8462SApril.Chin@Sun.COM 				Namval_t *np=nv_bfsearch(argp->argval,lexp->sh->fun_tree, (Namval_t**)&t->comnamq,(char**)0);
1309*8462SApril.Chin@Sun.COM 				if(cmdarg==0)
1310*8462SApril.Chin@Sun.COM 					t->comnamp = (void*)np;
1311*8462SApril.Chin@Sun.COM 				if(np && is_abuiltin(np))
13124887Schin 				{
1313*8462SApril.Chin@Sun.COM 					if(nv_isattr(np,BLT_DCL))
1314*8462SApril.Chin@Sun.COM 					{
1315*8462SApril.Chin@Sun.COM 						assignment = 1+(*argp->argval=='a');
1316*8462SApril.Chin@Sun.COM 						if(np==SYSTYPESET)
1317*8462SApril.Chin@Sun.COM 							lexp->intypeset = 1;
1318*8462SApril.Chin@Sun.COM 						key_on = 1;
1319*8462SApril.Chin@Sun.COM 					}
1320*8462SApril.Chin@Sun.COM 					else if(np==SYSCOMMAND)
1321*8462SApril.Chin@Sun.COM 						cmdarg++;
1322*8462SApril.Chin@Sun.COM 					else if(np==SYSEXEC)
1323*8462SApril.Chin@Sun.COM 						lexp->inexec = 1;
1324*8462SApril.Chin@Sun.COM 					else if(np->nvalue.bfp==b_getopts)
1325*8462SApril.Chin@Sun.COM 						opt_get |= FOPTGET;
13264887Schin 				}
13274887Schin 			}
13284887Schin 			*argtail = argp;
13294887Schin 			argtail = &(argp->argnxt.ap);
1330*8462SApril.Chin@Sun.COM 			if(!(lexp->assignok=key_on)  && !(flag&SH_NOIO) && sh_isoption(SH_NOEXEC))
1331*8462SApril.Chin@Sun.COM 				lexp->assignok = SH_COMPASSIGN;
1332*8462SApril.Chin@Sun.COM 			lexp->aliasok = 0;
13334887Schin 		}
13344887Schin 	retry:
1335*8462SApril.Chin@Sun.COM 		tok = sh_lex(lexp);
1336*8462SApril.Chin@Sun.COM 		if(tok==LABLSYM && (flag&SH_ASSIGN))
1337*8462SApril.Chin@Sun.COM 			lexp->token = tok = 0;
13384887Schin #if SHOPT_DEVFD
13394887Schin 		if((tok==IPROCSYM || tok==OPROCSYM))
13404887Schin 		{
13414887Schin 			Shnode_t *t;
13424887Schin 			int mode = (tok==OPROCSYM);
1343*8462SApril.Chin@Sun.COM 			t = sh_cmd(lexp,RPAREN,SH_NL);
1344*8462SApril.Chin@Sun.COM 			argp = (struct argnod*)stkalloc(stkp,sizeof(struct argnod));
13454887Schin 			*argp->argval = 0;
1346*8462SApril.Chin@Sun.COM 			argmax = 0;
13474887Schin 			argno = -1;
13484887Schin 			*argtail = argp;
13494887Schin 			argtail = &(argp->argnxt.ap);
1350*8462SApril.Chin@Sun.COM 			argp->argchn.ap = (struct argnod*)makeparent(lexp,mode?TFORK|FPIN|FAMP|FPCL:TFORK|FPOU,t);
13514887Schin 			argp->argflag =  (ARG_EXP|mode);
13524887Schin 			goto retry;
13534887Schin 		}
13544887Schin #endif	/* SHOPT_DEVFD */
13554887Schin 		if(tok==LPAREN)
13564887Schin 		{
13574887Schin 			if(argp->argflag&ARG_ASSIGN)
13584887Schin 			{
1359*8462SApril.Chin@Sun.COM 				int intypeset = lexp->intypeset;
1360*8462SApril.Chin@Sun.COM 				int tdef = 0;
1361*8462SApril.Chin@Sun.COM 				lexp->intypeset = 0;
1362*8462SApril.Chin@Sun.COM 				if(t->comnamp==SYSTYPESET && t->comarg->argnxt.ap && strcmp(t->comarg->argnxt.ap->argval,"-T")==0)
1363*8462SApril.Chin@Sun.COM 					tdef = 1;
1364*8462SApril.Chin@Sun.COM 				argp = assign(lexp,argp,tdef);
1365*8462SApril.Chin@Sun.COM 				lexp->intypeset = intypeset;
13664887Schin 				if(associative)
1367*8462SApril.Chin@Sun.COM 					lexp->assignok |= SH_ASSIGN;
13684887Schin 				goto retry;
13694887Schin 			}
13704887Schin 			else if(argno==1 && !t->comset)
13714887Schin 			{
13724887Schin 				/* SVR2 style function */
1373*8462SApril.Chin@Sun.COM 				if(sh_lex(lexp) == RPAREN)
13744887Schin 				{
1375*8462SApril.Chin@Sun.COM 					lexp->arg = argp;
1376*8462SApril.Chin@Sun.COM 					return(funct(lexp));
13774887Schin 				}
1378*8462SApril.Chin@Sun.COM 				lexp->token = LPAREN;
13794887Schin 			}
13804887Schin 		}
13814887Schin 		else if(flag&SH_ASSIGN)
13824887Schin 		{
13834887Schin 			if(tok==RPAREN)
13844887Schin 				break;
13854887Schin 			else if(tok==NL && (flag&SH_ARRAY))
1386*8462SApril.Chin@Sun.COM 			{
1387*8462SApril.Chin@Sun.COM 				lexp->comp_assign = 2;
13884887Schin 				goto retry;
1389*8462SApril.Chin@Sun.COM 			}
1390*8462SApril.Chin@Sun.COM 
13914887Schin 		}
13924887Schin 		if(!(flag&SH_NOIO))
13934887Schin 		{
13944887Schin 			if(io)
13954887Schin 			{
13964887Schin 				while(io->ionxt)
13974887Schin 					io = io->ionxt;
1398*8462SApril.Chin@Sun.COM 				io->ionxt = inout(lexp,(struct ionod*)0,0);
13994887Schin 			}
14004887Schin 			else
1401*8462SApril.Chin@Sun.COM 				t->comio = io = inout(lexp,(struct ionod*)0,0);
14024887Schin 		}
14034887Schin 	}
14044887Schin 	*argtail = 0;
1405*8462SApril.Chin@Sun.COM 	if(argno>0)
1406*8462SApril.Chin@Sun.COM 		argmax = argno;
1407*8462SApril.Chin@Sun.COM 	t->comtyp = TCOM | (argmax<<(COMBITS+2));
14084887Schin #if SHOPT_KIA
1409*8462SApril.Chin@Sun.COM 	if(lexp->kiafile && !(flag&SH_NOIO))
14104887Schin 	{
14114887Schin 		register Namval_t *np=(Namval_t*)t->comnamp;
14124887Schin 		unsigned long r=0;
14134887Schin 		int line = t->comline;
14144887Schin 		argp = t->comarg;
14154887Schin 		if(np)
1416*8462SApril.Chin@Sun.COM 			r = kiaentity(lexp,nv_name(np),-1,'p',-1,0,lexp->unknown,'b',0,"");
14174887Schin 		else if(argp)
1418*8462SApril.Chin@Sun.COM 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',-1,0,lexp->unknown,'c',0,"");
14194887Schin 		if(r>0)
1420*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;c;\n",lexp->current,r,line,line);
14214887Schin 		if(t->comset && argno==0)
1422*8462SApril.Chin@Sun.COM 			writedefs(lexp,t->comset,line,'v',t->comarg);
14234887Schin 		else if(np && nv_isattr(np,BLT_DCL))
1424*8462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
14254887Schin 		else if(argp && strcmp(argp->argval,"read")==0)
1426*8462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,0,NIL(struct argnod*));
14274887Schin #if 0
14284887Schin 		else if(argp && strcmp(argp->argval,"unset")==0)
1429*8462SApril.Chin@Sun.COM 			writedefs(lexp,argp,line,'u',NIL(struct argnod*));
14304887Schin #endif
14314887Schin 		else if(argp && *argp->argval=='.' && argp->argval[1]==0 && (argp=argp->argnxt.ap))
14324887Schin 		{
1433*8462SApril.Chin@Sun.COM 			r = kiaentity(lexp,sh_argstr(argp),-1,'p',0,0,lexp->script,'d',0,"");
1434*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;p;%..64d;%d;%d;d;\n",lexp->current,r,line,line);
14354887Schin 		}
14364887Schin 	}
14374887Schin #endif /* SHOPT_KIA */
14384887Schin 	if(t->comnamp && (argp=t->comarg->argnxt.ap))
14394887Schin 	{
14404887Schin 		Namval_t *np=(Namval_t*)t->comnamp;
14414887Schin 		if((np==SYSBREAK || np==SYSCONT) && (argp->argflag&ARG_RAW) && !isdigit(*argp->argval))
14424887Schin 		{
14434887Schin 			register char *cp = argp->argval;
14444887Schin 			/* convert break/continue labels to numbers */
14454887Schin 			tok = 0;
14464887Schin 			for(argp=label_list;argp!=label_last;argp=argp->argnxt.ap)
14474887Schin 			{
14484887Schin 				if(strcmp(cp,argp->argval))
14494887Schin 					continue;
14504887Schin 				tok = loop_level-argp->argflag;
14514887Schin 				if(tok>=1)
14524887Schin 				{
14534887Schin 					argp = t->comarg->argnxt.ap;
14544887Schin 					if(tok>9)
14554887Schin 					{
14564887Schin 						argp->argval[1] = '0'+tok%10;
14574887Schin 						argp->argval[2] = 0;
14584887Schin 						tok /= 10;
14594887Schin 					}
14604887Schin 					else
14614887Schin 						argp->argval[1] = 0;
14624887Schin 					*argp->argval = '0'+tok;
14634887Schin 				}
14644887Schin 				break;
14654887Schin 			}
14664887Schin 			if(sh_isoption(SH_NOEXEC) && tok==0)
1467*8462SApril.Chin@Sun.COM 				errormsg(SH_DICT,ERROR_warn(0),e_lexlabunknown,lexp->sh->inlineno-(lexp->token=='\n'),cp);
14684887Schin 		}
14694887Schin 		else if(sh_isoption(SH_NOEXEC) && np==SYSSET && ((tok= *argp->argval)=='-'||tok=='+') &&
14704887Schin 			(argp->argval[1]==0||strchr(argp->argval,'k')))
1471*8462SApril.Chin@Sun.COM 			errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete5,lexp->sh->inlineno-(lexp->token=='\n'),argp->argval);
14724887Schin 	}
14734887Schin 	/* expand argument list if possible */
14744887Schin 	if(argno>0)
14754887Schin 		t->comarg = qscan(t,argno);
14764887Schin 	else if(t->comarg)
14774887Schin 		t->comtyp |= COMSCAN;
1478*8462SApril.Chin@Sun.COM 	lexp->aliasok = 0;
14794887Schin 	return((Shnode_t*)t);
14804887Schin }
14814887Schin 
14824887Schin /*
14834887Schin  * skip past newlines but issue prompt if interactive
14844887Schin  */
1485*8462SApril.Chin@Sun.COM static int	skipnl(Lex_t *lexp,int flag)
14864887Schin {
14874887Schin 	register int token;
1488*8462SApril.Chin@Sun.COM 	while((token=sh_lex(lexp))==NL);
14894887Schin 	if(token==';' && !(flag&SH_SEMI))
1490*8462SApril.Chin@Sun.COM 		sh_syntax(lexp);
14914887Schin 	return(token);
14924887Schin }
14934887Schin 
14944887Schin /*
14954887Schin  * check for and process and i/o redirections
14964887Schin  * if flag>0 then an alias can be in the next word
14974887Schin  * if flag<0 only one redirection will be processed
14984887Schin  */
1499*8462SApril.Chin@Sun.COM static struct ionod	*inout(Lex_t *lexp,struct ionod *lastio,int flag)
15004887Schin {
1501*8462SApril.Chin@Sun.COM 	register int 		iof = lexp->digits, token=lexp->token;
15024887Schin 	register struct ionod	*iop;
1503*8462SApril.Chin@Sun.COM 	Stk_t			*stkp = lexp->sh->stk;
15044887Schin 	char *iovname=0;
15054887Schin #if SHOPT_BASH
15064887Schin 	register int		errout=0;
15074887Schin #endif
15084887Schin 	if(token==IOVNAME)
15094887Schin 	{
1510*8462SApril.Chin@Sun.COM 		iovname=lexp->arg->argval+1;
1511*8462SApril.Chin@Sun.COM 		token= sh_lex(lexp);
15124887Schin 		iof = 0;
15134887Schin 	}
15144887Schin 	switch(token&0xff)
15154887Schin 	{
15164887Schin 	    case '<':
15174887Schin 		if(token==IODOCSYM)
15184887Schin 			iof |= (IODOC|IORAW);
15194887Schin 		else if(token==IOMOV0SYM)
15204887Schin 			iof |= IOMOV;
15214887Schin 		else if(token==IORDWRSYM)
15224887Schin 			iof |= IORDW;
15234887Schin 		else if((token&SYMSHARP) == SYMSHARP)
15244887Schin 		{
15254887Schin 			int n;
15264887Schin 			iof |= IOLSEEK;
15274887Schin 			if(fcgetc(n)=='#')
15284887Schin 				iof |= IOCOPY;
15294887Schin 			else if(n>0)
15304887Schin 				fcseek(-1);
15314887Schin 		}
15324887Schin 		break;
15334887Schin 
15344887Schin 	    case '>':
15354887Schin #if SHOPT_BASH
15364887Schin 		if(iof<0)
15374887Schin 		{
15384887Schin 			errout = 1;
15394887Schin 			iof = 1;
15404887Schin 		}
15414887Schin #endif
15424887Schin 		iof |= IOPUT;
15434887Schin 		if(token==IOAPPSYM)
15444887Schin 			iof |= IOAPP;
15454887Schin 		else if(token==IOMOV1SYM)
15464887Schin 			iof |= IOMOV;
15474887Schin 		else if(token==IOCLOBSYM)
15484887Schin 			iof |= IOCLOB;
15494887Schin 		else if((token&SYMSHARP) == SYMSHARP)
15504887Schin 			iof |= IOLSEEK;
1551*8462SApril.Chin@Sun.COM 		else if((token&SYMSEMI) == SYMSEMI)
1552*8462SApril.Chin@Sun.COM 			iof |= IOREWRITE;
15534887Schin 		break;
15544887Schin 
15554887Schin 	    default:
15564887Schin 		return(lastio);
15574887Schin 	}
1558*8462SApril.Chin@Sun.COM 	lexp->digits=0;
1559*8462SApril.Chin@Sun.COM 	iop=(struct ionod*) stkalloc(stkp,sizeof(struct ionod));
15604887Schin 	iop->iodelim = 0;
1561*8462SApril.Chin@Sun.COM 	if(token=sh_lex(lexp))
15624887Schin 	{
1563*8462SApril.Chin@Sun.COM 		if(token==RPAREN && (iof&IOLSEEK) && lexp->comsub)
15644887Schin 		{
1565*8462SApril.Chin@Sun.COM 			lexp->arg = (struct argnod*)stkalloc(stkp,sizeof(struct argnod)+3);
1566*8462SApril.Chin@Sun.COM 			strcpy(lexp->arg->argval,"CUR");
1567*8462SApril.Chin@Sun.COM 			lexp->arg->argflag = ARG_RAW;
15684887Schin 			iof |= IOARITH;
15694887Schin 			fcseek(-1);
15704887Schin 		}
15714887Schin 		else if(token==EXPRSYM && (iof&IOLSEEK))
15724887Schin 			iof |= IOARITH;
15734887Schin 		else
1574*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
15754887Schin 	}
1576*8462SApril.Chin@Sun.COM 	iop->ioname=lexp->arg->argval;
15774887Schin 	iop->iovname = iovname;
15784887Schin 	if(iof&IODOC)
15794887Schin 	{
1580*8462SApril.Chin@Sun.COM 		if(lexp->digits==2)
15814887Schin 		{
15824887Schin 			iof |= IOSTRG;
1583*8462SApril.Chin@Sun.COM 			if(!(lexp->arg->argflag&ARG_RAW))
15844887Schin 				iof &= ~IORAW;
15854887Schin 		}
15864887Schin 		else
15874887Schin 		{
1588*8462SApril.Chin@Sun.COM 			if(!lexp->sh->heredocs)
1589*8462SApril.Chin@Sun.COM 				lexp->sh->heredocs = sftmp(HERE_MEM);
1590*8462SApril.Chin@Sun.COM 			iop->iolst=lexp->heredoc;
1591*8462SApril.Chin@Sun.COM 			lexp->heredoc=iop;
1592*8462SApril.Chin@Sun.COM 			if(lexp->arg->argflag&ARG_QUOTED)
15934887Schin 				iof |= IOQUOTE;
1594*8462SApril.Chin@Sun.COM 			if(lexp->digits==3)
15954887Schin 				iof |= IOLSEEK;
1596*8462SApril.Chin@Sun.COM 			if(lexp->digits)
15974887Schin 				iof |= IOSTRIP;
15984887Schin 		}
15994887Schin 	}
16004887Schin 	else
16014887Schin 	{
16024887Schin 		iop->iolst = 0;
1603*8462SApril.Chin@Sun.COM 		if(lexp->arg->argflag&ARG_RAW)
16044887Schin 			iof |= IORAW;
16054887Schin 	}
16064887Schin 	iop->iofile=iof;
16074887Schin 	if(flag>0)
16084887Schin 		/* allow alias substitutions and parameter assignments */
1609*8462SApril.Chin@Sun.COM 		lexp->aliasok = lexp->assignok = 1;
16104887Schin #if SHOPT_KIA
1611*8462SApril.Chin@Sun.COM 	if(lexp->kiafile)
16124887Schin 	{
1613*8462SApril.Chin@Sun.COM 		int n = lexp->sh->inlineno-(lexp->token=='\n');
16144887Schin 		if(!(iof&IOMOV))
16154887Schin 		{
1616*8462SApril.Chin@Sun.COM 			unsigned long r=kiaentity(lexp,(iof&IORAW)?sh_fmtq(iop->ioname):iop->ioname,-1,'f',0,0,lexp->script,'f',0,"");
1617*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;%c;%d\n",lexp->current,r,n,n,(iof&IOPUT)?((iof&IOAPP)?'a':'w'):((iof&IODOC)?'h':'r'),iof&IOUFD);
16184887Schin 		}
16194887Schin 	}
16204887Schin #endif /* SHOPT_KIA */
16214887Schin 	if(flag>=0)
16224887Schin 	{
16234887Schin 		struct ionod *ioq=iop;
1624*8462SApril.Chin@Sun.COM 		sh_lex(lexp);
16254887Schin #if SHOPT_BASH
16264887Schin 		if(errout)
16274887Schin 		{
16284887Schin 			/* redirect standard output to standard error */
1629*8462SApril.Chin@Sun.COM 			ioq = (struct ionod*)stkalloc(stkp,sizeof(struct ionod));
16304887Schin 			ioq->ioname = "1";
16314887Schin 			ioq->iolst = 0;
16324887Schin 			ioq->iodelim = 0;
16334887Schin 			ioq->iofile = IORAW|IOPUT|IOMOV|2;
16344887Schin 			iop->ionxt=ioq;
16354887Schin 		}
16364887Schin #endif
1637*8462SApril.Chin@Sun.COM 		ioq->ionxt=inout(lexp,lastio,flag);
16384887Schin 	}
16394887Schin 	else
16404887Schin 		iop->ionxt=0;
16414887Schin 	return(iop);
16424887Schin }
16434887Schin 
16444887Schin /*
16454887Schin  * convert argument chain to argument list when no special arguments
16464887Schin  */
16474887Schin 
16484887Schin static struct argnod *qscan(struct comnod *ac,int argn)
16494887Schin {
16504887Schin 	register char **cp;
16514887Schin 	register struct argnod *ap;
16524887Schin 	register struct dolnod* dp;
16534887Schin 	register int special=0;
16544887Schin 	/* special hack for test -t compatibility */
16554887Schin 	if((Namval_t*)ac->comnamp==SYSTEST)
16564887Schin 		special = 2;
16574887Schin 	else if(*(ac->comarg->argval)=='[' && ac->comarg->argval[1]==0)
16584887Schin 		special = 3;
16594887Schin 	if(special)
16604887Schin 	{
16614887Schin 		ap = ac->comarg->argnxt.ap;
16624887Schin 		if(argn==(special+1) && ap->argval[1]==0 && *ap->argval=='!')
16634887Schin 			ap = ap->argnxt.ap;
16644887Schin 		else if(argn!=special)
16654887Schin 			special=0;
16664887Schin 	}
16674887Schin 	if(special)
16684887Schin 	{
16694887Schin 		const char *message;
16704887Schin 		if(strcmp(ap->argval,"-t"))
16714887Schin 		{
16724887Schin 			message = "line %d: Invariant test";
16734887Schin 			special=0;
16744887Schin 		}
16754887Schin 		else
16764887Schin 		{
16774887Schin 			message = "line %d: -t requires argument";
16784887Schin 			argn++;
16794887Schin 		}
16804887Schin 		if(sh_isoption(SH_NOEXEC))
16814887Schin 			errormsg(SH_DICT,ERROR_warn(0),message,ac->comline);
16824887Schin 	}
16834887Schin 	/* leave space for an extra argument at the front */
16844887Schin 	dp = (struct dolnod*)stakalloc((unsigned)sizeof(struct dolnod) + ARG_SPARE*sizeof(char*) + argn*sizeof(char*));
16854887Schin 	cp = dp->dolval+ARG_SPARE;
16864887Schin 	dp->dolnum = argn;
16874887Schin 	dp->dolbot = ARG_SPARE;
16884887Schin 	ap = ac->comarg;
16894887Schin 	while(ap)
16904887Schin 	{
16914887Schin 		*cp++ = ap->argval;
16924887Schin 		ap = ap->argnxt.ap;
16934887Schin 	}
16944887Schin 	if(special==3)
16954887Schin 	{
16964887Schin 		cp[0] = cp[-1];
16974887Schin 		cp[-1] = "1";
16984887Schin 		cp++;
16994887Schin 	}
17004887Schin 	else if(special)
17014887Schin 		*cp++ = "1";
17024887Schin 	*cp = 0;
17034887Schin 	return((struct argnod*)dp);
17044887Schin }
17054887Schin 
1706*8462SApril.Chin@Sun.COM static Shnode_t *test_expr(Lex_t *lp,int sym)
17074887Schin {
1708*8462SApril.Chin@Sun.COM 	register Shnode_t *t = test_or(lp);
1709*8462SApril.Chin@Sun.COM 	if(lp->token!=sym)
1710*8462SApril.Chin@Sun.COM 		sh_syntax(lp);
17114887Schin 	return(t);
17124887Schin }
17134887Schin 
1714*8462SApril.Chin@Sun.COM static Shnode_t *test_or(Lex_t *lp)
17154887Schin {
1716*8462SApril.Chin@Sun.COM 	register Shnode_t *t = test_and(lp);
1717*8462SApril.Chin@Sun.COM 	while(lp->token==ORFSYM)
1718*8462SApril.Chin@Sun.COM 		t = makelist(lp,TORF|TTEST,t,test_and(lp));
17194887Schin 	return(t);
17204887Schin }
17214887Schin 
1722*8462SApril.Chin@Sun.COM static Shnode_t *test_and(Lex_t *lp)
17234887Schin {
1724*8462SApril.Chin@Sun.COM 	register Shnode_t *t = test_primary(lp);
1725*8462SApril.Chin@Sun.COM 	while(lp->token==ANDFSYM)
1726*8462SApril.Chin@Sun.COM 		t = makelist(lp,TAND|TTEST,t,test_primary(lp));
17274887Schin 	return(t);
17284887Schin }
17294887Schin 
17304887Schin /*
17314887Schin  * convert =~ into == ~(E)
17324887Schin  */
17334887Schin static void ere_match(void)
17344887Schin {
17354887Schin 	Sfio_t *base, *iop = sfopen((Sfio_t*)0," ~(E)","s");
17364887Schin 	register int c;
17374887Schin 	while( fcgetc(c),(c==' ' || c=='\t'));
17384887Schin 	if(c)
17394887Schin 		fcseek(-1);
17404887Schin 	if(!(base=fcfile()))
17414887Schin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
17424887Schin 	fcclose();
17434887Schin         sfstack(base,iop);
17444887Schin         fcfopen(base);
17454887Schin }
17464887Schin 
1747*8462SApril.Chin@Sun.COM static Shnode_t *test_primary(Lex_t *lexp)
17484887Schin {
17494887Schin 	register struct argnod *arg;
17504887Schin 	register Shnode_t *t;
17514887Schin 	register int num,token;
1752*8462SApril.Chin@Sun.COM 	token = skipnl(lexp,0);
1753*8462SApril.Chin@Sun.COM 	num = lexp->digits;
17544887Schin 	switch(token)
17554887Schin 	{
17564887Schin 	    case '(':
1757*8462SApril.Chin@Sun.COM 		t = test_expr(lexp,')');
1758*8462SApril.Chin@Sun.COM 		t = makelist(lexp,TTST|TTEST|TPAREN ,t, (Shnode_t*)pointerof(lexp->sh->inlineno));
17594887Schin 		break;
17604887Schin 	    case '!':
1761*8462SApril.Chin@Sun.COM 		if(!(t = test_primary(lexp)))
1762*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
17634887Schin 		t->tre.tretyp |= TNEGATE;
17644887Schin 		return(t);
17654887Schin 	    case TESTUNOP:
1766*8462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
1767*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
17684887Schin #if SHOPT_KIA
1769*8462SApril.Chin@Sun.COM 		if(lexp->kiafile && !strchr("sntzoOG",num))
17704887Schin 		{
1771*8462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno- (lexp->token==NL);
17724887Schin 			unsigned long r;
1773*8462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->script,'t',0,"");
1774*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
17754887Schin 		}
17764887Schin #endif /* SHOPT_KIA */
1777*8462SApril.Chin@Sun.COM 		t = makelist(lexp,TTST|TTEST|TUNARY|(num<<TSHIFT),
1778*8462SApril.Chin@Sun.COM 			(Shnode_t*)lexp->arg,(Shnode_t*)lexp->arg);
1779*8462SApril.Chin@Sun.COM 		t->tst.tstline =  lexp->sh->inlineno;
17804887Schin 		break;
17814887Schin 	    /* binary test operators */
17824887Schin 	    case 0:
1783*8462SApril.Chin@Sun.COM 		arg = lexp->arg;
1784*8462SApril.Chin@Sun.COM 		if((token=sh_lex(lexp))==TESTBINOP)
17854887Schin 		{
1786*8462SApril.Chin@Sun.COM 			num = lexp->digits;
17874887Schin 			if(num==TEST_REP)
17884887Schin 			{
17894887Schin 				ere_match();
17904887Schin 				num = TEST_PEQ;
17914887Schin 			}
17924887Schin 		}
17934887Schin 		else if(token=='<')
17944887Schin 			num = TEST_SLT;
17954887Schin 		else if(token=='>')
17964887Schin 			num = TEST_SGT;
17974887Schin 		else if(token==ANDFSYM||token==ORFSYM||token==ETESTSYM||token==RPAREN)
17984887Schin 		{
1799*8462SApril.Chin@Sun.COM 			t = makelist(lexp,TTST|TTEST|TUNARY|('n'<<TSHIFT),
18004887Schin 				(Shnode_t*)arg,(Shnode_t*)arg);
1801*8462SApril.Chin@Sun.COM 			t->tst.tstline =  lexp->sh->inlineno;
18024887Schin 			return(t);
18034887Schin 		}
18044887Schin 		else
1805*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18064887Schin #if SHOPT_KIA
1807*8462SApril.Chin@Sun.COM 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
18084887Schin 		{
1809*8462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno- (lexp->token==NL);
18104887Schin 			unsigned long r;
1811*8462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
1812*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
18134887Schin 		}
18144887Schin #endif /* SHOPT_KIA */
1815*8462SApril.Chin@Sun.COM 		if(sh_lex(lexp))
1816*8462SApril.Chin@Sun.COM 			sh_syntax(lexp);
18174887Schin 		if(num&TEST_PATTERN)
18184887Schin 		{
1819*8462SApril.Chin@Sun.COM 			if(lexp->arg->argflag&(ARG_EXP|ARG_MAC))
18204887Schin 				num &= ~TEST_PATTERN;
18214887Schin 		}
18224887Schin 		t = getnode(tstnod);
18234887Schin 		t->lst.lsttyp = TTST|TTEST|TBINARY|(num<<TSHIFT);
18244887Schin 		t->lst.lstlef = (Shnode_t*)arg;
1825*8462SApril.Chin@Sun.COM 		t->lst.lstrit = (Shnode_t*)lexp->arg;
1826*8462SApril.Chin@Sun.COM 		t->tst.tstline =  lexp->sh->inlineno;
18274887Schin #if SHOPT_KIA
1828*8462SApril.Chin@Sun.COM 		if(lexp->kiafile && (num==TEST_EF||num==TEST_NT||num==TEST_OT))
18294887Schin 		{
1830*8462SApril.Chin@Sun.COM 			int line = lexp->sh->inlineno-(lexp->token==NL);
18314887Schin 			unsigned long r;
1832*8462SApril.Chin@Sun.COM 			r=kiaentity(lexp,sh_argstr(lexp->arg),-1,'f',0,0,lexp->current,'t',0,"");
1833*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiatmp,"p;%..64d;f;%..64d;%d;%d;t;\n",lexp->current,r,line,line);
18344887Schin 		}
18354887Schin #endif /* SHOPT_KIA */
18364887Schin 		break;
18374887Schin 	    default:
18384887Schin 		return(0);
18394887Schin 	}
1840*8462SApril.Chin@Sun.COM 	skipnl(lexp,0);
18414887Schin 	return(t);
18424887Schin }
18434887Schin 
18444887Schin #if SHOPT_KIA
18454887Schin /*
18464887Schin  * return an entity checksum
18474887Schin  * The entity is created if it doesn't exist
18484887Schin  */
1849*8462SApril.Chin@Sun.COM unsigned long kiaentity(Lex_t *lexp,const char *name,int len,int type,int first,int last,unsigned long parent, int pkind, int width, const char *attr)
18504887Schin {
1851*8462SApril.Chin@Sun.COM 	Stk_t	*stkp = lexp->sh->stk;
18524887Schin 	Namval_t *np;
1853*8462SApril.Chin@Sun.COM 	long offset = stktell(stkp);
1854*8462SApril.Chin@Sun.COM 	sfputc(stkp,type);
18554887Schin 	if(len>0)
1856*8462SApril.Chin@Sun.COM 		sfwrite(stkp,name,len);
18574887Schin 	else
18584887Schin 	{
18594887Schin 		if(type=='p')
1860*8462SApril.Chin@Sun.COM 			sfputr(stkp,path_basename(name),0);
18614887Schin 		else
1862*8462SApril.Chin@Sun.COM 			sfputr(stkp,name,0);
18634887Schin 	}
1864*8462SApril.Chin@Sun.COM 	np = nv_search(stakptr(offset),lexp->entity_tree,NV_ADD);
1865*8462SApril.Chin@Sun.COM 	stkseek(stkp,offset);
18664887Schin 	np->nvalue.i = pkind;
18674887Schin 	nv_setsize(np,width);
18684887Schin 	if(!nv_isattr(np,NV_TAGGED) && first>=0)
18694887Schin 	{
18704887Schin 		nv_onattr(np,NV_TAGGED);
18714887Schin 		if(!pkind)
18724887Schin 			pkind = '0';
18734887Schin 		if(len>0)
1874*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiafile,"%..64d;%c;%.*s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,len,name,first,last,parent,lexp->fscript,pkind,width,attr);
18754887Schin 		else
1876*8462SApril.Chin@Sun.COM 			sfprintf(lexp->kiafile,"%..64d;%c;%s;%d;%d;%..64d;%..64d;%c;%d;%s\n",np->hash,type,name,first,last,parent,lexp->fscript,pkind,width,attr);
18774887Schin 	}
18784887Schin 	return(np->hash);
18794887Schin }
18804887Schin 
18814887Schin static void kia_add(register Namval_t *np, void *data)
18824887Schin {
18834887Schin 	char *name = nv_name(np);
1884*8462SApril.Chin@Sun.COM 	Lex_t	*lp = (Lex_t*)data;
18854887Schin 	NOT_USED(data);
1886*8462SApril.Chin@Sun.COM 	kiaentity(lp,name+1,-1,*name,0,-1,(*name=='p'?lp->unknown:lp->script),np->nvalue.i,nv_size(np),"");
18874887Schin }
18884887Schin 
1889*8462SApril.Chin@Sun.COM int kiaclose(Lex_t *lexp)
18904887Schin {
18914887Schin 	register off_t off1,off2;
18924887Schin 	register int n;
1893*8462SApril.Chin@Sun.COM 	if(lexp->kiafile)
18944887Schin 	{
1895*8462SApril.Chin@Sun.COM 		unsigned long r = kiaentity(lexp,lexp->scriptname,-1,'p',-1,lexp->sh->inlineno-1,0,'s',0,"");
1896*8462SApril.Chin@Sun.COM 		kiaentity(lexp,lexp->scriptname,-1,'p',1,lexp->sh->inlineno-1,r,'s',0,"");
1897*8462SApril.Chin@Sun.COM 		kiaentity(lexp,lexp->scriptname,-1,'f',1,lexp->sh->inlineno-1,r,'s',0,"");
1898*8462SApril.Chin@Sun.COM 		nv_scan(lexp->entity_tree,kia_add,(void*)lexp,NV_TAGGED,0);
1899*8462SApril.Chin@Sun.COM 		off1 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
1900*8462SApril.Chin@Sun.COM 		sfseek(lexp->kiatmp,(off_t)0,SEEK_SET);
1901*8462SApril.Chin@Sun.COM 		sfmove(lexp->kiatmp,lexp->kiafile,SF_UNBOUND,-1);
1902*8462SApril.Chin@Sun.COM 		off2 = sfseek(lexp->kiafile,(off_t)0,SEEK_END);
19034887Schin #ifdef SF_BUFCONST
19044887Schin 		if(off2==off1)
1905*8462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin));
19064887Schin 		else
1907*8462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%lld;%d\nRELATIONSHIP;%lld;%d\nDIRECTORY;",(Sflong_t)lexp->kiabegin,(size_t)(off1-lexp->kiabegin),(Sflong_t)off1,(size_t)(off2-off1));
19084887Schin 		if(off2 >= INT_MAX)
19094887Schin 			off2 = -(n+12);
1910*8462SApril.Chin@Sun.COM 		sfprintf(lexp->kiafile,"%010.10lld;%010d\n",(Sflong_t)off2+10, n+12);
19114887Schin #else
19124887Schin 		if(off2==off1)
1913*8462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin);
19144887Schin 		else
1915*8462SApril.Chin@Sun.COM 			n= sfprintf(lexp->kiafile,"DIRECTORY\nENTITY;%d;%d\nRELATIONSHIP;%d;%d\nDIRECTORY;",lexp->kiabegin,off1-lexp->kiabegin,off1,off2-off1);
1916*8462SApril.Chin@Sun.COM 		sfprintf(lexp->kiafile,"%010d;%010d\n",off2+10, n+12);
19174887Schin #endif
19184887Schin 	}
1919*8462SApril.Chin@Sun.COM 	return(sfclose(lexp->kiafile));
19204887Schin }
19214887Schin #endif /* SHOPT_KIA */
1922