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