1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
26 * arithmetic expression evaluator
28 * this version compiles the expression onto a stack
29 * and has a separate executor
36 #include "FEATURE/externs"
37 #include "defs.h" /* for sh.decomma */
39 #ifndef ERROR_dictionary
40 # define ERROR_dictionary(s) (s)
43 # define SH_DICT "libshell"
47 #define SMALL_STACK 12
50 * The following are used with tokenbits() macro
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)
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))))
66 struct vars
/* vars stacked per invocation */
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 */
79 Sfdouble_t (*convert
)(const char**,struct lval
*,int,Sfdouble_t
);
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
);
90 #define getchr(vp) (*(vp)->nextchr++)
91 #define peekchr(vp) (*(vp)->nextchr)
92 #define ungetchr(vp) ((vp)->nextchr--)
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))):\
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: \
107 (c=='.'?A_DOT:(c=='~'?A_TILDE:A_REG)))))))))))))))))))))))
110 #define seterror(v,msg) _seterror(v,ERROR_dictionary(msg))
111 #define ERROR(vp,msg) return(seterror((vp),msg))
114 * set error message string and return(0)
116 static int _seterror(struct vars
*vp
,const char *msg
)
118 if(!vp
->errmsg
.value
)
119 vp
->errmsg
.value
= (char*)msg
;
120 vp
->errchr
= vp
->nextchr
;
127 static void arith_error(const char *message
,const char *expr
, int mode
)
131 errormsg(SH_DICT
,ERROR_exit(mode
),message
,expr
);
135 static Sfdouble_t
U2F(Sfulong_t u
)
153 Sfdouble_t
arith_exec(Arith_t
*ep
)
155 register Sfdouble_t num
=0,*dp
,*sp
;
156 register unsigned char *cp
= ep
->code
;
157 register int c
,type
=0;
159 Sfdouble_t small_stack
[SMALL_STACK
+1];
160 const char *ptr
= "";
163 node
.emode
= ep
->emode
;
164 node
.expr
= ep
->expr
;
165 node
.elen
= ep
->elen
;
168 if(level
++ >=MAXLEVEL
)
170 arith_error(e_recursive
,ep
->expr
,ep
->emode
);
173 if(ep
->staksize
< SMALL_STACK
)
176 sp
= (Sfdouble_t
*)stakalloc(ep
->staksize
*(sizeof(Sfdouble_t
)+1));
177 tp
= (char*)(sp
+ep
->staksize
);
183 if(type
==1 || ((c
&T_BINARY
) && (c
&T_OP
)!=A_MOD
&& tp
[-1]==1))
184 arith_error(e_incompatible
,ep
->expr
,ep
->emode
);
188 case A_JMP
: case A_JMPZ
: case A_JMPNZ
:
190 cp
= roundptr(ep
,cp
,short);
191 if((c
==A_JMPZ
&& num
) || (c
==A_JMPNZ
&&!num
))
194 cp
= (unsigned char*)ep
+ *((short*)cp
);
202 (*ep
->fun
)(&ptr
,&node
,ASSIGN
,num
+1);
206 (*ep
->fun
)(&ptr
,&node
,ASSIGN
,num
-1);
211 num
= (*ep
->fun
)(&ptr
,&node
,ASSIGN
,num
);
216 num
= (*ep
->fun
)(&ptr
,&node
,ASSIGN
,num
);
228 cp
= roundptr(ep
,cp
,Sfdouble_t
*);
229 dp
= *((Sfdouble_t
**)cp
);
230 cp
+= sizeof(Sfdouble_t
*);
233 node
.value
= (char*)dp
;
237 num
= (*ep
->fun
)(&ptr
,&node
,VALUE
,num
);
238 if(node
.value
!= (char*)dp
)
239 arith_error(node
.value
,ptr
,ep
->emode
);
242 if(num
> LDBL_ULLONG_MAX
|| num
< LDBL_LLONG_MIN
)
247 if(num
> LDBL_LLONG_MAX
&& num
<= LDBL_ULLONG_MAX
)
261 cp
= roundptr(ep
,cp
,Sfdouble_t
*);
262 dp
= *((Sfdouble_t
**)cp
);
263 cp
+= sizeof(Sfdouble_t
*);
268 node
.value
= (char*)dp
;
270 num
= (*ep
->fun
)(&ptr
,&node
,ASSIGN
,num
);
274 cp
= roundptr(ep
,cp
,Math_f
);
275 *++sp
= (Sfdouble_t
)(cp
-ep
->code
);
276 cp
+= sizeof(Math_f
);
280 cp
= roundptr(ep
,cp
,Sfdouble_t
);
281 num
= *((Sfdouble_t
*)cp
);
282 cp
+= sizeof(Sfdouble_t
);
284 *++tp
= type
= *cp
++;
294 num
= ~((Sflong_t
)(num
));
306 num
= pow(sp
[-1],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
));
314 num
= (Sflong_t
)(sp
[-1]) % (Sflong_t
)(num
);
317 if(type
==1 || tp
[-1]==1)
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
));
327 num
= (Sflong_t
)(sp
[-1]) / (Sflong_t
)(num
);
331 num
= U2F((Sfulong_t
)(sp
[-1]) << (long)(num
));
333 num
= (Sflong_t
)(sp
[-1]) << (long)(num
);
337 num
= U2F((Sfulong_t
)(sp
[-1]) >> (long)(num
));
339 num
= (Sflong_t
)(sp
[-1]) >> (long)(num
);
342 if(type
==2 || tp
[-1]==2)
343 num
= U2F((Sfulong_t
)(sp
[-1]) ^ (Sfulong_t
)(num
));
345 num
= (Sflong_t
)(sp
[-1]) ^ (Sflong_t
)(num
);
348 if(type
==2 || tp
[-1]==2)
349 num
= U2F((Sfulong_t
)(sp
[-1]) | (Sfulong_t
)(num
));
351 num
= (Sflong_t
)(sp
[-1]) | (Sflong_t
)(num
);
354 if(type
==2 || tp
[-1]==2)
355 num
= U2F((Sfulong_t
)(sp
[-1]) & (Sfulong_t
)(num
));
357 num
= (Sflong_t
)(sp
[-1]) & (Sflong_t
)(num
);
385 fun
= *((Math_f
*)(ep
->code
+(int)(*sp
)));
387 num
= (*((Math_1f_f
)fun
))(num
);
391 fun
= *((Math_f
*)(ep
->code
+(int)(*sp
)));
393 num
= (*((Math_1i_f
)fun
))(num
);
397 fun
= *((Math_f
*)(ep
->code
+(int)(*sp
)));
399 num
= (*((Math_2f_f
)fun
))(sp
[1],num
);
403 fun
= *((Math_f
*)(ep
->code
+(int)(*sp
)));
405 num
= (*((Math_2i_f
)fun
))(sp
[1],num
);
409 fun
= *((Math_f
*)(ep
->code
+(int)(*sp
)));
411 num
= (*((Math_3f_f
)fun
))(sp
[1],sp
[2],num
);
425 * This returns operator tokens or A_REG or A_NUM
427 static int gettok(register struct vars
*vp
)
430 vp
->errchr
= vp
->nextchr
;
437 vp
->errchr
= vp
->nextchr
;
443 if(sh
.decomma
&& (c
=peekchr(vp
))>='0' && c
<='9')
450 if((c
=peekchr(vp
))>='0' && c
<='9')
455 case A_DIG
: case A_REG
: case A_LIT
:
466 case A_LT
: case A_GT
:
474 case A_NOT
: case A_COLON
:
479 case A_PLUS
: case A_MINUS
:
480 case A_OR
: case A_AND
:
492 * evaluate a subexpression with precedence
495 static int expr(register struct vars
*vp
,register int precedence
)
499 struct lval lvalue
,assignop
;
514 ERROR(vp
,e_moretokens
);
523 op
= A_DECR
|T_NOFLOAT
;
527 op
= A_INCR
|T_NOFLOAT
;
537 vp
->nextchr
= vp
->errchr
;
545 if(op
==A_DIG
|| op
==A_REG
|| op
==A_LIT
)
551 if(wasop
++ && op
!=A_LPAR
)
553 /* check for assignment operation */
554 if(peekchr(vp
)== '=' && !(strval_precedence
[op
]&NOASSIGN
))
556 if((!lvalue
.value
|| precedence
> 3))
557 ERROR(vp
,e_notlvalue
);
566 c
= (strval_precedence
[op
]&PRECMASK
);
567 if(c
==MAXPREC
|| op
==A_POW
)
571 /* from here on c is the new precedence level */
572 if(lvalue
.value
&& (op
!=A_ASSIGN
))
574 if(vp
->staksize
++>=vp
->stakmaxsize
)
575 vp
->stakmaxsize
= vp
->staksize
;
577 stakpush(vp
,lvalue
.value
,char*);
580 stakpush(vp
,lvalue
.flag
,short);
583 if(!(strval_precedence
[op
]&SEQPOINT
))
587 else if(precedence
==A_LVALUE
)
588 ERROR(vp
,e_notlvalue
);
589 if(invalid
&& op
>A_ASSIGN
)
593 if(strval_precedence
[op
]&RASSOC
)
595 if((c
< (2*MAXPREC
+1)) && !(strval_precedence
[op
]&SEQPOINT
))
621 stakseek(staktell()-1);
629 int infun
= vp
->infun
;
630 Sfdouble_t (*fun
)(Sfdouble_t
,...);
631 int nargs
= lvalue
.nargs
;
636 if(vp
->staksize
++>=vp
->stakmaxsize
)
637 vp
->stakmaxsize
= vp
->staksize
;
640 stakpush(vp
,fun
,Math_f
);
653 int x
= (nargs
>7)?2:-1;
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
;
663 if (gettok(vp
) != A_RPAR
)
675 ERROR(vp
,e_notlvalue
);
679 stakpush(vp
,lvalue
.value
,char*);
680 stakpush(vp
,lvalue
.flag
,short);
692 offset1
= stakpush(vp
,0,short);
696 if(gettok(vp
)!=A_COLON
)
697 ERROR(vp
,e_questcolon
);
699 offset2
= stakpush(vp
,0,short);
700 *((short*)stakptr(offset1
)) = staktell();
704 *((short*)stakptr(offset2
)) = staktell();
711 ERROR(vp
,e_badcolon
);
724 offset
= stakpush(vp
,0,short);
728 *((short*)stakptr(offset
)) = staktell();
735 case A_AND
: case A_OR
: case A_XOR
: case A_LSHIFT
:
736 case A_RSHIFT
: case A_MOD
:
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
);
745 case A_NOT
: case A_TILDE
:
750 if(*vp
->nextchr
=='L' && vp
->nextchr
[1]=='\'')
757 lvalue
.expr
= vp
->expr
;
758 lvalue
.emode
= vp
->emode
;
761 /* character constants */
762 if(pos
[1]=='\\' && pos
[2]=='\'' && pos
[3]!='\'')
768 d
= chresc(pos
+1,(char**)&vp
->nextchr
);
769 /* posix allows the trailing ' to be optional */
770 if(*vp
->nextchr
=='\'')
774 d
= (*vp
->convert
)(&vp
->nextchr
, &lvalue
, LOOKUP
, 0);
775 if (vp
->nextchr
== pos
)
777 if(vp
->errmsg
.value
= lvalue
.value
)
779 ERROR(vp
,op
==A_LIT
?e_charconst
:e_synbad
);
781 if(op
==A_DIG
|| op
==A_LIT
)
784 if(vp
->staksize
++>=vp
->stakmaxsize
)
785 vp
->stakmaxsize
= vp
->staksize
;
786 stakpush(vp
,d
,Sfdouble_t
);
787 stakputc(lvalue
.isfloat
);
790 /* check for function call */
798 if(vp
->staksize
++>=vp
->stakmaxsize
)
799 vp
->stakmaxsize
= vp
->staksize
;
802 stakputc(c
&1?A_ASSIGNOP
:A_STORE
);
803 stakpush(vp
,assignop
.value
,char*);
804 stakpush(vp
,assignop
.flag
,short);
808 vp
->nextchr
= vp
->errchr
;
812 Arith_t
*arith_compile(const char *string
,char **last
,Sfdouble_t(*fun
)(const char**,struct lval
*,int,Sfdouble_t
),int emode
)
815 register Arith_t
*ep
;
817 memset((void*)&cur
,0,sizeof(cur
));
819 cur
.expr
= cur
.nextchr
= string
;
822 cur
.errmsg
.value
= 0;
823 cur
.errmsg
.emode
= emode
;
824 stakseek(sizeof(Arith_t
));
825 if(!expr(&cur
,0) && cur
.errmsg
.value
)
829 (*fun
)( &string
, &cur
.errmsg
, MESSAGE
, 0);
830 cur
.nextchr
= cur
.errchr
;
834 ep
= (Arith_t
*)stakfreeze(0);
836 ep
->elen
= strlen(string
);
837 ep
->code
= (unsigned char*)(ep
+1);
840 ep
->size
= offset
- sizeof(Arith_t
);
841 ep
->staksize
= cur
.stakmaxsize
+1;
843 *last
= (char*)(cur
.nextchr
);
848 * evaluate an integer arithmetic expression in s
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
857 * NOTE: (*convert)() may call strval()
860 Sfdouble_t
strval(const char *s
,char **end
,Sfdouble_t(*conv
)(const char**,struct lval
*,int,Sfdouble_t
),int emode
)
866 if(offset
=staktell())
868 ep
= arith_compile(s
,end
,conv
,emode
);
871 stakset(sp
?sp
:(char*)ep
,offset
);
875 #if _mem_name__exception
876 #undef _mem_name_exception
877 #define _mem_name_exception 1
879 #define exception _exception
883 #if _mem_name_exception
887 #if _BLD_shell && defined(__EXPORT__)
888 #define extern __EXPORT__
892 #define DOMAIN _DOMAIN
895 #define OVERFLOW _OVERFLOW
901 extern int matherr(struct exception
*ep
)
908 message
= ERROR_dictionary(e_domain
);
913 message
= ERROR_dictionary(e_overflow
);
918 message
= ERROR_dictionary(e_singularity
);
925 errormsg(SH_DICT
,ERROR_exit(1),message
,ep
->name
);
931 #endif /* _mem_name_exception */