home *** CD-ROM | disk | FTP | other *** search
- /*
-
- This is part 2 of the expression evaluator
-
- */
-
- #include "datapriv.hpp"
-
-
- /************************************************************************
-
- This is the actual expression evaluator, it takes a pointer to a pointer
- to a string, and returns an integer representing the value of the string.
-
- It also updates the string pointer to point to the first character after
- the expression.
-
- ************************************************************************/
-
-
- op *expval::exeval(char **s,record *recp)
- {
- char ws[255],*wsp,*wsp1;
- struct op *rv;
-
- exworkp=exwork;
-
- if (**s==EXSTART) rv=evalstr(s,0,recp); /* Already tokenised */
- else
- {
- wsp1=ws;
- wsp=exetoken(*s,&wsp1); /* Tokenise the string */
- wsp1=ws;
- rv=evalstr(&wsp1,0,recp);
- *s=wsp;
- }
-
- memcpy(&retop,rv,sizeof(struct op));
- return(&retop);
- }
-
-
-
- /*
- This routine evaluates a tokenised string, returning an integer which
- is the value of the string.
-
- It takes a pointer to a pointer to a string, and updates it to point to
- the first character after the expression, it is recursive, lop should
- point be the priority of a previous operator, and initially should be set
- to 0.
-
- */
-
- op *expval::evalstr(char **s,int ilop,record *recp)
- {
- int end=0; // flag end of expression
- int thisst=0; // Shows this started with EXSTART
- struct op funcpar[16]; // function parameters
- struct op *fo,*so; /* First and second operands */
- char c; /* Temporary char */
- time_t tclock; /* Current time */
- struct tm *tms;
- char *wsp; /* Local work space */
- int lop=ilop;
- int x,y,z; // useful ints
- field *f; // field
- double rnum,fnum,snum; // Floats used in evaluation
- int rint,fint,sint; // Integers used in evaluation
- int rlen,flen; // Length of result,1st op
- char *rstr,*fstr; // First string, Result string
- int copflag;
-
- if (**s==EXSTART) {(*s)++; lop=0; thisst=1;} /* Skip expression marker */
-
- c=**s; (*s)++;
-
- fo=(struct op *)exealloc(sizeof(struct op));
- fo->optype=OPINT;
- fo->num=0;
-
- if (c<0) /* Must be a number or string of some sort */
- switch(c)
- {
- case EXINT : fo->num=**(double **)s; *s+=sizeof(double);
- break;
-
- case EXVAR : x=**(int **)s; *s+=sizeof(int);
- f=db->getfield(x);
- switch(f->type)
- {
- case 'C' : fo->optype=OPSTR;
- fo->str=exealloc(f->getlen()+1);
- strcpy(fo->str,recp->getfield(x,0));
- fo->oplen=f->getlen();
- break;
- case 'N' : fo->num=atof(recp->getfield(x)); break;
- case 'L' : fo->optype=OPLOG;
- x=*(char *)(recp->getfield(x)) & 0xdf;
- fo->num=(x=='Y' || x=='T') ? 1 : 0; break;
- case 'D' : fo->optype=OPDATE;
- strncpy(fo->date,recp->getfield(x),8);
- fo->date[8]=0;
- break;
- case 'M' : fo->optype=OPSTR; fo->str=recp->getfield(x,0);
- if (recp->indflg) err("No Memo in index");
- break;
- }
- break;
-
- case EXSTR : fo->optype=OPSTR; fo->str=strcpy(exealloc(strlen(*s)+1),*s);
- fo->oplen=strlen(fo->str);
- while(**s) (*s)++; (*s)++;
- break;
-
- case EXSTART : (*s)--; fo=evalstr(s,0,recp); break;
-
- default : err("Error in expression - a"); goto errend;
- }
- else /* Must be an operator, or a function */
- if (oppt[c].type==BINARY)
- {err("Error in expression - b"); goto errend;}
- else
- {
- so=funcpar+1;
- if ((oppt[c].type!=FUNCTION) || ((oppt[c].type==FUNCTION) && oppt[c].pri))
- {
- // Now for a function collect the correct number of parameters, however
- // to speed the program type checking is performed on the first 2
- // parameters, and fo copies the 1st par. and so points to the 2nd
- // The only parameter retained is fo.
-
- if (oppt[c].type>=FUNCTION)
- {
- for(int i=0; i<oppt[c].pri+oppt[c].type-4; funcpar[i++]=*evalstr(s,99,recp));
- *fo=funcpar[0];
- if (!(fo->optype & oppt[c].type1) ||
- (oppt[c].pri>1 && !(so->optype & oppt[c].type2)))
- {err("Wrong operand type F"); goto errend;}
- }
- else // Unary operator, pick up the operand
- {
- fo=evalstr(s,oppt[c].num==NOT ? oppt[c].pri : 99,recp);
- if (!(fo->optype & oppt[c].type1))
- {err("Wrong operand type 1"); goto errend;}
- }
- }
- if (fo->optype==OPINT || fo->optype==OPLOG) {fint=fnum=fo->num;}
- if (fo->optype==OPSTR) {fstr=fo->str; flen=strlen(fstr)+1;}
- if (so->optype==OPINT) {sint=snum=so->num;}
- if (oppt[c].optype) fo->optype=oppt[c].optype;
- rlen=fo->oplen;
- rint=-1000;
- copflag=1; // Show if result needs copying after evaluation
- switch(oppt[c].num) // Unary operations
- {
- case PLUS : copflag=0; break;
- case MINUS : rnum=-fnum; break;
- case NOT : rint=(!fint) ? -1 : 0; break;
- case ABS : rnum=fabs(fnum); break;
- case ASC : rint=*fstr; break;
- case AT : wsp=strstr(so->str,fstr);
- rint=(wsp) ? wsp-so->str+1 : 0; break;
- case CDOW : rstr=strcpy(exealloc(9),cdow(fo->date)); rlen=9; break;
- case CHR : rstr=exealloc(2); *rstr=fint; rstr[1]=0; rlen=1; break;
- case CMONTH : rstr=strcpy(exealloc(10),cmonth(fo->date)); rlen=9; break;
- case CTOD : rstr=fstr; ctod(fo->date,rstr); break;
- case DATE : time(&tclock); strcpy(fo->date,getdate(tclock)); break;
- case DAY : gnums(fo->date,rint,y,z); break;
- case DOW : rint=dow(fo->date); break;
- case DTOC : rstr=exealloc(11); gnums(fo->date,x,y,z);
- sprintf(rstr,"%02d/%02d/%02d",x,y,z%100); rlen=8;
- break;
- case DTOS : rstr=strcpy(exealloc(9),fo->date); rlen=8; break;
- case IIF : if (recp->indflg)
- {
- if (so->optype!=funcpar[2].optype) err("Inv Ind");
- rlen=(so->oplen>funcpar[2].oplen) ?
- so->oplen : funcpar[2].oplen;
- }
- if (fint) *fo=*so; else *fo=funcpar[2]; copflag=0;
- break;
- case INT : rnum=(fnum>=0) ? floor(fnum) : ceil(fnum); break;
- case ISALPHA: rint=isalpha(*(fstr)); break;
- case ISDIGIT: rint=isdigit(*(fstr)); break;
- case ISLOWER: rint=islower(*(fstr)); break;
- case ISUPPER: rint=isupper(*(fstr)); break;
- case LEFT : if (sint<1) {*fstr=0; rlen=0;}
- else {if (flen-1>sint) fstr[sint]=0; rlen=sint;}
- copflag=0; break;
- case LOWER : rstr=strlwr(fstr); break;
- case UPPER : rstr=strupr(fstr); break;
- case LTRIM : rstr=fstr; while(*rstr==' ') rstr++; break;
- case LEN : rint=flen-1; break;
- case MAX : if (fo->optype==OPDATE)
- {if (strcmp(fo->date,so->date)<0) *fo=*so;}
- else if (fnum<snum) *fo=*so;
- copflag=0;
- break;
- case MIN : if (fo->optype==OPDATE)
- {if (strcmp(fo->date,so->date)>0) *fo=*so;}
- else if (fnum>snum) *fo=*so;
- copflag=0;
- break;
- case MOD : rnum=fmod(fnum,snum); break;
- case MONTH : gnums(fo->date,x,rint,z); break;
- case RECCOUNT : rnum=db->getnrec(); break;
- case RECNO : rnum=recp->getrecnum(); break;
- case RECSIZE : rint=db->getreclen(); break;
- case REPLICATE :
- rstr=exealloc(flen*sint); *rstr=0; rlen=sint*(flen-1);
- for(x=0; x<sint; x++) strcat(rstr,fstr);
- break;
- case RIGHT : if (sint<1) {*fstr=0; rlen=0;}
- else {if (sint<flen-1) fstr+=flen-1-sint; rlen=sint;}
- rstr=fstr; break;
- case ROUND : if (snum>=0)
- {
- wsp=exealloc(32); sprintf(wsp,"%%.%df",sint);
- sprintf(exworkp,wsp,fnum); rnum=atof(exworkp);
- exworkp=wsp;
- }
- else // Negative rounding
- {
- rnum=floor(fnum/pow(10,-sint)+0.5)*pow(10,-sint);
- }
- break;
- case TRIM :
- case RTRIM : rstr=rtrim(fstr); break;
- case SOUNDEX: rstr=soundex(exealloc(5),fstr); rlen=4; break;
- case SPACE : if (fint<0) fint=0;
- rstr=wsp=exealloc(1+fint); rlen=fint;
- while(wsp<exworkp-1) *wsp++=' '; *wsp=0;
- break;
- case STR : wsp=exealloc(32);
- if (funcpar[2].optype!=1) {err("No. expected"); goto errend;}
- x=(sint==-1) ? 10 : sint;
- y=(funcpar[2].num==-1) ? 0 : funcpar[2].num;
- sprintf(wsp,"%%%d.%df",x,y);
- sprintf(exworkp,wsp,fnum); exworkp[x]=0;
- rstr=exealloc(strlen(exworkp)+1);
- rlen=x;
- break;
- case STUFF : if (funcpar[2].optype!=OPINT || funcpar[3].optype!=OPSTR)
- {err("Wrong par. type"); goto errend;}
- x=sint; if (!x) x=1;
- rstr=exealloc(strlen(funcpar[3].str)+flen);
- strcpy(rstr,fstr);
- if (x>strlen(rstr))
- {fo->str=strcat(rstr,funcpar[3].str); break;}
- rstr[x-1]=0; strcat(rstr,funcpar[3].str);
- if(x+funcpar[2].num<flen)
- strcat(rstr,fstr+(int)(x+(int)(funcpar[2].num)-1));
- rlen=fo->oplen-funcpar[2].num;
- if (rlen<0) rlen=0;
- rlen+=sint-1+funcpar[3].oplen;
- break;
- case SUBSTR : if (sint<1) {*fstr=0; rlen=0;}
- else if (sint<flen-1)
- {
- fstr+=sint-1;
- x=funcpar[2].num;
- if (x>0 && x<strlen(fstr)) *(fstr+x)=0;
- rlen=(x>0) ? x : fo->oplen-sint+1;
- }
- rstr=fstr; break;
- case SWAPDATA: rstr=swapdata(fstr); break;
- case TIME : time(&tclock); rstr=exealloc(30);
- strcpy(rstr,asctime(localtime(&tclock))+11); rlen=8;
- rstr[8]=0;
- break;
- case TYPE : rstr=exealloc(2); rstr[1]=0;
- switch(fo->optype)
- {
- case OPINT : *rstr='N'; break;
- case OPSTR : *rstr='C'; break;
- case OPDATE : *rstr='D'; break;
- case OPLOG : *rstr='L'; break;
- }
- fo->optype=OPSTR; rlen=1; break;
- case VAL : rnum=atof(fstr); break;
- case YEAR : gnums(fo->date,x,y,rint); break;
- }
- fo->oplen=rlen; // Copy in results
- if (copflag)
- {
- if (fo->optype==OPINT || fo->optype==OPLOG)
- fo->num=(rint!=-1000) ? rint : rnum;
- if (fo->optype==OPSTR) fo->str=rstr;
- }
- }
-
- while(!end)
- {
- // We should now be pointing at the end of expression or a binary operator
- // fo has been set to the value of the first operand
-
- c=**s; (*s)++;
- if (c==EXEND) {end=1; if (!thisst) (*s)--; return(fo);} // ret - end expr.
-
- if (c<=OBRAC) {err("Error in expression - c"); goto errend;}
-
- if (oppt[c].pri<=lop) {(*s)--; return(fo);} /* return if priority lower */
-
- so=evalstr(s,oppt[c].pri,recp);
-
- if (!((fo->optype & oppt[c].type1) && (so->optype & oppt[c].type2)))
- {err("Wrong operand type 2"); goto errend;}
-
- switch(oppt[c].num) /* Binary Operators */
- {
- case PLUS :
- case MINUS : plumin(fo,so,oppt[c].num); break;
- case DOLLAR : fo->num=(strstr(so->str,fo->str)!=0); fo->optype=OPLOG; break;
- case POW2 :
- case POW : fo->num=pow(fo->num,so->num); break;
- case TIMES : fo->num*=so->num; break;
- case DIVIDE : if (!so->num) {err("Divide by 0"); goto errend;}
- fo->num/=so->num; break;
- case AND : fo->num=(fo->num && so->num) ? -1 : 0; break;
- case OR : fo->num=(fo->num || so->num) ? -1 : 0; break;
- case GT :
- case LT :
- case GTE :
- case LTE :
- case NE :
- case NE2 :
- case EQUAL : execomp(fo,so,oppt[c].num); break;
- }
- }
-
- return(fo);
-
- errend: /* Find the end of the equation in case of error */
- while(!end)
- {
- c=(**s); (*s)++;
- switch(c)
- {
- case EXSTART : end++; break;
- case EXINT : (*s)+=sizeof(float); break;
- case EXSTR :
- case EXVAR : while(**s) (*s)++; (*s)++; break;
- case EXEND : end=1; if (!thisst) (*s)--; break;
- }
- }
-
- return(fo);
- }
-
-
- /***************************************************************************/
-
- // Handle plus and minus
-
- void expval::plumin(struct op *fo, struct op *so,int in)
- {
- int n=(in==PLUS);
- char *wsp;
-
- if (fo->optype==OPINT && so->optype==OPINT) // number & number
- {
- fo->num-=so->num-2*n*so->num; return;
- }
-
- if (fo->optype==OPSTR && so->optype==OPSTR) // string & string
- {
- strcpy(exworkp,fo->str);
- if (n) strcat(exworkp,so->str);
- else
- {
- int x;
- wsp=exworkp; while(*wsp++);
- wsp--; wsp--; x=0; while(*wsp==' ') {wsp--; x++;}
- wsp++; *wsp=0;
- strcat(exworkp,so->str);
- wsp=exworkp; while(*wsp++); wsp--; while(x--) *wsp++=' ';
- *wsp=0;
- }
- fo->str=exealloc(strlen(exworkp)+1);
- fo->oplen+=so->oplen;
- return;
- }
-
- if (n && fo->optype==OPINT && so->optype==OPDATE)
- {
- op temp=*so; *so=*fo; *fo=temp;
- }
-
- if (fo->optype==OPDATE && so->optype==OPINT)
- {
- daystodate(fo->date,days(fo->date)-so->num+2*n*so->num); return;
- }
-
- if (!n)
- {
- if (fo->optype==OPDATE && so->optype==OPDATE)
- {
- fo->optype=OPINT;
- fo->num=days(fo->date)-days(so->date);
- return;
- }
- }
-
- err("Wrong operand Type");
- }
-
-
-