xref: /onnv-gate/usr/src/lib/libshell/common/sh/streval.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.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 /*
234887Schin  * D. G. Korn
244887Schin  * AT&T Labs
254887Schin  *
264887Schin  * arithmetic expression evaluator
274887Schin  *
284887Schin  * this version compiles the expression onto a stack
294887Schin  *	 and has a separate executor
304887Schin  */
314887Schin 
324887Schin #include	"streval.h"
334887Schin #include	<ctype.h>
344887Schin #include	<error.h>
354887Schin #include	<stak.h>
364887Schin #include	"FEATURE/externs"
37*12068SRoger.Faulkner@Oracle.COM #include	"defs.h"	/* for sh.decomma */
384887Schin 
394887Schin #ifndef ERROR_dictionary
404887Schin #   define ERROR_dictionary(s)	(s)
414887Schin #endif
424887Schin #ifndef SH_DICT
434887Schin #   define SH_DICT	"libshell"
444887Schin #endif
454887Schin 
464887Schin #define MAXLEVEL	9
474887Schin #define SMALL_STACK	12
484887Schin 
494887Schin /*
504887Schin  * The following are used with tokenbits() macro
514887Schin  */
524887Schin #define T_OP		0x3f		/* mask for operator number */
534887Schin #define T_BINARY	0x40		/* binary operators */
544887Schin #define T_NOFLOAT	0x80		/* non floating point operator */
554887Schin #define A_LVALUE	(2*MAXPREC+2)
564887Schin 
574887Schin #define pow2size(x)		((x)<=2?2:(x)<=4?4:(x)<=8?8:(x)<=16?16:(x)<=32?32:64)
584887Schin #define round(x,size)		(((x)+(size)-1)&~((size)-1))
594887Schin #define stakpush(v,val,type)	((((v)->offset=round(staktell(),pow2size(sizeof(type)))),\
604887Schin 				stakseek((v)->offset+sizeof(type)), \
614887Schin 				*((type*)stakptr((v)->offset)) = (val)),(v)->offset)
624887Schin #define roundptr(ep,cp,type)	(((unsigned char*)(ep))+round(cp-((unsigned char*)(ep)),pow2size(sizeof(type))))
634887Schin 
644887Schin static int level;
654887Schin 
664887Schin struct vars				/* vars stacked per invocation */
674887Schin {
684887Schin 	const char	*expr;		/* current expression */
694887Schin 	const char	*nextchr;	/* next char in current expression */
704887Schin 	const char	*errchr; 	/* next char after error	*/
714887Schin 	const char	*errstr;	/* error string			*/
724887Schin 	struct lval	errmsg;	 	/* error message text		*/
734887Schin 	int		offset;		/* offset for pushchr macro	*/
744887Schin 	int		staksize;	/* current stack size needed	*/
754887Schin 	int		stakmaxsize;	/* maximum stack size needed	*/
764887Schin 	unsigned char	paren;	 	/* parenthesis level		*/
774887Schin 	char		infun;	/* incremented by comma inside function	*/
784887Schin 	int		emode;
794887Schin 	Sfdouble_t	(*convert)(const char**,struct lval*,int,Sfdouble_t);
804887Schin };
814887Schin 
8210898Sroland.mainz@nrubsig.org typedef Sfdouble_t (*Math_f)(Sfdouble_t,...);
8310898Sroland.mainz@nrubsig.org typedef Sfdouble_t (*Math_1f_f)(Sfdouble_t);
8410898Sroland.mainz@nrubsig.org typedef int	   (*Math_1i_f)(Sfdouble_t);
8510898Sroland.mainz@nrubsig.org typedef Sfdouble_t (*Math_2f_f)(Sfdouble_t,Sfdouble_t);
8610898Sroland.mainz@nrubsig.org typedef int        (*Math_2i_f)(Sfdouble_t,Sfdouble_t);
8710898Sroland.mainz@nrubsig.org typedef Sfdouble_t (*Math_3f_f)(Sfdouble_t,Sfdouble_t,Sfdouble_t);
8810898Sroland.mainz@nrubsig.org typedef int        (*Math_3i_f)(Sfdouble_t,Sfdouble_t,Sfdouble_t);
894887Schin 
904887Schin #define getchr(vp)	(*(vp)->nextchr++)
914887Schin #define peekchr(vp)	(*(vp)->nextchr)
924887Schin #define ungetchr(vp)	((vp)->nextchr--)
934887Schin 
944887Schin #if ('a'==97)	/* ASCII encodings */
954887Schin #   define getop(c)	(((c) >= sizeof(strval_states))? \
964887Schin 				((c)=='|'?A_OR:((c)=='^'?A_XOR:((c)=='~'?A_TILDE:A_REG))):\
974887Schin 				strval_states[(c)])
984887Schin #else
994887Schin #   define getop(c)	(isdigit(c)?A_DIG:((c==' '||c=='\t'||c=='\n'||c=='"')?0: \
1004887Schin 			(c=='<'?A_LT:(c=='>'?A_GT:(c=='='?A_ASSIGN: \
1014887Schin 			(c=='+'?A_PLUS:(c=='-'?A_MINUS:(c=='*'?A_TIMES: \
1024887Schin 			(c=='/'?A_DIV:(c=='%'?A_MOD:(c==','?A_COMMA: \
1034887Schin 			(c=='&'?A_AND:(c=='!'?A_NOT:(c=='('?A_LPAR: \
1044887Schin 			(c==')'?A_RPAR:(c==0?A_EOF:(c==':'?A_COLON: \
1054887Schin 			(c=='?'?A_QUEST:(c=='|'?A_OR:(c=='^'?A_XOR: \
1064887Schin 			(c=='\''?A_LIT: \
1074887Schin 			(c=='.'?A_DOT:(c=='~'?A_TILDE:A_REG)))))))))))))))))))))))
1084887Schin #endif
1094887Schin 
1104887Schin #define seterror(v,msg)		_seterror(v,ERROR_dictionary(msg))
1114887Schin #define ERROR(vp,msg)		return(seterror((vp),msg))
1124887Schin 
1134887Schin /*
1144887Schin  * set error message string and return(0)
1154887Schin  */
_seterror(struct vars * vp,const char * msg)1164887Schin static int _seterror(struct vars *vp,const char *msg)
1174887Schin {
1184887Schin 	if(!vp->errmsg.value)
1194887Schin 		vp->errmsg.value = (char*)msg;
1204887Schin 	vp->errchr = vp->nextchr;
1214887Schin 	vp->nextchr = "";
1224887Schin 	level = 0;
1234887Schin 	return(0);
1244887Schin }
1254887Schin 
1264887Schin 
arith_error(const char * message,const char * expr,int mode)1274887Schin static void arith_error(const char *message,const char *expr, int mode)
1284887Schin {
1294887Schin         level = 0;
1304887Schin 	mode = (mode&3)!=0;
1314887Schin         errormsg(SH_DICT,ERROR_exit(mode),message,expr);
1324887Schin }
1334887Schin 
1344887Schin #if _ast_no_um2fm
U2F(Sfulong_t u)1354887Schin static Sfdouble_t U2F(Sfulong_t u)
1364887Schin {
1374887Schin 	Sflong_t	s = u;
1384887Schin 	Sfdouble_t	f;
1394887Schin 
1404887Schin 	if (s >= 0)
1414887Schin 		return s;
1424887Schin 	s = u / 2;
1434887Schin 	f = s;
1444887Schin 	f *= 2;
1454887Schin 	if (u & 1)
1464887Schin 		f++;
1474887Schin 	return f;
1484887Schin }
1494887Schin #else
1504887Schin #define U2F(x)		x
1514887Schin #endif
1524887Schin 
arith_exec(Arith_t * ep)1534887Schin Sfdouble_t	arith_exec(Arith_t *ep)
1544887Schin {
1554887Schin 	register Sfdouble_t num=0,*dp,*sp;
1564887Schin 	register unsigned char *cp = ep->code;
1574887Schin 	register int c,type=0;
1584887Schin 	register char *tp;
1594887Schin 	Sfdouble_t small_stack[SMALL_STACK+1];
1604887Schin 	const char *ptr = "";
16110898Sroland.mainz@nrubsig.org 	Math_f fun;
1624887Schin 	struct lval node;
1634887Schin 	node.emode = ep->emode;
1644887Schin 	node.expr = ep->expr;
1654887Schin 	node.elen = ep->elen;
166*12068SRoger.Faulkner@Oracle.COM 	node.value = 0;
167*12068SRoger.Faulkner@Oracle.COM 	node.nosub = 0;
1684887Schin 	if(level++ >=MAXLEVEL)
1694887Schin 	{
1704887Schin 		arith_error(e_recursive,ep->expr,ep->emode);
1714887Schin 		return(0);
1724887Schin 	}
1734887Schin 	if(ep->staksize < SMALL_STACK)
1744887Schin 		sp = small_stack;
1754887Schin 	else
1764887Schin 		sp = (Sfdouble_t*)stakalloc(ep->staksize*(sizeof(Sfdouble_t)+1));
1774887Schin 	tp = (char*)(sp+ep->staksize);
1784887Schin 	tp--,sp--;
1794887Schin 	while(c = *cp++)
1804887Schin 	{
1814887Schin 		if(c&T_NOFLOAT)
1824887Schin 		{
1834887Schin 			if(type==1 || ((c&T_BINARY) && (c&T_OP)!=A_MOD  && tp[-1]==1))
1844887Schin 				arith_error(e_incompatible,ep->expr,ep->emode);
1854887Schin 		}
1864887Schin 		switch(c&T_OP)
1874887Schin 		{
1884887Schin 		    case A_JMP: case A_JMPZ: case A_JMPNZ:
1894887Schin 			c &= T_OP;
1904887Schin 			cp = roundptr(ep,cp,short);
1914887Schin 			if((c==A_JMPZ && num) || (c==A_JMPNZ &&!num))
1924887Schin 				cp += sizeof(short);
1934887Schin 			else
1944887Schin 				cp = (unsigned char*)ep + *((short*)cp);
1954887Schin 			continue;
1964887Schin 		    case A_NOTNOT:
1974887Schin 			num = (num!=0);
1984887Schin 			type=0;
1994887Schin 			break;
2004887Schin 		    case A_PLUSPLUS:
201*12068SRoger.Faulkner@Oracle.COM 			node.nosub = 1;
2024887Schin 			(*ep->fun)(&ptr,&node,ASSIGN,num+1);
2034887Schin 			break;
2044887Schin 		    case A_MINUSMINUS:
205*12068SRoger.Faulkner@Oracle.COM 			node.nosub = 1;
2064887Schin 			(*ep->fun)(&ptr,&node,ASSIGN,num-1);
2074887Schin 			break;
2084887Schin 		    case A_INCR:
2094887Schin 			num = num+1;
210*12068SRoger.Faulkner@Oracle.COM 			node.nosub = 1;
2114887Schin 			num = (*ep->fun)(&ptr,&node,ASSIGN,num);
2124887Schin 			break;
2134887Schin 		    case A_DECR:
2144887Schin 			num = num-1;
215*12068SRoger.Faulkner@Oracle.COM 			node.nosub = 1;
2164887Schin 			num = (*ep->fun)(&ptr,&node,ASSIGN,num);
2174887Schin 			break;
2184887Schin 		    case A_SWAP:
2194887Schin 			num = sp[-1];
2204887Schin 			sp[-1] = *sp;
2214887Schin 			type = tp[-1];
2224887Schin 			tp[-1] = *tp;
2234887Schin 			break;
2244887Schin 		    case A_POP:
2254887Schin 			sp--;
2264887Schin 			continue;
2274887Schin 		    case A_PUSHV:
2284887Schin 			cp = roundptr(ep,cp,Sfdouble_t*);
2294887Schin 			dp = *((Sfdouble_t**)cp);
2304887Schin 			cp += sizeof(Sfdouble_t*);
2314887Schin 			c = *(short*)cp;
2324887Schin 			cp += sizeof(short);
2334887Schin 			node.value = (char*)dp;
2344887Schin 			node.flag = c;
2354887Schin 			node.isfloat=0;
2364887Schin 			node.level = level;
2374887Schin 			num = (*ep->fun)(&ptr,&node,VALUE,num);
2384887Schin 			if(node.value != (char*)dp)
2394887Schin 				arith_error(node.value,ptr,ep->emode);
2404887Schin 			*++sp = num;
2414887Schin 			type = node.isfloat;
2424887Schin 			if(num > LDBL_ULLONG_MAX || num < LDBL_LLONG_MIN)
2434887Schin 				type = 1;
2444887Schin 			else
2454887Schin 			{
2464887Schin 				Sfdouble_t d=num;
2474887Schin 				if(num > LDBL_LLONG_MAX && num <= LDBL_ULLONG_MAX)
2484887Schin 				{
2494887Schin 					type = 2;
2504887Schin 					d -= LDBL_LLONG_MAX;
2514887Schin 				}
2524887Schin 				if((Sflong_t)d!=d)
2534887Schin 					type = 1;
2544887Schin 			}
2554887Schin 			*++tp = type;
2564887Schin 			c = 0;
2574887Schin 			break;
258*12068SRoger.Faulkner@Oracle.COM 		    case A_ASSIGNOP:
259*12068SRoger.Faulkner@Oracle.COM 			node.nosub = 1;
2604887Schin 		    case A_STORE:
2614887Schin 			cp = roundptr(ep,cp,Sfdouble_t*);
2624887Schin 			dp = *((Sfdouble_t**)cp);
2634887Schin 			cp += sizeof(Sfdouble_t*);
2644887Schin 			c = *(short*)cp;
2654887Schin 			if(c<0)
2664887Schin 				c = 0;
2674887Schin 			cp += sizeof(short);
2684887Schin 			node.value = (char*)dp;
2694887Schin 			node.flag = c;
2704887Schin 			num = (*ep->fun)(&ptr,&node,ASSIGN,num);
27110898Sroland.mainz@nrubsig.org 			c=0;
2724887Schin 			break;
2734887Schin 		    case A_PUSHF:
27410898Sroland.mainz@nrubsig.org 			cp = roundptr(ep,cp,Math_f);
2754887Schin 			*++sp = (Sfdouble_t)(cp-ep->code);
27610898Sroland.mainz@nrubsig.org 			cp += sizeof(Math_f);
2774887Schin 			*++tp = *cp++;
2784887Schin 			continue;
2794887Schin 		    case A_PUSHN:
2804887Schin 			cp = roundptr(ep,cp,Sfdouble_t);
2814887Schin 			num = *((Sfdouble_t*)cp);
2824887Schin 			cp += sizeof(Sfdouble_t);
2834887Schin 			*++sp = num;
2844887Schin 			*++tp = type = *cp++;
2854887Schin 			break;
2864887Schin 		    case A_NOT:
2874887Schin 			type=0;
2884887Schin 			num = !num;
2894887Schin 			break;
2904887Schin 		    case A_UMINUS:
2914887Schin 			num = -num;
2924887Schin 			break;
2934887Schin 		    case A_TILDE:
2944887Schin 			num = ~((Sflong_t)(num));
2954887Schin 			break;
2964887Schin 		    case A_PLUS:
2974887Schin 			num += sp[-1];
2984887Schin 			break;
2994887Schin 		    case A_MINUS:
3004887Schin 			num = sp[-1] - num;
3014887Schin 			break;
3024887Schin 		    case A_TIMES:
3034887Schin 			num *= sp[-1];
3044887Schin 			break;
3054887Schin 		    case A_POW:
3064887Schin 			num = pow(sp[-1],num);
3074887Schin 			break;
3084887Schin 		    case A_MOD:
3094887Schin 			if(!(Sflong_t)num)
3104887Schin 				arith_error(e_divzero,ep->expr,ep->emode);
3114887Schin 			if(type==2 || tp[-1]==2)
3124887Schin 				num = U2F((Sfulong_t)(sp[-1]) % (Sfulong_t)(num));
3134887Schin 			else
3144887Schin 				num = (Sflong_t)(sp[-1]) % (Sflong_t)(num);
3154887Schin 			break;
3164887Schin 		    case A_DIV:
3174887Schin 			if(type==1 || tp[-1]==1)
3184887Schin 			{
3194887Schin 				num = sp[-1]/num;
3204887Schin 				type = 1;
3214887Schin 			}
3224887Schin 			else if((Sfulong_t)(num)==0)
3234887Schin 				arith_error(e_divzero,ep->expr,ep->emode);
3244887Schin 			else if(type==2 || tp[-1]==2)
3254887Schin 				num = U2F((Sfulong_t)(sp[-1]) / (Sfulong_t)(num));
3264887Schin 			else
3274887Schin 				num = (Sflong_t)(sp[-1]) / (Sflong_t)(num);
3284887Schin 			break;
3294887Schin 		    case A_LSHIFT:
3304887Schin 			if(tp[-1]==2)
3314887Schin 				num = U2F((Sfulong_t)(sp[-1]) << (long)(num));
3324887Schin 			else
3334887Schin 				num = (Sflong_t)(sp[-1]) << (long)(num);
3344887Schin 			break;
3354887Schin 		    case A_RSHIFT:
3364887Schin 			if(tp[-1]==2)
3374887Schin 				num = U2F((Sfulong_t)(sp[-1]) >> (long)(num));
3384887Schin 			else
3394887Schin 				num = (Sflong_t)(sp[-1]) >> (long)(num);
3404887Schin 			break;
3414887Schin 		    case A_XOR:
3424887Schin 			if(type==2 || tp[-1]==2)
3434887Schin 				num = U2F((Sfulong_t)(sp[-1]) ^ (Sfulong_t)(num));
3444887Schin 			else
3454887Schin 				num = (Sflong_t)(sp[-1]) ^ (Sflong_t)(num);
3464887Schin 			break;
3474887Schin 		    case A_OR:
3484887Schin 			if(type==2 || tp[-1]==2)
3494887Schin 				num = U2F((Sfulong_t)(sp[-1]) | (Sfulong_t)(num));
3504887Schin 			else
3514887Schin 				num = (Sflong_t)(sp[-1]) | (Sflong_t)(num);
3524887Schin 			break;
3534887Schin 		    case A_AND:
3544887Schin 			if(type==2 || tp[-1]==2)
3554887Schin 				num = U2F((Sfulong_t)(sp[-1]) & (Sfulong_t)(num));
3564887Schin 			else
3574887Schin 				num = (Sflong_t)(sp[-1]) & (Sflong_t)(num);
3584887Schin 			break;
3594887Schin 		    case A_EQ:
3604887Schin 			num = (sp[-1]==num);
3614887Schin 			type=0;
3624887Schin 			break;
3634887Schin 		    case A_NEQ:
3644887Schin 			num = (sp[-1]!=num);
3654887Schin 			type=0;
3664887Schin 			break;
3674887Schin 		    case A_LE:
3684887Schin 			num = (sp[-1]<=num);
3694887Schin 			type=0;
3704887Schin 			break;
3714887Schin 		    case A_GE:
3724887Schin 			num = (sp[-1]>=num);
3734887Schin 			type=0;
3744887Schin 			break;
3754887Schin 		    case A_GT:
3764887Schin 			num = (sp[-1]>num);
3774887Schin 			type=0;
3784887Schin 			break;
3794887Schin 		    case A_LT:
3804887Schin 			num = (sp[-1]<num);
3814887Schin 			type=0;
3824887Schin 			break;
38310898Sroland.mainz@nrubsig.org 		    case A_CALL1F:
3844887Schin 			sp--,tp--;
38510898Sroland.mainz@nrubsig.org 			fun = *((Math_f*)(ep->code+(int)(*sp)));
3864887Schin 			type = 0;
38710898Sroland.mainz@nrubsig.org 			num = (*((Math_1f_f)fun))(num);
3884887Schin 			break;
38910898Sroland.mainz@nrubsig.org 		    case A_CALL1I:
3904887Schin 			sp--,tp--;
39110898Sroland.mainz@nrubsig.org 			fun = *((Math_f*)(ep->code+(int)(*sp)));
3924887Schin 			type = *tp;
39310898Sroland.mainz@nrubsig.org 			num = (*((Math_1i_f)fun))(num);
3944887Schin 			break;
39510898Sroland.mainz@nrubsig.org 		    case A_CALL2F:
3964887Schin 			sp-=2,tp-=2;
39710898Sroland.mainz@nrubsig.org 			fun = *((Math_f*)(ep->code+(int)(*sp)));
39810898Sroland.mainz@nrubsig.org 			type = 0;
39910898Sroland.mainz@nrubsig.org 			num = (*((Math_2f_f)fun))(sp[1],num);
4004887Schin 			break;
40110898Sroland.mainz@nrubsig.org 		    case A_CALL2I:
40210898Sroland.mainz@nrubsig.org 			sp-=2,tp-=2;
40310898Sroland.mainz@nrubsig.org 			fun = *((Math_f*)(ep->code+(int)(*sp)));
40410898Sroland.mainz@nrubsig.org 			type = *tp;
40510898Sroland.mainz@nrubsig.org 			num = (*((Math_2i_f)fun))(sp[1],num);
40610898Sroland.mainz@nrubsig.org 			break;
40710898Sroland.mainz@nrubsig.org 		    case A_CALL3F:
4084887Schin 			sp-=3,tp-=3;
40910898Sroland.mainz@nrubsig.org 			fun = *((Math_f*)(ep->code+(int)(*sp)));
41010898Sroland.mainz@nrubsig.org 			type = 0;
41110898Sroland.mainz@nrubsig.org 			num = (*((Math_3f_f)fun))(sp[1],sp[2],num);
4124887Schin 			break;
4134887Schin 		}
4144887Schin 		if(c&T_BINARY)
4154887Schin 			sp--,tp--;
4164887Schin 		*sp = num;
4174887Schin 		*tp = type;
4184887Schin 	}
4194887Schin 	if(level>0)
4204887Schin 		level--;
4214887Schin 	return(num);
4224887Schin }
4234887Schin 
4244887Schin /*
4254887Schin  * This returns operator tokens or A_REG or A_NUM
4264887Schin  */
gettok(register struct vars * vp)4274887Schin static int gettok(register struct vars *vp)
4284887Schin {
4294887Schin 	register int c,op;
4304887Schin 	vp->errchr = vp->nextchr;
4314887Schin 	while(1)
4324887Schin 	{
4334887Schin 		c = getchr(vp);
4344887Schin 		switch(op=getop(c))
4354887Schin 		{
4364887Schin 		    case 0:
4374887Schin 			vp->errchr = vp->nextchr;
4384887Schin 			continue;
4394887Schin 		    case A_EOF:
4404887Schin 			vp->nextchr--;
4414887Schin 			break;
442*12068SRoger.Faulkner@Oracle.COM 		    case A_COMMA:
443*12068SRoger.Faulkner@Oracle.COM 			if(sh.decomma && (c=peekchr(vp))>='0' && c<='9')
4444887Schin 			{
445*12068SRoger.Faulkner@Oracle.COM 				op = A_DIG;
446*12068SRoger.Faulkner@Oracle.COM 		    		goto keep;
4474887Schin 			}
448*12068SRoger.Faulkner@Oracle.COM 			break;
449*12068SRoger.Faulkner@Oracle.COM 		    case A_DOT:
450*12068SRoger.Faulkner@Oracle.COM 			if((c=peekchr(vp))>='0' && c<='9')
451*12068SRoger.Faulkner@Oracle.COM 				op = A_DIG;
452*12068SRoger.Faulkner@Oracle.COM 			else
453*12068SRoger.Faulkner@Oracle.COM 				op = A_REG;
454*12068SRoger.Faulkner@Oracle.COM 			/*FALL THRU*/
455*12068SRoger.Faulkner@Oracle.COM 		    case A_DIG: case A_REG: case A_LIT:
456*12068SRoger.Faulkner@Oracle.COM 		    keep:
4574887Schin 			ungetchr(vp);
4584887Schin 			break;
4594887Schin 		    case A_QUEST:
4604887Schin 			if(peekchr(vp)==':')
4614887Schin 			{
4624887Schin 				getchr(vp);
4634887Schin 				op = A_QCOLON;
4644887Schin 			}
4654887Schin 			break;
4664887Schin 		    case A_LT:	case A_GT:
4674887Schin 			if(peekchr(vp)==c)
4684887Schin 			{
4694887Schin 				getchr(vp);
4704887Schin 				op -= 2;
4714887Schin 				break;
4724887Schin 			}
4734887Schin 			/* FALL THRU */
4744887Schin 		    case A_NOT:	case A_COLON:
4754887Schin 			c = '=';
4764887Schin 			/* FALL THRU */
4774887Schin 		    case A_ASSIGN:
4784887Schin 		    case A_TIMES:
4794887Schin 		    case A_PLUS:	case A_MINUS:
4804887Schin 		    case A_OR:	case A_AND:
4814887Schin 			if(peekchr(vp)==c)
4824887Schin 			{
4834887Schin 				getchr(vp);
4844887Schin 				op--;
4854887Schin 			}
4864887Schin 		}
4874887Schin 		return(op);
4884887Schin 	}
4894887Schin }
4904887Schin 
4914887Schin /*
4924887Schin  * evaluate a subexpression with precedence
4934887Schin  */
4944887Schin 
expr(register struct vars * vp,register int precedence)4954887Schin static int expr(register struct vars *vp,register int precedence)
4964887Schin {
4974887Schin 	register int	c, op;
4984887Schin 	int		invalid,wasop=0;
4994887Schin 	struct lval	lvalue,assignop;
5004887Schin 	const char	*pos;
501*12068SRoger.Faulkner@Oracle.COM 	Sfdouble_t	d;
5024887Schin 
5034887Schin 	lvalue.value = 0;
5044887Schin 	lvalue.fun = 0;
5054887Schin again:
5064887Schin 	op = gettok(vp);
5074887Schin 	c = 2*MAXPREC+1;
5084887Schin 	switch(op)
5094887Schin 	{
5104887Schin 	    case A_PLUS:
5114887Schin 		goto again;
5124887Schin 	    case A_EOF:
5138462SApril.Chin@Sun.COM 		if(precedence>2)
5144887Schin 			ERROR(vp,e_moretokens);
5154887Schin 		return(1);
5164887Schin 	    case A_MINUS:
5174887Schin 		op =  A_UMINUS;
5184887Schin 		goto common;
5194887Schin 	    case A_NOT:
5204887Schin 		goto common;
5214887Schin 	    case A_MINUSMINUS:
5224887Schin 		c = A_LVALUE;
5234887Schin 		op = A_DECR|T_NOFLOAT;
5244887Schin 		goto common;
5254887Schin 	    case A_PLUSPLUS:
5264887Schin 		c = A_LVALUE;
5274887Schin 		op = A_INCR|T_NOFLOAT;
5284887Schin 		/* FALL THRU */
5294887Schin 	    case A_TILDE:
5304887Schin 		op |= T_NOFLOAT;
5314887Schin 	    common:
5324887Schin 		if(!expr(vp,c))
5334887Schin 			return(0);
5344887Schin 		stakputc(op);
5354887Schin 		break;
5364887Schin 	    default:
5374887Schin 		vp->nextchr = vp->errchr;
5384887Schin 		wasop = 1;
5394887Schin 	}
5404887Schin 	invalid = wasop;
5414887Schin 	while(1)
5424887Schin 	{
5434887Schin 		assignop.value = 0;
5444887Schin 		op = gettok(vp);
5454887Schin 		if(op==A_DIG || op==A_REG || op==A_LIT)
5464887Schin 		{
5474887Schin 			if(!wasop)
5484887Schin 				ERROR(vp,e_synbad);
5494887Schin 			goto number;
5504887Schin 		}
5514887Schin 		if(wasop++ && op!=A_LPAR)
5524887Schin 			ERROR(vp,e_synbad);
5534887Schin 		/* check for assignment operation */
5544887Schin 		if(peekchr(vp)== '=' && !(strval_precedence[op]&NOASSIGN))
5554887Schin 		{
5564887Schin 			if((!lvalue.value || precedence > 3))
5574887Schin 				ERROR(vp,e_notlvalue);
5584887Schin 			if(precedence==3)
5594887Schin 				precedence = 2;
5604887Schin 			assignop = lvalue;
5614887Schin 			getchr(vp);
5624887Schin 			c = 3;
5634887Schin 		}
5644887Schin 		else
5654887Schin 		{
5664887Schin 			c = (strval_precedence[op]&PRECMASK);
5674887Schin 			if(c==MAXPREC || op==A_POW)
5684887Schin 				c++;
5694887Schin 			c *= 2;
5704887Schin 		}
5714887Schin 		/* from here on c is the new precedence level */
5724887Schin 		if(lvalue.value && (op!=A_ASSIGN))
5734887Schin 		{
5744887Schin 			if(vp->staksize++>=vp->stakmaxsize)
5754887Schin 				vp->stakmaxsize = vp->staksize;
5764887Schin 			stakputc(A_PUSHV);
5774887Schin 			stakpush(vp,lvalue.value,char*);
5784887Schin 			if(lvalue.flag<0)
5794887Schin 				lvalue.flag = 0;
5804887Schin 			stakpush(vp,lvalue.flag,short);
5814887Schin 			if(vp->nextchr==0)
5824887Schin 				ERROR(vp,e_badnum);
5834887Schin 			if(!(strval_precedence[op]&SEQPOINT))
5844887Schin 				lvalue.value = 0;
5854887Schin 			invalid = 0;
5864887Schin 		}
5874887Schin 		else if(precedence==A_LVALUE)
5884887Schin 			ERROR(vp,e_notlvalue);
5894887Schin 		if(invalid && op>A_ASSIGN)
5904887Schin 			ERROR(vp,e_synbad);
5914887Schin 		if(precedence >= c)
5924887Schin 			goto done;
5934887Schin 		if(strval_precedence[op]&RASSOC)
5944887Schin 			c--;
5954887Schin 		if((c < (2*MAXPREC+1)) && !(strval_precedence[op]&SEQPOINT))
5964887Schin 		{
5974887Schin 			wasop = 0;
5984887Schin 			if(!expr(vp,c))
5994887Schin 				return(0);
6004887Schin 		}
6014887Schin 		switch(op)
6024887Schin 		{
6034887Schin 		case A_RPAR:
6044887Schin 			if(!vp->paren)
6054887Schin 				ERROR(vp,e_paren);
6064887Schin 			if(invalid)
6074887Schin 				ERROR(vp,e_synbad);
6084887Schin 			goto done;
6094887Schin 
6104887Schin 		case A_COMMA:
6114887Schin 			wasop = 0;
6124887Schin 			if(vp->infun)
6134887Schin 				vp->infun++;
6144887Schin 			else
6154887Schin 			{
6164887Schin 				stakputc(A_POP);
6174887Schin 				vp->staksize--;
6184887Schin 			}
6194887Schin 			if(!expr(vp,c))
62010898Sroland.mainz@nrubsig.org 			{
621*12068SRoger.Faulkner@Oracle.COM 				stakseek(staktell()-1);
6224887Schin 				return(0);
62310898Sroland.mainz@nrubsig.org 			}
6244887Schin 			lvalue.value = 0;
6254887Schin 			break;
6264887Schin 
6274887Schin 		case A_LPAR:
6284887Schin 		{
6294887Schin 			int	infun = vp->infun;
6304887Schin 			Sfdouble_t (*fun)(Sfdouble_t,...);
6314887Schin 			int nargs = lvalue.nargs;
6324887Schin 			fun = lvalue.fun;
6334887Schin 			lvalue.fun = 0;
6344887Schin 			if(fun)
6354887Schin 			{
6364887Schin 				if(vp->staksize++>=vp->stakmaxsize)
6374887Schin 					vp->stakmaxsize = vp->staksize;
6384887Schin 				vp->infun=1;
6394887Schin 				stakputc(A_PUSHF);
64010898Sroland.mainz@nrubsig.org 				stakpush(vp,fun,Math_f);
6414887Schin 				stakputc(1);
6424887Schin 			}
6434887Schin 			else
6444887Schin 				vp->infun = 0;
6454887Schin 			if(!invalid)
6464887Schin 				ERROR(vp,e_synbad);
6474887Schin 			vp->paren++;
6484887Schin 			if(!expr(vp,1))
6494887Schin 				return(0);
6504887Schin 			vp->paren--;
6514887Schin 			if(fun)
6524887Schin 			{
65310898Sroland.mainz@nrubsig.org 				int  x= (nargs>7)?2:-1;
6544887Schin 				nargs &= 7;
6554887Schin 				if(vp->infun != nargs)
6564887Schin 					ERROR(vp,e_argcount);
6574887Schin 				if(vp->staksize+=nargs>=vp->stakmaxsize)
6584887Schin 					vp->stakmaxsize = vp->staksize+nargs;
65910898Sroland.mainz@nrubsig.org 				stakputc(A_CALL1F+nargs+x);
6604887Schin 				vp->staksize -= nargs;
6614887Schin 			}
6624887Schin 			vp->infun = infun;
6634887Schin 			if (gettok(vp) != A_RPAR)
6644887Schin 				ERROR(vp,e_paren);
6654887Schin 			wasop = 0;
6664887Schin 			break;
6674887Schin 		}
6684887Schin 
6694887Schin 		case A_PLUSPLUS:
6704887Schin 		case A_MINUSMINUS:
6714887Schin 			wasop=0;
6724887Schin 			op |= T_NOFLOAT;
6734887Schin 		case A_ASSIGN:
6744887Schin 			if(!lvalue.value)
6754887Schin 				ERROR(vp,e_notlvalue);
6764887Schin 			if(op==A_ASSIGN)
6774887Schin 			{
6784887Schin 				stakputc(A_STORE);
6794887Schin 				stakpush(vp,lvalue.value,char*);
6804887Schin 				stakpush(vp,lvalue.flag,short);
6814887Schin 				vp->staksize--;
6824887Schin 			}
6834887Schin 			else
6844887Schin 				stakputc(op);
6854887Schin 			lvalue.value = 0;
6864887Schin 			break;
6874887Schin 
6884887Schin 		case A_QUEST:
6894887Schin 		{
6904887Schin 			int offset1,offset2;
6914887Schin 			stakputc(A_JMPZ);
6924887Schin 			offset1 = stakpush(vp,0,short);
6934887Schin 			stakputc(A_POP);
6944887Schin 			if(!expr(vp,1))
6954887Schin 				return(0);
6964887Schin 			if(gettok(vp)!=A_COLON)
6974887Schin 				ERROR(vp,e_questcolon);
6984887Schin 			stakputc(A_JMP);
6994887Schin 			offset2 = stakpush(vp,0,short);
7004887Schin 			*((short*)stakptr(offset1)) = staktell();
7014887Schin 			stakputc(A_POP);
7024887Schin 			if(!expr(vp,3))
7034887Schin 				return(0);
7044887Schin 			*((short*)stakptr(offset2)) = staktell();
7054887Schin 			lvalue.value = 0;
7064887Schin 			wasop = 0;
7074887Schin 			break;
7084887Schin 		}
7094887Schin 
7104887Schin 		case A_COLON:
7114887Schin 			ERROR(vp,e_badcolon);
7124887Schin 			break;
7134887Schin 
7144887Schin 		case A_QCOLON:
7154887Schin 		case A_ANDAND:
7164887Schin 		case A_OROR:
7174887Schin 		{
7184887Schin 			int offset;
7194887Schin 			if(op==A_ANDAND)
7204887Schin 				op = A_JMPZ;
7214887Schin 			else
7224887Schin 				op = A_JMPNZ;
7234887Schin 			stakputc(op);
7244887Schin 			offset = stakpush(vp,0,short);
7254887Schin 			stakputc(A_POP);
7264887Schin 			if(!expr(vp,c))
7274887Schin 				return(0);
7284887Schin 			*((short*)stakptr(offset)) = staktell();
7294887Schin 			if(op!=A_QCOLON)
7304887Schin 				stakputc(A_NOTNOT);
7314887Schin 			lvalue.value = 0;
7324887Schin 			wasop=0;
7334887Schin 			break;
7344887Schin 		}
7354887Schin 		case A_AND:	case A_OR:	case A_XOR:	case A_LSHIFT:
7364887Schin 		case A_RSHIFT:	case A_MOD:
7374887Schin 			op |= T_NOFLOAT;
7384887Schin 			/* FALL THRU */
7394887Schin 		case A_PLUS:	case A_MINUS:	case A_TIMES:	case A_DIV:
7404887Schin 		case A_EQ:	case A_NEQ:	case A_LT:	case A_LE:
7414887Schin 		case A_GT:	case A_GE:	case A_POW:
7424887Schin 			stakputc(op|T_BINARY);
7434887Schin 			vp->staksize--;
7444887Schin 			break;
7454887Schin 		case A_NOT: case A_TILDE:
7464887Schin 		default:
7474887Schin 			ERROR(vp,e_synbad);
7484887Schin 		number:
7494887Schin 			wasop = 0;
7504887Schin 			if(*vp->nextchr=='L' && vp->nextchr[1]=='\'')
7514887Schin 			{
7524887Schin 				vp->nextchr++;
7534887Schin 				op = A_LIT;
7544887Schin 			}
7554887Schin 			pos = vp->nextchr;
7564887Schin 			lvalue.isfloat = 0;
7574887Schin 			lvalue.expr = vp->expr;
7584887Schin 			lvalue.emode = vp->emode;
7594887Schin 			if(op==A_LIT)
7604887Schin 			{
7614887Schin 				/* character constants */
7624887Schin 				if(pos[1]=='\\' && pos[2]=='\'' && pos[3]!='\'')
7634887Schin 				{
7644887Schin 					d = '\\';
7654887Schin 					vp->nextchr +=2;
7664887Schin 				}
7674887Schin 				else
7684887Schin 					d = chresc(pos+1,(char**)&vp->nextchr);
7694887Schin 				/* posix allows the trailing ' to be optional */
7704887Schin 				if(*vp->nextchr=='\'')
7714887Schin 					vp->nextchr++;
7724887Schin 			}
7734887Schin 			else
7744887Schin 				d = (*vp->convert)(&vp->nextchr, &lvalue, LOOKUP, 0);
7754887Schin 			if (vp->nextchr == pos)
7764887Schin 			{
7774887Schin 				if(vp->errmsg.value = lvalue.value)
7784887Schin 					vp->errstr = pos;
7794887Schin 				ERROR(vp,op==A_LIT?e_charconst:e_synbad);
7804887Schin 			}
7814887Schin 			if(op==A_DIG || op==A_LIT)
7824887Schin 			{
7834887Schin 				stakputc(A_PUSHN);
7844887Schin 				if(vp->staksize++>=vp->stakmaxsize)
7854887Schin 					vp->stakmaxsize = vp->staksize;
7864887Schin 				stakpush(vp,d,Sfdouble_t);
7874887Schin 				stakputc(lvalue.isfloat);
7884887Schin 			}
7894887Schin 
7904887Schin 			/* check for function call */
7914887Schin 			if(lvalue.fun)
7924887Schin 				continue;
7934887Schin 			break;
7944887Schin 		}
7954887Schin 		invalid = 0;
7964887Schin 		if(assignop.value)
7974887Schin 		{
7984887Schin 			if(vp->staksize++>=vp->stakmaxsize)
7994887Schin 				vp->stakmaxsize = vp->staksize;
8004887Schin 			if(assignop.flag<0)
8014887Schin 				assignop.flag = 0;
802*12068SRoger.Faulkner@Oracle.COM 			stakputc(c&1?A_ASSIGNOP:A_STORE);
8034887Schin 			stakpush(vp,assignop.value,char*);
8044887Schin 			stakpush(vp,assignop.flag,short);
8054887Schin 		}
8064887Schin 	}
8074887Schin  done:
8084887Schin 	vp->nextchr = vp->errchr;
8094887Schin 	return(1);
8104887Schin }
8114887Schin 
arith_compile(const char * string,char ** last,Sfdouble_t (* fun)(const char **,struct lval *,int,Sfdouble_t),int emode)8124887Schin Arith_t *arith_compile(const char *string,char **last,Sfdouble_t(*fun)(const char**,struct lval*,int,Sfdouble_t),int emode)
8134887Schin {
8144887Schin 	struct vars cur;
8154887Schin 	register Arith_t *ep;
8164887Schin 	int offset;
8174887Schin 	memset((void*)&cur,0,sizeof(cur));
8184887Schin 	cur.emode = emode;
8194887Schin      	cur.expr = cur.nextchr = string;
8204887Schin 	cur.convert = fun;
8214887Schin 	cur.emode = emode;
8224887Schin 	cur.errmsg.value = 0;
8234887Schin 	cur.errmsg.emode = emode;
8244887Schin 	stakseek(sizeof(Arith_t));
8254887Schin 	if(!expr(&cur,0) && cur.errmsg.value)
8264887Schin         {
8274887Schin 		if(cur.errstr)
8284887Schin 			string = cur.errstr;
8294887Schin 		(*fun)( &string , &cur.errmsg, MESSAGE, 0);
8304887Schin 		cur.nextchr = cur.errchr;
8314887Schin 	}
8324887Schin 	stakputc(0);
8334887Schin 	offset = staktell();
8344887Schin 	ep = (Arith_t*)stakfreeze(0);
8354887Schin 	ep->expr = string;
8364887Schin 	ep->elen = strlen(string);
8374887Schin 	ep->code = (unsigned char*)(ep+1);
8384887Schin 	ep->fun = fun;
8394887Schin 	ep->emode = emode;
8404887Schin 	ep->size = offset - sizeof(Arith_t);
8414887Schin 	ep->staksize = cur.stakmaxsize+1;
8424887Schin 	if(last)
8434887Schin 		*last = (char*)(cur.nextchr);
8444887Schin 	return(ep);
8454887Schin }
8464887Schin 
8474887Schin /*
8484887Schin  * evaluate an integer arithmetic expression in s
8494887Schin  *
8504887Schin  * (Sfdouble_t)(*convert)(char** end, struct lval* string, int type, Sfdouble_t value)
8514887Schin  *     is a user supplied conversion routine that is called when unknown
8524887Schin  *     chars are encountered.
8534887Schin  * *end points to the part to be converted and must be adjusted by convert to
8544887Schin  * point to the next non-converted character; if typ is MESSAGE then string
8554887Schin  * points to an error message string
8564887Schin  *
8574887Schin  * NOTE: (*convert)() may call strval()
8584887Schin  */
8594887Schin 
strval(const char * s,char ** end,Sfdouble_t (* conv)(const char **,struct lval *,int,Sfdouble_t),int emode)8604887Schin Sfdouble_t strval(const char *s,char **end,Sfdouble_t(*conv)(const char**,struct lval*,int,Sfdouble_t),int emode)
8614887Schin {
8624887Schin 	Arith_t *ep;
8634887Schin 	Sfdouble_t d;
8644887Schin 	char *sp=0;
8654887Schin 	int offset;
8664887Schin 	if(offset=staktell())
8674887Schin 		sp = stakfreeze(1);
8684887Schin 	ep = arith_compile(s,end,conv,emode);
8694887Schin 	ep->emode = emode;
8704887Schin 	d = arith_exec(ep);
8714887Schin 	stakset(sp?sp:(char*)ep,offset);
8724887Schin 	return(d);
8734887Schin }
8744887Schin 
8754887Schin #if _mem_name__exception
8764887Schin #undef	_mem_name_exception
8774887Schin #define	_mem_name_exception	1
8784887Schin #undef	exception
8794887Schin #define	exception		_exception
8804887Schin #undef	matherr
8814887Schin #endif
8824887Schin 
8834887Schin #if _mem_name_exception
8844887Schin 
8854887Schin #undef	error
8864887Schin 
8874887Schin #if _BLD_shell && defined(__EXPORT__)
8884887Schin #define extern			__EXPORT__
8894887Schin #endif
8904887Schin 
8914887Schin #ifndef DOMAIN
8924887Schin #define DOMAIN			_DOMAIN
8934887Schin #endif
8944887Schin #ifndef OVERFLOW
8954887Schin #define OVERFLOW		_OVERFLOW
8964887Schin #endif
8974887Schin #ifndef SING
8984887Schin #define SING			_SING
8994887Schin #endif
9004887Schin 
matherr(struct exception * ep)9014887Schin     extern int matherr(struct exception *ep)
9024887Schin     {
9034887Schin 	const char *message;
9044887Schin 	switch(ep->type)
9054887Schin 	{
9064887Schin #ifdef DOMAIN
9074887Schin 	    case DOMAIN:
9084887Schin 		message = ERROR_dictionary(e_domain);
9094887Schin 		break;
9104887Schin #endif
9114887Schin #ifdef OVERFLOW
9124887Schin 	    case OVERFLOW:
9134887Schin 		message = ERROR_dictionary(e_overflow);
9144887Schin 		break;
9154887Schin #endif
9164887Schin #ifdef SING
9174887Schin 	    case SING:
9184887Schin 		message = ERROR_dictionary(e_singularity);
9194887Schin 		break;
9204887Schin #endif
9214887Schin 	    default:
9224887Schin 		return(1);
9234887Schin 	}
9244887Schin 	level=0;
9254887Schin 	errormsg(SH_DICT,ERROR_exit(1),message,ep->name);
9264887Schin 	return(0);
9274887Schin     }
9284887Schin 
9294887Schin #undef	extern
9304887Schin 
9314887Schin #endif /* _mem_name_exception */
932