xref: /titanic_41/usr/src/lib/libshell/common/sh/streval.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2009 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                  David Korn <dgk@research.att.com>                   *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 
22 /*
23  * D. G. Korn
24  * AT&T Labs
25  *
26  * arithmetic expression evaluator
27  *
28  * this version compiles the expression onto a stack
29  *	 and has a separate executor
30  */
31 
32 #include	"streval.h"
33 #include	<ctype.h>
34 #include	<error.h>
35 #include	<stak.h>
36 #include	"FEATURE/externs"
37 
38 #ifndef ERROR_dictionary
39 #   define ERROR_dictionary(s)	(s)
40 #endif
41 #ifndef SH_DICT
42 #   define SH_DICT	"libshell"
43 #endif
44 
45 #define MAXLEVEL	9
46 #define SMALL_STACK	12
47 
48 /*
49  * The following are used with tokenbits() macro
50  */
51 #define T_OP		0x3f		/* mask for operator number */
52 #define T_BINARY	0x40		/* binary operators */
53 #define T_NOFLOAT	0x80		/* non floating point operator */
54 #define A_LVALUE	(2*MAXPREC+2)
55 
56 #define pow2size(x)		((x)<=2?2:(x)<=4?4:(x)<=8?8:(x)<=16?16:(x)<=32?32:64)
57 #define round(x,size)		(((x)+(size)-1)&~((size)-1))
58 #define stakpush(v,val,type)	((((v)->offset=round(staktell(),pow2size(sizeof(type)))),\
59 				stakseek((v)->offset+sizeof(type)), \
60 				*((type*)stakptr((v)->offset)) = (val)),(v)->offset)
61 #define roundptr(ep,cp,type)	(((unsigned char*)(ep))+round(cp-((unsigned char*)(ep)),pow2size(sizeof(type))))
62 
63 static int level;
64 
65 struct vars				/* vars stacked per invocation */
66 {
67 	const char	*expr;		/* current expression */
68 	const char	*nextchr;	/* next char in current expression */
69 	const char	*errchr; 	/* next char after error	*/
70 	const char	*errstr;	/* error string			*/
71 	struct lval	errmsg;	 	/* error message text		*/
72 	int		offset;		/* offset for pushchr macro	*/
73 	int		staksize;	/* current stack size needed	*/
74 	int		stakmaxsize;	/* maximum stack size needed	*/
75 	unsigned char	paren;	 	/* parenthesis level		*/
76 	char		infun;	/* incremented by comma inside function	*/
77 	int		emode;
78 	Sfdouble_t	(*convert)(const char**,struct lval*,int,Sfdouble_t);
79 };
80 
81 typedef Sfdouble_t (*Math_f)(Sfdouble_t,...);
82 typedef Sfdouble_t (*Math_1f_f)(Sfdouble_t);
83 typedef int	   (*Math_1i_f)(Sfdouble_t);
84 typedef Sfdouble_t (*Math_2f_f)(Sfdouble_t,Sfdouble_t);
85 typedef int        (*Math_2i_f)(Sfdouble_t,Sfdouble_t);
86 typedef Sfdouble_t (*Math_3f_f)(Sfdouble_t,Sfdouble_t,Sfdouble_t);
87 typedef int        (*Math_3i_f)(Sfdouble_t,Sfdouble_t,Sfdouble_t);
88 
89 #define getchr(vp)	(*(vp)->nextchr++)
90 #define peekchr(vp)	(*(vp)->nextchr)
91 #define ungetchr(vp)	((vp)->nextchr--)
92 
93 #if ('a'==97)	/* ASCII encodings */
94 #   define getop(c)	(((c) >= sizeof(strval_states))? \
95 				((c)=='|'?A_OR:((c)=='^'?A_XOR:((c)=='~'?A_TILDE:A_REG))):\
96 				strval_states[(c)])
97 #else
98 #   define getop(c)	(isdigit(c)?A_DIG:((c==' '||c=='\t'||c=='\n'||c=='"')?0: \
99 			(c=='<'?A_LT:(c=='>'?A_GT:(c=='='?A_ASSIGN: \
100 			(c=='+'?A_PLUS:(c=='-'?A_MINUS:(c=='*'?A_TIMES: \
101 			(c=='/'?A_DIV:(c=='%'?A_MOD:(c==','?A_COMMA: \
102 			(c=='&'?A_AND:(c=='!'?A_NOT:(c=='('?A_LPAR: \
103 			(c==')'?A_RPAR:(c==0?A_EOF:(c==':'?A_COLON: \
104 			(c=='?'?A_QUEST:(c=='|'?A_OR:(c=='^'?A_XOR: \
105 			(c=='\''?A_LIT: \
106 			(c=='.'?A_DOT:(c=='~'?A_TILDE:A_REG)))))))))))))))))))))))
107 #endif
108 
109 #define seterror(v,msg)		_seterror(v,ERROR_dictionary(msg))
110 #define ERROR(vp,msg)		return(seterror((vp),msg))
111 
112 /*
113  * set error message string and return(0)
114  */
115 static int _seterror(struct vars *vp,const char *msg)
116 {
117 	if(!vp->errmsg.value)
118 		vp->errmsg.value = (char*)msg;
119 	vp->errchr = vp->nextchr;
120 	vp->nextchr = "";
121 	level = 0;
122 	return(0);
123 }
124 
125 
126 static void arith_error(const char *message,const char *expr, int mode)
127 {
128         level = 0;
129 	mode = (mode&3)!=0;
130         errormsg(SH_DICT,ERROR_exit(mode),message,expr);
131 }
132 
133 #if _ast_no_um2fm
134 static Sfdouble_t U2F(Sfulong_t u)
135 {
136 	Sflong_t	s = u;
137 	Sfdouble_t	f;
138 
139 	if (s >= 0)
140 		return s;
141 	s = u / 2;
142 	f = s;
143 	f *= 2;
144 	if (u & 1)
145 		f++;
146 	return f;
147 }
148 #else
149 #define U2F(x)		x
150 #endif
151 
152 Sfdouble_t	arith_exec(Arith_t *ep)
153 {
154 	register Sfdouble_t num=0,*dp,*sp;
155 	register unsigned char *cp = ep->code;
156 	register int c,type=0;
157 	register char *tp;
158 	Sfdouble_t small_stack[SMALL_STACK+1];
159 	const char *ptr = "";
160 	Math_f fun;
161 	struct lval node;
162 	node.emode = ep->emode;
163 	node.expr = ep->expr;
164 	node.elen = ep->elen;
165 	if(level++ >=MAXLEVEL)
166 	{
167 		arith_error(e_recursive,ep->expr,ep->emode);
168 		return(0);
169 	}
170 	if(ep->staksize < SMALL_STACK)
171 		sp = small_stack;
172 	else
173 		sp = (Sfdouble_t*)stakalloc(ep->staksize*(sizeof(Sfdouble_t)+1));
174 	tp = (char*)(sp+ep->staksize);
175 	tp--,sp--;
176 	while(c = *cp++)
177 	{
178 		if(c&T_NOFLOAT)
179 		{
180 			if(type==1 || ((c&T_BINARY) && (c&T_OP)!=A_MOD  && tp[-1]==1))
181 				arith_error(e_incompatible,ep->expr,ep->emode);
182 		}
183 		switch(c&T_OP)
184 		{
185 		    case A_JMP: case A_JMPZ: case A_JMPNZ:
186 			c &= T_OP;
187 			cp = roundptr(ep,cp,short);
188 			if((c==A_JMPZ && num) || (c==A_JMPNZ &&!num))
189 				cp += sizeof(short);
190 			else
191 				cp = (unsigned char*)ep + *((short*)cp);
192 			continue;
193 		    case A_NOTNOT:
194 			num = (num!=0);
195 			type=0;
196 			break;
197 		    case A_PLUSPLUS:
198 			(*ep->fun)(&ptr,&node,ASSIGN,num+1);
199 			break;
200 		    case A_MINUSMINUS:
201 			(*ep->fun)(&ptr,&node,ASSIGN,num-1);
202 			break;
203 		    case A_INCR:
204 			num = num+1;
205 			num = (*ep->fun)(&ptr,&node,ASSIGN,num);
206 			break;
207 		    case A_DECR:
208 			num = num-1;
209 			num = (*ep->fun)(&ptr,&node,ASSIGN,num);
210 			break;
211 		    case A_SWAP:
212 			num = sp[-1];
213 			sp[-1] = *sp;
214 			type = tp[-1];
215 			tp[-1] = *tp;
216 			break;
217 		    case A_POP:
218 			sp--;
219 			continue;
220 		    case A_PUSHV:
221 			cp = roundptr(ep,cp,Sfdouble_t*);
222 			dp = *((Sfdouble_t**)cp);
223 			cp += sizeof(Sfdouble_t*);
224 			c = *(short*)cp;
225 			cp += sizeof(short);
226 			node.value = (char*)dp;
227 			node.flag = c;
228 			node.isfloat=0;
229 			node.level = level;
230 			num = (*ep->fun)(&ptr,&node,VALUE,num);
231 			if(node.value != (char*)dp)
232 				arith_error(node.value,ptr,ep->emode);
233 			*++sp = num;
234 			type = node.isfloat;
235 			if(num > LDBL_ULLONG_MAX || num < LDBL_LLONG_MIN)
236 				type = 1;
237 			else
238 			{
239 				Sfdouble_t d=num;
240 				if(num > LDBL_LLONG_MAX && num <= LDBL_ULLONG_MAX)
241 				{
242 					type = 2;
243 					d -= LDBL_LLONG_MAX;
244 				}
245 				if((Sflong_t)d!=d)
246 					type = 1;
247 			}
248 			*++tp = type;
249 			c = 0;
250 			break;
251 		    case A_STORE:
252 			cp = roundptr(ep,cp,Sfdouble_t*);
253 			dp = *((Sfdouble_t**)cp);
254 			cp += sizeof(Sfdouble_t*);
255 			c = *(short*)cp;
256 			if(c<0)
257 				c = 0;
258 			cp += sizeof(short);
259 			node.value = (char*)dp;
260 			node.flag = c;
261 			num = (*ep->fun)(&ptr,&node,ASSIGN,num);
262 			c=0;
263 			break;
264 		    case A_PUSHF:
265 			cp = roundptr(ep,cp,Math_f);
266 			*++sp = (Sfdouble_t)(cp-ep->code);
267 			cp += sizeof(Math_f);
268 			*++tp = *cp++;
269 			continue;
270 		    case A_PUSHN:
271 			cp = roundptr(ep,cp,Sfdouble_t);
272 			num = *((Sfdouble_t*)cp);
273 			cp += sizeof(Sfdouble_t);
274 			*++sp = num;
275 			*++tp = type = *cp++;
276 			break;
277 		    case A_NOT:
278 			type=0;
279 			num = !num;
280 			break;
281 		    case A_UMINUS:
282 			num = -num;
283 			break;
284 		    case A_TILDE:
285 			num = ~((Sflong_t)(num));
286 			break;
287 		    case A_PLUS:
288 			num += sp[-1];
289 			break;
290 		    case A_MINUS:
291 			num = sp[-1] - num;
292 			break;
293 		    case A_TIMES:
294 			num *= sp[-1];
295 			break;
296 		    case A_POW:
297 			num = pow(sp[-1],num);
298 			break;
299 		    case A_MOD:
300 			if(!(Sflong_t)num)
301 				arith_error(e_divzero,ep->expr,ep->emode);
302 			if(type==2 || tp[-1]==2)
303 				num = U2F((Sfulong_t)(sp[-1]) % (Sfulong_t)(num));
304 			else
305 				num = (Sflong_t)(sp[-1]) % (Sflong_t)(num);
306 			break;
307 		    case A_DIV:
308 			if(type==1 || tp[-1]==1)
309 			{
310 				num = sp[-1]/num;
311 				type = 1;
312 			}
313 			else if((Sfulong_t)(num)==0)
314 				arith_error(e_divzero,ep->expr,ep->emode);
315 			else if(type==2 || tp[-1]==2)
316 				num = U2F((Sfulong_t)(sp[-1]) / (Sfulong_t)(num));
317 			else
318 				num = (Sflong_t)(sp[-1]) / (Sflong_t)(num);
319 			break;
320 		    case A_LSHIFT:
321 			if(tp[-1]==2)
322 				num = U2F((Sfulong_t)(sp[-1]) << (long)(num));
323 			else
324 				num = (Sflong_t)(sp[-1]) << (long)(num);
325 			break;
326 		    case A_RSHIFT:
327 			if(tp[-1]==2)
328 				num = U2F((Sfulong_t)(sp[-1]) >> (long)(num));
329 			else
330 				num = (Sflong_t)(sp[-1]) >> (long)(num);
331 			break;
332 		    case A_XOR:
333 			if(type==2 || tp[-1]==2)
334 				num = U2F((Sfulong_t)(sp[-1]) ^ (Sfulong_t)(num));
335 			else
336 				num = (Sflong_t)(sp[-1]) ^ (Sflong_t)(num);
337 			break;
338 		    case A_OR:
339 			if(type==2 || tp[-1]==2)
340 				num = U2F((Sfulong_t)(sp[-1]) | (Sfulong_t)(num));
341 			else
342 				num = (Sflong_t)(sp[-1]) | (Sflong_t)(num);
343 			break;
344 		    case A_AND:
345 			if(type==2 || tp[-1]==2)
346 				num = U2F((Sfulong_t)(sp[-1]) & (Sfulong_t)(num));
347 			else
348 				num = (Sflong_t)(sp[-1]) & (Sflong_t)(num);
349 			break;
350 		    case A_EQ:
351 			num = (sp[-1]==num);
352 			type=0;
353 			break;
354 		    case A_NEQ:
355 			num = (sp[-1]!=num);
356 			type=0;
357 			break;
358 		    case A_LE:
359 			num = (sp[-1]<=num);
360 			type=0;
361 			break;
362 		    case A_GE:
363 			num = (sp[-1]>=num);
364 			type=0;
365 			break;
366 		    case A_GT:
367 			num = (sp[-1]>num);
368 			type=0;
369 			break;
370 		    case A_LT:
371 			num = (sp[-1]<num);
372 			type=0;
373 			break;
374 		    case A_CALL1F:
375 			sp--,tp--;
376 			fun = *((Math_f*)(ep->code+(int)(*sp)));
377 			type = 0;
378 			num = (*((Math_1f_f)fun))(num);
379 			break;
380 		    case A_CALL1I:
381 			sp--,tp--;
382 			fun = *((Math_f*)(ep->code+(int)(*sp)));
383 			type = *tp;
384 			num = (*((Math_1i_f)fun))(num);
385 			break;
386 		    case A_CALL2F:
387 			sp-=2,tp-=2;
388 			fun = *((Math_f*)(ep->code+(int)(*sp)));
389 			type = 0;
390 			num = (*((Math_2f_f)fun))(sp[1],num);
391 			break;
392 		    case A_CALL2I:
393 			sp-=2,tp-=2;
394 			fun = *((Math_f*)(ep->code+(int)(*sp)));
395 			type = *tp;
396 			num = (*((Math_2i_f)fun))(sp[1],num);
397 			break;
398 		    case A_CALL3F:
399 			sp-=3,tp-=3;
400 			fun = *((Math_f*)(ep->code+(int)(*sp)));
401 			type = 0;
402 			num = (*((Math_3f_f)fun))(sp[1],sp[2],num);
403 			break;
404 		}
405 		if(c&T_BINARY)
406 			sp--,tp--;
407 		*sp = num;
408 		*tp = type;
409 	}
410 	if(level>0)
411 		level--;
412 	return(num);
413 }
414 
415 /*
416  * This returns operator tokens or A_REG or A_NUM
417  */
418 static int gettok(register struct vars *vp)
419 {
420 	register int c,op;
421 	vp->errchr = vp->nextchr;
422 	while(1)
423 	{
424 		c = getchr(vp);
425 		switch(op=getop(c))
426 		{
427 		    case 0:
428 			vp->errchr = vp->nextchr;
429 			continue;
430 		    case A_EOF:
431 			vp->nextchr--;
432 			break;
433 			/*FALL THRU*/
434 		    case A_DIG: case A_REG: case A_DOT: case A_LIT:
435 			if(op==A_DOT)
436 			{
437 				if((c=peekchr(vp))>='0' && c<='9')
438 					op = A_DIG;
439 				else
440 					op = A_REG;
441 			}
442 			ungetchr(vp);
443 			break;
444 		    case A_QUEST:
445 			if(peekchr(vp)==':')
446 			{
447 				getchr(vp);
448 				op = A_QCOLON;
449 			}
450 			break;
451 		    case A_LT:	case A_GT:
452 			if(peekchr(vp)==c)
453 			{
454 				getchr(vp);
455 				op -= 2;
456 				break;
457 			}
458 			/* FALL THRU */
459 		    case A_NOT:	case A_COLON:
460 			c = '=';
461 			/* FALL THRU */
462 		    case A_ASSIGN:
463 		    case A_TIMES:
464 		    case A_PLUS:	case A_MINUS:
465 		    case A_OR:	case A_AND:
466 			if(peekchr(vp)==c)
467 			{
468 				getchr(vp);
469 				op--;
470 			}
471 		}
472 		return(op);
473 	}
474 }
475 
476 /*
477  * evaluate a subexpression with precedence
478  */
479 
480 static int expr(register struct vars *vp,register int precedence)
481 {
482 	register int	c, op;
483 	int		invalid,wasop=0;
484 	struct lval	lvalue,assignop;
485 	const char	*pos;
486 	Sfdouble_t		d;
487 
488 	lvalue.value = 0;
489 	lvalue.fun = 0;
490 again:
491 	op = gettok(vp);
492 	c = 2*MAXPREC+1;
493 	switch(op)
494 	{
495 	    case A_PLUS:
496 		goto again;
497 	    case A_EOF:
498 		if(precedence>2)
499 			ERROR(vp,e_moretokens);
500 		return(1);
501 	    case A_MINUS:
502 		op =  A_UMINUS;
503 		goto common;
504 	    case A_NOT:
505 		goto common;
506 	    case A_MINUSMINUS:
507 		c = A_LVALUE;
508 		op = A_DECR|T_NOFLOAT;
509 		goto common;
510 	    case A_PLUSPLUS:
511 		c = A_LVALUE;
512 		op = A_INCR|T_NOFLOAT;
513 		/* FALL THRU */
514 	    case A_TILDE:
515 		op |= T_NOFLOAT;
516 	    common:
517 		if(!expr(vp,c))
518 			return(0);
519 		stakputc(op);
520 		break;
521 	    default:
522 		vp->nextchr = vp->errchr;
523 		wasop = 1;
524 	}
525 	invalid = wasop;
526 	while(1)
527 	{
528 		assignop.value = 0;
529 		op = gettok(vp);
530 		if(op==A_DIG || op==A_REG || op==A_LIT)
531 		{
532 			if(!wasop)
533 				ERROR(vp,e_synbad);
534 			goto number;
535 		}
536 		if(wasop++ && op!=A_LPAR)
537 			ERROR(vp,e_synbad);
538 		/* check for assignment operation */
539 		if(peekchr(vp)== '=' && !(strval_precedence[op]&NOASSIGN))
540 		{
541 			if((!lvalue.value || precedence > 3))
542 				ERROR(vp,e_notlvalue);
543 			if(precedence==3)
544 				precedence = 2;
545 			assignop = lvalue;
546 			getchr(vp);
547 			c = 3;
548 		}
549 		else
550 		{
551 			c = (strval_precedence[op]&PRECMASK);
552 			if(c==MAXPREC || op==A_POW)
553 				c++;
554 			c *= 2;
555 		}
556 		/* from here on c is the new precedence level */
557 		if(lvalue.value && (op!=A_ASSIGN))
558 		{
559 			if(vp->staksize++>=vp->stakmaxsize)
560 				vp->stakmaxsize = vp->staksize;
561 			stakputc(A_PUSHV);
562 			stakpush(vp,lvalue.value,char*);
563 			if(lvalue.flag<0)
564 				lvalue.flag = 0;
565 			stakpush(vp,lvalue.flag,short);
566 			if(vp->nextchr==0)
567 				ERROR(vp,e_badnum);
568 			if(!(strval_precedence[op]&SEQPOINT))
569 				lvalue.value = 0;
570 			invalid = 0;
571 		}
572 		else if(precedence==A_LVALUE)
573 			ERROR(vp,e_notlvalue);
574 		if(invalid && op>A_ASSIGN)
575 			ERROR(vp,e_synbad);
576 		if(precedence >= c)
577 			goto done;
578 		if(strval_precedence[op]&RASSOC)
579 			c--;
580 		if((c < (2*MAXPREC+1)) && !(strval_precedence[op]&SEQPOINT))
581 		{
582 			wasop = 0;
583 			if(!expr(vp,c))
584 				return(0);
585 		}
586 		switch(op)
587 		{
588 		case A_RPAR:
589 			if(!vp->paren)
590 				ERROR(vp,e_paren);
591 			if(invalid)
592 				ERROR(vp,e_synbad);
593 			goto done;
594 
595 		case A_COMMA:
596 			wasop = 0;
597 			if(vp->infun)
598 				vp->infun++;
599 			else
600 			{
601 				stakputc(A_POP);
602 				vp->staksize--;
603 			}
604 			if(!expr(vp,c))
605 			{
606 				stakseek(-1);
607 				return(0);
608 			}
609 			lvalue.value = 0;
610 			break;
611 
612 		case A_LPAR:
613 		{
614 			int	infun = vp->infun;
615 			Sfdouble_t (*fun)(Sfdouble_t,...);
616 			int nargs = lvalue.nargs;
617 			fun = lvalue.fun;
618 			lvalue.fun = 0;
619 			if(fun)
620 			{
621 				if(vp->staksize++>=vp->stakmaxsize)
622 					vp->stakmaxsize = vp->staksize;
623 				vp->infun=1;
624 				stakputc(A_PUSHF);
625 				stakpush(vp,fun,Math_f);
626 				stakputc(1);
627 			}
628 			else
629 				vp->infun = 0;
630 			if(!invalid)
631 				ERROR(vp,e_synbad);
632 			vp->paren++;
633 			if(!expr(vp,1))
634 				return(0);
635 			vp->paren--;
636 			if(fun)
637 			{
638 				int  x= (nargs>7)?2:-1;
639 				nargs &= 7;
640 				if(vp->infun != nargs)
641 					ERROR(vp,e_argcount);
642 				if(vp->staksize+=nargs>=vp->stakmaxsize)
643 					vp->stakmaxsize = vp->staksize+nargs;
644 				stakputc(A_CALL1F+nargs+x);
645 				vp->staksize -= nargs;
646 			}
647 			vp->infun = infun;
648 			if (gettok(vp) != A_RPAR)
649 				ERROR(vp,e_paren);
650 			wasop = 0;
651 			break;
652 		}
653 
654 		case A_PLUSPLUS:
655 		case A_MINUSMINUS:
656 			wasop=0;
657 			op |= T_NOFLOAT;
658 		case A_ASSIGN:
659 			if(!lvalue.value)
660 				ERROR(vp,e_notlvalue);
661 			if(op==A_ASSIGN)
662 			{
663 				stakputc(A_STORE);
664 				stakpush(vp,lvalue.value,char*);
665 				stakpush(vp,lvalue.flag,short);
666 				vp->staksize--;
667 			}
668 			else
669 				stakputc(op);
670 			lvalue.value = 0;
671 			break;
672 
673 		case A_QUEST:
674 		{
675 			int offset1,offset2;
676 			stakputc(A_JMPZ);
677 			offset1 = stakpush(vp,0,short);
678 			stakputc(A_POP);
679 			if(!expr(vp,1))
680 				return(0);
681 			if(gettok(vp)!=A_COLON)
682 				ERROR(vp,e_questcolon);
683 			stakputc(A_JMP);
684 			offset2 = stakpush(vp,0,short);
685 			*((short*)stakptr(offset1)) = staktell();
686 			stakputc(A_POP);
687 			if(!expr(vp,3))
688 				return(0);
689 			*((short*)stakptr(offset2)) = staktell();
690 			lvalue.value = 0;
691 			wasop = 0;
692 			break;
693 		}
694 
695 		case A_COLON:
696 			ERROR(vp,e_badcolon);
697 			break;
698 
699 		case A_QCOLON:
700 		case A_ANDAND:
701 		case A_OROR:
702 		{
703 			int offset;
704 			if(op==A_ANDAND)
705 				op = A_JMPZ;
706 			else
707 				op = A_JMPNZ;
708 			stakputc(op);
709 			offset = stakpush(vp,0,short);
710 			stakputc(A_POP);
711 			if(!expr(vp,c))
712 				return(0);
713 			*((short*)stakptr(offset)) = staktell();
714 			if(op!=A_QCOLON)
715 				stakputc(A_NOTNOT);
716 			lvalue.value = 0;
717 			wasop=0;
718 			break;
719 		}
720 		case A_AND:	case A_OR:	case A_XOR:	case A_LSHIFT:
721 		case A_RSHIFT:	case A_MOD:
722 			op |= T_NOFLOAT;
723 			/* FALL THRU */
724 		case A_PLUS:	case A_MINUS:	case A_TIMES:	case A_DIV:
725 		case A_EQ:	case A_NEQ:	case A_LT:	case A_LE:
726 		case A_GT:	case A_GE:	case A_POW:
727 			stakputc(op|T_BINARY);
728 			vp->staksize--;
729 			break;
730 		case A_NOT: case A_TILDE:
731 		default:
732 			ERROR(vp,e_synbad);
733 		number:
734 			wasop = 0;
735 			if(*vp->nextchr=='L' && vp->nextchr[1]=='\'')
736 			{
737 				vp->nextchr++;
738 				op = A_LIT;
739 			}
740 			pos = vp->nextchr;
741 			lvalue.isfloat = 0;
742 			lvalue.expr = vp->expr;
743 			lvalue.emode = vp->emode;
744 			if(op==A_LIT)
745 			{
746 				/* character constants */
747 				if(pos[1]=='\\' && pos[2]=='\'' && pos[3]!='\'')
748 				{
749 					d = '\\';
750 					vp->nextchr +=2;
751 				}
752 				else
753 					d = chresc(pos+1,(char**)&vp->nextchr);
754 				/* posix allows the trailing ' to be optional */
755 				if(*vp->nextchr=='\'')
756 					vp->nextchr++;
757 			}
758 			else
759 				d = (*vp->convert)(&vp->nextchr, &lvalue, LOOKUP, 0);
760 			if (vp->nextchr == pos)
761 			{
762 				if(vp->errmsg.value = lvalue.value)
763 					vp->errstr = pos;
764 				ERROR(vp,op==A_LIT?e_charconst:e_synbad);
765 			}
766 			if(op==A_DIG || op==A_LIT)
767 			{
768 				stakputc(A_PUSHN);
769 				if(vp->staksize++>=vp->stakmaxsize)
770 					vp->stakmaxsize = vp->staksize;
771 				stakpush(vp,d,Sfdouble_t);
772 				stakputc(lvalue.isfloat);
773 			}
774 
775 			/* check for function call */
776 			if(lvalue.fun)
777 				continue;
778 			break;
779 		}
780 		invalid = 0;
781 		if(assignop.value)
782 		{
783 			if(vp->staksize++>=vp->stakmaxsize)
784 				vp->stakmaxsize = vp->staksize;
785 			if(assignop.flag<0)
786 				assignop.flag = 0;
787 			stakputc(A_STORE);
788 			stakpush(vp,assignop.value,char*);
789 			stakpush(vp,assignop.flag,short);
790 		}
791 	}
792  done:
793 	vp->nextchr = vp->errchr;
794 	return(1);
795 }
796 
797 Arith_t *arith_compile(const char *string,char **last,Sfdouble_t(*fun)(const char**,struct lval*,int,Sfdouble_t),int emode)
798 {
799 	struct vars cur;
800 	register Arith_t *ep;
801 	int offset;
802 	memset((void*)&cur,0,sizeof(cur));
803 	cur.emode = emode;
804      	cur.expr = cur.nextchr = string;
805 	cur.convert = fun;
806 	cur.emode = emode;
807 	cur.errmsg.value = 0;
808 	cur.errmsg.emode = emode;
809 	stakseek(sizeof(Arith_t));
810 	if(!expr(&cur,0) && cur.errmsg.value)
811         {
812 		if(cur.errstr)
813 			string = cur.errstr;
814 		(*fun)( &string , &cur.errmsg, MESSAGE, 0);
815 		cur.nextchr = cur.errchr;
816 	}
817 	stakputc(0);
818 	offset = staktell();
819 	ep = (Arith_t*)stakfreeze(0);
820 	ep->expr = string;
821 	ep->elen = strlen(string);
822 	ep->code = (unsigned char*)(ep+1);
823 	ep->fun = fun;
824 	ep->emode = emode;
825 	ep->size = offset - sizeof(Arith_t);
826 	ep->staksize = cur.stakmaxsize+1;
827 	if(last)
828 		*last = (char*)(cur.nextchr);
829 	return(ep);
830 }
831 
832 /*
833  * evaluate an integer arithmetic expression in s
834  *
835  * (Sfdouble_t)(*convert)(char** end, struct lval* string, int type, Sfdouble_t value)
836  *     is a user supplied conversion routine that is called when unknown
837  *     chars are encountered.
838  * *end points to the part to be converted and must be adjusted by convert to
839  * point to the next non-converted character; if typ is MESSAGE then string
840  * points to an error message string
841  *
842  * NOTE: (*convert)() may call strval()
843  */
844 
845 Sfdouble_t strval(const char *s,char **end,Sfdouble_t(*conv)(const char**,struct lval*,int,Sfdouble_t),int emode)
846 {
847 	Arith_t *ep;
848 	Sfdouble_t d;
849 	char *sp=0;
850 	int offset;
851 	if(offset=staktell())
852 		sp = stakfreeze(1);
853 	ep = arith_compile(s,end,conv,emode);
854 	ep->emode = emode;
855 	d = arith_exec(ep);
856 	stakset(sp?sp:(char*)ep,offset);
857 	return(d);
858 }
859 
860 #if _mem_name__exception
861 #undef	_mem_name_exception
862 #define	_mem_name_exception	1
863 #undef	exception
864 #define	exception		_exception
865 #undef	matherr
866 #endif
867 
868 #if _mem_name_exception
869 
870 #undef	error
871 
872 #if _BLD_shell && defined(__EXPORT__)
873 #define extern			__EXPORT__
874 #endif
875 
876 #ifndef DOMAIN
877 #define DOMAIN			_DOMAIN
878 #endif
879 #ifndef OVERFLOW
880 #define OVERFLOW		_OVERFLOW
881 #endif
882 #ifndef SING
883 #define SING			_SING
884 #endif
885 
886     extern int matherr(struct exception *ep)
887     {
888 	const char *message;
889 	switch(ep->type)
890 	{
891 #ifdef DOMAIN
892 	    case DOMAIN:
893 		message = ERROR_dictionary(e_domain);
894 		break;
895 #endif
896 #ifdef OVERFLOW
897 	    case OVERFLOW:
898 		message = ERROR_dictionary(e_overflow);
899 		break;
900 #endif
901 #ifdef SING
902 	    case SING:
903 		message = ERROR_dictionary(e_singularity);
904 		break;
905 #endif
906 	    default:
907 		return(1);
908 	}
909 	level=0;
910 	errormsg(SH_DICT,ERROR_exit(1),message,ep->name);
911 	return(0);
912     }
913 
914 #undef	extern
915 
916 #endif /* _mem_name_exception */
917