From 0dab63bf3bc32af5420b38e84412bcd5a31ffcec Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Sun, 14 Apr 2024 22:02:55 +0200 Subject: [PATCH] mathexpr: Introduce changes by Jean-Philippe Meuret --- mathexpr/mathexpr/mathexpr.cpp | 208 ++++++++++++++++++++++++++++----- mathexpr/mathexpr/mathexpr.h | 27 ++++- 2 files changed, 200 insertions(+), 35 deletions(-) diff --git a/mathexpr/mathexpr/mathexpr.cpp b/mathexpr/mathexpr/mathexpr.cpp index 885d34e..d58bf62 100644 --- a/mathexpr/mathexpr/mathexpr.cpp +++ b/mathexpr/mathexpr/mathexpr.cpp @@ -1,6 +1,6 @@ /* -mathexpr.cpp version 2.0 +mathexpr.cpp version 2.1 Copyright (c) 1997-2000 Yann OLLIVIER @@ -12,7 +12,33 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include"mathexpr.h" +/* 2009 changes by Jean-Philippe Meuret for Qatsh + - added EFunction class to support external functions with any number of parameters + - fixed memory leaks in ROperation::Expr() in the Num, Var and Error cases + - added code comments in several places + - ROperation::ROperation(const char*,int,PRVar*,int,PRFunction*) : + changed 1st arg from 'char*' to 'const char*' for GCC 4.2 (deprecated conversion) + - optimised IsNumeric(char), IsFunction(const char*,int,int,PRFunction*), + and IsolateVars(...). + - added parenthesis at line 513 on GCC suggestion : + before: if(s[i]==opc&&(op!=Sub||i&&s[i-1]==')'))return i; + after : if(s[i]==opc&&(op!=Sub||(i&&s[i-1]==')')))return i; + + TODO: + - make code more readable (1 instruction per line, consistent indentation, + at least all the end-of-block '}' on their own line, ...) + - give member data a special name, for easier understanding (ex: a leading "_" or "m_") + - reimplement code parts without any goto instruction + - add more comments + - use constants everywhere the same litteral is used more than once in the code + - use strxxx standard libC functions for all string manipulations + - and even better ... move all "[const] char*" to sdt::string + */ + +#include + +#include "mathexpr.h" + char* MidStr(const char*s,int i1,int i2) { @@ -27,10 +53,12 @@ char* MidStr(const char*s,int i1,int i2) s1[i2-i1+1]=0;return s1; } +// Return a copy of the given string (use strdup ?) char* CopyStr(const char*s) {char*s1=new char[strlen(s)+1];char*s12=s1;const char*s2=s; while((*s12++=*s2++));return s1;} +// Insert a char at a given position in a string (increase string length by 1) void InsStr(char*&s,int n,char c)// Warning : deletes the old string {if(n<0||n>(int)strlen(s))return; char*s1=new char[strlen(s)+2]; @@ -48,6 +76,7 @@ for(i=0;s[i];i++)if(s[i]!=s2[i])return 0; return 1; } +// Tell if s[n...] == s2 signed char CompStr(const char*s,int n,const char*s2) {if(n<0||n>=(int)strlen(s)||n+(int)strlen(s2)>(int)strlen(s))return 0; int i; @@ -72,7 +101,49 @@ RVar::RVar(const char*namep,double*pvalp) {pval=pvalp;name=CopyStr(namep);} RVar::~RVar() -{if(name!=NULL)delete[] name;} +{ + if(name!=NULL)delete[] name; +} + +EFunction::EFunction(unsigned nvarsp) +{ + nvars = nvarsp; + pvars = new double[nvarsp]; +} + +EFunction::~EFunction() +{ + if (pvars) + delete[] pvars; +} + +double EFunction::operator()(double* pvarsp) +{ + // Store variables in the pvars array. + unsigned i; + for (i = 0; i < nvars; i++) + pvars[i] = pvarsp[i]; + + // Compute value. + return Val(); +} + +double EFunction::operator()(double var1p, ...) +{ + // Store 1st variable (always here) in the pvars array. + pvars[0] = var1p; + + // Store other variables in the pvars array. + va_list vl; + va_start(vl, var1p); + unsigned i; + for (i = 1; i < nvars; i++) + pvars[i] = (double)va_arg(vl, double); + va_end(vl); + + // Compute value. + return Val(); +} RFunction::RFunction() { @@ -86,11 +157,18 @@ RFunction::RFunction(double ((*pfuncvalp)(double))) nvars=1;ppvar=NULL;op=ErrVal;buf=NULL; } +RFunction::RFunction(EFunction& efunc) +{ + type=2;pfuncobjval=&efunc;name=new char[1];name[0]=0; + nvars=efunc.nvars;ppvar=NULL;op=ErrVal;buf=NULL; +} + RFunction::RFunction(const RFunction& rfunc) { if(this==&rfunc)return; type=rfunc.type;op=rfunc.op; pfuncval=rfunc.pfuncval; + pfuncobjval=rfunc.pfuncobjval; name=CopyStr(rfunc.name); nvars=rfunc.nvars; if(rfunc.ppvar!=NULL&&nvars){ @@ -129,6 +207,7 @@ RFunction& RFunction::operator=(const RFunction& rfunc) if(this==&rfunc)return *this; type=rfunc.type;op=rfunc.op; pfuncval=rfunc.pfuncval; + pfuncobjval=rfunc.pfuncobjval; delete[]name; name=CopyStr(rfunc.name); if(ppvar!=NULL)delete[]ppvar; @@ -150,6 +229,7 @@ double RFunction::Val(double x) const { if(type==-1||nvars>=2)return ErrVal; if(type==0)return (*pfuncval)(x); + if(type==2)return (*pfuncobjval)(x); double xb=*(*ppvar)->pval,y; *(*ppvar)->pval=x; // Warning : could cause trouble if this value is used in a parallel process y=op.Val(); @@ -161,6 +241,7 @@ double RFunction::Val(double*pv) const { if(type==-1)return ErrVal; if(type==0)return (*pfuncval)(*pv); + if(type==2)return (*pfuncobjval)(pv); double y; int i; for(i=0;i'9')&&c!='.') + return 0; + return 1; } +// Tell if a string is a decimal literal (TODO: fix positive answer even when multiple dots). signed char IsTNumeric(char *s) {int i;for(i=0;i<(int)strlen(s);i++)if(!IsNumeric(s[i]))return 0;return 1; } +//Searchs the corresponding bracket of an opening bracket int SearchCorOpenbracket(char*s,int n) //Searchs the corresponding bracket of an opening bracket {if(n>=(int)strlen(s)-1)return -1; int i,c=1; @@ -392,6 +478,7 @@ for(i=n+1;s[i];i++){ return -1; } +//Searchs the corresponding bracket of a closing bracket int SearchCorClosebracket(char*s,int n) //Searchs the corresponding bracket of a closing bracket {if(n<1)return -1; int i,c=1; @@ -414,22 +501,26 @@ int SearchOperator(char*s,ROperator op) case Div:opc='/';break; case Pow:opc='^';break; case NthRoot:opc='#';break; - case E10:opc='E';break; + case E10:opc='E';break; default:return -1; }; int i; for(i=(int)strlen(s)-1;i>=0;i--){ - if(s[i]==opc&&(op!=Sub||i&&s[i-1]==')'))return i; + if(s[i]==opc&&(op!=Sub||(i&&s[i-1]==')')))return i; if(s[i]==')'){i=SearchCorClosebracket(s,i);if(i==-1)return -1;}; }; return -1; } void SimplifyStr(char*&s) //Warning : deletes the old string -{if(!strlen(s))return; +{ + // Nothing more to do if string is empty +if(!strlen(s))return; + // Remove useless matching parenthesis (1st and last char) char*s1=s,*s2=s+strlen(s);signed char ind=0; if(s1[0]=='('&&SearchCorOpenbracket(s1,0)==s2-s1-1){ s1++;s2--;ind=1;} + // Return an empty string if nothing remains if(s1==s2) { delete[]s; @@ -437,7 +528,9 @@ if(s1==s2) s[0]=0; return; } + // Remove any leading spaces if(s1[0]==' '){ind=1;while(s1[0]==' '&&s1s1&&*(s2-1)==' ')s2--;} *s2=0; + // Replace input string by simplified one s1=CopyStr(s1);delete[]s;s=s1; + // Continue simplification (recursive) if needed if(ind)SimplifyStr(s); } int max(int a, int b){return (a>b?a:b);} +// Detect the name of a variable from the given list, and return its length ; +// the longest possible name is kept (xyz wins against xy) int IsVar(const char*s,int n,int nvar,PRVar*ppvar) { if(n<0||n>(int)strlen(s))return 0; @@ -461,6 +559,7 @@ int IsVar(const char*s,int n,int nvar,PRVar*ppvar) return l; } +// Detect the name of a standard function, and return its length int IsFunction(const char*s,int n) { if(CompStr(s,n,"sin")||CompStr(s,n,"cos")||CompStr(s,n,"exp") @@ -474,15 +573,17 @@ int IsFunction(const char*s,int n) return 0; } +// Detect the name of a function (be it a user defined one from the given list, or a standard one), +// and return its length ; the longest possible name is kept (xyz wins against xy) +// Limitations: standard functions are searched first, and may mask user defined ones +// whose name begins with a standard one (ex: user "sine" masked by standard "sin") +// WARNING: IF PATCHED TO DO OTHERWISE, SHOULD BE PATCHED TOGETHER WITH THE +// PARSER BELOW which treats standard functions before user-defined ones int IsFunction(const char*s,int n,int nfunc,PRFunction*ppfunc) - //Not recognized if a user-defined function is eg "sine" ie begins like - //a standard function - //IF PATCHED TO DO OTHERWISE, SHOULD BE PATCHED TOGETHER WITH THE - //PARSER BELOW which treats standard functions before user-defined ones { int l=IsFunction(s,n); if(l)return l; - int i;l=0; + int i; for(i=0;iname))l=max(l,strlen(ppfunc[i]->name)); return l; } @@ -492,49 +593,68 @@ signed char IsFunction(ROperator op) op==Atan||op==Asin||op==Acos||op==Atan||op==Sqrt||op==Opp); } +// Enclose numbers between parenthesis (deletes the old string). void IsolateVars(char*&s,int nvar,PRVar*ppvar,int nfunc,PRFunction*ppfunc)//Deletes the old string { int i,j; i=0; for(i=0;s[i];i++){ + // Jump over a (...) bloc if any if(s[i]=='('){i=SearchCorOpenbracket(s,i);if(i==-1)return;continue;}; + // When detecting a variable or constant name, if no longer function name can match, + // and if enclose it between ( and ) if(((j=IsVar(s,i,nvar,ppvar))>IsFunction(s,i,nfunc,ppfunc))||((CompStr(s,i,"pi")||CompStr(s,i,"PI")||CompStr(s,i,"Pi"))&&(j=2))){ InsStr(s,i,'(');InsStr(s,i+j+1,')');i+=j+1;continue;}; - if(IsFunction(s,i,nfunc,ppfunc)){i+=IsFunction(s,i,nfunc,ppfunc)-1;if(!s[i])return;continue;}; + if((j=IsFunction(s,i,nfunc,ppfunc))){i+=j-1;if(!s[i])return;continue;}; }; } +// Enclose numbers between parenthesis (deletes the old string). void IsolateNumbers(char*&s,int nvar,RVar**ppvar,int nfunc,RFunction**ppfunc)//Deletes the old string { - int i,i2,ind=0,t1,t2; + int i,i2=0,ind=0,t1,t2; for(i=0;s[i];i++){ + // When detecting the end of a number, enclose it between ( and ) if(ind&&!IsNumeric(s[i])){ind=0;InsStr(s,i2,'(');i++;InsStr(s,i,')');continue;}; + // Jump over a variable or a function name if any t1=IsVar(s,i,nvar,ppvar);t2=IsFunction(s,i,nfunc,ppfunc); if(t1||t2){i+=max(t1,t2)-1;continue;}; + // Jump over a (...) bloc if any (the remainder of the function "call") if(s[i]=='('){i=SearchCorOpenbracket(s,i);if(i==-1)return;continue;}; + // Here, we detect the beginning of a number if(!ind&&IsNumeric(s[i])){i2=i;ind=1;}; }; + // If the end of a number has not yet been detected, now it _is_, so enclose it between ( and ) if(ind)InsStr(s,i2,'(');i++;InsStr(s,i,')'); } -ROperation::ROperation(char*sp,int nvar,PRVar*ppvarp,int nfuncp,PRFunction*ppfuncp) +ROperation::ROperation(const char*sp,int nvar,PRVar*ppvarp,int nfuncp,PRFunction*ppfuncp) { ValC=ErrVal;mmb1=NULL;mmb2=NULL;pvar=NULL;op=ErrOp;pvarval=NULL;containfuncflag=0;pfunc=NULL;pinstr=NULL;pvals=NULL;ppile=NULL;pfuncpile=NULL; int i,j,k,l;signed char flag=1; char*s=CopyStr(sp),*s1=NULL,*s2=NULL; + // Simplify formula and remove leading : and ; (why ?) SimplifyStr(s);if(!s[0]||!strcmp(s,"Error")){goto fin;} while(s[0]==':'||s[0]==';'){ s1=CopyStr(s+1);delete[]s;s=s1;s1=NULL; SimplifyStr(s);if(!s[0]||!strcmp(s,"Error")){goto fin;} } + // Case 1: Formula = Integer or decimal litteral, or predefined constant litteral (pi) if(IsTNumeric(s)){op=Num;ValC=atof(s);mmb1=NULL;mmb2=NULL;goto fin;}; if(EqStr(s,"pi")||EqStr(s,"PI")||EqStr(s,"Pi")) {op=Num;ValC=3.141592653589793238462643383279L;mmb1=NULL;mmb2=NULL;goto fin;}; + // Case 2: Formula = Variable with a name that is longer than a matching user defined or standard + // function (Note: remaining chars are ignored if any !). if(IsFunction(s,0,nfuncp,ppfuncp)name)) {pvar=ppvarp[i];pvarval=pvar->pval;op=Var;mmb1=NULL;mmb2=NULL;goto fin;}; + // Case 3: Something else. for(k=0;s[k];k++){ + // Jump over a (...) block. if(s[k]=='('){k=SearchCorOpenbracket(s,k);if(k==-1)break;continue;}; + // Detect a function (user defined or standard one), with a name that is longer + // than the one of any matching variable => add a : or ; at the end of its name + // (; if f(...) notation used, : if ????) if((l=IsFunction(s,k,nfuncp,ppfuncp))&&l>=IsVar(s,k,nvar,ppvarp)){ i=k+l;while(s[i]==' ')i++; if(s[i]=='('){ @@ -543,38 +663,49 @@ ROperation::ROperation(char*sp,int nvar,PRVar*ppvarp,int nfuncp,PRFunction*ppfun }else if(s[i]!=':'&&s[i]!=';'){InsStr(s,i,':');k=i;} } } + // Enclose any number, constant (Pi) and var name between parenthesis, + // and remove any (useless) space, tab or new line. IsolateNumbers(s,nvar,ppvarp,nfuncp,ppfuncp); if(nvar)IsolateVars(s,nvar,ppvarp,nfuncp,ppfuncp); SupprSpaces(s); + // Case 3a: "," binary operator (Juxtaposition) i=SearchOperator(s,Juxt); if(i!=-1){s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); op=Juxt;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp); mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Case 3b: "+" binary operator (Addition) i=SearchOperator(s,Add); if(i!=-1){s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); op=Add;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp); mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Case 3c: "-" binary operator (Substraction) i=SearchOperator(s,Sub); if(i!=-1){ s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); op=Sub;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp); mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Case 3d: "-" unary operator (Negation) if(s[0]=='-'){s2=MidStr(s,1,strlen(s)-1); op=Opp;mmb1=NULL; mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Enclose function "calls" between parenthesis for(i=0;s[i];i++){ + // Jump over a (...) block. if(s[i]=='('){i=SearchCorOpenbracket(s,i);if(i==-1)break;continue;}; + // Detecting a function "call" : if(IsFunction(s,i,nfuncp,ppfuncp)){ - k=i+IsFunction(s,i,nfuncp,ppfuncp);while(s[k]==' ')k++; + k=i+IsFunction(s,i,nfuncp,ppfuncp);while(s[k]==' ')k++; // Ignore spaces (Is it usefull, as SupprSpaces was called before ?) + // f(...) notation => enclose it between parenthesis (=> "(f(...))" ) if(s[k]==';'){ // s=DelStr(s,k); j=k;while(s[j]!='(')j++; j=SearchCorOpenbracket(s,j); if(j!=-1){InsStr(s,j,')');InsStr(s,i,'(');i=j+2;} + // ??? => enclose it between parenthesis (=> "(???)" ) }else if(s[k]==':'){ // s=DelStr(s,k); for(j=k;s[j];j++) @@ -591,8 +722,10 @@ ROperation::ROperation(char*sp,int nvar,PRVar*ppvarp,int nfuncp,PRFunction*ppfun } } } + // Add explicit multiply operator "*" anywhere implicit ( (...)(...) ) for(i=0;s[i]&&s[i+1];i++)if(s[i]==')'&&s[i+1]=='(') InsStr(s,++i,'*'); + // Case 3e: Standard or user defined function if(s[0]=='('&&SearchCorOpenbracket(s,0)==(int)strlen(s)-1){ if(CompStr(s,1,"exp")){op=Exp;s2=MidStr(s,4,strlen(s)-2);} else if(CompStr(s,1,"abs")){op=Abs;s2=MidStr(s,4,strlen(s)-2);} @@ -622,21 +755,25 @@ ROperation::ROperation(char*sp,int nvar,PRVar*ppvarp,int nfuncp,PRFunction*ppfun if(op==Fun)if(mmb2->NMembers()!=pfunc->nvars){op=ErrOp;mmb1=NULL;mmb2=NULL;goto fin;} goto fin; }; + // Case 3f: "*" binary operator (Multiplication) i=SearchOperator(s,Mult); if(i!=-1){s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); op=Mult;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp); mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Case 3g: "/" binary operator (Division) i=SearchOperator(s,Div); if(i!=-1){s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); op=Div;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp); mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Case 3h: "^" binary operator (Power) i=SearchOperator(s,Pow); if(i!=-1){s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); op=Pow;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp); mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Case 3i: "#" binary operator (Square or N>2 th root) i=SearchOperator(s,NthRoot); if(i!=-1){s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); if(i==0||s[i-1]!=')') @@ -644,12 +781,17 @@ ROperation::ROperation(char*sp,int nvar,PRVar*ppvarp,int nfuncp,PRFunction*ppfun {op=NthRoot;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp);}; mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + // Case 3k: "E" binary operator (power of 10) i=SearchOperator(s,E10); if(i!=-1){s1=MidStr(s,0,i-1);s2=MidStr(s,i+1,strlen(s)-1); op=E10;mmb1=new ROperation(s1,nvar,ppvarp,nfuncp,ppfuncp); mmb2=new ROperation(s2,nvar,ppvarp,nfuncp,ppfuncp);goto fin; }; + + // Other cases: Error. op=ErrOp;mmb1=NULL;mmb2=NULL; + + // fin: BuildCode(); delete[]s;if(s1!=NULL)delete[] s1;if(s2!=NULL)delete[]s2; @@ -677,6 +819,7 @@ int operator==(const RFunction& f1,const RFunction& f2) if(f1.type!=f2.type)return 0; if(f1.type==-1)return 1; // Nonfunction==nonfunction if(f1.type==0)return (f1.pfuncval==f2.pfuncval&&EqStr(f1.name,f2.name)); + if(f1.type==2)return (f1.pfuncobjval==f2.pfuncobjval&&EqStr(f1.name,f2.name)); if(f1.op!=f2.op)return 0; if(!EqStr(f1.name,f2.name))return 0; if(f1.nvars!=f2.nvars)return 0; @@ -761,7 +904,7 @@ signed char ROperation::HasError(const ROperation*pop) const int ROperation::NMembers() const //Number of members for an operation like a,b,c... { - if(op==Fun)return(pfunc->type==1?pfunc->op.NMembers():pfunc->type==0?1:0); + if(op==Fun)return(pfunc->type==1?pfunc->op.NMembers():pfunc->type==0?1:pfunc->type==2?pfunc->nvars:0); if(op!=Juxt)return 1;else if(mmb2==NULL)return 0;else return 1+mmb2->NMembers(); } @@ -823,7 +966,7 @@ ROperation ROperation::Diff(const RVar& var) const case Asin:return(mmb2->Diff(var)/sqrt(1-((*mmb2)^2))); case Acos:return(-mmb2->Diff(var)/sqrt(1-((*mmb2)^2))); case Abs:return(mmb2->Diff(var)*(*mmb2)/(*this)); - case Fun:if(pfunc->type==-1||pfunc->type==0)return ErrVal; + case Fun:if(pfunc->type==-1||pfunc->type==0||pfunc->type==2)return ErrVal; if(pfunc->nvars==0)return 0.; else if(pfunc->op.NMembers()>1){ j=pfunc->op.NMembers(); @@ -832,7 +975,7 @@ ROperation ROperation::Diff(const RVar& var) const op2=ApplyOperator(pfunc->nvars,ppop1,&operator,); for(i=0;invars;i++)delete ppop1[i]; delete[]ppop1; - return op2; + return op2; }else{ ppop1=new ROperation*[pfunc->nvars]; for(i=0;invars;i++){ @@ -844,7 +987,7 @@ ROperation ROperation::Diff(const RVar& var) const op2=ApplyOperator(pfunc->nvars,ppop1,&::operator+); for(i=0;invars;i++)delete ppop1[i]; delete[]ppop1; - return op2; + return op2; // In the obtained expression, f' will have been replaced with its expression but f will remain pointing to itself ; this could cause some trouble if changing f afterwards } default:return ErrVal; @@ -866,8 +1009,8 @@ char* ROperation::Expr() const if(mmb2!=NULL){s2=mmb2->Expr();n+=strlen(s2);g=IsFunction(mmb2->op);} s=new char[n]; switch(op){ - case Num:return ValToStr(ValC); - case Var:return CopyStr(pvar->name); + case Num:delete[]s;return ValToStr(ValC); + case Var:delete[]s;return CopyStr(pvar->name); case Juxt:sprintf(s,"%s , %s",s1,s2);break; case Add: f=f||(mmb1->op==Juxt); @@ -982,7 +1125,7 @@ char* ROperation::Expr() const case Fun: sprintf(s,"%s(%s)",pfunc->name,s2); break; - default:return CopyStr("Error"); + default:delete[]s;return CopyStr("Error"); }; if(s1!=NULL)delete[] s1;if(s2!=NULL)delete[] s2; return s; @@ -1063,7 +1206,7 @@ double ROperation::Val() const { pfoncld*p1=pinstr;double**p2=pvals,*p3=ppile-1;PRFunction*p4=pfuncpile; for(;*p1!=NULL;p1++) - if(*p1==&NextVal)*(++p3)=**(p2++);else + if(*p1==&NextVal)*(++p3)=**(p2++);else if(*p1==&RFunc) ApplyRFunc(*(p4++),p3); else (**p1)(p3); return *p3; @@ -1158,6 +1301,7 @@ void ROperation::BuildCode() if(pvals!=NULL){delete[]pvals;pvals=NULL;}//does not delete pvals[0] in case it was to be deleted... (no way to know) if(ppile!=NULL){delete[]ppile;ppile=NULL;} if(pfuncpile!=NULL){delete[]pfuncpile;pfuncpile=NULL;} + switch(op){ case ErrOp:pinstr=new pfoncld[2];pinstr[0]=&NextVal;pinstr[1]=NULL; pvals=new double*[2];pvals[0]=new double(ErrVal);pvals[1]=NULL; diff --git a/mathexpr/mathexpr/mathexpr.h b/mathexpr/mathexpr/mathexpr.h index 4ea9c40..94bba25 100644 --- a/mathexpr/mathexpr/mathexpr.h +++ b/mathexpr/mathexpr/mathexpr.h @@ -1,6 +1,6 @@ /* -mathexpr.h version 2.0 +mathexpr.h version 2.1 Copyright (c) 1997-2000 Yann OLLIVIER @@ -12,6 +12,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ +/* 2009 changes by Jean-Philippe Meuret for Qatsh + - added EFunction class to support external function with any number of parameters + - ROperation::ROperation(const char*,int,PRVar*,int,PRFunction*) : + changed 1st arg from 'char*' to 'const char*' for GCC 4.2 (deprecated conversion) + */ + #ifndef _MATHEXPR_H #define _MATHEXPR_H @@ -79,7 +85,7 @@ class ROperation{ ROperation(const ROperation&); ROperation(double); ROperation(const RVar&); - ROperation(char*sp,int nvarp=0,PRVar*ppvarp=NULL,int nfuncp=0,PRFunction*ppfuncp=NULL); + ROperation(const char*sp,int nvarp=0,PRVar*ppvarp=NULL,int nfuncp=0,PRFunction*ppfuncp=NULL); ~ROperation(); double Val() const; signed char ContainVar(const RVar&) const; @@ -114,15 +120,30 @@ class ROperation{ ROperation Substitute(const RVar&,const ROperation&) const; }; +class EFunction{ +public: + unsigned nvars; + double* pvars; + EFunction(unsigned nvarsp); + virtual ~EFunction(); + double operator()(double* pvarsp); + double operator()(double var1p, ...); // Warning: Only double vars supported + // Compute function value from pvars[] after operator () filled it + // => (re)implement only this function + virtual double Val() = 0; +}; + class RFunction{ double*buf; public: - signed char type; + signed char type; //Compute the value through: 2=>pfuncobjval, 1=>op, 0=>pfuncval, -1=>Can't do it. double ((*pfuncval)(double)); + EFunction* pfuncobjval; ROperation op;int nvars;RVar** ppvar; char*name; RFunction(); RFunction(double ((*)(double))); + RFunction(EFunction& efunc); RFunction(const ROperation& opp,RVar* pvarp); RFunction(const ROperation& opp,int nvarsp,RVar**ppvarp); RFunction(const RFunction&);