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  * KornShell  lexical analyzer
234887Schin  *
244887Schin  * Written by David Korn
254887Schin  * AT&T Labs
264887Schin  *
274887Schin  */
284887Schin 
294887Schin #include	<ast.h>
304887Schin #include	<stak.h>
314887Schin #include	<fcin.h>
324887Schin #include	<nval.h>
334887Schin #include	"FEATURE/options"
344887Schin 
354887Schin #if KSHELL
364887Schin #   include	"defs.h"
374887Schin #else
384887Schin #   include	<shell.h>
394887Schin #   define	nv_getval(np)	((np)->nvalue)
404887Schin     Shell_t sh  =  {1};
414887Schin #endif /* KSHELL */
424887Schin 
434887Schin #include	"argnod.h"
444887Schin #include	"test.h"
454887Schin #include	"lexstates.h"
464887Schin #include	"io.h"
474887Schin 
484887Schin #define TEST_RE		3
494887Schin #define SYNBAD		3	/* exit value for syntax errors */
504887Schin #define STACK_ARRAY	3	/* size of depth match stack growth */
514887Schin 
524887Schin #if _lib_iswblank < 0	/* set in lexstates.h to enable this code */
534887Schin 
544887Schin int
554887Schin local_iswblank(wchar_t wc)
564887Schin {
574887Schin 	static int      initialized;
584887Schin 	static wctype_t wt;
594887Schin 
604887Schin 	if (!initialized)
614887Schin 	{
624887Schin 		initialized = 1;
634887Schin 		wt = wctype("blank");
644887Schin 	}
654887Schin 	return(iswctype(wc, wt));
664887Schin }
674887Schin 
684887Schin #endif
694887Schin 
704887Schin /*
714887Schin  * This structure allows for arbitrary depth nesting of (...), {...}, [...]
724887Schin  */
734887Schin struct lexstate
744887Schin {
754887Schin 	char		incase;		/* 1 for case pattern, 2 after case */
764887Schin 	char		intest;		/* 1 inside [[...]] */
774887Schin 	char		testop1;	/* 1 when unary test op legal */
784887Schin 	char		testop2;	/* 1 when binary test op legal */
794887Schin 	char		reservok;	/* >0 for reserved word legal */
804887Schin 	char		skipword;	/* next word can't be reserved */
814887Schin 	char		last_quote;	/* last multi-line quote character */
824887Schin };
834887Schin 
844887Schin struct lexdata
854887Schin {
864887Schin 	char		nocopy;
874887Schin 	char		paren;
884887Schin 	char		dolparen;
894887Schin 	char		nest;
904887Schin 	char		docword;
914887Schin 	char 		*docend;
924887Schin 	char		noarg;
934887Schin 	char		balance;
944887Schin 	char		warn;
954887Schin 	char		message;
964887Schin 	char		arith;
974887Schin 	char 		*first;
984887Schin 	int		level;
994887Schin 	int		lastc;
1004887Schin 	int		lex_max;
1014887Schin 	int		*lex_match;
1024887Schin 	int		lex_state;
1034887Schin #if SHOPT_KIA
1044887Schin 	off_t		kiaoff;
1054887Schin #endif
1064887Schin };
1074887Schin 
1084887Schin #define _SHLEX_PRIVATE \
109*8462SApril.Chin@Sun.COM 	struct lexdata  lexd; \
110*8462SApril.Chin@Sun.COM 	struct lexstate  lex;
1114887Schin 
1124887Schin #include	"shlex.h"
1134887Schin 
1144887Schin 
115*8462SApril.Chin@Sun.COM #define	pushlevel(lp,c,s)	((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\
116*8462SApril.Chin@Sun.COM 				((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\
117*8462SApril.Chin@Sun.COM 				lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
118*8462SApril.Chin@Sun.COM #define oldmode(lp)	(lp->lexd.lastc>>CHAR_BIT)
119*8462SApril.Chin@Sun.COM #define endchar(lp)	(lp->lexd.lastc&0xff)
120*8462SApril.Chin@Sun.COM #define setchar(lp,c)	(lp->lexd.lastc = ((lp->lexd.lastc&~0xff)|(c)))
121*8462SApril.Chin@Sun.COM #define poplevel(lp)	(lp->lexd.lastc=lp->lexd.lex_match[--lp->lexd.level])
1224887Schin 
1234887Schin static char		*fmttoken(Lex_t*, int, char*);
1244887Schin #ifdef SF_BUFCONST
1254887Schin     static int          alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
1264887Schin #else
1274887Schin     static int 		alias_exceptf(Sfio_t*, int, Sfdisc_t*);
1284887Schin #endif
1294887Schin static void		setupalias(Lex_t*,const char*, Namval_t*);
130*8462SApril.Chin@Sun.COM static int		comsub(Lex_t*,int);
1314887Schin static void		nested_here(Lex_t*);
1324887Schin static int		here_copy(Lex_t*, struct ionod*);
1334887Schin static int 		stack_grow(Lex_t*);
1344887Schin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL };
1354887Schin 
1364887Schin #if SHOPT_KIA
1374887Schin 
138*8462SApril.Chin@Sun.COM static void refvar(Lex_t *lp, int type)
1394887Schin {
140*8462SApril.Chin@Sun.COM 	register Shell_t *shp = lp->sh;
141*8462SApril.Chin@Sun.COM 	register Stk_t	*stkp = shp->stk;
142*8462SApril.Chin@Sun.COM 	off_t off = (fcseek(0)-(type+1))-(lp->lexd.first?lp->lexd.first:fcfirst());
1434887Schin 	unsigned long r;
144*8462SApril.Chin@Sun.COM 	if(lp->lexd.first)
1454887Schin 	{
146*8462SApril.Chin@Sun.COM 		off = (fcseek(0)-(type+1)) - lp->lexd.first;
147*8462SApril.Chin@Sun.COM 		r=kiaentity(lp,lp->lexd.first+lp->lexd.kiaoff+type,off-lp->lexd.kiaoff,'v',-1,-1,lp->current,'v',0,"");
1484887Schin 	}
1494887Schin 	else
1504887Schin 	{
151*8462SApril.Chin@Sun.COM 		int n,offset = stktell(stkp);
1524887Schin 		char *savptr,*begin;
1534887Schin 		off = offset + (fcseek(0)-(type+1)) - fcfirst();
154*8462SApril.Chin@Sun.COM 		if(lp->lexd.kiaoff < offset)
1554887Schin 		{
1564887Schin 			/* variable starts on stak, copy remainder */
1574887Schin 			if(off>offset)
158*8462SApril.Chin@Sun.COM 				sfwrite(stkp,fcfirst()+type,off-offset);
159*8462SApril.Chin@Sun.COM 			n = stktell(stkp)-lp->lexd.kiaoff;
160*8462SApril.Chin@Sun.COM 			begin = stkptr(stkp,lp->lexd.kiaoff);
1614887Schin 		}
1624887Schin 		else
1634887Schin 		{
1644887Schin 			/* variable in data buffer */
165*8462SApril.Chin@Sun.COM 			begin = fcfirst()+(type+lp->lexd.kiaoff-offset);
166*8462SApril.Chin@Sun.COM 			n = off-lp->lexd.kiaoff;
1674887Schin 		}
168*8462SApril.Chin@Sun.COM 		savptr = stkfreeze(stkp,0);
169*8462SApril.Chin@Sun.COM 		r=kiaentity(lp,begin,n,'v',-1,-1,lp->current,'v',0,"");
170*8462SApril.Chin@Sun.COM 		stkset(stkp,savptr,offset);
1714887Schin 	}
172*8462SApril.Chin@Sun.COM 	sfprintf(lp->kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",lp->current,r,shp->inlineno,shp->inlineno);
1734887Schin }
1744887Schin #endif /* SHOPT_KIA */
1754887Schin 
1764887Schin /*
1774887Schin  * This routine gets called when reading across a buffer boundary
1784887Schin  * If lexd.nocopy is off, then current token is saved on the stack
1794887Schin  */
180*8462SApril.Chin@Sun.COM static void lex_advance(Sfio_t *iop, const char *buff, register int size, void *context)
1814887Schin {
182*8462SApril.Chin@Sun.COM 	register Lex_t		*lp = (Lex_t*)context;
183*8462SApril.Chin@Sun.COM 	register Shell_t	*shp = lp->sh;
184*8462SApril.Chin@Sun.COM 	register Sfio_t		*log= shp->funlog;
185*8462SApril.Chin@Sun.COM 	Stk_t			*stkp = shp->stk;
1864887Schin #if KSHELL
1874887Schin 	/* write to history file and to stderr if necessary */
1884887Schin 	if(iop && !sfstacked(iop))
1894887Schin 	{
1904887Schin 		if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
1914887Schin 			log = shp->hist_ptr->histfp;
1924887Schin 		sfwrite(log, (void*)buff, size);
1934887Schin 		if(sh_isstate(SH_VERBOSE))
1944887Schin 			sfwrite(sfstderr, buff, size);
1954887Schin 	}
1964887Schin #endif
197*8462SApril.Chin@Sun.COM 	if(lp->lexd.nocopy)
1984887Schin 		return;
199*8462SApril.Chin@Sun.COM 	if(lp->lexd.first)
2004887Schin 	{
201*8462SApril.Chin@Sun.COM 		size -= (lp->lexd.first-(char*)buff);
202*8462SApril.Chin@Sun.COM 		buff = lp->lexd.first;
203*8462SApril.Chin@Sun.COM 		if(!lp->lexd.noarg)
204*8462SApril.Chin@Sun.COM 			lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
2054887Schin #if SHOPT_KIA
206*8462SApril.Chin@Sun.COM 		lp->lexd.kiaoff += ARGVAL;
2074887Schin #endif /* SHOPT_KIA */
2084887Schin 	}
209*8462SApril.Chin@Sun.COM 	if(size>0 && (lp->arg||lp->lexd.noarg))
2104887Schin 	{
211*8462SApril.Chin@Sun.COM 		sfwrite(stkp,buff,size);
212*8462SApril.Chin@Sun.COM 		lp->lexd.first = 0;
2134887Schin 	}
2144887Schin }
2154887Schin 
2164887Schin /*
2174887Schin  * fill up another input buffer
2184887Schin  * preserves lexical state
2194887Schin  */
220*8462SApril.Chin@Sun.COM static int lexfill(Lex_t *lp)
2214887Schin {
2224887Schin 	register int c;
223*8462SApril.Chin@Sun.COM 	Lex_t savelex;
2244887Schin 	struct argnod *ap;
2254887Schin 	int aok;
226*8462SApril.Chin@Sun.COM 	savelex = *lp;
227*8462SApril.Chin@Sun.COM 	ap = lp->arg;
2284887Schin 	c = fcfill();
2294887Schin 	if(ap)
230*8462SApril.Chin@Sun.COM 		lp->arg = ap;
231*8462SApril.Chin@Sun.COM 	lp->lex = savelex.lex;
232*8462SApril.Chin@Sun.COM 	lp->lexd = savelex.lexd;
233*8462SApril.Chin@Sun.COM 	if(fcfile() ||  c)
234*8462SApril.Chin@Sun.COM 		lp->lexd.first = 0;
235*8462SApril.Chin@Sun.COM 	aok= lp->aliasok;
236*8462SApril.Chin@Sun.COM 	ap = lp->arg;
237*8462SApril.Chin@Sun.COM 	memcpy(lp, &savelex, offsetof(Lex_t,lexd));
238*8462SApril.Chin@Sun.COM 	lp->arg = ap;
239*8462SApril.Chin@Sun.COM 	lp->aliasok = aok;
2404887Schin 	return(c);
2414887Schin }
2424887Schin 
2434887Schin /*
2444887Schin  * mode=1 for reinitialization
2454887Schin  */
2464887Schin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode)
2474887Schin {
2484887Schin 	if(!lp)
2494887Schin 	{
2504887Schin 		lp = (Lex_t*)newof(0,Lex_t,1,0);
251*8462SApril.Chin@Sun.COM 		lp->sh = sp;
2524887Schin 	}
253*8462SApril.Chin@Sun.COM 	fcnotify(lex_advance,lp);
254*8462SApril.Chin@Sun.COM 	lp->lex.intest = lp->lex.incase = lp->lex.skipword = lp->lexd.warn = 0;
255*8462SApril.Chin@Sun.COM 	lp->comp_assign = 0;
256*8462SApril.Chin@Sun.COM 	lp->lex.reservok = 1;
2574887Schin 	if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC))
258*8462SApril.Chin@Sun.COM 		lp->lexd.warn=1;
2594887Schin 	if(!mode)
2604887Schin 	{
261*8462SApril.Chin@Sun.COM 		lp->lexd.noarg = lp->lexd.level= lp->lexd.dolparen = lp->lexd.balance = 0;
262*8462SApril.Chin@Sun.COM 		lp->lexd.nocopy = lp->lexd.docword = lp->lexd.nest = lp->lexd.paren = 0;
2634887Schin 	}
264*8462SApril.Chin@Sun.COM 	lp->comsub = 0;
2654887Schin 	return(lp);
2664887Schin }
2674887Schin 
2684887Schin #ifdef DBUG
269*8462SApril.Chin@Sun.COM extern int lextoken(Lex_t*);
270*8462SApril.Chin@Sun.COM int sh_lex(Lex_t *lp)
2714887Schin {
272*8462SApril.Chin@Sun.COM 	Shell_t *shp = lp->sh;
2734887Schin 	register int flag;
2744887Schin 	char *quoted, *macro, *split, *expand;
2754887Schin 	char tokstr[3];
2764887Schin 	register int tok = lextoken();
2774887Schin 	quoted = macro = split = expand = "";
278*8462SApril.Chin@Sun.COM 	if(tok==0 && (flag=lp->arg->argflag))
2794887Schin 	{
2804887Schin 		if(flag&ARG_MAC)
2814887Schin 			macro = "macro:";
2824887Schin 		if(flag&ARG_EXP)
2834887Schin 			expand = "expand:";
2844887Schin 		if(flag&ARG_QUOTED)
2854887Schin 			quoted = "quoted:";
2864887Schin 	}
2874887Schin 	sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted,
2884887Schin 		macro, split, expand, fmttoken(lp,tok,tokstr));
2894887Schin 	return(tok);
2904887Schin }
2914887Schin #define sh_lex	lextoken
2924887Schin #endif
2934887Schin 
2944887Schin /*
2954887Schin  * Get the next word and put it on the top of the stak
296*8462SApril.Chin@Sun.COM  * A pointer to the current word is stored in lp->arg
2974887Schin  * Returns the token type
2984887Schin  */
299*8462SApril.Chin@Sun.COM int sh_lex(Lex_t* lp)
3004887Schin {
301*8462SApril.Chin@Sun.COM 	register Shell_t *shp = lp->sh;
3024887Schin 	register const char	*state;
303*8462SApril.Chin@Sun.COM 	register int		n, c, mode=ST_BEGIN, wordflags=0;
304*8462SApril.Chin@Sun.COM 	Stk_t			*stkp = shp->stk;
305*8462SApril.Chin@Sun.COM 	int		inlevel=lp->lexd.level, assignment=0, ingrave=0;
3064887Schin 	Sfio_t *sp;
3074887Schin #if SHOPT_MULTIBYTE
3084887Schin 	LEN=1;
3094887Schin #endif /* SHOPT_MULTIBYTE */
310*8462SApril.Chin@Sun.COM 	if(lp->lexd.paren)
3114887Schin 	{
312*8462SApril.Chin@Sun.COM 		lp->lexd.paren = 0;
313*8462SApril.Chin@Sun.COM 		return(lp->token=LPAREN);
3144887Schin 	}
315*8462SApril.Chin@Sun.COM 	if(lp->lex.incase)
316*8462SApril.Chin@Sun.COM 		lp->assignok = 0;
3174887Schin 	else
318*8462SApril.Chin@Sun.COM 		lp->assignok |= lp->lex.reservok;
319*8462SApril.Chin@Sun.COM 	if(lp->comp_assign==2)
320*8462SApril.Chin@Sun.COM 		lp->comp_assign = lp->lex.reservok = 0;
321*8462SApril.Chin@Sun.COM 	lp->lexd.arith = (lp->lexd.nest==1);
322*8462SApril.Chin@Sun.COM 	if(lp->lexd.nest)
3234887Schin 	{
324*8462SApril.Chin@Sun.COM 		pushlevel(lp,lp->lexd.nest,ST_NONE);
325*8462SApril.Chin@Sun.COM 		lp->lexd.nest = 0;
326*8462SApril.Chin@Sun.COM 		mode = lp->lexd.lex_state;
3274887Schin 	}
328*8462SApril.Chin@Sun.COM 	else if(lp->lexd.docword)
3294887Schin 	{
3304887Schin 		if(fcgetc(c)=='-' || c=='#')
3314887Schin 		{
332*8462SApril.Chin@Sun.COM 			lp->lexd.docword++;
333*8462SApril.Chin@Sun.COM 			lp->digits=(c=='#'?3:1);
3344887Schin 		}
3354887Schin 		else if(c=='<')
3364887Schin 		{
337*8462SApril.Chin@Sun.COM 			lp->digits=2;
338*8462SApril.Chin@Sun.COM 			lp->lexd.docword=0;
3394887Schin 		}
3404887Schin 		else if(c>0)
3414887Schin 			fcseek(-1);
3424887Schin 	}
343*8462SApril.Chin@Sun.COM 	if(!lp->lexd.dolparen)
3444887Schin 	{
345*8462SApril.Chin@Sun.COM 		lp->arg = 0;
3464887Schin 		if(mode!=ST_BEGIN)
347*8462SApril.Chin@Sun.COM 			lp->lexd.first = fcseek(0);
3484887Schin 		else
349*8462SApril.Chin@Sun.COM 			lp->lexd.first = 0;
3504887Schin 	}
351*8462SApril.Chin@Sun.COM 	lp->lastline = lp->sh->inlineno;
3524887Schin 	while(1)
3534887Schin 	{
3544887Schin 		/* skip over characters in the current state */
3554887Schin 		state = sh_lexstates[mode];
3564887Schin 		while((n=STATE(state,c))==0);
3574887Schin 		switch(n)
3584887Schin 		{
3594887Schin 			case S_BREAK:
3604887Schin 				fcseek(-1);
3614887Schin 				goto breakloop;
3624887Schin 			case S_EOF:
3634887Schin 				sp = fcfile();
364*8462SApril.Chin@Sun.COM 				if((n=lexfill(lp)) > 0)
3654887Schin 				{
3664887Schin 					fcseek(-1);
3674887Schin 					continue;
3684887Schin 				}
3694887Schin 				/* check for zero byte in file */
3704887Schin 				if(n==0 && fcfile())
3714887Schin 				{
3724887Schin 					if(shp->readscript)
3734887Schin 					{
3744887Schin 						char *cp = error_info.id;
3754887Schin 						errno = ENOEXEC;
3764887Schin 						error_info.id = shp->readscript;
3774887Schin 						errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp);
3784887Schin 					}
3794887Schin 					else
3804887Schin 					{
381*8462SApril.Chin@Sun.COM 						lp->token = -1;
382*8462SApril.Chin@Sun.COM 						sh_syntax(lp);
3834887Schin 					}
3844887Schin 				}
3854887Schin 				/* end-of-file */
3864887Schin 				if(mode==ST_BEGIN)
387*8462SApril.Chin@Sun.COM 					return(lp->token=EOFSYM);
388*8462SApril.Chin@Sun.COM 				if(mode >ST_NORM && lp->lexd.level>0)
3894887Schin 				{
390*8462SApril.Chin@Sun.COM 					switch(c=endchar(lp))
3914887Schin 					{
3924887Schin 						case '$':
3934887Schin 							if(mode==ST_LIT)
3944887Schin 							{
3954887Schin 								c = '\'';
3964887Schin 								break;
3974887Schin 							}
398*8462SApril.Chin@Sun.COM 							mode = oldmode(lp);
399*8462SApril.Chin@Sun.COM 							poplevel(lp);
4004887Schin 							continue;
4014887Schin 						case RBRACT:
4024887Schin 							c = LBRACT;
4034887Schin 							break;
4044887Schin 						case 1:	/* for ((...)) */
4054887Schin 						case RPAREN:
4064887Schin 							c = LPAREN;
4074887Schin 							break;
4084887Schin 						default:
4094887Schin 							c = LBRACE;
4104887Schin 							break;
4114887Schin 						case '"': case '`': case '\'':
412*8462SApril.Chin@Sun.COM 							lp->lexd.balance = c;
4134887Schin 							break;
4144887Schin 					}
4154887Schin 					if(sp && !(sfset(sp,0,0)&SF_STRING))
4164887Schin 					{
417*8462SApril.Chin@Sun.COM 						lp->lasttok = c;
418*8462SApril.Chin@Sun.COM 						lp->token = EOFSYM;
419*8462SApril.Chin@Sun.COM 						sh_syntax(lp);
4204887Schin 					}
421*8462SApril.Chin@Sun.COM 					lp->lexd.balance = c;
4224887Schin 				}
4234887Schin 				goto breakloop;
4244887Schin 			case S_COM:
4254887Schin 				/* skip one or more comment line(s) */
426*8462SApril.Chin@Sun.COM 				lp->lex.reservok = !lp->lex.intest;
427*8462SApril.Chin@Sun.COM 				if((n=lp->lexd.nocopy) && lp->lexd.dolparen)
428*8462SApril.Chin@Sun.COM 					lp->lexd.nocopy--;
4294887Schin 				do
4304887Schin 				{
4314887Schin 					while(fcgetc(c)>0 && c!='\n');
432*8462SApril.Chin@Sun.COM 					if(c<=0 || lp->heredoc)
4334887Schin 						break;
4344887Schin 					while(shp->inlineno++,fcpeek(0)=='\n')
4354887Schin 						fcseek(1);
4364887Schin 					while(state[c=fcpeek(0)]==0)
4374887Schin 						fcseek(1);
4384887Schin 				}
4394887Schin 				while(c=='#');
440*8462SApril.Chin@Sun.COM 				lp->lexd.nocopy = n;
4414887Schin 				if(c<0)
442*8462SApril.Chin@Sun.COM 					return(lp->token=EOFSYM);
4434887Schin 				n = S_NLTOK;
4444887Schin 				shp->inlineno--;
4454887Schin 				/* FALL THRU */
4464887Schin 			case S_NLTOK:
4474887Schin 				/* check for here-document */
448*8462SApril.Chin@Sun.COM 				if(lp->heredoc)
4494887Schin 				{
450*8462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen)
451*8462SApril.Chin@Sun.COM 						lp->lexd.nocopy++;
4524887Schin 					c = shp->inlineno;
453*8462SApril.Chin@Sun.COM 					if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok)
4544887Schin 					{
455*8462SApril.Chin@Sun.COM 						lp->lasttok = IODOCSYM;
456*8462SApril.Chin@Sun.COM 						lp->token = EOFSYM;
457*8462SApril.Chin@Sun.COM 						lp->lastline = c;
458*8462SApril.Chin@Sun.COM 						sh_syntax(lp);
4594887Schin 					}
460*8462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen)
461*8462SApril.Chin@Sun.COM 						lp->lexd.nocopy--;
462*8462SApril.Chin@Sun.COM 					lp->heredoc = 0;
4634887Schin 				}
464*8462SApril.Chin@Sun.COM 				lp->lex.reservok = !lp->lex.intest;
465*8462SApril.Chin@Sun.COM 				lp->lex.skipword = 0;
4664887Schin 				/* FALL THRU */
4674887Schin 			case S_NL:
4684887Schin 				/* skip over new-lines */
469*8462SApril.Chin@Sun.COM 				lp->lex.last_quote = 0;
4704887Schin 				while(shp->inlineno++,fcget()=='\n');
4714887Schin 				fcseek(-1);
4724887Schin 				if(n==S_NLTOK)
4734887Schin 				{
474*8462SApril.Chin@Sun.COM 					lp->comp_assign = 0;
475*8462SApril.Chin@Sun.COM 					return(lp->token='\n');
4764887Schin 				}
4774887Schin 			case S_BLNK:
478*8462SApril.Chin@Sun.COM 				if(lp->lex.incase<=TEST_RE)
4794887Schin 					continue;
4804887Schin 				/* implicit RPAREN for =~ test operator */
481*8462SApril.Chin@Sun.COM 				if(inlevel+1==lp->lexd.level)
4824887Schin 				{
483*8462SApril.Chin@Sun.COM 					if(lp->lex.intest)
484*8462SApril.Chin@Sun.COM 						fcseek(-1);
4854887Schin 					c = RPAREN;
4864887Schin 					goto do_pop;
4874887Schin 				}
4884887Schin 				continue;
4894887Schin 			case S_OP:
4904887Schin 				/* return operator token */
4914887Schin 				if(c=='<' || c=='>')
4924887Schin 				{
493*8462SApril.Chin@Sun.COM 					if(lp->lex.testop2)
494*8462SApril.Chin@Sun.COM 						lp->lex.testop2 = 0;
4954887Schin 					else
4964887Schin 					{
497*8462SApril.Chin@Sun.COM 						lp->digits = (c=='>');
498*8462SApril.Chin@Sun.COM 						lp->lex.skipword = 1;
499*8462SApril.Chin@Sun.COM 						lp->aliasok = lp->lex.reservok;
500*8462SApril.Chin@Sun.COM 						lp->lex.reservok = 0;
5014887Schin 					}
5024887Schin 				}
5034887Schin 				else
5044887Schin 				{
505*8462SApril.Chin@Sun.COM 					lp->lex.reservok = !lp->lex.intest;
5064887Schin 					if(c==RPAREN)
5074887Schin 					{
508*8462SApril.Chin@Sun.COM 						if(!lp->lexd.dolparen)
509*8462SApril.Chin@Sun.COM 							lp->lex.incase = 0;
510*8462SApril.Chin@Sun.COM 						return(lp->token=c);
5114887Schin 					}
512*8462SApril.Chin@Sun.COM 					lp->lex.testop1 = lp->lex.intest;
5134887Schin 				}
5144887Schin 				if(fcgetc(n)>0)
5154887Schin 					fcseek(-1);
5164887Schin 				if(state[n]==S_OP || n=='#')
5174887Schin 				{
5184887Schin 					if(n==c)
5194887Schin 					{
5204887Schin 						if(c=='<')
521*8462SApril.Chin@Sun.COM 							lp->lexd.docword=1;
5224887Schin 						else if(n==LPAREN)
5234887Schin 						{
524*8462SApril.Chin@Sun.COM 							lp->lexd.nest=1;
525*8462SApril.Chin@Sun.COM 							lp->lastline = shp->inlineno;
526*8462SApril.Chin@Sun.COM 							lp->lexd.lex_state = ST_NESTED;
5274887Schin 							fcseek(1);
528*8462SApril.Chin@Sun.COM 							return(sh_lex(lp));
5294887Schin 						}
5304887Schin 						c  |= SYMREP;
5314887Schin 					}
5324887Schin 					else if(c=='(' || c==')')
533*8462SApril.Chin@Sun.COM 						return(lp->token=c);
5344887Schin 					else if(c=='&')
5354887Schin 					{
5364887Schin #if SHOPT_BASH
5374887Schin 						if(!sh_isoption(SH_POSIX) && n=='>')
5384887Schin 						{
539*8462SApril.Chin@Sun.COM 							lp->digits = -1;
5404887Schin 							c = '>';
5414887Schin 						}
5424887Schin 						else
5434887Schin #endif
5444887Schin 							n = 0;
5454887Schin 					}
5464887Schin 					else if(n=='&')
5474887Schin 						c  |= SYMAMP;
5484887Schin 					else if(c!='<' && c!='>')
5494887Schin 						n = 0;
5504887Schin 					else if(n==LPAREN)
5514887Schin 					{
5524887Schin 						c  |= SYMLPAR;
553*8462SApril.Chin@Sun.COM 						lp->lex.reservok = 1;
554*8462SApril.Chin@Sun.COM 						lp->lex.skipword = 0;
5554887Schin 					}
5564887Schin 					else if(n=='|')
5574887Schin 						c  |= SYMPIPE;
5584887Schin 					else if(c=='<' && n=='>')
5594887Schin 						c = IORDWRSYM;
5604887Schin 					else if(n=='#' && (c=='<'||c=='>'))
5614887Schin 						c |= SYMSHARP;
562*8462SApril.Chin@Sun.COM 					else if(n==';' && c=='>')
563*8462SApril.Chin@Sun.COM 					{
564*8462SApril.Chin@Sun.COM 						c |= SYMSEMI;
565*8462SApril.Chin@Sun.COM 						if(lp->inexec)
566*8462SApril.Chin@Sun.COM 						{
567*8462SApril.Chin@Sun.COM 							lp->token = c;
568*8462SApril.Chin@Sun.COM 							sh_syntax(lp);
569*8462SApril.Chin@Sun.COM 						}
570*8462SApril.Chin@Sun.COM 					}
5714887Schin 					else
5724887Schin 						n = 0;
5734887Schin 					if(n)
5744887Schin 					{
5754887Schin 						fcseek(1);
576*8462SApril.Chin@Sun.COM 						lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM);
5774887Schin 					}
5784887Schin 					else
5794887Schin 					{
580*8462SApril.Chin@Sun.COM 						if((n=fcpeek(0))!=RPAREN && n!=LPAREN && lp->lexd.warn)
5814887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n);
5824887Schin 					}
5834887Schin 				}
584*8462SApril.Chin@Sun.COM 				if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase)
585*8462SApril.Chin@Sun.COM 					lp->comp_assign = 2;
5864887Schin 				else
587*8462SApril.Chin@Sun.COM 					lp->comp_assign = 0;
588*8462SApril.Chin@Sun.COM 				return(lp->token=c);
5894887Schin 			case S_ESC:
5904887Schin 				/* check for \<new-line> */
5914887Schin 				fcgetc(n);
5924887Schin 				c=2;
5934887Schin #if SHOPT_CRNL
5944887Schin 				if(n=='\r')
5954887Schin 				{
5964887Schin 					if(fcgetc(n)=='\n')
5974887Schin 						c=3;
5984887Schin 					else
5994887Schin 					{
6004887Schin 						n='\r';
6014887Schin 						fcseek(-1);
6024887Schin 					}
6034887Schin 				}
6044887Schin #endif /* SHOPT_CRNL */
6054887Schin 				if(n=='\n')
6064887Schin 				{
6074887Schin 					Sfio_t *sp;
6084887Schin 					struct argnod *ap;
6094887Schin 					shp->inlineno++;
6104887Schin 					/* synchronize */
6114887Schin 					if(!(sp=fcfile()))
6124887Schin 						state=fcseek(0);
6134887Schin 					fcclose();
614*8462SApril.Chin@Sun.COM 					ap = lp->arg;
6154887Schin 					if(sp)
6164887Schin 						fcfopen(sp);
6174887Schin 					else
6184887Schin 						fcsopen((char*)state);
6194887Schin 					/* remove \new-line */
620*8462SApril.Chin@Sun.COM 					n = stktell(stkp)-c;
621*8462SApril.Chin@Sun.COM 					stkseek(stkp,n);
622*8462SApril.Chin@Sun.COM 					lp->arg = ap;
6234887Schin 					if(n<=ARGVAL)
6244887Schin 					{
6254887Schin 						mode = 0;
626*8462SApril.Chin@Sun.COM 						lp->lexd.first = 0;
6274887Schin 					}
6284887Schin 					continue;
6294887Schin 				}
6304887Schin 				wordflags |= ARG_QUOTED;
6314887Schin 				if(mode==ST_DOL)
6324887Schin 					goto err;
6334887Schin #ifndef STR_MAXIMAL
634*8462SApril.Chin@Sun.COM 				else if(mode==ST_NESTED && lp->lexd.warn &&
635*8462SApril.Chin@Sun.COM 					endchar(lp)==RBRACE &&
6364887Schin 					sh_lexstates[ST_DOL][n]==S_DIG
6374887Schin 				)
6384887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n);
6394887Schin #endif /* STR_MAXIMAL */
6404887Schin 				break;
6414887Schin 			case S_NAME:
642*8462SApril.Chin@Sun.COM 				if(!lp->lex.skipword)
643*8462SApril.Chin@Sun.COM 					lp->lex.reservok *= 2;
6444887Schin 				/* FALL THRU */
6454887Schin 			case S_TILDE:
6464887Schin 			case S_RES:
647*8462SApril.Chin@Sun.COM 				if(!lp->lexd.dolparen)
648*8462SApril.Chin@Sun.COM 					lp->lexd.first = fcseek(0)-LEN;
649*8462SApril.Chin@Sun.COM 				else if(lp->lexd.docword)
650*8462SApril.Chin@Sun.COM 					lp->lexd.docend = fcseek(0)-LEN;
6514887Schin 				mode = ST_NAME;
6524887Schin 				if(c=='.')
6534887Schin 					fcseek(-1);
6544887Schin 				if(n!=S_TILDE)
6554887Schin 					continue;
6564887Schin 				fcgetc(n);
6574887Schin 				if(n>0)
658*8462SApril.Chin@Sun.COM 				{
659*8462SApril.Chin@Sun.COM 					if(c=='~' && n==LPAREN && lp->lex.incase)
660*8462SApril.Chin@Sun.COM 						lp->lex.incase = TEST_RE;
6614887Schin 					fcseek(-1);
662*8462SApril.Chin@Sun.COM 				}
6634887Schin 				if(n==LPAREN)
6644887Schin 					goto epat;
6654887Schin 				wordflags = ARG_MAC;
6664887Schin 				mode = ST_NORM;
6674887Schin 				continue;
6684887Schin 			case S_REG:
6694887Schin 				if(mode==ST_BEGIN)
6704887Schin 				{
671*8462SApril.Chin@Sun.COM 				do_reg:
6724887Schin 					/* skip new-line joining */
6734887Schin 					if(c=='\\' && fcpeek(0)=='\n')
6744887Schin 					{
6754887Schin 						shp->inlineno++;
6764887Schin 						fcseek(1);
6774887Schin 						continue;
6784887Schin 					}
6794887Schin 					fcseek(-1);
680*8462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen)
681*8462SApril.Chin@Sun.COM 						lp->lexd.first = fcseek(0);
682*8462SApril.Chin@Sun.COM 					else if(lp->lexd.docword)
683*8462SApril.Chin@Sun.COM 						lp->lexd.docend = fcseek(0);
684*8462SApril.Chin@Sun.COM 					if(c=='[' && lp->assignok>=SH_ASSIGN)
6854887Schin 					{
6864887Schin 						mode = ST_NAME;
6874887Schin 						continue;
6884887Schin 					}
6894887Schin 				}
6904887Schin 				mode = ST_NORM;
6914887Schin 				continue;
6924887Schin 			case S_LIT:
693*8462SApril.Chin@Sun.COM 				if(oldmode(lp)==ST_NONE && !lp->lexd.noarg)	/*  in ((...)) */
6944887Schin 				{
6954887Schin 					if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']')
6964887Schin 					{
6974887Schin 						if(fcpeek(1)=='\'')
6984887Schin 							fcseek(2);
6994887Schin 					}
7004887Schin 					continue;
7014887Schin 				}
7024887Schin 				wordflags |= ARG_QUOTED;
7034887Schin 				if(mode==ST_DOL)
7044887Schin 				{
705*8462SApril.Chin@Sun.COM 					if(endchar(lp)!='$')
7064887Schin 						goto err;
707*8462SApril.Chin@Sun.COM 					if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */
7084887Schin 					{
709*8462SApril.Chin@Sun.COM 						if(lp->lexd.warn)
7104887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
7114887Schin 						mode = ST_LIT;
7124887Schin 					}
7134887Schin 				}
7144887Schin 				if(mode!=ST_LIT)
7154887Schin 				{
716*8462SApril.Chin@Sun.COM 					if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
717*8462SApril.Chin@Sun.COM 						errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
718*8462SApril.Chin@Sun.COM 					lp->lex.last_quote = 0;
719*8462SApril.Chin@Sun.COM 					lp->lastline = shp->inlineno;
7204887Schin 					if(mode!=ST_DOL)
721*8462SApril.Chin@Sun.COM 						pushlevel(lp,'\'',mode);
7224887Schin 					mode = ST_LIT;
7234887Schin 					continue;
7244887Schin 				}
7254887Schin 				/* check for multi-line single-quoted string */
726*8462SApril.Chin@Sun.COM 				else if(shp->inlineno > lp->lastline)
727*8462SApril.Chin@Sun.COM 					lp->lex.last_quote = '\'';
728*8462SApril.Chin@Sun.COM 				mode = oldmode(lp);
729*8462SApril.Chin@Sun.COM 				poplevel(lp);
7304887Schin 				break;
7314887Schin 			case S_ESC2:
7324887Schin 				/* \ inside '' */
733*8462SApril.Chin@Sun.COM 				if(endchar(lp)=='$')
7344887Schin 				{
7354887Schin 					fcgetc(n);
7364887Schin 					if(n=='\n')
7374887Schin 						shp->inlineno++;
7384887Schin 				}
7394887Schin 				continue;
7404887Schin 			case S_GRAVE:
741*8462SApril.Chin@Sun.COM 				if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`'))
7424887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno);
7434887Schin 				wordflags |=(ARG_MAC|ARG_EXP);
7444887Schin 				if(mode==ST_QUOTE)
7454887Schin 					ingrave = !ingrave;
7464887Schin 				/* FALL THRU */
7474887Schin 			case S_QUOTE:
748*8462SApril.Chin@Sun.COM 				if(oldmode(lp)==ST_NONE && lp->lexd.arith)	/*  in ((...)) */
749*8462SApril.Chin@Sun.COM 				{
750*8462SApril.Chin@Sun.COM 					if(n!=S_GRAVE || fcpeek(0)=='\'')
751*8462SApril.Chin@Sun.COM 						continue;
752*8462SApril.Chin@Sun.COM 				}
7534887Schin 				if(n==S_QUOTE)
7544887Schin 					wordflags |=ARG_QUOTED;
7554887Schin 				if(mode!=ST_QUOTE)
7564887Schin 				{
7574887Schin 					if(c!='"' || mode!=ST_QNEST)
7584887Schin 					{
759*8462SApril.Chin@Sun.COM 						if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
760*8462SApril.Chin@Sun.COM 							errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
761*8462SApril.Chin@Sun.COM 						lp->lex.last_quote=0;
762*8462SApril.Chin@Sun.COM 						lp->lastline = shp->inlineno;
763*8462SApril.Chin@Sun.COM 						pushlevel(lp,c,mode);
7644887Schin 					}
7654887Schin 					ingrave = (c=='`');
7664887Schin 					mode = ST_QUOTE;
7674887Schin 					continue;
7684887Schin 				}
769*8462SApril.Chin@Sun.COM 				else if((n=endchar(lp))==c)
7704887Schin 				{
771*8462SApril.Chin@Sun.COM 					if(shp->inlineno > lp->lastline)
772*8462SApril.Chin@Sun.COM 						lp->lex.last_quote = c;
773*8462SApril.Chin@Sun.COM 					mode = oldmode(lp);
774*8462SApril.Chin@Sun.COM 					poplevel(lp);
7754887Schin 				}
7764887Schin 				else if(c=='"' && n==RBRACE)
7774887Schin 					mode = ST_QNEST;
7784887Schin 				break;
7794887Schin 			case S_DOL:
7804887Schin 				/* don't check syntax inside `` */
7814887Schin 				if(mode==ST_QUOTE && ingrave)
7824887Schin 					continue;
7834887Schin #if SHOPT_KIA
784*8462SApril.Chin@Sun.COM 				if(lp->lexd.first)
785*8462SApril.Chin@Sun.COM 					lp->lexd.kiaoff = fcseek(0)-lp->lexd.first;
7864887Schin 				else
787*8462SApril.Chin@Sun.COM 					lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst();
7884887Schin #endif /* SHOPT_KIA */
789*8462SApril.Chin@Sun.COM 				pushlevel(lp,'$',mode);
7904887Schin 				mode = ST_DOL;
7914887Schin 				continue;
7924887Schin 			case S_PAR:
793*8462SApril.Chin@Sun.COM 			do_comsub:
7944887Schin 				wordflags |= ARG_MAC;
795*8462SApril.Chin@Sun.COM 				mode = oldmode(lp);
796*8462SApril.Chin@Sun.COM 				poplevel(lp);
7974887Schin 				fcseek(-1);
798*8462SApril.Chin@Sun.COM 				wordflags |= comsub(lp,c);
7994887Schin 				continue;
8004887Schin 			case S_RBRA:
801*8462SApril.Chin@Sun.COM 				if((n=endchar(lp)) == '$')
8024887Schin 					goto err;
8034887Schin 				if(mode!=ST_QUOTE || n==RBRACE)
8044887Schin 				{
805*8462SApril.Chin@Sun.COM 					mode = oldmode(lp);
806*8462SApril.Chin@Sun.COM 					poplevel(lp);
8074887Schin 				}
8084887Schin 				break;
8094887Schin 			case S_EDOL:
8104887Schin 				/* end $identifier */
8114887Schin #if SHOPT_KIA
812*8462SApril.Chin@Sun.COM 				if(lp->kiafile)
813*8462SApril.Chin@Sun.COM 					refvar(lp,0);
8144887Schin #endif /* SHOPT_KIA */
815*8462SApril.Chin@Sun.COM 				if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED)
8164887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno);
8174887Schin 				fcseek(-1);
818*8462SApril.Chin@Sun.COM 				mode = oldmode(lp);
819*8462SApril.Chin@Sun.COM 				poplevel(lp);
8204887Schin 				break;
8214887Schin 			case S_DOT:
8224887Schin 				/* make sure next character is alpha */
8234887Schin 				if(fcgetc(n)>0)
824*8462SApril.Chin@Sun.COM 				{
825*8462SApril.Chin@Sun.COM 					if(n=='.')
826*8462SApril.Chin@Sun.COM 						fcgetc(n);
827*8462SApril.Chin@Sun.COM 					if(n>0)
828*8462SApril.Chin@Sun.COM 						fcseek(-1);
829*8462SApril.Chin@Sun.COM 				}
8304887Schin 				if(isaletter(n) || n==LBRACT)
8314887Schin 					continue;
8324887Schin 				if(mode==ST_NAME)
8334887Schin 				{
8344887Schin 					if(n=='=')
8354887Schin 						continue;
8364887Schin 					break;
8374887Schin 				}
8384887Schin 				else if(n==RBRACE)
8394887Schin 					continue;
8404887Schin 				if(isastchar(n))
8414887Schin 					continue;
8424887Schin 				goto err;
8434887Schin 			case S_SPC1:
8444887Schin 				wordflags |= ARG_MAC;
845*8462SApril.Chin@Sun.COM 				if(endchar(lp)==RBRACE)
8464887Schin 				{
847*8462SApril.Chin@Sun.COM 					setchar(lp,c);
8484887Schin 					continue;
8494887Schin 				}
8504887Schin 				/* FALL THRU */
8514887Schin 			case S_ALP:
852*8462SApril.Chin@Sun.COM 				if(c=='.' && endchar(lp)=='$')
8534887Schin 					goto err;
8544887Schin 			case S_SPC2:
8554887Schin 			case S_DIG:
8564887Schin 				wordflags |= ARG_MAC;
857*8462SApril.Chin@Sun.COM 				switch(endchar(lp))
8584887Schin 				{
8594887Schin 					case '$':
8604887Schin 						if(n==S_ALP) /* $identifier */
8614887Schin 							mode = ST_DOLNAME;
8624887Schin 						else
8634887Schin 						{
864*8462SApril.Chin@Sun.COM 							mode = oldmode(lp);
865*8462SApril.Chin@Sun.COM 							poplevel(lp);
8664887Schin 						}
8674887Schin 						break;
8684887Schin #if SHOPT_TYPEDEF
8694887Schin 					case '@':
8704887Schin #endif /* SHOPT_TYPEDEF */
8714887Schin 					case '!':
8724887Schin 						if(n!=S_ALP)
8734887Schin 							goto dolerr;
8744887Schin 					case '#':
8754887Schin 					case RBRACE:
8764887Schin 						if(n==S_ALP)
8774887Schin 						{
878*8462SApril.Chin@Sun.COM 							setchar(lp,RBRACE);
8794887Schin 							if(c=='.')
8804887Schin 								fcseek(-1);
8814887Schin 							mode = ST_BRACE;
8824887Schin 						}
8834887Schin 						else
8844887Schin 						{
8854887Schin 							if(fcgetc(c)>0)
8864887Schin 								fcseek(-1);
8874887Schin 							if(state[c]==S_ALP)
8884887Schin 								goto err;
8894887Schin 							if(n==S_DIG)
890*8462SApril.Chin@Sun.COM 								setchar(lp,'0');
8914887Schin 							else
892*8462SApril.Chin@Sun.COM 								setchar(lp,'!');
8934887Schin 						}
8944887Schin 						break;
8954887Schin 					case '0':
8964887Schin 						if(n==S_DIG)
8974887Schin 							break;
8984887Schin 					default:
8994887Schin 						goto dolerr;
9004887Schin 				}
9014887Schin 				break;
9024887Schin 			dolerr:
9034887Schin 			case S_ERR:
904*8462SApril.Chin@Sun.COM 				if((n=endchar(lp)) == '$')
9054887Schin 					goto err;
9064887Schin 				if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2)
9074887Schin 				{
9084887Schin 					/* see whether inside `...` */
909*8462SApril.Chin@Sun.COM 					mode = oldmode(lp);
910*8462SApril.Chin@Sun.COM 					poplevel(lp);
911*8462SApril.Chin@Sun.COM 					if((n = endchar(lp)) != '`')
9124887Schin 						goto err;
913*8462SApril.Chin@Sun.COM 					pushlevel(lp,RBRACE,mode);
9144887Schin 				}
9154887Schin 				else
916*8462SApril.Chin@Sun.COM 					setchar(lp,RBRACE);
9174887Schin 				mode = ST_NESTED;
9184887Schin 				continue;
9194887Schin 			case S_MOD1:
920*8462SApril.Chin@Sun.COM 				if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE)
9214887Schin 				{
9224887Schin 					/* allow ' inside "${...}" */
9234887Schin 					if(c==':' && fcgetc(n)>0)
9244887Schin 					{
9254887Schin 						n = state[n];
9264887Schin 						fcseek(-1);
9274887Schin 					}
9284887Schin 					if(n==S_MOD1)
9294887Schin 					{
9304887Schin 						mode = ST_QUOTE;
9314887Schin 						continue;
9324887Schin 					}
9334887Schin 				}
9344887Schin 				/* FALL THRU */
9354887Schin 			case S_MOD2:
9364887Schin #if SHOPT_KIA
937*8462SApril.Chin@Sun.COM 				if(lp->kiafile)
938*8462SApril.Chin@Sun.COM 					refvar(lp,1);
9394887Schin #endif /* SHOPT_KIA */
9404887Schin 				if(c!=':' && fcgetc(n)>0)
9414887Schin 				{
9424887Schin 					if(n!=c)
9434887Schin 						c = 0;
9444887Schin 					if(!c || (fcgetc(n)>0))
9454887Schin 					{
9464887Schin 						fcseek(-1);
9474887Schin 						if(n==LPAREN)
9484887Schin 						{
9494887Schin 							if(c!='%')
9504887Schin 							{
951*8462SApril.Chin@Sun.COM 								lp->token = n;
952*8462SApril.Chin@Sun.COM 								sh_syntax(lp);
9534887Schin 							}
954*8462SApril.Chin@Sun.COM 							else if(lp->lexd.warn)
9554887Schin 								errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%');
9564887Schin 						}
9574887Schin 					}
9584887Schin 				}
9594887Schin 				mode = ST_NESTED;
9604887Schin 				continue;
9614887Schin 			case S_LBRA:
962*8462SApril.Chin@Sun.COM 				if((c=endchar(lp)) == '$')
9634887Schin 				{
9644887Schin 					if(fcgetc(c)>0)
9654887Schin 						fcseek(-1);
966*8462SApril.Chin@Sun.COM 					setchar(lp,RBRACE);
9674887Schin 					if(state[c]!=S_ERR && c!=RBRACE)
9684887Schin 						continue;
969*8462SApril.Chin@Sun.COM 					if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK)
970*8462SApril.Chin@Sun.COM 					{
971*8462SApril.Chin@Sun.COM 						c = LBRACE;
972*8462SApril.Chin@Sun.COM 						goto do_comsub;
973*8462SApril.Chin@Sun.COM 					}
9744887Schin 				}
9754887Schin 			err:
976*8462SApril.Chin@Sun.COM 				n = endchar(lp);
977*8462SApril.Chin@Sun.COM 				mode = oldmode(lp);
978*8462SApril.Chin@Sun.COM 				poplevel(lp);
9794887Schin 				if(n!='$')
9804887Schin 				{
981*8462SApril.Chin@Sun.COM 					lp->token = c;
982*8462SApril.Chin@Sun.COM 					sh_syntax(lp);
9834887Schin 				}
9844887Schin 				else
9854887Schin 				{
986*8462SApril.Chin@Sun.COM 					if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE))
9874887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
9884887Schin 					else if(c=='"' && mode!=ST_QUOTE)
9894887Schin 						wordflags |= ARG_MESSAGE;
9904887Schin 					fcseek(-1);
9914887Schin 				}
9924887Schin 				continue;
9934887Schin 			case S_META:
994*8462SApril.Chin@Sun.COM 				if(lp->lexd.warn && endchar(lp)==RBRACE)
9954887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
9964887Schin 				continue;
9974887Schin 			case S_PUSH:
998*8462SApril.Chin@Sun.COM 				pushlevel(lp,RPAREN,mode);
9994887Schin 				mode = ST_NESTED;
10004887Schin 				continue;
10014887Schin 			case S_POP:
10024887Schin 			do_pop:
1003*8462SApril.Chin@Sun.COM 				if(lp->lexd.level <= inlevel)
10044887Schin 					break;
1005*8462SApril.Chin@Sun.COM 				if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest)
1006*8462SApril.Chin@Sun.COM 				{
1007*8462SApril.Chin@Sun.COM 					fcseek(-1);
1008*8462SApril.Chin@Sun.COM 					goto breakloop;
1009*8462SApril.Chin@Sun.COM 				}
1010*8462SApril.Chin@Sun.COM 				n = endchar(lp);
10114887Schin 				if(c==RBRACT  && !(n==RBRACT || n==RPAREN))
10124887Schin 					continue;
10134887Schin 				if((c==RBRACE||c==RPAREN) && n==RPAREN)
10144887Schin 				{
10154887Schin 					if(fcgetc(n)==LPAREN)
10164887Schin 					{
10174887Schin 						if(c!=RPAREN)
10184887Schin 							fcseek(-1);
10194887Schin 						continue;
10204887Schin 					}
10214887Schin 					if(n>0)
10224887Schin 						fcseek(-1);
10234887Schin 					n = RPAREN;
10244887Schin 				}
10254887Schin 				if(c==';' && n!=';')
10264887Schin 				{
1027*8462SApril.Chin@Sun.COM 					if(lp->lexd.warn && n==RBRACE)
10284887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
10294887Schin 					continue;
10304887Schin 				}
10314887Schin 				if(mode==ST_QNEST)
10324887Schin 				{
1033*8462SApril.Chin@Sun.COM 					if(lp->lexd.warn)
10344887Schin 						errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c);
10354887Schin 					continue;
10364887Schin 				}
1037*8462SApril.Chin@Sun.COM 				mode = oldmode(lp);
1038*8462SApril.Chin@Sun.COM 				poplevel(lp);
10394887Schin 				/* quotes in subscript need expansion */
10404887Schin 				if(mode==ST_NAME && (wordflags&ARG_QUOTED))
10414887Schin 					wordflags |= ARG_MAC;
10424887Schin 				/* check for ((...)) */
10434887Schin 				if(n==1 && c==RPAREN)
10444887Schin 				{
10454887Schin 					if(fcgetc(n)==RPAREN)
10464887Schin 					{
1047*8462SApril.Chin@Sun.COM 						if(mode==ST_NONE && !lp->lexd.dolparen)
10484887Schin 							goto breakloop;
1049*8462SApril.Chin@Sun.COM 						lp->lex.reservok = 1;
1050*8462SApril.Chin@Sun.COM 						lp->lex.skipword = 0;
1051*8462SApril.Chin@Sun.COM 						return(lp->token=EXPRSYM);
10524887Schin 					}
10534887Schin 					/* backward compatibility */
1054*8462SApril.Chin@Sun.COM 					if(lp->lexd.dolparen)
10554887Schin 						fcseek(-1);
10564887Schin 					else
10574887Schin 					{
1058*8462SApril.Chin@Sun.COM 						if(lp->lexd.warn)
10594887Schin 							errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
1060*8462SApril.Chin@Sun.COM 						if(!(state=lp->lexd.first))
10614887Schin 							state = fcfirst();
10624887Schin 						fcseek(state-fcseek(0));
1063*8462SApril.Chin@Sun.COM 						if(lp->arg)
10644887Schin 						{
1065*8462SApril.Chin@Sun.COM 							lp->arg = (struct argnod*)stkfreeze(stkp,1);
1066*8462SApril.Chin@Sun.COM 							setupalias(lp,lp->arg->argval,NIL(Namval_t*));
10674887Schin 						}
1068*8462SApril.Chin@Sun.COM 						lp->lexd.paren = 1;
10694887Schin 					}
1070*8462SApril.Chin@Sun.COM 					return(lp->token=LPAREN);
10714887Schin 				}
10724887Schin 				if(mode==ST_NONE)
10734887Schin 					return(0);
10744887Schin 				if(c!=n)
10754887Schin 				{
1076*8462SApril.Chin@Sun.COM 					lp->token = c;
1077*8462SApril.Chin@Sun.COM 					sh_syntax(lp);
10784887Schin 				}
10794887Schin 				if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
10804887Schin 					goto epat;
10814887Schin 				continue;
10824887Schin 			case S_EQ:
1083*8462SApril.Chin@Sun.COM 				assignment = lp->assignok;
10844887Schin 				/* FALL THRU */
10854887Schin 			case S_COLON:
10864887Schin 				if(assignment)
10874887Schin 				{
10884887Schin 					if((c=fcget())=='~')
10894887Schin 						wordflags |= ARG_MAC;
10904887Schin 					else if(c!=LPAREN && assignment==SH_COMPASSIGN)
10914887Schin 						assignment = 0;
10924887Schin 					fcseek(-1);
10934887Schin 				}
10944887Schin 				break;
10954887Schin 			case S_LABEL:
1096*8462SApril.Chin@Sun.COM 				if(lp->lex.reservok && !lp->lex.incase)
10974887Schin 				{
10984887Schin 					c = fcget();
10994887Schin 					fcseek(-1);
11004887Schin 					if(state[c]==S_BREAK)
11014887Schin 					{
11024887Schin 						assignment = -1;
11034887Schin 						goto breakloop;
11044887Schin 					}
11054887Schin 				}
11064887Schin 				break;
11074887Schin 			case S_BRACT:
11084887Schin 				/* check for possible subscript */
1109*8462SApril.Chin@Sun.COM 				if((n=endchar(lp))==RBRACT || n==RPAREN ||
11104887Schin 					(mode==ST_BRACE) ||
1111*8462SApril.Chin@Sun.COM 					(oldmode(lp)==ST_NONE) ||
1112*8462SApril.Chin@Sun.COM 					(mode==ST_NAME && (lp->assignok||lp->lexd.level)))
11134887Schin 				{
1114*8462SApril.Chin@Sun.COM 					pushlevel(lp,RBRACT,mode);
11154887Schin 					wordflags |= ARG_QUOTED;
11164887Schin 					mode = ST_NESTED;
11174887Schin 					continue;
11184887Schin 				}
11194887Schin 				wordflags |= ARG_EXP;
11204887Schin 				break;
11214887Schin 			case S_BRACE:
11224887Schin 			{
11234887Schin 				int isfirst;
1124*8462SApril.Chin@Sun.COM 				if(lp->lexd.dolparen)
1125*8462SApril.Chin@Sun.COM 				{
1126*8462SApril.Chin@Sun.COM 					if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub))
1127*8462SApril.Chin@Sun.COM 					{
1128*8462SApril.Chin@Sun.COM 						fcgetc(n);
1129*8462SApril.Chin@Sun.COM 						if(n>0)
1130*8462SApril.Chin@Sun.COM 							fcseek(-1);
1131*8462SApril.Chin@Sun.COM 						else
1132*8462SApril.Chin@Sun.COM 							n = '\n';
1133*8462SApril.Chin@Sun.COM 						if(n==RBRACT || sh_lexstates[ST_NORM][n])
1134*8462SApril.Chin@Sun.COM 							return(lp->token=c);
1135*8462SApril.Chin@Sun.COM 					}
11364887Schin 					break;
1137*8462SApril.Chin@Sun.COM 				}
1138*8462SApril.Chin@Sun.COM 				else if(mode==ST_BEGIN)
1139*8462SApril.Chin@Sun.COM 				{
1140*8462SApril.Chin@Sun.COM 					if(lp->comsub && c==RBRACE)
1141*8462SApril.Chin@Sun.COM 						return(lp->token=c);
1142*8462SApril.Chin@Sun.COM 					goto do_reg;
1143*8462SApril.Chin@Sun.COM 				}
1144*8462SApril.Chin@Sun.COM 				isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1);
11454887Schin 				fcgetc(n);
11464887Schin 				/* check for {} */
11474887Schin 				if(c==LBRACE && n==RBRACE)
11484887Schin 					break;
11494887Schin 				if(n>0)
11504887Schin 					fcseek(-1);
1151*8462SApril.Chin@Sun.COM 				else if(lp->lex.reservok)
11524887Schin 					break;
11534887Schin 				/* check for reserved word { or } */
1154*8462SApril.Chin@Sun.COM 				if(lp->lex.reservok && state[n]==S_BREAK && isfirst)
11554887Schin 					break;
11564887Schin 				if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
1157*8462SApril.Chin@Sun.COM 					&& !lp->lex.incase && !lp->lex.intest
1158*8462SApril.Chin@Sun.COM 					&& !lp->lex.skipword)
11594887Schin 				{
11604887Schin 					wordflags |= ARG_EXP;
11614887Schin 				}
11624887Schin 				if(c==RBRACE && n==LPAREN)
11634887Schin 					goto epat;
11644887Schin 				break;
11654887Schin 			}
11664887Schin 			case S_PAT:
11674887Schin 				wordflags |= ARG_EXP;
11684887Schin 				/* FALL THRU */
11694887Schin 			case S_EPAT:
11704887Schin 			epat:
11714887Schin 				if(fcgetc(n)==LPAREN)
11724887Schin 				{
1173*8462SApril.Chin@Sun.COM 					if(lp->lex.incase==TEST_RE)
11744887Schin 					{
1175*8462SApril.Chin@Sun.COM 						lp->lex.incase++;
1176*8462SApril.Chin@Sun.COM 						pushlevel(lp,RPAREN,ST_NORM);
11774887Schin 						mode = ST_NESTED;
11784887Schin 					}
11794887Schin 					wordflags |= ARG_EXP;
1180*8462SApril.Chin@Sun.COM 					pushlevel(lp,RPAREN,mode);
11814887Schin 					mode = ST_NESTED;
11824887Schin 					continue;
11834887Schin 				}
11844887Schin 				if(n>0)
11854887Schin 					fcseek(-1);
11864887Schin 				if(n=='=' && c=='+' && mode==ST_NAME)
11874887Schin 					continue;
11884887Schin 				break;
11894887Schin 		}
1190*8462SApril.Chin@Sun.COM 		lp->comp_assign = 0;
11914887Schin 		if(mode==ST_NAME)
11924887Schin 			mode = ST_NORM;
11934887Schin 		else if(mode==ST_NONE)
11944887Schin 			return(0);
11954887Schin 	}
11964887Schin breakloop:
1197*8462SApril.Chin@Sun.COM 	if(lp->lexd.nocopy)
11984887Schin 	{
1199*8462SApril.Chin@Sun.COM 		lp->lexd.balance = 0;
1200*8462SApril.Chin@Sun.COM 		return(0);
1201*8462SApril.Chin@Sun.COM 	}
1202*8462SApril.Chin@Sun.COM 	if(lp->lexd.dolparen)
1203*8462SApril.Chin@Sun.COM 	{
1204*8462SApril.Chin@Sun.COM 		lp->lexd.balance = 0;
1205*8462SApril.Chin@Sun.COM 		if(lp->lexd.docword)
12064887Schin 			nested_here(lp);
1207*8462SApril.Chin@Sun.COM 		lp->lexd.message = (wordflags&ARG_MESSAGE);
1208*8462SApril.Chin@Sun.COM 		return(lp->token=0);
12094887Schin 	}
1210*8462SApril.Chin@Sun.COM 	if(!(state=lp->lexd.first))
12114887Schin 		state = fcfirst();
12124887Schin 	n = fcseek(0)-(char*)state;
1213*8462SApril.Chin@Sun.COM 	if(!lp->arg)
1214*8462SApril.Chin@Sun.COM 		lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
12154887Schin 	if(n>0)
1216*8462SApril.Chin@Sun.COM 		sfwrite(stkp,state,n);
12174887Schin 	/* add balancing character if necessary */
1218*8462SApril.Chin@Sun.COM 	if(lp->lexd.balance)
12194887Schin 	{
1220*8462SApril.Chin@Sun.COM 		sfputc(stkp,lp->lexd.balance);
1221*8462SApril.Chin@Sun.COM 		lp->lexd.balance = 0;
12224887Schin 	}
1223*8462SApril.Chin@Sun.COM 	sfputc(stkp,0);
1224*8462SApril.Chin@Sun.COM 	stkseek(stkp,stktell(stkp)-1);
1225*8462SApril.Chin@Sun.COM 	state = stkptr(stkp,ARGVAL);
1226*8462SApril.Chin@Sun.COM 	n = stktell(stkp)-ARGVAL;
1227*8462SApril.Chin@Sun.COM 	lp->lexd.first=0;
12284887Schin 	if(n==1)
12294887Schin 	{
12304887Schin 		/* check for numbered redirection */
12314887Schin 		n = state[0];
12324887Schin 		if((c=='<' || c=='>') && isadigit(n))
12334887Schin 		{
1234*8462SApril.Chin@Sun.COM 			c = sh_lex(lp);
1235*8462SApril.Chin@Sun.COM 			lp->digits = (n-'0');
12364887Schin 			return(c);
12374887Schin 		}
12384887Schin 		if(n==LBRACT)
12394887Schin 			c = 0;
1240*8462SApril.Chin@Sun.COM 		else if(n==RBRACE && lp->comsub)
1241*8462SApril.Chin@Sun.COM 			return(lp->token=n);
12424887Schin 		else if(n=='~')
12434887Schin 			c = ARG_MAC;
12444887Schin 		else
12454887Schin 			c = (wordflags&ARG_EXP);
12464887Schin 		n = 1;
12474887Schin 	}
1248*8462SApril.Chin@Sun.COM 	else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
12494887Schin 	{
12504887Schin 		if(!strchr(state,','))
12514887Schin 		{
1252*8462SApril.Chin@Sun.COM 			stkseek(stkp,stktell(stkp)-1);
1253*8462SApril.Chin@Sun.COM 			lp->arg = (struct argnod*)stkfreeze(stkp,1);
1254*8462SApril.Chin@Sun.COM 			return(lp->token=IOVNAME);
12554887Schin 		}
12564887Schin 		c = wordflags;
12574887Schin 	}
12584887Schin 	else
12594887Schin 		c = wordflags;
12604887Schin 	if(assignment<0)
12614887Schin 	{
1262*8462SApril.Chin@Sun.COM 		stkseek(stkp,stktell(stkp)-1);
1263*8462SApril.Chin@Sun.COM 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
1264*8462SApril.Chin@Sun.COM 		lp->lex.reservok = 1;
1265*8462SApril.Chin@Sun.COM 		return(lp->token=LABLSYM);
12664887Schin 	}
1267*8462SApril.Chin@Sun.COM 	if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE)
12684887Schin 		c &= ~ARG_EXP;
12694887Schin 	if((c&ARG_EXP) && (c&ARG_QUOTED))
12704887Schin 		c |= ARG_MAC;
12714887Schin 	if(mode==ST_NONE)
12724887Schin 	{
12734887Schin 		/* eliminate trailing )) */
1274*8462SApril.Chin@Sun.COM 		stkseek(stkp,stktell(stkp)-2);
12754887Schin 	}
12764887Schin 	if(c&ARG_MESSAGE)
12774887Schin 	{
12784887Schin 		if(sh_isoption(SH_DICTIONARY))
1279*8462SApril.Chin@Sun.COM 			lp->arg = sh_endword(shp,2);
12804887Schin 		if(!sh_isoption(SH_NOEXEC))
12814887Schin 		{
1282*8462SApril.Chin@Sun.COM 			lp->arg = sh_endword(shp,1);
12834887Schin 			c &= ~ARG_MESSAGE;
12844887Schin 		}
12854887Schin 	}
1286*8462SApril.Chin@Sun.COM 	if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lp->lexd.warn && !lp->lexd.docword))
12874887Schin 	{
1288*8462SApril.Chin@Sun.COM 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
1289*8462SApril.Chin@Sun.COM 		lp->arg->argflag = (c?c:ARG_RAW);
12904887Schin 	}
12914887Schin 	else if(mode==ST_NONE)
1292*8462SApril.Chin@Sun.COM 		lp->arg = sh_endword(shp,-1);
12934887Schin 	else
1294*8462SApril.Chin@Sun.COM 		lp->arg = sh_endword(shp,0);
1295*8462SApril.Chin@Sun.COM 	state = lp->arg->argval;
1296*8462SApril.Chin@Sun.COM 	lp->comp_assign = assignment;
12974887Schin 	if(assignment)
1298*8462SApril.Chin@Sun.COM 		lp->arg->argflag |= ARG_ASSIGN;
1299*8462SApril.Chin@Sun.COM 	else if(!lp->lex.skipword)
1300*8462SApril.Chin@Sun.COM 		lp->assignok = 0;
1301*8462SApril.Chin@Sun.COM 	lp->arg->argchn.cp = 0;
1302*8462SApril.Chin@Sun.COM 	lp->arg->argnxt.ap = 0;
13034887Schin 	if(mode==ST_NONE)
1304*8462SApril.Chin@Sun.COM 		return(lp->token=EXPRSYM);
1305*8462SApril.Chin@Sun.COM 	if(lp->lex.intest)
13064887Schin 	{
1307*8462SApril.Chin@Sun.COM 		if(lp->lex.testop1)
13084887Schin 		{
1309*8462SApril.Chin@Sun.COM 			lp->lex.testop1 = 0;
13104887Schin 			if(n==2 && state[0]=='-' && state[2]==0 &&
13114887Schin 				strchr(test_opchars,state[1]))
13124887Schin 			{
1313*8462SApril.Chin@Sun.COM 				if(lp->lexd.warn && state[1]=='a')
13144887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
1315*8462SApril.Chin@Sun.COM 				lp->digits = state[1];
1316*8462SApril.Chin@Sun.COM 				lp->token = TESTUNOP;
13174887Schin 			}
13184887Schin 			else if(n==1 && state[0]=='!' && state[1]==0)
13194887Schin 			{
1320*8462SApril.Chin@Sun.COM 				lp->lex.testop1 = 1;
1321*8462SApril.Chin@Sun.COM 				lp->token = '!';
13224887Schin 			}
13234887Schin 			else
13244887Schin 			{
1325*8462SApril.Chin@Sun.COM 				lp->lex.testop2 = 1;
1326*8462SApril.Chin@Sun.COM 				lp->token = 0;
13274887Schin 			}
1328*8462SApril.Chin@Sun.COM 			return(lp->token);
13294887Schin 		}
1330*8462SApril.Chin@Sun.COM 		lp->lex.incase = 0;
13314887Schin 		c = sh_lookup(state,shtab_testops);
13324887Schin 		switch(c)
13334887Schin 		{
13344887Schin 		case TEST_END:
1335*8462SApril.Chin@Sun.COM 			lp->lex.testop2 = lp->lex.intest = 0;
1336*8462SApril.Chin@Sun.COM 			lp->lex.reservok = 1;
1337*8462SApril.Chin@Sun.COM 			lp->token = ETESTSYM;
1338*8462SApril.Chin@Sun.COM 			return(lp->token);
13394887Schin 
13404887Schin 		case TEST_SEQ:
1341*8462SApril.Chin@Sun.COM 			if(lp->lexd.warn && state[1]==0)
13424887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
13434887Schin 			/* FALL THRU */
13444887Schin 		default:
1345*8462SApril.Chin@Sun.COM 			if(lp->lex.testop2)
13464887Schin 			{
1347*8462SApril.Chin@Sun.COM 				if(lp->lexd.warn && (c&TEST_ARITH))
13484887Schin 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
13494887Schin 				if(c&TEST_PATTERN)
1350*8462SApril.Chin@Sun.COM 					lp->lex.incase = 1;
13514887Schin 				else if(c==TEST_REP)
1352*8462SApril.Chin@Sun.COM 					lp->lex.incase = TEST_RE;
1353*8462SApril.Chin@Sun.COM 				lp->lex.testop2 = 0;
1354*8462SApril.Chin@Sun.COM 				lp->digits = c;
1355*8462SApril.Chin@Sun.COM 				lp->token = TESTBINOP;
1356*8462SApril.Chin@Sun.COM 				return(lp->token);
13574887Schin 			}
13584887Schin 
13594887Schin 		case TEST_OR: case TEST_AND:
13604887Schin 		case 0:
1361*8462SApril.Chin@Sun.COM 			return(lp->token=0);
13624887Schin 		}
13634887Schin 	}
1364*8462SApril.Chin@Sun.COM 	if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2)
13654887Schin 	{
13664887Schin 		/* check for {, }, ! */
13674887Schin 		c = state[0];
13684887Schin 		if(n==1 && (c=='{' || c=='}' || c=='!'))
13694887Schin 		{
1370*8462SApril.Chin@Sun.COM 			if(lp->lexd.warn && c=='{' && lp->lex.incase==2)
13714887Schin 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
1372*8462SApril.Chin@Sun.COM 			if(lp->lex.incase==1 && c==RBRACE)
1373*8462SApril.Chin@Sun.COM 				lp->lex.incase = 0;
1374*8462SApril.Chin@Sun.COM 			return(lp->token=c);
13754887Schin 		}
1376*8462SApril.Chin@Sun.COM 		else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT)
13774887Schin 		{
1378*8462SApril.Chin@Sun.COM 			lp->lex.intest = lp->lex.testop1 = 1;
1379*8462SApril.Chin@Sun.COM 			lp->lex.testop2 = lp->lex.reservok = 0;
1380*8462SApril.Chin@Sun.COM 			return(lp->token=BTESTSYM);
13814887Schin 		}
13824887Schin 	}
13834887Schin 	c = 0;
1384*8462SApril.Chin@Sun.COM 	if(!lp->lex.skipword)
13854887Schin 	{
1386*8462SApril.Chin@Sun.COM 		if(n>1 && lp->lex.reservok==1 && mode==ST_NAME &&
13874887Schin 			(c=sh_lookup(state,shtab_reserved)))
13884887Schin 		{
1389*8462SApril.Chin@Sun.COM 			if(lp->lex.incase)
13904887Schin 			{
1391*8462SApril.Chin@Sun.COM 				if(lp->lex.incase >1)
1392*8462SApril.Chin@Sun.COM 					lp->lex.incase = 1;
13934887Schin 				else if(c==ESACSYM)
1394*8462SApril.Chin@Sun.COM 					lp->lex.incase = 0;
13954887Schin 				else
13964887Schin 					c = 0;
13974887Schin 			}
13984887Schin 			else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
13994887Schin 			{
1400*8462SApril.Chin@Sun.COM 				lp->lex.skipword = 1;
1401*8462SApril.Chin@Sun.COM 				lp->lex.incase = 2*(c==CASESYM);
14024887Schin 			}
14034887Schin 			else
1404*8462SApril.Chin@Sun.COM 				lp->lex.skipword = 0;
14054887Schin 			if(c==INSYM)
1406*8462SApril.Chin@Sun.COM 				lp->lex.reservok = 0;
14074887Schin 			else if(c==TIMESYM)
14084887Schin 			{
14094887Schin 				/* yech - POSIX requires time -p */
14104887Schin 				while(fcgetc(n)==' ' || n=='\t');
14114887Schin 				if(n>0)
14124887Schin 					fcseek(-1);
14134887Schin 				if(n=='-')
14144887Schin 					c=0;
14154887Schin 			}
1416*8462SApril.Chin@Sun.COM 			return(lp->token=c);
14174887Schin 		}
1418*8462SApril.Chin@Sun.COM 		if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok))
14194887Schin 		{
14204887Schin 			/* check for aliases */
14214887Schin 			Namval_t* np;
1422*8462SApril.Chin@Sun.COM 			if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN &&
14234887Schin 				(np=nv_search(state,shp->alias_tree,HASH_SCOPE))
14244887Schin 				&& !nv_isattr(np,NV_NOEXPAND)
14254887Schin #if KSHELL
14264887Schin 				&& (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
14274887Schin #endif /* KSHELL */
14284887Schin 				&& (state=nv_getval(np)))
14294887Schin 			{
14304887Schin 				setupalias(lp,state,np);
14314887Schin 				nv_onattr(np,NV_NOEXPAND);
1432*8462SApril.Chin@Sun.COM 				lp->lex.reservok = 1;
1433*8462SApril.Chin@Sun.COM 				lp->assignok |= lp->lex.reservok;
1434*8462SApril.Chin@Sun.COM 				return(sh_lex(lp));
14354887Schin 			}
14364887Schin 		}
1437*8462SApril.Chin@Sun.COM 		lp->lex.reservok = 0;
14384887Schin 	}
1439*8462SApril.Chin@Sun.COM 	lp->lex.skipword = lp->lexd.docword = 0;
1440*8462SApril.Chin@Sun.COM 	return(lp->token=c);
14414887Schin }
14424887Schin 
14434887Schin /*
14444887Schin  * read to end of command substitution
14454887Schin  */
1446*8462SApril.Chin@Sun.COM static int comsub(register Lex_t *lp, int endtok)
14474887Schin {
14484887Schin 	register int	n,c,count=1;
1449*8462SApril.Chin@Sun.COM 	register int	line=lp->sh->inlineno;
14504887Schin 	char word[5];
1451*8462SApril.Chin@Sun.COM 	int messages=0, assignok=lp->assignok, csub;
14524887Schin 	struct lexstate	save;
1453*8462SApril.Chin@Sun.COM 	save = lp->lex;
1454*8462SApril.Chin@Sun.COM 	csub = lp->comsub;
1455*8462SApril.Chin@Sun.COM 	sh_lexopen(lp,lp->sh,1);
1456*8462SApril.Chin@Sun.COM 	lp->lexd.dolparen++;
1457*8462SApril.Chin@Sun.COM 	lp->lex.incase=0;
1458*8462SApril.Chin@Sun.COM 	pushlevel(lp,0,0);
1459*8462SApril.Chin@Sun.COM 	lp->comsub = (endtok==LBRACE);
1460*8462SApril.Chin@Sun.COM 	if(sh_lex(lp)==endtok)
14614887Schin 	{
14624887Schin 		while(1)
14634887Schin 		{
14644887Schin 			/* look for case and esac */
14654887Schin 			n=0;
14664887Schin 			while(1)
14674887Schin 			{
14684887Schin 				fcgetc(c);
14694887Schin 				/* skip leading white space */
14704887Schin 				if(n==0 && !sh_lexstates[ST_BEGIN][c])
14714887Schin 					continue;
14724887Schin 				if(n==4)
14734887Schin 					break;
14744887Schin 				if(sh_lexstates[ST_NAME][c])
14754887Schin 					goto skip;
14764887Schin 				word[n++] = c;
14774887Schin 			}
14784887Schin 			if(sh_lexstates[ST_NAME][c]==S_BREAK)
14794887Schin 			{
14804887Schin 				if(memcmp(word,"case",4)==0)
1481*8462SApril.Chin@Sun.COM 					lp->lex.incase=1;
14824887Schin 				else if(memcmp(word,"esac",4)==0)
1483*8462SApril.Chin@Sun.COM 					lp->lex.incase=0;
14844887Schin 			}
14854887Schin 		skip:
14864887Schin 			if(c && (c!='#' || n==0))
14874887Schin 				fcseek(-1);
1488*8462SApril.Chin@Sun.COM 			if(c==RBRACE && lp->lex.incase)
1489*8462SApril.Chin@Sun.COM 				lp->lex.incase=0;
1490*8462SApril.Chin@Sun.COM 			switch(c=sh_lex(lp))
14914887Schin 			{
1492*8462SApril.Chin@Sun.COM 			    case LBRACE:
1493*8462SApril.Chin@Sun.COM 				if(endtok==LBRACE && !lp->lex.incase)
1494*8462SApril.Chin@Sun.COM 				{
1495*8462SApril.Chin@Sun.COM 					lp->comsub = 0;
1496*8462SApril.Chin@Sun.COM 					count++;
1497*8462SApril.Chin@Sun.COM 				}
1498*8462SApril.Chin@Sun.COM 				break;
1499*8462SApril.Chin@Sun.COM 			    case RBRACE:
1500*8462SApril.Chin@Sun.COM 			    rbrace:
1501*8462SApril.Chin@Sun.COM 				if(endtok==LBRACE && --count<=0)
1502*8462SApril.Chin@Sun.COM 					goto done;
1503*8462SApril.Chin@Sun.COM 				lp->comsub = (count==1);
1504*8462SApril.Chin@Sun.COM 				break;
1505*8462SApril.Chin@Sun.COM 			    case IPROCSYM:	case OPROCSYM:
1506*8462SApril.Chin@Sun.COM 			    case LPAREN:
1507*8462SApril.Chin@Sun.COM 				if(endtok==LPAREN && !lp->lex.incase)
15084887Schin 					count++;
15094887Schin 				break;
15104887Schin 			    case RPAREN:
1511*8462SApril.Chin@Sun.COM 				if(lp->lex.incase)
1512*8462SApril.Chin@Sun.COM 					lp->lex.incase=0;
1513*8462SApril.Chin@Sun.COM 				else if(endtok==LPAREN && --count<=0)
15144887Schin 					goto done;
15154887Schin 				break;
15164887Schin 			    case EOFSYM:
1517*8462SApril.Chin@Sun.COM 				lp->lastline = line;
1518*8462SApril.Chin@Sun.COM 				lp->lasttok = endtok;
1519*8462SApril.Chin@Sun.COM 				sh_syntax(lp);
15204887Schin 			    case IOSEEKSYM:
15214887Schin 				if(fcgetc(c)!='#' && c>0)
15224887Schin 					fcseek(-1);
15234887Schin 				break;
15244887Schin 			    case IODOCSYM:
1525*8462SApril.Chin@Sun.COM 				sh_lex(lp);
15264887Schin 				break;
15274887Schin 			    case 0:
1528*8462SApril.Chin@Sun.COM 				lp->lex.reservok = 0;
1529*8462SApril.Chin@Sun.COM 				messages |= lp->lexd.message;
1530*8462SApril.Chin@Sun.COM 				break;
1531*8462SApril.Chin@Sun.COM 			    case ';':
1532*8462SApril.Chin@Sun.COM 				fcgetc(c);
1533*8462SApril.Chin@Sun.COM 				if(c==RBRACE && endtok==LBRACE)
1534*8462SApril.Chin@Sun.COM 					goto rbrace;
1535*8462SApril.Chin@Sun.COM 				if(c>0)
1536*8462SApril.Chin@Sun.COM 					fcseek(-1);
1537*8462SApril.Chin@Sun.COM 				/* fall through*/
1538*8462SApril.Chin@Sun.COM 			    default:
1539*8462SApril.Chin@Sun.COM 				lp->lex.reservok = 1;
15404887Schin 			}
15414887Schin 		}
15424887Schin 	}
15434887Schin done:
1544*8462SApril.Chin@Sun.COM 	poplevel(lp);
1545*8462SApril.Chin@Sun.COM 	lp->comsub = csub;
1546*8462SApril.Chin@Sun.COM 	lp->lastline = line;
1547*8462SApril.Chin@Sun.COM 	lp->lexd.dolparen--;
1548*8462SApril.Chin@Sun.COM 	lp->lex = save;
1549*8462SApril.Chin@Sun.COM 	lp->assignok = (endchar(lp)==RBRACT?assignok:0);
15504887Schin 	return(messages);
15514887Schin }
15524887Schin 
15534887Schin /*
15544887Schin  * here-doc nested in $(...)
15554887Schin  * allocate ionode with delimiter filled in without disturbing stak
15564887Schin  */
15574887Schin static void nested_here(register Lex_t *lp)
15584887Schin {
1559*8462SApril.Chin@Sun.COM 	register struct ionod	*iop;
1560*8462SApril.Chin@Sun.COM 	register int		n,offset;
1561*8462SApril.Chin@Sun.COM 	struct argnod		*arg = lp->arg;
1562*8462SApril.Chin@Sun.COM 	Stk_t			*stkp = lp->sh->stk;
1563*8462SApril.Chin@Sun.COM 	char			*base;
1564*8462SApril.Chin@Sun.COM 	if(offset=stktell(stkp))
1565*8462SApril.Chin@Sun.COM 		base = stkfreeze(stkp,0);
1566*8462SApril.Chin@Sun.COM 	n = fcseek(0)-lp->lexd.docend;
15674887Schin 	iop = newof(0,struct ionod,1,n+ARGVAL);
1568*8462SApril.Chin@Sun.COM 	iop->iolst = lp->heredoc;
1569*8462SApril.Chin@Sun.COM 	stkseek(stkp,ARGVAL);
1570*8462SApril.Chin@Sun.COM 	sfwrite(stkp,lp->lexd.docend,n);
1571*8462SApril.Chin@Sun.COM 	lp->arg = sh_endword(lp->sh,0);
15724887Schin 	iop->ioname = (char*)(iop+1);
1573*8462SApril.Chin@Sun.COM 	strcpy(iop->ioname,lp->arg->argval);
15744887Schin 	iop->iofile = (IODOC|IORAW);
1575*8462SApril.Chin@Sun.COM 	if(lp->lexd.docword>1)
15764887Schin 		iop->iofile |= IOSTRIP;
1577*8462SApril.Chin@Sun.COM 	lp->heredoc = iop;
1578*8462SApril.Chin@Sun.COM 	lp->arg = arg;
1579*8462SApril.Chin@Sun.COM 	lp->lexd.docword = 0;
15804887Schin 	if(offset)
1581*8462SApril.Chin@Sun.COM 		stkset(stkp,base,offset);
15824887Schin 	else
1583*8462SApril.Chin@Sun.COM 		stkseek(stkp,0);
15844887Schin }
15854887Schin 
15864887Schin /*
15874887Schin  * skip to <close> character
15884887Schin  * if <copy> is non,zero, then the characters are copied to the stack
15894887Schin  * <state> is the initial lexical state
15904887Schin  */
1591*8462SApril.Chin@Sun.COM void sh_lexskip(Lex_t *lp,int close, register int copy, int  state)
15924887Schin {
15934887Schin 	register char	*cp;
1594*8462SApril.Chin@Sun.COM 	lp->lexd.nest = close;
1595*8462SApril.Chin@Sun.COM 	lp->lexd.lex_state = state;
1596*8462SApril.Chin@Sun.COM 	lp->lexd.noarg = 1;
15974887Schin 	if(copy)
1598*8462SApril.Chin@Sun.COM 		fcnotify(lex_advance,lp);
15994887Schin 	else
1600*8462SApril.Chin@Sun.COM 		lp->lexd.nocopy++;
1601*8462SApril.Chin@Sun.COM 	sh_lex(lp);
1602*8462SApril.Chin@Sun.COM 	lp->lexd.noarg = 0;
16034887Schin 	if(copy)
16044887Schin 	{
1605*8462SApril.Chin@Sun.COM 		fcnotify(0,lp);
1606*8462SApril.Chin@Sun.COM 		if(!(cp=lp->lexd.first))
16074887Schin 			cp = fcfirst();
16084887Schin 		if((copy = fcseek(0)-cp) > 0)
1609*8462SApril.Chin@Sun.COM 			sfwrite(lp->sh->stk,cp,copy);
16104887Schin 	}
16114887Schin 	else
1612*8462SApril.Chin@Sun.COM 		lp->lexd.nocopy--;
16134887Schin }
16144887Schin 
16154887Schin #if SHOPT_CRNL
16164887Schin     ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
16174887Schin     {
16184887Schin 	const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
16194887Schin 	int m=0,k;
16204887Schin 	while(next = (const char*)memchr(next,'\r',ep-next))
16214887Schin 		if(*++next=='\n')
16224887Schin 		{
16234887Schin 			if(k=next-cp-1)
16244887Schin 			{
16254887Schin 				if((k=sfwrite(sp,cp,k)) < 0)
16264887Schin 					return(m>0?m:-1);
16274887Schin 				m += k;
16284887Schin 			}
16294887Schin 			cp = next;
16304887Schin 		}
16314887Schin 	if((k=sfwrite(sp,cp,ep-cp)) < 0)
16324887Schin 		return(m>0?m:-1);
16334887Schin 	return(m+k);
16344887Schin     }
16354887Schin #   define sfwrite	_sfwrite
16364887Schin #endif /* SHOPT_CRNL */
16374887Schin 
16384887Schin /*
16394887Schin  * read in here-document from script
16404887Schin  * quoted here documents, and here-documents without special chars are
16414887Schin  * noted with the IOQUOTE flag
16424887Schin  * returns 1 for complete here-doc, 0 for EOF
16434887Schin  */
16444887Schin 
16454887Schin static int here_copy(Lex_t *lp,register struct ionod *iop)
16464887Schin {
16474887Schin 	register const char	*state;
16484887Schin 	register int		c,n;
16494887Schin 	register char		*bufp,*cp;
1650*8462SApril.Chin@Sun.COM 	register Sfio_t		*sp=lp->sh->heredocs, *funlog;
16514887Schin 	int			stripcol=0,stripflg, nsave, special=0;
1652*8462SApril.Chin@Sun.COM 	if(funlog=lp->sh->funlog)
16534887Schin 	{
16544887Schin 		if(fcfill()>0)
16554887Schin 			fcseek(-1);
1656*8462SApril.Chin@Sun.COM 		lp->sh->funlog = 0;
16574887Schin 	}
16584887Schin 	if(iop->iolst)
16594887Schin 		here_copy(lp,iop->iolst);
16604887Schin 	iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
16614887Schin 	iop->iosize = 0;
16624887Schin 	iop->iodelim=iop->ioname;
16634887Schin 	/* check for and strip quoted characters in delimiter string */
16644887Schin 	if(stripflg=iop->iofile&IOSTRIP)
16654887Schin 	{
16664887Schin 		while(*iop->iodelim=='\t')
16674887Schin 			iop->iodelim++;
16684887Schin 		/* skip over leading tabs in document */
16694887Schin 		if(iop->iofile&IOLSEEK)
16704887Schin 		{
16714887Schin 			iop->iofile &= ~IOLSEEK;
16724887Schin 			while(fcgetc(c)=='\t' || c==' ')
16734887Schin 			{
16744887Schin 				if(c==' ')
16754887Schin 					stripcol++;
16764887Schin 				else
16774887Schin 					stripcol += 8 - stripcol%8;
16784887Schin 			}
16794887Schin 		}
16804887Schin 		else
16814887Schin 			while(fcgetc(c)=='\t');
16824887Schin 		if(c>0)
16834887Schin 			fcseek(-1);
16844887Schin 	}
16854887Schin 	if(iop->iofile&IOQUOTE)
16864887Schin 		state = sh_lexstates[ST_LIT];
16874887Schin 	else
16884887Schin 		state = sh_lexstates[ST_QUOTE];
16894887Schin 	bufp = fcseek(0);
16904887Schin 	n = S_NL;
16914887Schin 	while(1)
16924887Schin 	{
16934887Schin 		if(n!=S_NL)
16944887Schin 		{
16954887Schin 			/* skip over regular characters */
16964887Schin 			while((n=STATE(state,c))==0);
16974887Schin 		}
16984887Schin 		if(n==S_EOF || !(c=fcget()))
16994887Schin 		{
1700*8462SApril.Chin@Sun.COM 			if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp))
17014887Schin 			{
17024887Schin 				if(n==S_ESC)
17034887Schin 					c--;
17044887Schin 				if((c=sfwrite(sp,bufp,c))>0)
17054887Schin 					iop->iosize += c;
17064887Schin 			}
1707*8462SApril.Chin@Sun.COM 			if((c=lexfill(lp))<=0)
17084887Schin 				break;
17094887Schin 			if(n==S_ESC)
17104887Schin 			{
17114887Schin #if SHOPT_CRNL
17124887Schin 				if(c=='\r' && (c=fcget())!=NL)
17134887Schin 					fcseek(-1);
17144887Schin #endif /* SHOPT_CRNL */
17154887Schin 				if(c==NL)
17164887Schin 					fcseek(1);
17174887Schin 				else
17184887Schin 					sfputc(sp,'\\');
17194887Schin 			}
17204887Schin 			bufp = fcseek(-1);
17214887Schin 		}
17224887Schin 		else
17234887Schin 			fcseek(-1);
17244887Schin 		switch(n)
17254887Schin 		{
17264887Schin 		    case S_NL:
1727*8462SApril.Chin@Sun.COM 			lp->sh->inlineno++;
17284887Schin 			if((stripcol && c==' ') || (stripflg && c=='\t'))
17294887Schin 			{
1730*8462SApril.Chin@Sun.COM 				if(!lp->lexd.dolparen)
17314887Schin 				{
17324887Schin 					/* write out line */
17334887Schin 					n = fcseek(0)-bufp;
17344887Schin 					if((n=sfwrite(sp,bufp,n))>0)
17354887Schin 						iop->iosize += n;
17364887Schin 				}
17374887Schin 				/* skip over tabs */
17384887Schin 				if(stripcol)
17394887Schin 				{
17404887Schin 					int col=0;
17414887Schin 					do
17424887Schin 					{
17434887Schin 						fcgetc(c);
17444887Schin 						if(c==' ')
17454887Schin 							col++;
17464887Schin 						else
17474887Schin 							col += 8 - col%8;
17484887Schin 						if(col>stripcol)
17494887Schin 							break;
17504887Schin 					}
17514887Schin 					while (c==' ' || c=='\t');
17524887Schin 				}
17534887Schin 				else while(c=='\t')
17544887Schin 					fcgetc(c);
17554887Schin 				if(c<=0)
17564887Schin 					goto done;
17574887Schin 				bufp = fcseek(-1);
17584887Schin 			}
17594887Schin 			if(c!=iop->iodelim[0])
17604887Schin 				break;
17614887Schin 			cp = fcseek(0);
17624887Schin 			nsave = n = 0;
17634887Schin 			while(1)
17644887Schin 			{
17654887Schin 				if(!(c=fcget()))
17664887Schin 				{
1767*8462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen && (c=cp-bufp))
17684887Schin 					{
17694887Schin 						if((c=sfwrite(sp,cp=bufp,c))>0)
17704887Schin 							iop->iosize+=c;
17714887Schin 					}
17724887Schin 					nsave = n;
1773*8462SApril.Chin@Sun.COM 					if((c=lexfill(lp))<=0)
17744887Schin 					{
17754887Schin 						c = iop->iodelim[n]==0;
17764887Schin 						goto done;
17774887Schin 					}
17784887Schin 				}
17794887Schin #if SHOPT_CRNL
17804887Schin 				if(c=='\r' && (c=fcget())!=NL)
17814887Schin 				{
17824887Schin 					if(c)
17834887Schin 						fcseek(-1);
17844887Schin 					c='\r';
17854887Schin 				}
17864887Schin #endif /* SHOPT_CRNL */
17874887Schin 				if(c==NL)
1788*8462SApril.Chin@Sun.COM 					lp->sh->inlineno++;
17894887Schin 				if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
17904887Schin 				{
1791*8462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen && (n=cp-bufp))
17924887Schin 					{
17934887Schin 						if((n=sfwrite(sp,bufp,n))>0)
17944887Schin 							iop->iosize += n;
17954887Schin 					}
1796*8462SApril.Chin@Sun.COM 					lp->sh->inlineno--;
17974887Schin 					if(c==RPAREN)
17984887Schin 						fcseek(-1);
17994887Schin 					goto done;
18004887Schin 				}
18014887Schin 				if(iop->iodelim[n++]!=c)
18024887Schin 				{
18034887Schin 					/*
18044887Schin 					 * The match for delimiter failed.
18054887Schin 					 * nsave>0 only when a buffer boundary
18064887Schin 					 * was crossed while checking the
18074887Schin 					 * delimiter
18084887Schin 					 */
1809*8462SApril.Chin@Sun.COM 					if(!lp->lexd.dolparen && nsave>0)
18104887Schin 					{
18114887Schin 						if((n=sfwrite(sp,bufp,nsave))>0)
18124887Schin 							iop->iosize += n;
18134887Schin 						bufp = fcfirst();
18144887Schin 					}
18154887Schin 					if(c==NL)
18164887Schin 						fcseek(-1);
18174887Schin 					break;
18184887Schin 				}
18194887Schin 			}
18204887Schin 			break;
18214887Schin 		    case S_ESC:
18224887Schin 			n=1;
18234887Schin #if SHOPT_CRNL
18244887Schin 			if(c=='\r')
18254887Schin 			{
18264887Schin 				fcseek(1);
18274887Schin 				if(c=fcget())
18284887Schin 					fcseek(-1);
18294887Schin 				if(c==NL)
18304887Schin 					n=2;
18314887Schin 				else
18324887Schin 				{
18334887Schin 					special++;
18344887Schin 					break;
18354887Schin 				}
18364887Schin 			}
18374887Schin #endif /* SHOPT_CRNL */
18384887Schin 			if(c==NL)
18394887Schin 			{
18404887Schin 				/* new-line joining */
1841*8462SApril.Chin@Sun.COM 				lp->sh->inlineno++;
1842*8462SApril.Chin@Sun.COM 				if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>0)
18434887Schin 				{
18444887Schin 					if((n=sfwrite(sp,bufp,n))>0)
18454887Schin 						iop->iosize += n;
18464887Schin 					bufp = fcseek(0)+1;
18474887Schin 				}
18484887Schin 			}
18494887Schin 			else
18504887Schin 				special++;
18514887Schin 			fcget();
18524887Schin 			break;
18534887Schin 
18544887Schin 		    case S_GRAVE:
18554887Schin 		    case S_DOL:
18564887Schin 			special++;
18574887Schin 			break;
18584887Schin 		}
18594887Schin 		n=0;
18604887Schin 	}
18614887Schin done:
1862*8462SApril.Chin@Sun.COM 	lp->sh->funlog = funlog;
1863*8462SApril.Chin@Sun.COM 	if(lp->lexd.dolparen)
18644887Schin 		free((void*)iop);
18654887Schin 	else if(!special)
18664887Schin 		iop->iofile |= IOQUOTE;
18674887Schin 	return(c);
18684887Schin }
18694887Schin 
18704887Schin /*
18714887Schin  * generates string for given token
18724887Schin  */
18734887Schin static char	*fmttoken(Lex_t *lp, register int sym, char *tok)
18744887Schin {
18754887Schin 	if(sym < 0)
18764887Schin 		return((char*)sh_translate(e_lexzerobyte));
18774887Schin 	if(sym==0)
1878*8462SApril.Chin@Sun.COM 		return(lp->arg?lp->arg->argval:"?");
1879*8462SApril.Chin@Sun.COM 	if(lp->lex.intest && lp->arg && *lp->arg->argval)
1880*8462SApril.Chin@Sun.COM 		return(lp->arg->argval);
18814887Schin 	if(sym&SYMRES)
18824887Schin 	{
18834887Schin 		register const Shtable_t *tp=shtab_reserved;
18844887Schin 		while(tp->sh_number && tp->sh_number!=sym)
18854887Schin 			tp++;
18864887Schin 		return((char*)tp->sh_name);
18874887Schin 	}
18884887Schin 	if(sym==EOFSYM)
18894887Schin 		return((char*)sh_translate(e_endoffile));
18904887Schin 	if(sym==NL)
18914887Schin 		return((char*)sh_translate(e_newline));
18924887Schin 	tok[0] = sym;
18934887Schin 	if(sym&SYMREP)
18944887Schin 		tok[1] = sym;
18954887Schin 	else
18964887Schin 	{
18974887Schin 		switch(sym&SYMMASK)
18984887Schin 		{
18994887Schin 			case SYMAMP:
19004887Schin 				sym = '&';
19014887Schin 				break;
19024887Schin 			case SYMPIPE:
19034887Schin 				sym = '|';
19044887Schin 				break;
19054887Schin 			case SYMGT:
19064887Schin 				sym = '>';
19074887Schin 				break;
19084887Schin 			case SYMLPAR:
19094887Schin 				sym = LPAREN;
19104887Schin 				break;
19114887Schin 			case SYMSHARP:
19124887Schin 				sym = '#';
19134887Schin 				break;
1914*8462SApril.Chin@Sun.COM 			case SYMSEMI:
1915*8462SApril.Chin@Sun.COM 				sym = ';';
1916*8462SApril.Chin@Sun.COM 				break;
19174887Schin 			default:
19184887Schin 				sym = 0;
19194887Schin 		}
19204887Schin 		tok[1] = sym;
19214887Schin 	}
19224887Schin 	tok[2] = 0;
19234887Schin 	return(tok);
19244887Schin }
19254887Schin 
19264887Schin /*
19274887Schin  * print a bad syntax message
19284887Schin  */
19294887Schin 
1930*8462SApril.Chin@Sun.COM void	sh_syntax(Lex_t *lp)
19314887Schin {
1932*8462SApril.Chin@Sun.COM 	register Shell_t *shp = lp->sh;
19334887Schin 	register const char *cp = sh_translate(e_unexpected);
19344887Schin 	register char *tokstr;
1935*8462SApril.Chin@Sun.COM 	register int tok = lp->token;
19364887Schin 	char tokbuf[3];
19374887Schin 	Sfio_t *sp;
1938*8462SApril.Chin@Sun.COM 	if((tok==EOFSYM) && lp->lasttok)
19394887Schin 	{
1940*8462SApril.Chin@Sun.COM 		tok = lp->lasttok;
19414887Schin 		cp = sh_translate(e_unmatched);
19424887Schin 	}
19434887Schin 	else
1944*8462SApril.Chin@Sun.COM 		lp->lastline = shp->inlineno;
19454887Schin 	tokstr = fmttoken(lp,tok,tokbuf);
19464887Schin 	if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
19474887Schin 	{
19484887Schin 		/* clear out any pending input */
19494887Schin 		register Sfio_t *top;
19504887Schin 		while(fcget()>0);
19514887Schin 		fcclose();
19524887Schin 		while(top=sfstack(sp,SF_POPSTACK))
19534887Schin 			sfclose(top);
19544887Schin 	}
19554887Schin 	else
19564887Schin 		fcclose();
1957*8462SApril.Chin@Sun.COM 	shp->inlineno = lp->inlineno;
1958*8462SApril.Chin@Sun.COM 	shp->st.firstline = lp->firstline;
19594887Schin #if KSHELL
19604887Schin 	if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
19614887Schin #else
19624887Schin 	if(shp->inlineno!=1)
19634887Schin #endif
1964*8462SApril.Chin@Sun.COM 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
19654887Schin 	else
19664887Schin 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
19674887Schin }
19684887Schin 
1969*8462SApril.Chin@Sun.COM static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
19704887Schin {
19714887Schin 	register char *ep;
1972*8462SApril.Chin@Sun.COM 	register int offset = stktell(stkp);
1973*8462SApril.Chin@Sun.COM 	register int left = offset-(sp-stkptr(stkp,0));
19744887Schin 	register int shift = (dp+1-sp);
19754887Schin 	offset += shift;
1976*8462SApril.Chin@Sun.COM 	stkseek(stkp,offset);
1977*8462SApril.Chin@Sun.COM 	sp = stkptr(stkp,offset);
19784887Schin 	ep = sp - shift;
19794887Schin 	while(left--)
19804887Schin 		*--sp = *--ep;
19814887Schin 	return(sp);
19824887Schin }
19834887Schin 
19844887Schin /*
19854887Schin  * Assumes that current word is unfrozen on top of the stak
19864887Schin  * If <mode> is zero, gets rid of quoting and consider argument as string
19874887Schin  *    and returns pointer to frozen arg
19884887Schin  * If mode==1, just replace $"..." strings with international strings
19894887Schin  *    The result is left on the stak
19904887Schin  * If mode==2, the each $"" string is printed on standard output
19914887Schin  */
1992*8462SApril.Chin@Sun.COM struct argnod *sh_endword(Shell_t *shp,int mode)
19934887Schin {
19944887Schin 	register const char *state = sh_lexstates[ST_NESTED];
19954887Schin 	register int n;
19964887Schin 	register char *sp,*dp;
19974887Schin 	register int inquote=0, inlit=0; /* set within quoted strings */
19984887Schin 	struct argnod* argp=0;
19994887Schin 	char	*ep=0, *xp=0;
20004887Schin 	int bracket=0;
2001*8462SApril.Chin@Sun.COM 	Stk_t		*stkp=shp->stk;
2002*8462SApril.Chin@Sun.COM 	sfputc(stkp,0);
2003*8462SApril.Chin@Sun.COM 	sp =  stkptr(stkp,ARGVAL);
20044887Schin #if SHOPT_MULTIBYTE
20054887Schin 	if(mbwide())
20064887Schin 	{
20074887Schin 		do
20084887Schin 		{
20094887Schin 			int len;
20104887Schin 			switch(len = mbsize(sp))
20114887Schin 			{
20124887Schin 			    case -1:	/* illegal multi-byte char */
20134887Schin 			    case 0:
20144887Schin 			    case 1:
20154887Schin 				n=state[*sp++];
20164887Schin 				break;
20174887Schin 			    default:
20184887Schin 				/*
20194887Schin 				 * None of the state tables contain
20204887Schin 				 * entries for multibyte characters,
20214887Schin 				 * however, they should be treated
20224887Schin 				 * the same as any other alph
20234887Schin 				 * character.  Therefore, we'll use
20244887Schin 				 * the state of the 'a' character.
20254887Schin 				 */
20264887Schin 				n=state['a'];
20274887Schin 				sp += len;
20284887Schin 			}
20294887Schin 		}
20304887Schin 		while(n == 0);
20314887Schin 	}
20324887Schin 	else
20334887Schin #endif /* SHOPT_MULTIBYTE */
20344887Schin 	while((n=state[*sp++])==0);
20354887Schin 	dp = sp;
20364887Schin 	if(mode<0)
20374887Schin 		inquote = 1;
20384887Schin 	while(1)
20394887Schin 	{
20404887Schin 		switch(n)
20414887Schin 		{
20424887Schin 		    case S_EOF:
2043*8462SApril.Chin@Sun.COM 			stkseek(stkp,dp-stkptr(stkp,0));
20444887Schin 			if(mode<=0)
20454887Schin 			{
2046*8462SApril.Chin@Sun.COM 				argp = (struct argnod*)stkfreeze(stkp,0);
20474887Schin 				argp->argflag = ARG_RAW|ARG_QUOTED;
20484887Schin 			}
20494887Schin 			return(argp);
20504887Schin 		    case S_LIT:
20514887Schin 			if(!(inquote&1))
20524887Schin 			{
20534887Schin 				inlit = !inlit;
20544887Schin 				if(mode==0 || (mode<0 && bracket))
20554887Schin 				{
20564887Schin 					dp--;
20574887Schin 					if(ep)
20584887Schin 					{
20594887Schin 						*dp = 0;
20604887Schin 						dp = ep+stresc(ep);
20614887Schin 					}
20624887Schin 					ep = 0;
20634887Schin 				}
20644887Schin 			}
20654887Schin 			break;
20664887Schin 		    case S_QUOTE:
20674887Schin 			if(mode<0 && !bracket)
20684887Schin 				break;
20694887Schin 			if(!inlit)
20704887Schin 			{
20714887Schin 				if(mode<=0)
20724887Schin 					dp--;
20734887Schin 				inquote = inquote^1;
20744887Schin 				if(ep)
20754887Schin 				{
20764887Schin 					char *msg;
20774887Schin 					if(mode==2)
20784887Schin 					{
20794887Schin 						sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
20804887Schin 						ep = 0;
20814887Schin 						break;
20824887Schin 					}
20834887Schin 					*--dp = 0;
20844887Schin #if ERROR_VERSION >= 20000317L
20854887Schin 					msg = ERROR_translate(0,error_info.id,0,ep);
20864887Schin #else
20874887Schin #   if ERROR_VERSION >= 20000101L
20884887Schin 					msg = ERROR_translate(error_info.id,ep);
20894887Schin #   else
20904887Schin 					msg = ERROR_translate(ep,2);
20914887Schin #   endif
20924887Schin #endif
20934887Schin 					n = strlen(msg);
20944887Schin 					dp = ep+n;
20954887Schin 					if(sp-dp <= 1)
20964887Schin 					{
2097*8462SApril.Chin@Sun.COM 						sp = stack_shift(stkp,sp,dp);
20984887Schin 						dp = sp-1;
20994887Schin 						ep = dp-n;
21004887Schin 					}
21014887Schin 					memmove(ep,msg,n);
21024887Schin 					*dp++ = '"';
21034887Schin 				}
21044887Schin 				ep = 0;
21054887Schin 			}
21064887Schin 			break;
21074887Schin 		    case S_DOL:	/* check for $'...'  and $"..." */
21084887Schin 			if(inlit)
21094887Schin 				break;
21104887Schin 			if(*sp==LPAREN || *sp==LBRACE)
21114887Schin 			{
21124887Schin 				inquote <<= 1;
21134887Schin 				break;
21144887Schin 			}
21154887Schin 			if(inquote&1)
21164887Schin 				break;
21174887Schin 			if(*sp=='\'' || *sp=='"')
21184887Schin 			{
21194887Schin 				if(*sp=='"')
21204887Schin 					inquote |= 1;
21214887Schin 				else
21224887Schin 					inlit = 1;
21234887Schin 				sp++;
21244887Schin 				if((mode==0||(mode<0&&bracket)) || (inquote&1))
21254887Schin 				{
21264887Schin 					if(mode==2)
21274887Schin 						ep = dp++;
21284887Schin 					else if(mode==1)
21294887Schin 						(ep=dp)[-1] = '"';
21304887Schin 					else
21314887Schin 						ep = --dp;
21324887Schin 				}
21334887Schin 			}
21344887Schin 			break;
21354887Schin 		    case S_ESC:
21364887Schin #if SHOPT_CRNL
21374887Schin 			if(*sp=='\r' && sp[1]=='\n')
21384887Schin 				sp++;
21394887Schin #endif /* SHOPT_CRNL */
21404887Schin 			if(inlit || mode>0)
21414887Schin 			{
21424887Schin 				if(mode<0)
21434887Schin 				{
21444887Schin 					if(dp>=sp)
21454887Schin 					{
2146*8462SApril.Chin@Sun.COM 						sp = stack_shift(stkp,sp,dp+1);
21474887Schin 						dp = sp-2;
21484887Schin 					}
21494887Schin 					*dp++ = '\\';
21504887Schin 				}
21514887Schin 				if(ep)
21524887Schin 					*dp++ = *sp++;
21534887Schin 				break;
21544887Schin 			}
21554887Schin 			n = *sp;
21564887Schin #if SHOPT_DOS
21574887Schin 			if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
21584887Schin 				break;
21594887Schin #endif /* SHOPT_DOS */
21604887Schin 			if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
21614887Schin 			{
21624887Schin 				if(n=='\n')
21634887Schin 					dp--;
21644887Schin 				else
21654887Schin 					dp[-1] = n;
21664887Schin 				sp++;
21674887Schin 			}
21684887Schin 			break;
21694887Schin 		    case S_POP:
21704887Schin 			if(sp[-1]!=RBRACT)
21714887Schin 				break;
21724887Schin 			if(!inlit && !(inquote&1))
21734887Schin 			{
21744887Schin 				inquote >>= 1;
21754887Schin 				if(xp)
21764887Schin 					dp = sh_checkid(xp,dp);
21774887Schin 				xp = 0;
21784887Schin 				if(--bracket<=0 && mode<0)
21794887Schin 					inquote = 1;
21804887Schin 			}
21814887Schin 			else if((inlit||inquote) && mode<0)
21824887Schin 			{
21834887Schin 				dp[-1] = '\\';
21844887Schin 				if(dp>=sp)
21854887Schin 				{
2186*8462SApril.Chin@Sun.COM 					sp = stack_shift(stkp,sp,dp);
21874887Schin 					dp = sp-1;
21884887Schin 				}
21894887Schin 				*dp++ = ']';
21904887Schin 			}
21914887Schin 			break;
21924887Schin 		    case S_BRACT:
21934887Schin 			if(dp[-2]=='.')
21944887Schin 				xp = dp;
21954887Schin 			if(mode<0)
21964887Schin 			{
21974887Schin 				if(inlit || (bracket&&inquote))
21984887Schin 				{
21994887Schin 					dp[-1] = '\\';
22004887Schin 					if(dp>=sp)
22014887Schin 					{
2202*8462SApril.Chin@Sun.COM 						sp = stack_shift(stkp,sp,dp);
22034887Schin 						dp = sp-1;
22044887Schin 					}
22054887Schin 					*dp++ = '[';
22064887Schin 				}
22074887Schin 				else if(bracket++==0)
22084887Schin 					inquote = 0;
22094887Schin 			}
22104887Schin 			break;
22114887Schin 		}
22124887Schin #if SHOPT_MULTIBYTE
22134887Schin 		if(mbwide())
22144887Schin 		{
22154887Schin 			do
22164887Schin 			{
22174887Schin 				int len;
22184887Schin 				switch(len = mbsize(sp))
22194887Schin 				{
22204887Schin 				    case -1: /* illegal multi-byte char */
22214887Schin 				    case 0:
22224887Schin 				    case 1:
22234887Schin 					n=state[*dp++ = *sp++];
22244887Schin 					break;
22254887Schin 				    default:
22264887Schin 					/*
22274887Schin 					 * None of the state tables contain
22284887Schin 					 * entries for multibyte characters,
22294887Schin 					 * however, they should be treated
22304887Schin 					 * the same as any other alph
22314887Schin 					 * character.  Therefore, we'll use
22324887Schin 					 * the state of the 'a' character.
22334887Schin 					 */
22344887Schin 					while(len--)
22354887Schin 						*dp++ = *sp++;
22364887Schin 					n=state['a'];
22374887Schin 				}
22384887Schin 			}
22394887Schin 			while(n == 0);
22404887Schin 		}
22414887Schin 		else
22424887Schin #endif /* SHOPT_MULTIBYTE */
22434887Schin 		while((n=state[*dp++ = *sp++])==0);
22444887Schin 	}
22454887Schin }
22464887Schin 
22474887Schin struct alias
22484887Schin {
22494887Schin 	Sfdisc_t	disc;
22504887Schin 	Namval_t	*np;
22514887Schin 	int		nextc;
22524887Schin 	int		line;
22534887Schin 	char		buf[2];
22544887Schin 	Lex_t		*lp;
22554887Schin };
22564887Schin 
22574887Schin /*
22584887Schin  * This code gets called whenever an end of string is found with alias
22594887Schin  */
22604887Schin 
22614887Schin #ifndef SF_ATEXIT
22624887Schin #   define SF_ATEXIT	0
22634887Schin #endif
22644887Schin /*
22654887Schin  * This code gets called whenever an end of string is found with alias
22664887Schin  */
22674887Schin #ifdef SF_BUFCONST
22684887Schin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
22694887Schin #else
22704887Schin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
22714887Schin #endif
22724887Schin {
22734887Schin 	register struct alias *ap = (struct alias*)handle;
22744887Schin 	register Namval_t *np;
22754887Schin 	register Lex_t	*lp;
22764887Schin 	if(type==0 || type==SF_ATEXIT || !ap)
22774887Schin 		return(0);
22784887Schin 	lp = ap->lp;
22794887Schin 	np = ap->np;
22804887Schin 	if(type!=SF_READ)
22814887Schin 	{
22824887Schin 		if(type==SF_CLOSING)
22834887Schin 		{
22844887Schin 			register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
22854887Schin 			if(dp!=handle)
22864887Schin 				sfdisc(iop,dp);
22874887Schin 		}
22884887Schin 		else if(type==SF_FINAL)
22894887Schin 			free((void*)ap);
22904887Schin 		goto done;
22914887Schin 	}
22924887Schin 	if(ap->nextc)
22934887Schin 	{
22944887Schin 		/* if last character is a blank, then next work can be alias */
22954887Schin 		register int c = fcpeek(-1);
22964887Schin 		if(isblank(c))
2297*8462SApril.Chin@Sun.COM 			lp->aliasok = 1;
22984887Schin 		*ap->buf = ap->nextc;
22994887Schin 		ap->nextc = 0;
23004887Schin 		sfsetbuf(iop,ap->buf,1);
23014887Schin 		return(1);
23024887Schin 	}
23034887Schin done:
23044887Schin 	if(np)
23054887Schin 		nv_offattr(np,NV_NOEXPAND);
23064887Schin 	return(0);
23074887Schin }
23084887Schin 
23094887Schin 
23104887Schin static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
23114887Schin {
23124887Schin 	register Sfio_t *iop, *base;
23134887Schin 	struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
23144887Schin 	ap->disc = alias_disc;
23154887Schin 	ap->lp = lp;
23164887Schin 	ap->buf[1] = 0;
23174887Schin 	if(ap->np = np)
23184887Schin 	{
23194887Schin #if SHOPT_KIA
2320*8462SApril.Chin@Sun.COM 		if(lp->kiafile)
23214887Schin 		{
23224887Schin 			unsigned long r;
2323*8462SApril.Chin@Sun.COM 			r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
2324*8462SApril.Chin@Sun.COM 			sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
23254887Schin 		}
23264887Schin #endif /* SHOPT_KIA */
23274887Schin 		if((ap->nextc=fcget())==0)
23284887Schin 			ap->nextc = ' ';
23294887Schin 	}
23304887Schin 	else
23314887Schin 		ap->nextc = 0;
23324887Schin 	iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
23334887Schin 	sfdisc(iop, &ap->disc);
2334*8462SApril.Chin@Sun.COM 	lp->lexd.nocopy++;
23354887Schin 	if(!(base=fcfile()))
23364887Schin 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
23374887Schin 	fcclose();
23384887Schin 	sfstack(base,iop);
23394887Schin 	fcfopen(base);
2340*8462SApril.Chin@Sun.COM 	lp->lexd.nocopy--;
23414887Schin }
23424887Schin 
23434887Schin /*
23444887Schin  * grow storage stack for nested constructs by STACK_ARRAY
23454887Schin  */
23464887Schin static int stack_grow(Lex_t *lp)
23474887Schin {
2348*8462SApril.Chin@Sun.COM 	lp->lexd.lex_max += STACK_ARRAY;
2349*8462SApril.Chin@Sun.COM 	if(lp->lexd.lex_match)
2350*8462SApril.Chin@Sun.COM 		lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
23514887Schin 	else
2352*8462SApril.Chin@Sun.COM 		lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
2353*8462SApril.Chin@Sun.COM 	return(lp->lexd.lex_match!=0);
23544887Schin }
23554887Schin 
2356