mathexpr: Introduce changes by Jean-Philippe Meuret
This commit is contained in:
parent
520274a73d
commit
0dab63bf3b
|
@ -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 <jpmeuret@free.fr> 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 <stdarg.h>
|
||||
|
||||
#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<nvars;i++){
|
||||
|
@ -311,8 +392,8 @@ ROperation resultat;
|
|||
resultat.op=Pow;resultat.mmb1=new ROperation(op1);
|
||||
resultat.mmb2=new ROperation(op2);
|
||||
return resultat;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ROperation sqrt(const ROperation& op)
|
||||
{ROperation rop;rop.op=Sqrt;rop.mmb2=new ROperation(op);return rop;}
|
||||
ROperation abs(const ROperation& op)
|
||||
|
@ -344,8 +425,8 @@ ROperation ApplyOperator(int n,ROperation**pops,ROperation (*func)(const ROperat
|
|||
|
||||
ROperation RFunction::operator()(const ROperation& op)
|
||||
{
|
||||
/* Code to use to replace explcitly instead of using a pointer to
|
||||
if(nvars!=op.NMembers()||type==-1||type==0)return ErrVal;
|
||||
/* Code to use to replace explicitly instead of using a pointer to
|
||||
if(nvars!=op.NMembers()||type==-1||type==0||type==2)return ErrVal;
|
||||
ROperation op2=*pop;int i;
|
||||
RVar**ppvar2=new PRVar[nvars];char s[11]="";
|
||||
for(i=0;i<nvars;i++){
|
||||
|
@ -364,24 +445,29 @@ ROperation RFunction::operator()(const ROperation& op)
|
|||
return op2;
|
||||
}
|
||||
|
||||
//Auxiliary string functions
|
||||
//Auxiliary string functions=====================================================
|
||||
|
||||
void SupprSpaces(char*&s)//Deletes the old string
|
||||
// Remove spaces, tabs and line feeds (deletes the old string)
|
||||
void SupprSpaces(char*&s)
|
||||
{
|
||||
int i;
|
||||
for(i=0;s[i];i++)if(s[i]==' '||s[i]=='\t'||s[i]=='\n')DelStr(s,i--);
|
||||
}
|
||||
|
||||
// Tell if a char is part of a decimal literal (decimal digits and decimal dot).
|
||||
signed char IsNumeric(char c)
|
||||
{if(c!='0'&&c!='1'&&c!='2'&&c!='3'&&c!='4'
|
||||
&&c!='5'&&c!='6'&&c!='7'&&c!='8'&&c!='9'&&c!='.')return 0;
|
||||
return 1;
|
||||
{
|
||||
if((c<'0'||c>'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]==' '&&s1<s2)s1++;}
|
||||
// Return an empty string if nothing remains
|
||||
if(s1==s2)
|
||||
{
|
||||
delete[]s;
|
||||
|
@ -445,14 +538,19 @@ if(s1==s2)
|
|||
s[0]=0;
|
||||
return;
|
||||
}
|
||||
// Remove any ending spaces
|
||||
if(*(s2-1)==' '){ind=1;while(s2>s1&&*(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;i<nfunc;i++)if(CompStr(s,n,ppfunc[i]->name))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)<IsVar(s,0,nvar,ppvarp))
|
||||
for(i=0;i<nvar;i++)if(EqStr(s,(*(ppvarp+i))->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 ( (...)<here>(...) )
|
||||
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;i<pfunc->nvars;i++)delete ppop1[i];
|
||||
delete[]ppop1;
|
||||
return op2;
|
||||
return op2;
|
||||
}else{
|
||||
ppop1=new ROperation*[pfunc->nvars];
|
||||
for(i=0;i<pfunc->nvars;i++){
|
||||
|
@ -844,7 +987,7 @@ ROperation ROperation::Diff(const RVar& var) const
|
|||
op2=ApplyOperator(pfunc->nvars,ppop1,&::operator+);
|
||||
for(i=0;i<pfunc->nvars;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;
|
||||
|
|
|
@ -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 <jpmeuret@free.fr> 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&);
|
||||
|
|
Loading…
Reference in New Issue