JKQtPlotter/lib/jkqtplottertools/jkqtpmathparser.cpp

1891 lines
69 KiB
C++
Raw Normal View History

/*
Copyright (c) 2008-2019 Jan W. Krieger (<jan@jkrieger.de>, <j.krieger@dkfz.de>)
This software is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/** \file jkqtpmathparser.cpp
* \ingroup jkmp
*/
#define COMPILING_THIS_JKMATHPARSER
#include "jkqtplottertools/jkqtpmathparser.h" // class's header file
#include <iostream>
#include <float.h>
#ifndef __WINDOWS__
# ifndef __LINUX__
# warning("these methods are ment to be used under windows or linux ... no other system were tested")
# endif
#endif
/* This just distinguishes between the different path formats on Windows and Unix:
* - on Windows you use a backslash '\' do separate directories
* - in Unix you use a slash '/' to separate directories
*/
#ifdef __WINDOWS__
/** \brief a separator between two directories in a path between \c " quotes */
#define JKQTPPATHSEPARATOR_STRING "\\"
/** \brief a separator between two directories in a path between \c ' quotes */
#define JKQTPPATHSEPARATOR_CHAR '\\'
#include<windows.h>
#include <io.h>
#else
/** \brief a separator between two directories in a path between \c " quotes */
#define JKQTPPATHSEPARATOR_STRING "/"
/** \brief a separator between two directories in a path between \c ' quotes */
#define JKQTPPATHSEPARATOR_CHAR '/'
#include <unistd.h>
#include <dirent.h>
#endif
/******************************************************************************************
* default-function implementations for math parser
******************************************************************************************/
namespace { // anonymous namespace to limit availability to this module (CPP-file)
JKQTPMathParser::jkmpResult fFloatToStr(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
std::ostringstream ost;
r.type=JKQTPMathParser::jkmpString;
if (n!=1) p->jkmpError("floattostr accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("floattostr needs double argument");
ost<<params[0].num;
r.str=ost.str();
return r;
}
JKQTPMathParser::jkmpResult fIntToStr(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
std::ostringstream ost;
r.type=JKQTPMathParser::jkmpString;
if (n!=1) p->jkmpError("inttostr accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("inttostr needs double argument");
ost<<int64_t(params[0].num);
r.str=ost.str();
return r;
}
JKQTPMathParser::jkmpResult fBoolToStr(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
std::ostringstream ost;
r.type=JKQTPMathParser::jkmpString;
if (n!=1) p->jkmpError("booltostr accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpBool) p->jkmpError("floattostr needs bool argument");
r.str=(r.boolean)?"true":"false";
return r;
}
JKQTPMathParser::jkmpResult fToSystemPathSeparator(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpString;
if (n!=1) p->jkmpError("tosystempathseparator accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpString) p->jkmpError("tosystempathseparator needs string argument");
r.str="";
for (size_t i=0; i<params[0].str.size(); i++) {
char ch=params[0].str[i];
if (ch=='/' || ch=='\\') ch=JKQTPPATHSEPARATOR_CHAR;
r.str+=ch;
}
return r;
}
JKQTPMathParser::jkmpResult fSetDefault(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpString;
if (n!=2) p->jkmpError("setdefault accepts 2 argument");
if (params[0].type!=JKQTPMathParser::jkmpString) p->jkmpError("setdefault needs a string as first argument");
r=params[1];
if (p->variableExists(params[0].str)) {
r=p->getVariable(params[0].str);
}
return r;
}
JKQTPMathParser::jkmpResult fStrDate(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpString;
std::string f="%Y-%m-%d";
if (n>1) p->jkmpError("strdate accepts 0 or 1 argumentment");
if (n>0 && params[0].type!=JKQTPMathParser::jkmpString) p->jkmpError("strdate needs a string as first argument");
if (n>0) f=params[0].str;
char re[1024];
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo=localtime(&rawtime);
strftime(re, 1024, f.c_str(), timeinfo);
r.str=re;
return r;
}
JKQTPMathParser::jkmpResult fCMDParam(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpString;
std::string def="";
if (n<1 || n>2) p->jkmpError("cmdparam(name, default) accepts 1 or 2 argument");
if (params[0].type!=JKQTPMathParser::jkmpString) p->jkmpError("cmdparam needs a string as first argument");
if (n>1 && params[1].type!=JKQTPMathParser::jkmpString) p->jkmpError("cmdparam needs a string as second argument");
if (n>1) def=params[1].str;
r.str=p->getArgCVParam(params[0].str, def);
return r;
}
JKQTPMathParser::jkmpResult fSinc(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("sinc accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("sinc needs double argument");
//r.num=sin(params[0].num)/params[0].num;
double x=params[0].num;
static double const taylor_0_bound = 3*DBL_MIN ;
static double const taylor_2_bound = sqrt(taylor_0_bound);
static double const taylor_n_bound = sqrt(taylor_2_bound);
double result = 1;
if (fabs(x) >= taylor_n_bound)
{
result= sin(x)/x;
}
else
{
// approximation by taylor series in x at 0 up to order 0
if (fabs(x) >= taylor_0_bound)
{
double x2 = x*x;
// approximation by taylor series in x at 0 up to order 2
result -= x2/static_cast<double>(6);
if (fabs(x) >= taylor_2_bound)
{
// approximation by taylor series in x at 0 up to order 4
result += (x2*x2)/static_cast<double>(120);
}
}
}
r.num=result;
return r;
}
JKQTPMathParser::jkmpResult fTanc(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("tanc accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("tanc needs double argument");
r.num=(params[0].num==0)?1.0:tan(params[0].num)/params[0].num;
return r;
}
JKQTPMathParser::jkmpResult fSin(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("sin accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("sin needs double argument");
r.num=sin(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fCos(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("cos accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("cos needs double argument");
r.num=cos(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fTan(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("tan accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("tan needs double argument");
r.num=tan(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fExp(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("exp accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("exp needs double argument");
r.num=exp(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fLog(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("log accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("log needs double argument");
r.num=log(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fLog10(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("log10 accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("log10 needs double argument");
r.num=log10(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fLog2(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("log2 accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("log2 needs double argument");
r.num=log2(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fSqrt(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("sqrt accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("sqrt needs double argument");
r.num=sqrt(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fCbrt(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("cbrt accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("cbrt needs double argument");
r.num=cbrt(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fSqr(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("sqr accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("sqr needs double argument");
r.num=params[0].num*params[0].num;
return r;
}
JKQTPMathParser::jkmpResult fAbs(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("abs accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("abs needs double argument");
r.num=fabs(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fIf(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
if (n!=3) p->jkmpError("If accepts 3 argument");
if (params[0].type!=JKQTPMathParser::jkmpBool) p->jkmpError("If needs bool as first argument");
if (params[0].boolean) return params[1]; else return params[2];
}
JKQTPMathParser::jkmpResult fASin(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("asin accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("asin needs double argument");
r.num=asin(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fACos(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("acos accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("acos needs double argument");
r.num=acos(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fATan(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("atan accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("atan needs double argument");
r.num=atan(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fATan2(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("atan2 accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("atan2 needs double argument");
r.num=atan2(params[0].num, params[1].num);
return r;
}
JKQTPMathParser::jkmpResult fSinh(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("sinh accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("sinh needs double argument");
r.num=sinh(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fCosh(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("cosh accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("cosh needs double argument");
r.num=cosh(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fTanh(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("tanh accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("tanh needs double argument");
r.num=tanh(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fErf(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("erf accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("erf needs double argument");
r.num=erf(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fErfc(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("erfc accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("erfc needs double argument");
r.num=erfc(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult flGamma(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("lgamma accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("lgamma needs double argument");
r.num=lgamma(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult ftGamma(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("tgamma accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("tgamma needs double argument");
r.num=tgamma(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fJ0(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("j0 accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("j0 needs double argument");
r.num=j0(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fJ1(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("j1 accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("j1 needs double argument");
r.num=j1(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fY0(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("y0 accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("y0 needs double argument");
r.num=y0(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fY1(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("y1 accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("y1 needs double argument");
r.num=y1(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fYn(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("yn accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("yn needs double argument");
r.num=yn(static_cast<int>(params[0].num), params[1].num);
return r;
}
JKQTPMathParser::jkmpResult fJn(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("jn accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("jn needs double argument");
r.num=jn(static_cast<int>(params[0].num), params[1].num);
return r;
}
JKQTPMathParser::jkmpResult fSRand(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("srand accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("srand needs double argument");
r.num=0;
srand(static_cast<unsigned int>(params[0].num));
return r;
}
JKQTPMathParser::jkmpResult fRand(JKQTPMathParser::jkmpResult* /*params*/, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=0) p->jkmpError("rand accepts 0 argument");
r.num=double(rand())/double(RAND_MAX);
return r;
}
JKQTPMathParser::jkmpResult fCeil(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("ceil accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("ceil needs double argument");
r.num=ceil(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fFloor(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("floor accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("floor needs double argument");
r.num=floor(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fTrunc(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("trunc accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("trunc needs double argument");
r.num=trunc(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fRound(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("round accepts 1 argument");
if (params[0].type!=JKQTPMathParser::jkmpDouble) p->jkmpError("round needs double argument");
r.num=round(params[0].num);
return r;
}
JKQTPMathParser::jkmpResult fFMod(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("fmod accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("fmod needs double argument");
r.num=fmod(static_cast<int>(params[0].num), params[1].num);
return r;
}
JKQTPMathParser::jkmpResult fMin(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("min accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("min needs double argument");
r.num=fmin(static_cast<int>(params[0].num), params[1].num);
return r;
}
JKQTPMathParser::jkmpResult fMax(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("max accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("max needs double argument");
r.num=fmax(static_cast<int>(params[0].num), params[1].num);
return r;
}
JKQTPMathParser::jkmpResult QFSPIMLightsheetEvaluationItem_fGauss(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("gauss accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("gauss needs double argument");
r.num=exp(-2*params[0].num*params[0].num/params[1].num/params[1].num);
return r;
}
JKQTPMathParser::jkmpResult fSlit(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=2) p->jkmpError("slit accepts 2 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)||(params[1].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("slit needs double argument");
r.num=((params[0].num>=-1.0*params[1].num/2)&&(params[0].num<=params[1].num/2))?1.0:0.0;
return r;
}
JKQTPMathParser::jkmpResult fTheta(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("theta accepts 1 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("theta needs double argument");
r.num=(params[0].num>=0)?1.0:0.0;
return r;
}
JKQTPMathParser::jkmpResult fSigmoid(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("sigmoid accepts 1 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("sigmoid needs double argument");
r.num=1.0/(1+exp(-1.0*params[0].num));
return r;
}
JKQTPMathParser::jkmpResult fSign(JKQTPMathParser::jkmpResult* params, unsigned char n, JKQTPMathParser* p){
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
if (n!=1) p->jkmpError("sign accepts 1 argument");
if ((params[0].type!=JKQTPMathParser::jkmpDouble)) p->jkmpError("sign needs double argument");
r.num=0.0;
if (params[0].num<0) { r.num=-1; }
else if (params[0].num>0) { r.num=+1; }
return r;
}
inline std::string strip(const std::string& s) {
std::string r;
r.reserve(s.size());
for (size_t i=0; i<s.size(); i++){
if ((s[i]!=' ')&&(s[i]!='\t')&&(s[i]!='\r')&&(s[i]!='\n')) {
r+=s[i];
}
}
return r;
}
}
std::string JKQTPMathParser::tokentostring(JKQTPMathParser::jkmpTokenType token) {
switch(token) {
case END: return "END";
case PRINT: return "PRINT (;)";
case PARAMETER_DIV: return "PARAMETER_DIV (,)";
case STRING_DELIM: return "STRING_DELIM (' or \")";
case NAME: return "NAME";
case NUMBER: return "NUMBER";
case PLUS: return "PLUS (+)";
case MINUS: return "MINUS (-)";
case MUL: return "MUL (*)";
case DIV: return "DIV (/)";
case MODULO: return "MODULO (%)";
case ASSIGN: return "ASSIGN (=)";
case LBRACKET: return "LBRACKET '('";
case RBRACKET: return "RBRACKET ')'";
case POWER: return "POWER (^)";
case FACTORIAL_LOGIC_NOT: return "FACTORIAL_LOGIC_NOT (!)";
case LOGIC_NOT: return "LOGIC_NOT (!/not)";
case LOGIC_AND: return "LOGIC_AND (&&/and)";
case LOGIC_OR: return "LOGIC_OR (||/or)";
case LOGIC_XOR: return "LOGIC_XOR (xor)";
case LOGIC_NOR: return "LOGIC_NOR (nor)";
case LOGIC_NAND: return "LOGIC_NAND (nand)";
case LOGIC_TRUE: return "LOGIC_TRUE (true)";
case LOGIC_FALSE: return "LOGIC_FALSE (false)";
case COMP_EQUALT: return "COMP_EQUALT (==)";
case COMP_UNEQUAL: return "COMP_UNEQUAL (!=)";
case COMP_GREATER: return "COMP_GREATER (>)";
case COMP_SMALLER: return "COMP_SMALLER (<)";
case COMP_GEQUAL: return "COMP_GEQUAL (>=)";
case COMP_SEQUAL: return "COMP_SEQUAL (<=)";
}
return "unknown";
}
std::string JKQTPMathParser::currenttokentostring() {
switch(CurrentToken) {
case END: return "END";
case PRINT: return "PRINT (;)";
case PARAMETER_DIV: return "PARAMETER_DIV (,)";
case STRING_DELIM: return "STRING_DELIM (' or \")";
case NAME: return jkqtp_format("NAME (%s)", StringValue.c_str());
case NUMBER: return jkqtp_format("NUMBER (%lf)", NumberValue);
case PLUS: return "PLUS (+)";
case MINUS: return "MINUS (-)";
case MUL: return "MUL (*)";
case DIV: return "DIV (/)";
case MODULO: return "MODULO (%)";
case ASSIGN: return "ASSIGN (=)";
case LBRACKET: return "LBRACKET '('";
case RBRACKET: return "RBRACKET ')'";
case POWER: return "POWER (^)";
case FACTORIAL_LOGIC_NOT: return "FACTORIAL_LOGIC_NOT (!)";
case LOGIC_NOT: return "LOGIC_NOT (!/not)";
case LOGIC_AND: return "LOGIC_AND (&/and)";
case LOGIC_OR: return "LOGIC_OR (|/or)";
case LOGIC_XOR: return "LOGIC_XOR (xor)";
case LOGIC_NOR: return "LOGIC_NOR (nor)";
case LOGIC_NAND: return "LOGIC_NAND (nand)";
case LOGIC_TRUE: return "LOGIC_TRUE (true)";
case LOGIC_FALSE: return "LOGIC_FALSE (false)";
case COMP_EQUALT: return "COMP_EQUALT (==)";
case COMP_UNEQUAL: return "COMP_UNEQUAL (!=)";
case COMP_GREATER: return "COMP_GREATER (>)";
case COMP_SMALLER: return "COMP_SMALLER (<)";
case COMP_GEQUAL: return "COMP_GEQUAL (>=)";
case COMP_SEQUAL: return "COMP_SEQUAL (<=)";
}
return "unknown";
}
/******************************************************************************************
* jkMathParser
******************************************************************************************/
// class constructor
JKQTPMathParser::JKQTPMathParser() {
jkmathparser_exception_function=nullptr;
data=nullptr;
argc=0;
argv=nullptr;
addStandardFunctions();
addStandardVariables();
}
void JKQTPMathParser::addStandardVariables(){
addVariableDouble("pi", M_PI);
addVariableDouble("e", M_E);
addVariableDouble("sqrt2", sqrt(2));
addVariableString("version", "0.2");
addVariableDouble("log2e", M_LOG2E);
addVariableDouble("log10e", M_LOG10E);
addVariableDouble("ln2", M_LN2);
addVariableDouble("ln10", M_LN10);
addVariableDouble("h", 6.6260689633E-34);
addVariableDouble("hbar", 1.05457162853E-34);
addVariableDouble("epsilon0", 8.854187817E-12);
addVariableDouble("mu0", 12.566370614E-7);
addVariableDouble("c", 299792458);
addVariableDouble("ce", 1.60217648740E-19);
addVariableDouble("muB", 927.40091523E-26);
addVariableDouble("muB_eV", 5.788381755579E-5);
addVariableDouble("muN", 5.0507832413E-27);
addVariableDouble("muN_eV", 3.152451232645E-8);
addVariableDouble("me", 9.1093821545E-31);
addVariableDouble("mp", 1.67262163783E-27);
addVariableDouble("mn", 1.67492721184E-27);
addVariableDouble("NA", 6.0221417930E23);
addVariableDouble("kB", 1.380650424E-23);
addVariableDouble("kB_eV", 8.61734315E-5);
}
void JKQTPMathParser::addStandardFunctions(){
addFunction("sinc", fSinc);
addFunction("asin", fASin);
addFunction("acos", fACos);
addFunction("atan", fATan);
addFunction("atan2", fATan2);
addFunction("sin", fSin);
addFunction("cos", fCos);
addFunction("tan", fTan);
addFunction("sinh", fSinh);
addFunction("cosh", fCosh);
addFunction("tanh", fTanh);
addFunction("log", fLog);
addFunction("log2", fLog2);
addFunction("log10", fLog10);
addFunction("exp", fExp);
addFunction("sqrt", fSqrt);
addFunction("cbrt", fCbrt);
addFunction("sqr", fSqr);
addFunction("abs", fAbs);
addFunction("if", fIf);
addFunction("erf", fErf);
addFunction("erfc", fErfc);
addFunction("lgamma", flGamma);
addFunction("tgamma", ftGamma);
addFunction("j0", fJ0);
addFunction("j1", fJ1);
addFunction("jn", fJn);
addFunction("y0", fY0);
addFunction("y1", fY1);
addFunction("yn", fYn);
addFunction("rand", fRand);
addFunction("srand", fSRand);
addFunction("ceil", fCeil);
addFunction("floor", fFloor);
addFunction("trunc", fTrunc);
addFunction("round", fRound);
addFunction("fmod", fFMod);
addFunction("min", fMin);
addFunction("max", fMax);
addFunction("inttostr", fIntToStr);
addFunction("floattostr", fFloatToStr);
addFunction("num2str", fFloatToStr);
addFunction("booltostr", fBoolToStr);
addFunction("bool2str", fBoolToStr);
addFunction("gauss", QFSPIMLightsheetEvaluationItem_fGauss);
addFunction("slit", fSlit);
addFunction("theta", fTheta);
addFunction("tanc", fTanc);
addFunction("sigmoid", fSigmoid);
addFunction("sign", fSign);
addFunction("tosystempathseparator", fToSystemPathSeparator);
addFunction("setdefault", fSetDefault);
addFunction("strdate", fStrDate);
addFunction("cmdparam", fCMDParam);
addFunction("argv", fCMDParam);
}
// class destructor
JKQTPMathParser::~JKQTPMathParser()
{
clearFunctions();
clearVariables();
}
void JKQTPMathParser::addVariableDouble(const std::string& ni, double* v)
{
std::string name=strip(ni);
jkmpVariable nv;
nv.type=JKQTPMathParser::jkmpDouble;
nv.num=v;
if (variableExists(name)) nv.internal=variables[name].internal; else nv.internal=false;
variables[name]=nv;
}
void JKQTPMathParser::addVariableString(const std::string& ni, std::string* v)
{
std::string name=strip(ni);
jkmpVariable nv;
nv.type=JKQTPMathParser::jkmpString;
nv.str=v;
if (variableExists(name)) nv.internal=variables[name].internal; else nv.internal=false;
variables[name]=nv;
}
void JKQTPMathParser::addVariableBoolean(const std::string& ni, bool* v)
{
std::string name=strip(ni);
jkmpVariable nv;
nv.type=JKQTPMathParser::jkmpBool;
nv.boolean=v;
if (variableExists(name)) nv.internal=variables[name].internal; else nv.internal=false;
variables[name]=nv;
}
void JKQTPMathParser::addVariableDouble(const std::string& name, double v)
{
jkmpVariable nv;
nv.type=JKQTPMathParser::jkmpDouble;
nv.num=new double;//static_cast<double*>(malloc(sizeof(double)));
nv.internal=true;
*(nv.num)=v;
// std::cout<<*(nv.num)<<std::endl;
variables[strip(name)]=nv;
}
void JKQTPMathParser::addVariableString(const std::string& name, const std::string& v)
{
jkmpVariable nv;
nv.type=JKQTPMathParser::jkmpString;
nv.str=new std::string;
nv.internal=true;
*(nv.str)=v;
variables[strip(name)]=nv;
}
void JKQTPMathParser::addVariableBoolean(const std::string& name, bool v)
{
jkmpVariable nv;
nv.type=JKQTPMathParser::jkmpBool;
nv.boolean=new bool;
nv.internal=true;
*(nv.boolean)=v;
variables[strip(name)]=nv;
}
void JKQTPMathParser::addVariable(const std::string& name, JKQTPMathParser::jkmpResult result)
{
switch(result.type) {
case jkmpDouble:
addVariableDouble(name, result.num);
break;
case jkmpString:
addVariableString(name, result.str);
break;
case jkmpBool:
addVariableBoolean(name, result.boolean);
break;
}
}
void JKQTPMathParser::printVariables() {
if (variables.size()>0) {
for(std::map<std::string, jkmpVariable>::const_iterator i=variables.begin(); i!=variables.end(); ++i) {
jkmpVariable v=variables[i->first];
std::cout<<"'"<<i->first.c_str()<<"'"<<"\t\t";
if (v.internal) std::cout<<"intern"; else std::cout<<"extern";
std::cout<<"\t";
if (v.type==JKQTPMathParser::jkmpBool) std::cout<<"bool\t";
if (v.type==JKQTPMathParser::jkmpDouble) std::cout<<"double\t";
if (v.type==JKQTPMathParser::jkmpString) std::cout<<"string\t";
std::cout<<std::endl;
}
}
}
std::vector<std::pair<std::string, JKQTPMathParser::jkmpVariable> > JKQTPMathParser::getVariables()
{
std::vector<std::pair<std::string, jkmpVariable> > result;
if (variables.size()>0) {
for(std::map<std::string, jkmpVariable>::const_iterator i=variables.begin(); i!=variables.end(); ++i) {
jkmpVariable v=variables[i->first];
result.push_back(make_pair(i->first, v));
}
}
return result;
}
void JKQTPMathParser::deleteVariable(const std::string& name) {
if (variableExists(name)) {
jkmpVariable v=variables[name];
if (v.internal) {
if (v.type==JKQTPMathParser::jkmpDouble) { delete v.num; }
else if (v.type==JKQTPMathParser::jkmpString) { delete v.str; }
else if (v.type==JKQTPMathParser::jkmpBool) { delete v.boolean; }
}
variables.erase(variables.find(name));
}
}
void JKQTPMathParser::clearVariables(){
if (variables.size()>0) {
for(std::map<std::string, jkmpVariable>::const_iterator i=variables.begin(); i!=variables.end(); ++i) {
jkmpVariable v=variables[i->first];
if (v.internal) {
if (v.type==JKQTPMathParser::jkmpDouble) { delete v.num; }
else if (v.type==JKQTPMathParser::jkmpString) { delete v.str; }
else if (v.type==JKQTPMathParser::jkmpBool) { delete v.boolean; }
}
}
variables.clear();
}
}
// gibt den aktuellen Wert einer Variablen zur<75>ck
JKQTPMathParser::jkmpResult JKQTPMathParser::getVariable(const std::string& name)
{
if (variableExists(name)) {
jkmpVariable v=variables[name];
JKQTPMathParser::jkmpResult r;
r.type=v.type;
if (v.type==JKQTPMathParser::jkmpDouble) {
r.num=*(v.num);
} else if (v.type==JKQTPMathParser::jkmpString) {
r.str=*(v.str);
} else if (v.type==JKQTPMathParser::jkmpBool) {
r.boolean=*(v.boolean);
}
return r;
} else {
// error
//std::cout <<"error for: '"<<name<<"'"<<std::endl;
jkmpError(jkqtp_format("variable '%s' does not exist (getVariable)", name.c_str()));
}
JKQTPMathParser::jkmpResult res;
res.isValid=false;
return res;
}
JKQTPMathParser::jkmpResult JKQTPMathParser::getVariableOrInvalid(const std::string& name)
{
if (variableExists(name)) {
jkmpVariable v=variables[name];
JKQTPMathParser::jkmpResult r;
r.type=v.type;
if (v.type==JKQTPMathParser::jkmpDouble) {
r.num=*(v.num);
} else if (v.type==JKQTPMathParser::jkmpString) {
r.str=*(v.str);
} else if (v.type==JKQTPMathParser::jkmpBool) {
r.boolean=*(v.boolean);
}
return r;
}
JKQTPMathParser::jkmpResult res;
res.isValid=false;
return res;
}
JKQTPMathParser::jkmpVariable JKQTPMathParser::getVariableDef(const std::string& name)
{
if (variableExists(name)) {
return variables[name];
} else {
// error
//std::cout <<"error for: '"<<name<<"'"<<std::endl;
jkmpError(jkqtp_format("variable '%s' does not exist (getVariableDef)", name.c_str()));
}
return jkmpVariable();
}
JKQTPMathParser::jkmpEvaluateFunc JKQTPMathParser::getFunctionDef(const std::string& name){
if (functionExists(name)) {
return functions[name].function;
} else {
// error
//std::cout <<name<<std::endl;
jkmpError(jkqtp_format("function '%s' does not exist (getFunctionDef)", name.c_str()));
}
return nullptr;
}
void JKQTPMathParser::addTempVariable(const std::string& name, JKQTPMathParser::jkmpResult value) {
jkmpTempVariable v;
v.name=name;
v.type=value.type;
v.internal=true;
if (v.type==JKQTPMathParser::jkmpDouble) { v.num=new double; }
else if (v.type==JKQTPMathParser::jkmpString) { v.str=new std::string; }
else if (v.type==JKQTPMathParser::jkmpBool) { v.boolean=new bool; }
tempvariables.push_back(v);
}
void JKQTPMathParser::setVariableDouble(const std::string& name, double value) {
JKQTPMathParser::jkmpResult r;
r.type=JKQTPMathParser::jkmpDouble;
r.num=value;
setVariable(name, r);
}
void JKQTPMathParser::setVariable(const std::string& name, JKQTPMathParser::jkmpResult value)
{
bool nexist=!variableExists(name);
jkmpVariable v=variables[name];
v.type=value.type;
if (value.type==JKQTPMathParser::jkmpDouble) {
if (nexist) {v.num=new double; v.internal=true;}
*(v.num)=value.num;
} else if (value.type==JKQTPMathParser::jkmpString) {
if (nexist) {v.str=new std::string; v.internal=true;}
*(v.str)=value.str;
} else if (value.type==JKQTPMathParser::jkmpBool) {
if (nexist) {v.boolean=new bool; v.internal=true;}
*(v.boolean)=value.boolean;
}
variables[name]=v;
}
// wertet eine Funktion aus
JKQTPMathParser::jkmpResult JKQTPMathParser::evaluateFunction(const std::string& name, JKQTPMathParser::jkmpResult* params, unsigned char n)
{
if (functionExists(name)) {
//std::cout <<"found" ;
return functions[name].function(params, n, this);
} else {
// error
//jkmpError("function does not exist")
jkmpError(jkqtp_format("function '%s' does not exist (evaluateFunction)", name.c_str()));
}
JKQTPMathParser::jkmpResult res;
res.isValid=false;
return res;
}
void JKQTPMathParser::addFunction(const std::string& name, jkmpEvaluateFunc function) {
jkmpFunctionDescriptor f;
f.function=function;
f.name=name;
functions[name]=f;
}
JKQTPMathParser::jkmpTokenType JKQTPMathParser::getToken(){
char ch=0;
while(program->get(ch) && isspace(ch)) {
;
}
switch (ch) {
case 0:
case -1:
return CurrentToken=END;
case ';':
return CurrentToken=PRINT;
case '*':
return CurrentToken=MUL;
case '/':
return CurrentToken=DIV;
case '%':
return CurrentToken=MODULO;
case '+':
return CurrentToken=PLUS;
case '-':
return CurrentToken=MINUS;
case '(':
return CurrentToken=LBRACKET;
case ')':
return CurrentToken=RBRACKET;
case ',':
return CurrentToken=PARAMETER_DIV;
case '"':
return CurrentToken=STRING_DELIM;
case '^':
return CurrentToken=POWER;
case '!':{
char ch1=0;
if (*program) program->get(ch1);
if (ch1=='=') return CurrentToken=COMP_UNEQUAL;
// else
program->putback(ch1);
return CurrentToken=FACTORIAL_LOGIC_NOT;
}
case '&':{
char ch1=0;
if (*program) program->get(ch1);
if (ch1=='&') return CurrentToken=LOGIC_AND;
// else
program->putback(ch1);
jkmpError("undefined operator '&'; Did you mean LOGICAL_AND ('&&' / 'and')?");
break;
}
case '|':{
char ch1=0;
if (*program) program->get(ch1);
if (ch1=='|') return CurrentToken=LOGIC_OR;
// else
program->putback(ch1);
jkmpError("undefined operator '|'; Did you mean LOGICAL_OR ('||' / 'or')?");
break;
}
case '=':{
char ch1=0;
if (*program) program->get(ch1);
if (ch1=='=') return CurrentToken=COMP_EQUALT;
// else
program->putback(ch1);
return CurrentToken=ASSIGN;
}
case '>':{
char ch1=0;
if (*program) program->get(ch1);
if (ch1=='=') return CurrentToken=COMP_GEQUAL;
// else
program->putback(ch1);
return CurrentToken=COMP_GREATER;
}
case '<':{
char ch1=0;
if (*program) program->get(ch1);
if (ch1=='=') return CurrentToken=COMP_SEQUAL;
// else
program->putback(ch1);
return CurrentToken=COMP_SMALLER;
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':{
program->putback(ch);
(*program) >> NumberValue;
return CurrentToken=NUMBER;
}
default:
if (isalpha(ch) || (ch=='_')) { // try to recognize NAME, LOGIC_TRUE, LOGIC_FALSE, DIFF_LBRACKET
StringValue=ch;
while (program->get(ch) && (isalnum(ch) || (ch=='_') || (ch=='.'))) {
if (isalnum(ch) || (ch=='_') || (ch=='.')) {
StringValue.push_back(ch);
}
}
program->putback(ch); // now put the last thing read back int the stream, as it
// could belong to the next token
if (StringValue=="true") return CurrentToken=LOGIC_TRUE;
if (StringValue=="false") return CurrentToken=LOGIC_FALSE;
if (StringValue=="and") return CurrentToken=LOGIC_AND;
if (StringValue=="or") return CurrentToken=LOGIC_OR;
if (StringValue=="xor") return CurrentToken=LOGIC_XOR;
if (StringValue=="not") return CurrentToken=LOGIC_NOT;
if (StringValue=="nor") return CurrentToken=LOGIC_NOR;
if (StringValue=="nand") return CurrentToken=LOGIC_NAND;
return CurrentToken=NAME;
}
// the parser has found an unknown token. an exception will be thrown
//std::cout<<StringValue<<", "<<ch<<std::endl;
jkmpError(jkqtp_format("unknown token currentCharacter='%s', currentString='%s'", jkqtp_chartostr(ch).c_str(), StringValue.c_str()));
}
return END;
}
JKQTPMathParser::jkmpNode* JKQTPMathParser::parse(const std::string& prog){
program=new std::istringstream(prog);
JKQTPMathParser::jkmpNode* res=nullptr;
JKQTPMathParser::jkmpNodeList* resList=new JKQTPMathParser::jkmpNodeList(this);
while(true) {
getToken();
if (CurrentToken == END) {
break;
}
res= logicalExpression(false);
resList->add(res);
}
delete program;
if (resList->getCount()==1) {
delete resList;
return res;
} else {
return resList;
}
}
JKQTPMathParser::jkmpResult JKQTPMathParser::evaluate(const std::string& prog) {
JKQTPMathParser::jkmpNode* res=parse(prog);
JKQTPMathParser::jkmpResult r=res->evaluate();
delete res;
return r;
}
JKQTPMathParser::jkmpNode* JKQTPMathParser::logicalExpression(bool get){
JKQTPMathParser::jkmpNode* left=logicalTerm(get);
for(;;) // forever, do until you find anything else than an expressions
switch(CurrentToken) {
case LOGIC_OR:
left= new jkmpBinaryBoolNode(jkmpLOPor, left, logicalTerm(true), this, nullptr);
break;
case LOGIC_XOR:
left= new jkmpBinaryBoolNode(jkmpLOPxor, left, logicalTerm(true), this, nullptr);
break;
case LOGIC_NOR:
left= new jkmpBinaryBoolNode(jkmpLOPnor, left, logicalTerm(true), this, nullptr);
break;
default:
return left;
}
}
JKQTPMathParser::jkmpNode* JKQTPMathParser::logicalTerm(bool get){
JKQTPMathParser::jkmpNode* left=compExpression(get);
for(;;) // forever, do until you find anything else than an expressions
switch(CurrentToken) {
case LOGIC_AND:
left= new jkmpBinaryBoolNode(jkmpLOPand, left, compExpression(true), this, nullptr);
break;
case LOGIC_NAND:
left= new jkmpBinaryBoolNode(jkmpLOPnand, left, compExpression(true), this, nullptr);
break;
default:
return left;
}
}
JKQTPMathParser::jkmpNode* JKQTPMathParser::compExpression(bool get){
JKQTPMathParser::jkmpNode* left=mathExpression(get);
for(;;) // forever, do until you find anything else than an expressions
switch(CurrentToken) {
case COMP_EQUALT:
left= new jkmpCompareNode(jkmpCOMPequal, left, mathExpression(true), this, nullptr);
break;
case COMP_UNEQUAL:
left= new jkmpCompareNode(jkmpCOMPnequal, left, mathExpression(true), this, nullptr);
break;
case COMP_GREATER:
left= new jkmpCompareNode(jkmpCOMPgreater, left, mathExpression(true), this, nullptr);
break;
case COMP_SMALLER:
left= new jkmpCompareNode(jkmpCOMPlesser, left, mathExpression(true), this, nullptr);
break;
case COMP_GEQUAL:
left= new jkmpCompareNode(jkmpCOMPgreaterequal, left, mathExpression(true), this, nullptr);
break;
case COMP_SEQUAL:
left= new jkmpCompareNode(jkmpCOMPlesserequal, left, mathExpression(true), this, nullptr);
break;
default:
return left;
}
}
JKQTPMathParser::jkmpNode* JKQTPMathParser::mathExpression(bool get){
JKQTPMathParser::jkmpNode* left=mathTerm(get);
for(;;) // forever, do until you find anything else than an expressions
switch(CurrentToken) {
case PLUS:
left= new jkmpBinaryArithmeticNode('+', left, mathTerm(true), this, nullptr);
break;
case MINUS:
left= new jkmpBinaryArithmeticNode('-', left, mathTerm(true), this, nullptr);
break;
default:
return left;
}
}
JKQTPMathParser::jkmpNode* JKQTPMathParser::mathTerm(bool get){
JKQTPMathParser::jkmpNode* left=primary(get);
for(;;) // forever, do until you find anything else than a term
switch(CurrentToken) {
case MUL:
left= new jkmpBinaryArithmeticNode('*', left, primary(true), this, nullptr);
break;
case DIV:
left= new jkmpBinaryArithmeticNode('/', left, primary(true), this, nullptr);
break;
case MODULO:
left= new jkmpBinaryArithmeticNode('%', left, primary(true), this, nullptr);
break;
default:
return left;
}
}
JKQTPMathParser::jkmpNode* JKQTPMathParser::primary(bool get){
JKQTPMathParser::jkmpNode* res=nullptr;
if (get) getToken();
switch(CurrentToken) {
case NUMBER: {
JKQTPMathParser::jkmpResult val;
val.type=JKQTPMathParser::jkmpDouble;
val.num=NumberValue;
getToken();
res= new jkmpConstantNode(val, this, nullptr);
break;
}
case NAME: {
//jkMathParser::jkmpNode* def=nullptr;
std::string varname=StringValue;
getToken();
if (CurrentToken == ASSIGN) { // assign a variable name
res=new jkmpVariableAssignNode(varname, logicalExpression(true), this, nullptr);
} else if (CurrentToken == LBRACKET) { // function found
JKQTPMathParser::jkmpNode** params=static_cast<JKQTPMathParser::jkmpNode**>(malloc(255*sizeof(JKQTPMathParser::jkmpNode*)));
unsigned char num=0;
getToken();
while ((CurrentToken != RBRACKET)&&(CurrentToken!=END)) {
JKQTPMathParser::jkmpNode* parameter=logicalExpression(num>0);
params[num]=parameter;
num++;
if ((CurrentToken!=RBRACKET)&&(CurrentToken!=PARAMETER_DIV)&&(CurrentToken!=END))
jkmpError(jkqtp_format("')' or ',' expected, but '%s' found", currenttokentostring().c_str()));
}
if ( CurrentToken != RBRACKET ) jkmpError(jkqtp_format("')' expected, but '%s' found", currenttokentostring().c_str()));;
JKQTPMathParser::jkmpNode** p=nullptr;
if (num>0) {
p=static_cast<JKQTPMathParser::jkmpNode**>(malloc(sizeof(JKQTPMathParser::jkmpNode*) * num));
for (int i=0; i<num; i++) {
p[i]=params[i];
}
}
res=new jkmpFunctionNode(varname, p, num, this, nullptr);
free(params);
getToken();
} else {
res=new jkmpVariableNode(varname, this, nullptr);
}
//res= def;
break;
}
case STRING_DELIM: {// found primary: "data" == string constant
JKQTPMathParser::jkmpResult val;
val.type=JKQTPMathParser::jkmpString;
val.str=readDelim('"');
res= new jkmpConstantNode(val, this, nullptr);
getToken();
break;
}
case MINUS: // found primary: - primary
res= new jkmpUnaryNode('-', primary(true), this, nullptr);
break;
case LOGIC_NOT:
res= new jkmpUnaryNode('!', primary(true), this, nullptr);
break;
case LBRACKET: { // found primary ( expression )
JKQTPMathParser::jkmpNode* expr=logicalExpression(true);
if (CurrentToken != RBRACKET) jkmpError(jkqtp_format("')' expected, but '%s' found", currenttokentostring().c_str()));
getToken(); // swallow ")"
res= expr;
break;
}
case FACTORIAL_LOGIC_NOT:
case LOGIC_TRUE: {// found 'true'
JKQTPMathParser::jkmpResult val;
val.type=JKQTPMathParser::jkmpBool;
val.boolean=true;
res= new jkmpConstantNode(val, this, nullptr);
getToken();
break;
}
case LOGIC_FALSE: {// found 'false'
JKQTPMathParser::jkmpResult val;
val.type=JKQTPMathParser::jkmpBool;
val.boolean=false;
res= new jkmpConstantNode(val, this, nullptr);
getToken();
break;
}
default:
jkmpError("primary expected");
}
if (CurrentToken==POWER) {
res=new jkmpBinaryArithmeticNode('^', res, primary(true), this, nullptr);
}
return res;
}
std::string JKQTPMathParser::readDelim(char delimiter){
std::string res="";
char ch=0;
while(program->get(ch)) {
if (ch==delimiter ) {
char ch1=program->peek();
if (ch1==delimiter) {
program->get(ch);
res=res+delimiter;
} else {
break;
}
} else if ((*program) && (ch!=delimiter)) res=res+ch;
}
return res;
}
/******************************************************************************************
* Klassenhierarchie, um Ausdr<EFBFBD>cke darzustellen
******************************************************************************************/
JKQTPMathParser::jkmpUnaryNode::jkmpUnaryNode(char op, JKQTPMathParser::jkmpNode* c, JKQTPMathParser* p, JKQTPMathParser::jkmpNode* par){
child=c;
child->setParent(this);
setParser(p);
setParent(par);
operation=op;
}
JKQTPMathParser::jkmpUnaryNode::~jkmpUnaryNode() {delete child;}
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpUnaryNode::evaluate(){
JKQTPMathParser::jkmpResult c=child->evaluate();
JKQTPMathParser::jkmpResult res;
res=c;
switch(operation) {
case '!':
if (c.type==JKQTPMathParser::jkmpBool) {
res.boolean=!c.boolean;
return res;
} else parser->jkmpError("'!' only defined for bool");
break;
case '-':
if (c.type==JKQTPMathParser::jkmpDouble) {
res.num=-c.num;
return res;
} else parser->jkmpError("'-' only defined for double");
break;
default: parser->jkmpError("unknown unary operation");
}
res.isValid=false;
return res;
}
JKQTPMathParser::jkmpBinaryArithmeticNode::jkmpBinaryArithmeticNode(char op, JKQTPMathParser::jkmpNode* l, JKQTPMathParser::jkmpNode* r, JKQTPMathParser* p, JKQTPMathParser::jkmpNode* par){
left=l;
right=r;
left->setParent(this);
right->setParent(this);
setParser(p);
setParent(par);
operation=op;
}
JKQTPMathParser::jkmpBinaryArithmeticNode::~jkmpBinaryArithmeticNode() { delete left; delete right;}
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpBinaryArithmeticNode::evaluate(){
JKQTPMathParser::jkmpResult l=left->evaluate();
JKQTPMathParser::jkmpResult r=right->evaluate();
JKQTPMathParser::jkmpResult res;
switch(operation) {
case '+':
if (l.type==r.type) {
if (l.type==JKQTPMathParser::jkmpDouble) {
res.type=JKQTPMathParser::jkmpDouble;
res.num=l.num+r.num;
return res;
}
if (l.type==JKQTPMathParser::jkmpString) {
res.type=JKQTPMathParser::jkmpString;
res.str=l.str+r.str;
return res;
}
parser->jkmpError("bool may not be added");
} else parser->jkmpError("different Types while adding");
break;
case '-':
if (l.type==r.type) {
if (l.type==JKQTPMathParser::jkmpDouble) {
res.type=JKQTPMathParser::jkmpDouble;
res.num=l.num-r.num;
return res;
}
parser->jkmpError("bool or string may not be subtractet");
} else parser->jkmpError("different Types while subtracting");
break;
case '*':
if (l.type==r.type) {
if (l.type==JKQTPMathParser::jkmpDouble) {
res.type=JKQTPMathParser::jkmpDouble;
res.num=l.num*r.num;
return res;
}
parser->jkmpError("bool or string may not be multiplied");
} else parser->jkmpError("different Types while multiplying");
break;
case '/':
if (l.type==r.type) {
if (l.type==JKQTPMathParser::jkmpDouble) {
res.type=JKQTPMathParser::jkmpDouble;
res.num=l.num/r.num;
return res;
}
parser->jkmpError("bool or string may not be divided");
} else parser->jkmpError("different Types while dividing");
break;
case '%':
if (l.type==r.type) {
if (l.type==JKQTPMathParser::jkmpDouble) {
if ((l.num==floor(l.num)) && (r.num==floor(r.num))) {
res.type=JKQTPMathParser::jkmpDouble;
res.num=l.num/r.num;
return res;
} else {
parser->jkmpError("modulo is only defined for integer arguments");
}
}
parser->jkmpError("modulo is not defined for bool or string arguments");
} else parser->jkmpError("different Types while calculating modulo");
break;
case '^':
if (l.type==r.type) {
if (l.type==JKQTPMathParser::jkmpDouble) {
res.type=JKQTPMathParser::jkmpDouble;
res.num=pow(l.num, r.num);
return res;
}
parser->jkmpError("bool or string may not be taken to powers");
} else parser->jkmpError("different types while taking to power");
break;
default: parser->jkmpError("unknown arithmetic operation");
}
res.isValid=false;
return res;
}
JKQTPMathParser::jkmpCompareNode::jkmpCompareNode(char op, JKQTPMathParser::jkmpNode* l, JKQTPMathParser::jkmpNode* r, JKQTPMathParser* p, JKQTPMathParser::jkmpNode* par){
left=l;
right=r;
left->setParent(this);
right->setParent(this);
setParser(p);
setParent(par);
operation=op;
}
JKQTPMathParser::jkmpCompareNode::~jkmpCompareNode() { delete left; delete right;}
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpCompareNode::evaluate(){
JKQTPMathParser::jkmpResult l=left->evaluate();
JKQTPMathParser::jkmpResult r=right->evaluate();
JKQTPMathParser::jkmpResult res;
res.type=JKQTPMathParser::jkmpBool;
if (l.type!=r.type) parser->jkmpError("you can't compare different datatypes");
switch(operation) {
case jkmpCOMPequal:
if (l.type==JKQTPMathParser::jkmpDouble) {
res.boolean=(l.num==r.num);
return res;
}
if (l.type==JKQTPMathParser::jkmpBool) {
res.boolean=(l.boolean==r.boolean);
return res;
}
if (l.type==JKQTPMathParser::jkmpString) {
res.boolean=(l.str==r.str);
return res;
}
break;
case jkmpCOMPnequal:
if (l.type==JKQTPMathParser::jkmpDouble) {
res.boolean=(l.num!=r.num);
return res;
}
if (l.type==JKQTPMathParser::jkmpBool) {
res.boolean=(l.boolean!=r.boolean);
return res;
}
if (l.type==JKQTPMathParser::jkmpString) {
res.boolean=(l.str!=r.str);
return res;
}
break;
case jkmpCOMPgreater:
if (l.type==JKQTPMathParser::jkmpDouble) {
res.boolean=(l.num>r.num);
return res;
}
if (l.type==JKQTPMathParser::jkmpBool) {
res.boolean=(l.boolean>r.boolean);
return res;
}
if (l.type==JKQTPMathParser::jkmpString) {
res.boolean=(l.str>r.str);
return res;
}
break;
case jkmpCOMPlesser:
if (l.type==JKQTPMathParser::jkmpDouble) {
res.boolean=(l.num<r.num);
return res;
}
if (l.type==JKQTPMathParser::jkmpBool) {
res.boolean=(l.boolean<r.boolean);
return res;
}
if (l.type==JKQTPMathParser::jkmpString) {
res.boolean=(l.str<r.str);
return res;
}
break;
case jkmpCOMPgreaterequal:
if (l.type==JKQTPMathParser::jkmpDouble) {
res.boolean=(l.num>=r.num);
return res;
}
if (l.type==JKQTPMathParser::jkmpBool) {
res.boolean=(l.boolean>=r.boolean);
return res;
}
if (l.type==JKQTPMathParser::jkmpString) {
res.boolean=(l.str>=r.str);
return res;
}
break;
case jkmpCOMPlesserequal:
if (l.type==JKQTPMathParser::jkmpDouble) {
res.boolean=(l.num<=r.num);
return res;
}
if (l.type==JKQTPMathParser::jkmpBool) {
res.boolean=(l.boolean<=r.boolean);
return res;
}
if (l.type==JKQTPMathParser::jkmpString) {
res.boolean=(l.str<=r.str);
return res;
}
break;
default: parser->jkmpError("unknown compare operation");
}
res.isValid=false;
return res;
}
JKQTPMathParser::jkmpBinaryBoolNode::jkmpBinaryBoolNode(char op, JKQTPMathParser::jkmpNode* l, JKQTPMathParser::jkmpNode* r, JKQTPMathParser* p, JKQTPMathParser::jkmpNode* par){
left=l;
right=r;
left->setParent(this);
right->setParent(this);
setParser(p);
setParent(par);
operation=op;
}
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpBinaryBoolNode::evaluate(){
JKQTPMathParser::jkmpResult l=left->evaluate();
JKQTPMathParser::jkmpResult r=right->evaluate();
JKQTPMathParser::jkmpResult res;
if ((l.type!=JKQTPMathParser::jkmpBool)||(r.type!=JKQTPMathParser::jkmpBool)) parser->jkmpError("logical operations only for bool");
switch(operation) {
case jkmpLOPand:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=l.boolean&&r.boolean;
return res;
break;
case jkmpLOPor:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=l.boolean||r.boolean;
return res;
break;
case jkmpLOPnor:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=!(l.boolean||r.boolean);
return res;
break;
case jkmpLOPxor:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=(l.boolean&& (!r.boolean))||(r.boolean&& (!l.boolean));
return res;
break;
case jkmpLOPnand:
res.type=JKQTPMathParser::jkmpBool;
res.boolean=!(l.boolean&&r.boolean);
return res;
break;
default: parser->jkmpError("unknown error");
}
res.isValid=false;
return res;
}
JKQTPMathParser::jkmpBinaryBoolNode::~jkmpBinaryBoolNode() { delete left; delete right;}
JKQTPMathParser::jkmpVariableNode::jkmpVariableNode(const std::string& name, JKQTPMathParser* p, JKQTPMathParser::jkmpNode* par) {
var=name;
setParser(p);
setParent(par);
};
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpVariableNode::evaluate() {
return getParser()->getVariable(var);
};
void JKQTPMathParser::jkmpNodeList::add(JKQTPMathParser::jkmpNode* n){
list.push_back(n);
}
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpNodeList::evaluate(){
int n=getCount();
JKQTPMathParser::jkmpResult res;
//std::cout<<"Nodelist.count()="<<n<<std::endl;
if (n>0) {
for (size_t i=0; i<static_cast<size_t>(n); i++) {
res=list[i]->evaluate();
}
return res;
} else parser->jkmpError("NodeList empty");
res.isValid=false;
return res;
}
JKQTPMathParser::jkmpNodeList::jkmpNodeList(JKQTPMathParser *p) { setParser(p); setParent(nullptr); }
JKQTPMathParser::jkmpNodeList::~jkmpNodeList() = default;
JKQTPMathParser::jkmpVariableAssignNode::~jkmpVariableAssignNode() {delete child;}
JKQTPMathParser::jkmpVariableAssignNode::jkmpVariableAssignNode(const std::string& var, JKQTPMathParser::jkmpNode* c, JKQTPMathParser* p, JKQTPMathParser::jkmpNode* par){
child=c;
child->setParent(this);
setParser(p);
setParent(par);
variable=var;
// std::cout<<"assign: "<<var<<std::endl;
}
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpVariableAssignNode::evaluate(){
JKQTPMathParser::jkmpResult res=child->evaluate();
// std::cout<<"assign: "<<variable<<" "<<res.num<<std::endl;
getParser()->setVariable(variable, res);
return res;
}
JKQTPMathParser::jkmpFunctionNode::jkmpFunctionNode(const std::string& name, JKQTPMathParser::jkmpNode** c, unsigned char num, JKQTPMathParser* p, JKQTPMathParser::jkmpNode* par) {
child=c;
n=num;
fun=name;
setParser(p);
setParent(par);
if (n>0) {
for (int i=0; i<n; i++) {
child[i]->setParent(this);
}
}
function=p->getFunctionDef(name);
}
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpFunctionNode::evaluate() {
JKQTPMathParser::jkmpResult data[255];
if (n>0) {
for (int i=0; i<n; i++) {
data[i]=child[i]->evaluate();
}
}
// jkMathParser::jkmpResult r= getParser()->evaluateFunction(fun, data,n);
return function(data,n, parser);
}
JKQTPMathParser::jkmpFunctionNode::~jkmpFunctionNode() {
/*if (n>0) {
for (int i=0; i<n; i++) {
delete child[i];
}
}*/
if ((child!=nullptr) && (n>0)) {
for (int i=0; i<n; i++) {
delete child[i];
}
free(child);
}
}
JKQTPMathParser::jkmpResult::jkmpResult()
{
isValid=true;
type=jkmpDouble; /*!< \brief type of the result */
str=""; /*!< \brief contains result if \c type==jkmpString */
num=0; /*!< \brief contains result if \c type==jkmpDouble */
boolean=false; /*!< \brief contains result if \c type==jkmpBool */
}
JKQTPMathParser::jkmpVariable::jkmpVariable()
{
type=jkmpDouble; /*!< \brief type of the variable */
internal=false; /*!< \brief this is an internal variable */
str=nullptr; /*!< \brief this points to the variable data if \c type==jkmpString */
num=nullptr; /*!< \brief this points to the variable data if \c type==jkmpDouble */
boolean=nullptr;
}
void JKQTPMathParser::setArgCV(int argc, char **argv) {
this->argc=argc;
this->argv=argv;
}
std::string JKQTPMathParser::getArgCVParam(const std::string& name, const std::string& defaultResult) {
if (!argv ) return defaultResult;
if (argc<=1) return defaultResult;
for (int i=1; i<argc; i++) {
if (name==std::string(argv[i]) && i+1<argc) {
return std::string(argv[i+1]);
}
}
return defaultResult;
}
JKQTPMathParser::jkmpNode::~jkmpNode() = default;
JKQTPMathParser::jkmpConstantNode::jkmpConstantNode(JKQTPMathParser::jkmpResult d, JKQTPMathParser *p, JKQTPMathParser::jkmpNode *par) { data=d; setParser(p); setParent(par); }
JKQTPMathParser::jkmpResult JKQTPMathParser::jkmpConstantNode::evaluate() { return data; }
JKQTPMathParser::jkmpException::~jkmpException() = default;
const char *JKQTPMathParser::jkmpException::what() const noexcept {
return getMessage().c_str();
}