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