2015-07-11 18:56:02 +08:00
/*
2019-01-12 23:01:55 +08:00
Copyright ( c ) 2008 - 2019 Jan W . Krieger ( < jan @ jkrieger . de > )
2015-07-11 18:56:02 +08:00
2015-07-12 22:34:27 +08:00
2015-07-11 18:56:02 +08:00
This software is free software : you can redistribute it and / or modify
it under the terms of the GNU Lesser General Public License ( LGPL ) as published by
2019-02-08 00:24:46 +08:00
the Free Software Foundation , either version 2.1 of the License , or
2015-07-11 18:56:02 +08:00
( 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 Lesser General Public License ( LGPL ) for more details .
You should have received a copy of the GNU Lesser General Public License ( LGPL )
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2019-01-13 01:53:16 +08:00
/*! \defgroup jkmp Parser/Evaluator for Mathematical Expressions
\ ingroup jkqtptools_math
2015-07-11 18:56:02 +08:00
In this group there are classes that form a parser and evaluator for mathematical expressions .
In the context of the sequencer program this is a tool class that can be used by the classes
2019-01-20 17:49:29 +08:00
in the project . E . g . used by JKQTPXParsedFunctionLineGraph , JKQTPYParsedFunctionLineGraph
2015-07-11 18:56:02 +08:00
2019-05-31 20:01:49 +08:00
\ defgroup jkmpultil JKQTPMathParser : Utilities
\ ingroup jkmp
2015-07-11 18:56:02 +08:00
2019-05-31 20:01:49 +08:00
\ defgroup jkmpNodes JKQTPMathParser : Memory Representation of Expressions
\ ingroup jkmp
2019-01-13 01:53:16 +08:00
2019-05-31 20:01:49 +08:00
\ defgroup jkmpErrorhandling JKQTPMathParser Error Handling
\ ingroup jkmp
*/
2019-01-13 01:53:16 +08:00
2015-07-11 18:56:02 +08:00
# include <iostream>
# include <cmath>
# include <string>
# include <cstdio>
# include <vector>
# include <map>
# include <sstream>
# include <exception>
# include <ctype.h>
# include <list>
# include <utility>
# ifndef JKQTPMATHPARSER_H
# define JKQTPMATHPARSER_H
/*! \brief A simple function parser to parse (build memory tree representation) and
evaluate simple mathematical expressions
2019-01-13 01:53:16 +08:00
\ ingroup jkmp
2019-01-19 23:54:31 +08:00
2015-07-11 18:56:02 +08:00
This class implements a simple function parser which can parse
mathematical expressions like < code > z = a * 3 + 2.34 ^ 2 * sin ( pi * sqrt ( x ) ) < / code > .
More than one expression can be separated by semicolon ' ; ' . The result of
a parse operation will be a memory structure ( tree ) representing the given
expression .
The parser can cope with constants and ( user defined ) variables and supports
the data types number ( double precision floating point ) , boolean ( true / false )
and string . It already contains a lot of fundamental mathematical functions
( i . e . nearly all the functions from C StdLib ) .
\ section jkmp_constantsAndVars constants and variables :
This class provides management utilities for constants and variables . Variables
can also be defined as external variables , when a pointer to corresponding
memory is provided by the calling program . The parser supports a variable
assign operation \ code a = < expression > \ endcode which allows to define new
variables during evaluation . There are some mathematical standard constants
2019-05-30 04:40:02 +08:00
registered by calling JKQTPMathParser : : addStandardVariables ( ) :
2015-07-11 18:56:02 +08:00
- \ c pi = \ f $ \ pi \ f $
- \ c e = \ f $ \ exp ( 1 ) \ f $
- \ c sqrt2 = \ f $ \ sqrt { 2 } \ f $
- \ c version = the parser version
- \ c log2e = \ f $ \ log_2 ( e ) \ f $
- \ c log10e = \ f $ \ log_ { 10 } ( e ) \ f $
- \ c ln2 = \ f $ \ ln ( 2 ) = \ log_ { e } ( 2 ) \ f $
- \ c ln10 = \ f $ \ ln ( 10 ) = \ log_ { e } ( 10 ) \ f $
- \ c h = \ f $ 6.6260689633 \ cdot 10 ^ { - 34 } \ ; \ mathrm { J \ cdot s } \ f $ ( planck constant )
- \ c hbar = \ f $ \ hbar = \ frac { h } { 2 \ pi } = 1.05457162853 \ cdot 10 ^ { - 34 } \ ; \ mathrm { J \ cdot s } \ f $ ( planck constant )
- \ c epsilon0 = \ f $ \ epsilon_0 = 8.854187817 \ cdot 10 ^ { - 12 } \ ; \ mathrm { \ frac { F } { m } } \ f $ ( electric constant )
- \ c mu0 = \ f $ \ mu_0 = 2 \ pi \ cdot 10 ^ { - 7 } = 12.566370614 \ cdot 10 ^ { - 7 } \ ; \ mathrm { \ frac { N } { A ^ 2 } } \ f $ ( magnetic constant )
- \ c c = \ f $ 299792458 \ ; \ mathrm { \ frac { m } { s } } \ f $ ( speed of light in vacuum )
- \ c ce = \ f $ 1.60217648740 \ cdot 10 ^ { - 19 } \ ; \ mathrm { C } \ f $ ( elementary charge )
- \ c muB = \ f $ \ mu_B = 927.40091523 \ cdot 10 ^ { - 26 } \ ; \ mathrm { \ frac { J } { T } } \ f $ ( Bohr magneton )
- \ c muB_eV = \ f $ \ mu_B = 5.788381755579 \ cdot 10 ^ { - 5 } \ ; \ mathrm { \ frac { eV } { T } } \ f $ ( Bohr magneton )
- \ c muN = \ f $ \ mu_N = 5.0507832413 \ cdot 10 ^ { - 27 } \ ; \ mathrm { \ frac { J } { T } } \ f $ ( nuclear magneton )
- \ c muN_eV = \ f $ \ mu_N = 3.152451232645 \ cdot 10 ^ { - 8 } \ ; \ mathrm { \ frac { eV } { T } } \ f $ ( nuclear magneton )
- \ c me = \ f $ m_e = 9.1093821545 \ cdot 10 ^ { - 31 } \ ; \ mathrm { kg } \ f $ ( mass of electron )
- \ c mp = \ f $ m_p = 1.67262163783 \ cdot 10 ^ { - 27 } \ ; \ mathrm { kg } \ f $ ( mass of proton )
- \ c mn = \ f $ m_n = 1.67492721184 \ cdot 10 ^ { - 27 } \ ; \ mathrm { kg } \ f $ ( mass of neutron )
- \ c NA = \ f $ N_A = 6.0221417930 \ cdot 10 ^ { 23 } \ f $ ( Avogadro constant = particles in 1 mol )
- \ c kB = \ f $ k_B = 1.380650424 \ cdot 10 ^ { - 23 } \ ; \ mathrm { \ frac { J } { K } } \ f $ ( Boltzman constant )
- \ c kB_eV = \ f $ k_B = 8.61734315 \ cdot 10 ^ { - 5 } \ ; \ mathrm { \ frac { eV } { K } } \ f $ ( Boltzman constant )
.
2019-05-30 04:40:02 +08:00
You can add user - defined contants by calling JKQTPMathParser : : addVariableDouble ( )
JKQTPMathParser : : addVariableBoolean ( ) or JKQTPMathParser : : addVariableString ( )
2015-07-11 18:56:02 +08:00
\ section jkmp_functions functions :
this class provides a wide range of ( mathematical ) functions :
- sinc , gauss , slit , theta , tanc , sigmoid
- asin , acos , atan , atan2 ,
- sin , cos , tan ,
- sinh , cosh , tanh
- log , log2 , log10 ,
- exp , sqr , sqrt
- abs , sign
- if
- erf , erfc , lgamma , tgamma , j0 , j1 , jn , y0 , y1 , yn
- rand , srand
- ceil , floor , trunc , round ,
- fmod , min , max
2019-01-20 23:15:10 +08:00
- floattostr , booltostr / bool2str , inttostr , num2str
- tosystempathseparator
- setdefault
- strdate
- cmdparam , argv
2015-07-11 18:56:02 +08:00
.
2019-05-30 04:40:02 +08:00
these functions are registered by calling JKQTPMathParser : : addStandardFunctions ( ) .
you can add new functions by calling JKQTPMathParser : : addFunction ( ) ;
2015-07-11 18:56:02 +08:00
\ section jkmp_resultsofparsing result of parsing and evaluation :
2019-05-30 04:40:02 +08:00
The result of calling JKQTPMathParser : : parse ( )
2015-07-11 18:56:02 +08:00
will be a tree - like structure in memory . The parse ( ) function will return
a pointer to the root node of this structure . All nodes inherit from
jkmpNode class . To evaluate such a structure simply call jkmpNode : : evaluate ( )
of the root node . This will then return a jkmpResult structure which contains
the result . This scheme allows for once parsing and multiply evaluating an expression .
So if you want to define a function by an expression you can provide an
external variable x as the argument and then evaluate the function for
each x .
\ section jkmp_ebnf EBNF definition of the parsed expressions
< pre > logical_expression - > logical_term
| logical_expression < b > or < / b > logical_term
| logical_expression < b > | | < / b > logical_term < / pre >
< pre > logical_term - > comp_expression
| logical_term < b > and < / b > comp_expression
| logical_term < b > & amp ; & amp ; < / b > comp_expression < / pre >
< pre > comp_expression - > math_expression
| expression < b > = = < / b > math_expression
| expression < b > ! = < / b > math_expression
| expression < b > & gt ; = < / b > math_expression
| expression < b > & lt ; = < / b > math_expression
| expression < b > & gt ; < / b > math_expression
| expression < b > & lt ; < / b > math_expression < / pre >
< pre > math_expression - > term
| math_expression < b > + < / b > math_term
| math_expression < b > - < / b > math_term < / pre >
< pre > math_term - > primary
| term < b > * < / b > primary
| term < b > / < / b > primary
| term ( < b > % < / b > | < b > mod < / b > ) primary < / pre >
< pre > primary - > < b > true < / b > | < b > false < / b >
| string_constant
| NUMBER
| NAME
| NAME < b > = < / b > logical_expression
| < b > + < / b > primary | < b > - < / b > primary | < b > ! < / b > primary | < b > not < / b > primary
| < b > ( < / b > logical_expression < b > ) < / b >
| NAME < b > ( < / b > parameter_list < b > ) < / b >
| primary < b > ^ < / b > primary < / pre >
< pre > string_constant - > < b > & quot ; < / b > STRING < b > & quot ; < / b > | < b > & apos ; < / b > STRING < b > & apos ; < / b > < / pre >
< pre > parameter_list - > \ f $ \ lambda \ f $ | logical_expression | logical_expression < b > , < / b > parameter_list < / pre >
2019-01-19 23:54:31 +08:00
\ section jkmp_example Simple Example of Usage
\ code
2019-01-20 23:15:10 +08:00
try {
2019-05-30 04:40:02 +08:00
JKQTPMathParser mp ; // instanciate
2019-01-20 23:15:10 +08:00
jkmpNode * n ;
jkmpResult r ;
// parse some numeric expression
n = mp . parse ( " pi^2+4*sin(65*pi/exp(3.45)) " ) ;
r = n - > evaluate ( ) ;
cout < < r . num < < endl ;
//delete n;
// parse some boolean expression
n = mp . parse ( " true==false " ) ;
r = n - > evaluate ( ) ;
if ( r . type = = jkmpBool ) {
if ( r . boolean ) cout < < " true " ;
else cout < < " false " ;
}
if ( r . type = = jkmpDouble ) cout < < r . num < < endl ;
if ( r . type = = jkmpString ) cout < < r . str < < endl ;
delete n ;
// parse some string expression
n = mp . parse ( " var1='false'; var1+'true' " ) ;
r = n - > evaluate ( ) ;
if ( r . type = = jkmpString ) cout < < r . str < < endl ;
delete n ;
} catch ( std : : exception & E ) {
cout < < " ERROR!!! \n " < < E . what ( ) < < endl < < endl ;
}
2019-01-19 23:54:31 +08:00
\ endcode
\ section jkmp_errorhandling Error Handling
In the above example we use error handling by use of exception ( default behauviour ) .
It is also possible to change the error handling from using exceptions to calling a specific
error handling function . This can be usefull in programs that don ' t support exceptions .
To do so , use this cod :
\ code
2019-01-26 20:00:40 +08:00
void error ( const std : : string & message ) {
2019-01-20 23:15:10 +08:00
cout < < " error: " + message ;
system ( " PAUSE " ) ;
abort ( ) ;
}
int main ( ) {
2019-05-30 04:40:02 +08:00
JKQTPMathParser mp ;
2019-01-26 20:00:40 +08:00
mp . setException_function ( error ) ; // make error ahndler known
2019-01-20 23:15:10 +08:00
. . .
}
2019-01-19 23:54:31 +08:00
\ endcode
2015-07-11 18:56:02 +08:00
*/
class JKQTPMathParser
{
protected :
void * data ;
2019-05-30 04:40:02 +08:00
/** \brief the possible tokens that can be recognized by the tokenizer in JKQTPMathParser::getToken()
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpultil
*/
2015-07-11 18:56:02 +08:00
enum jkmpTokenType {
END , /*!< \brief end token */
PRINT , /*!< \brief a semicolon ';' */
PARAMETER_DIV , /*!< \brief a comma ',' between two function parameters */
STRING_DELIM , /*!< \brief a string delimiter ' or " */
NAME , /*!< \brief a name (consisting of characters) of a variable or function */
NUMBER , /*!< \brief a number in scientific notation */
PLUS , /*!< \brief a plus operator '+' */
MINUS , /*!< \brief a minus operator '-' */
MUL , /*!< \brief a multiplication operator '*' */
DIV , /*!< \brief a division operator '/' */
MODULO , /*!< \brief a modulo operator '%' */
ASSIGN , /*!< \brief a variable assignment = */
LBRACKET , /*!< \brief left brackets '(' */
RBRACKET , /*!< \brief right brackets ')' */
POWER , /*!< \brief a power operator '^' */
FACTORIAL_LOGIC_NOT , /*!< \brief a factorial operator or a logical NOT '!' */
LOGIC_NOT , /*!< \brief a logical NOT '!' / 'not' */
LOGIC_AND , /*!< \brief a logical AND operator '&&' / 'and' */
LOGIC_OR , /*!< \brief a logical OR operator '||' / 'or' */
LOGIC_XOR , /*!< \brief a logical XOR operator 'xor' */
LOGIC_NOR , /*!< \brief a logical NOR operator 'nor' */
LOGIC_NAND , /*!< \brief a logical NAND operator 'nand' */
LOGIC_TRUE , /*!< \brief 'true' */
LOGIC_FALSE , /*!< \brief 'false' */
COMP_EQUALT , /*!< \brief equals operation '==' */
COMP_UNEQUAL , /*!< \brief unequal operation '!=' */
COMP_GREATER , /*!< \brief greater than operation '>' */
COMP_SMALLER , /*!< \brief smaller than operation '<' */
COMP_GEQUAL , /*!< \brief greater than or equal operation '>=' */
COMP_SEQUAL , /*!< \brief smaller than or equal operation '<=' */
} ;
2019-01-13 01:53:16 +08:00
/** \brief internal names for logic operations
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpultil */
2015-07-11 18:56:02 +08:00
enum {
jkmpLOPand = ' a ' ,
jkmpLOPor = ' o ' ,
jkmpLOPxor = ' x ' ,
jkmpLOPnor = ' n ' ,
jkmpLOPnand = ' A ' ,
jkmpLOPnot = ' n '
} ;
2019-01-13 01:53:16 +08:00
/** \brief jkmpCOMPdefs internal names for compare operations
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpultil */
2015-07-11 18:56:02 +08:00
enum {
jkmpCOMPequal = ' = ' ,
jkmpCOMPnequal = ' ! ' ,
jkmpCOMPlesser = ' < ' ,
jkmpCOMPgreater = ' > ' ,
jkmpCOMPlesserequal = ' a ' ,
jkmpCOMPgreaterequal = ' b '
} ;
2019-01-13 01:53:16 +08:00
2015-07-11 18:56:02 +08:00
public :
2019-01-13 01:53:16 +08:00
/** \brief possible result types
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpultil
2015-07-11 18:56:02 +08:00
*/
enum jkmpResultType { jkmpDouble , /*!< \brief a floating-point number with double precision. This is also used to deal with integers */
jkmpString , /*!< \brief a string of characters */
jkmpBool } ; /*!< \brief a boolean value true|false */
2019-01-13 01:53:16 +08:00
/** \brief result of any expression
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpultil */
2015-07-11 18:56:02 +08:00
struct jkmpResult {
jkmpResult ( ) ;
bool isValid ;
jkmpResultType type ; /*!< \brief type of the result */
std : : string str ; /*!< \brief contains result if \c type==jkmpString */
double num ; /*!< \brief contains result if \c type==jkmpDouble */
bool boolean ; /*!< \brief contains result if \c type==jkmpBool */
/** \brief convert the value this struct representens into a std::string */
2019-05-30 04:40:02 +08:00
std : : string toString ( ) ;
2015-07-11 18:56:02 +08:00
/** \brief convert the value this struct representens into a std::string and adds the name of the datatype in \c [...] */
2019-05-30 04:40:02 +08:00
std : : string toTypeString ( ) ;
2019-01-20 23:15:10 +08:00
} ;
2015-07-11 18:56:02 +08:00
/** \brief This struct is for managing variables. Unlike jkmpResult this struct
* only contains pointers to the data
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpultil
2015-07-11 18:56:02 +08:00
*/
struct jkmpVariable {
jkmpVariable ( ) ;
jkmpResultType type ; /*!< \brief type of the variable */
bool internal ; /*!< \brief this is an internal variable */
std : : string * str ; /*!< \brief this points to the variable data if \c type==jkmpString */
double * num ; /*!< \brief this points to the variable data if \c type==jkmpDouble */
bool * boolean ; /*!< \brief this points to the variable data if \c type==jkmpBool */
} ;
/** \brief This struct is for managing temporary variables. It is generally like jkmpVariable.
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpultil
2015-07-11 18:56:02 +08:00
*/
struct jkmpTempVariable {
std : : string name ; /*!< \brief name of the variable */
jkmpResultType type ; /*!< \brief type of the variable */
bool internal ; /*!< \brief this is an internal variable */
std : : string * str ; /*!< \brief this points to the variable data if \c type==jkmpString */
double * num ; /*!< \brief this points to the variable data if \c type==jkmpDouble */
bool * boolean ; /*!< \brief this points to the variable data if \c type==jkmpBool */
} ;
/** \brief This is a function prototype for adding new mathematical functions
* to the parser
*
* If you want to add more math functions ( like sin , cos , abs . . . ) to the
* parser , you will have to implement it with this prototype and then register
2019-05-30 04:40:02 +08:00
* it with JKQTPMathParser : : addFunction ( ) . The first parameter points to an array
2015-07-11 18:56:02 +08:00
* containing the input parameters while the second one specifies the number
* of supplied parameters . The result has to be of type jkmpResult .
*
* All error handling has to be done inside the function definition . Here is a
* simple example :
* \ code
2019-01-20 23:15:10 +08:00
* jkmpResult Abs ( jkmpResult * params , unsigned char n ) {
* jkmpResult r ;
* r . type = jkmpDouble ;
* if ( n ! = 1 ) jkmpError ( " abs accepts 1 argument " ) ;
* if ( params [ 0 ] . type ! = jkmpDouble ) jkmpError ( " abs needs double argument " ) ;
* r . num = fabs ( params [ 0 ] . num ) ;
* return r ;
* }
2015-07-11 18:56:02 +08:00
* \ endcode
*/
typedef jkmpResult ( * jkmpEvaluateFunc ) ( jkmpResult * , unsigned char , JKQTPMathParser * ) ;
/** \brief description of a user registered function */
struct jkmpFunctionDescriptor {
jkmpEvaluateFunc function ; /*!< \brief a pointer to the function implementation */
std : : string name ; /*!< \brief name of the function */
} ;
2019-01-13 01:53:16 +08:00
2015-07-11 18:56:02 +08:00
/**
* \ brief This class is the abstract base class for nodes .
* All allowed node types must inherit from jkmpNode
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpNode {
protected :
JKQTPMathParser * parser ; /*!< \brief points to the parser object that is used to evaluate this node */
jkmpNode * parent ; /*!< \brief points to the parent node */
public :
/** \brief virtual class destructor */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpNode ( ) ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
virtual jkmpResult evaluate ( ) = 0 ;
2019-05-30 04:40:02 +08:00
/** \brief return a pointer to the JKQTPMathParser */
JKQTPMathParser * getParser ( ) ;
2015-07-11 18:56:02 +08:00
2019-05-30 04:40:02 +08:00
/** \brief set the JKQTPMathParser */
void setParser ( JKQTPMathParser * mp ) ;
2015-07-11 18:56:02 +08:00
/** \brief returns a pointer to the parent node */
2019-05-30 04:40:02 +08:00
jkmpNode * getParent ( ) ;
2015-07-11 18:56:02 +08:00
/** \brief sets the parent node */
2019-05-30 04:40:02 +08:00
void setParent ( jkmpNode * par ) ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a binary arithmetic operation :
* add ( + ) , subtract ( - ) , multiply ( * ) , divide ( / ) , a to the power of b ( a ^ b )
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpBinaryArithmeticNode : public jkmpNode {
private :
jkmpNode * left , * right ;
char operation ;
public :
/** \brief constructor for a jkmpBinaryArithmeticNode
* \ param op the operation to be performed : add ( + ) , subtract ( - ) , multiply ( * ) , divide ( / ) , a to the power of b ( a ^ b )
* \ param l left child node / operand
* \ param r right child node / operand
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
jkmpBinaryArithmeticNode ( char op , jkmpNode * l , jkmpNode * r , JKQTPMathParser * p , jkmpNode * par ) ;
/** \brief standard destructor, also destroy the children (recursively) */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpBinaryArithmeticNode ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a binary boolean operation : and , or , xor , nor , nand
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpBinaryBoolNode : public jkmpNode {
private :
jkmpNode * left , * right ;
char operation ;
public :
/** \brief constructor for a jkmpBinaryBoolNode
* \ param op the operation to be performed : ( a ) nd , ( o ) r , ( x ) or , ( n ) or , nand ( A )
* \ param l left child node / operand
* \ param r right child node / operand
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
jkmpBinaryBoolNode ( char op , jkmpNode * l , jkmpNode * r , JKQTPMathParser * p , jkmpNode * par ) ;
/** \brief standard destructor, also destroy the children (recursively) */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpBinaryBoolNode ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a binary compare operation : ! = , = = , > = , < = , > , <
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpCompareNode : public jkmpNode {
private :
jkmpNode * left , * right ;
char operation ;
public :
/** \brief constructor for a jkmpCompareNode
* \ param op the operation to be performed : ! = ( ! ) , = = ( = ) , > = ( b ) , < = ( a ) , ( > ) , ( < )
* \ param l left child node / operand
* \ param r right child node / operand
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
jkmpCompareNode ( char op , jkmpNode * l , jkmpNode * r , JKQTPMathParser * p , jkmpNode * par ) ;
/** \brief standard destructor, also destroy the children (recursively) */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpCompareNode ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a unary operations : ! ( bool negation ) , - ( arithmetic negation )
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpUnaryNode : public jkmpNode {
private :
jkmpNode * child ;
char operation ;
public :
/** \brief constructor for a jkmpUnaryNode
* \ param op the operation to be performed : ( ! ) , ( - )
* \ param c child node / operand
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
jkmpUnaryNode ( char op , jkmpNode * c , JKQTPMathParser * p , jkmpNode * par ) ;
/** \brief standard destructor, also destroy the children (recursively) */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpUnaryNode ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a variable assignment ( a = expression )
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpVariableAssignNode : public jkmpNode {
private :
jkmpNode * child ;
std : : string variable ;
//char operation;
public :
/** \brief standard destructor, also destroy the children (recursively) */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpVariableAssignNode ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief constructor for a jkmpVariableAssignNode
* \ param var name of the variable to assign to
* \ param c child node / right - hand - side expression
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
2019-01-26 20:00:40 +08:00
jkmpVariableAssignNode ( const std : : string & var , jkmpNode * c , JKQTPMathParser * p , jkmpNode * par ) ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a number , a string contant or a boolean contant ( true / false )
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpConstantNode : public jkmpNode {
private :
jkmpResult data ;
public :
/** \brief constructor for a jkmpConstantNode
* \ param d the value of the constant
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
2018-12-28 05:52:00 +08:00
jkmpConstantNode ( jkmpResult d , JKQTPMathParser * p , jkmpNode * par ) ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2019-01-10 04:23:24 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a variable .
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*/
class jkmpVariableNode : public jkmpNode {
private :
std : : string var ;
public :
/** \brief constructor for a jkmpVariableNode
* \ param name name of the variable
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
2019-01-26 20:00:40 +08:00
jkmpVariableNode ( const std : : string & name , JKQTPMathParser * p , jkmpNode * par ) ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents an arbitrary function .
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*
* When initialized this class will get the function description that is
2019-05-30 04:40:02 +08:00
* linked to the supplied function name from JKQTPMathParser object . This
2015-07-11 18:56:02 +08:00
* information is saved locally and won ' t be changed when evaluating !
*
* Functions may have 8 parameters at the most .
*/
class jkmpFunctionNode : public jkmpNode {
private :
std : : string fun ;
jkmpNode * * child ;
unsigned char n ;
jkmpEvaluateFunc function ;
public :
/** \brief constructor for a jkmpFunctionNode
* \ param name name of the function
* \ param c a pointer to an array of jkmpNode objects that represent the parameter expressions
* \ param num number of children in c
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
* \ param par a pointer to the parent node
*/
2019-01-26 20:00:40 +08:00
jkmpFunctionNode ( const std : : string & name , jkmpNode * * c , unsigned char num , JKQTPMathParser * p , jkmpNode * par ) ;
2015-07-11 18:56:02 +08:00
/** \brief standard destructor, also destroy the children (recursively) */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpFunctionNode ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate this node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
} ;
/**
* \ brief This class represents a list of jkmpNode .
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpNodes
2015-07-11 18:56:02 +08:00
*
* when evaluating the result will be the result of the last node in the list .
*/
class jkmpNodeList : public jkmpNode {
private :
std : : vector < jkmpNode * > list ;
public :
/** \brief constructor for a jkmpNodeList
2019-05-30 04:40:02 +08:00
* \ param p a pointer to a JKQTPMathParser object
2015-07-11 18:56:02 +08:00
*/
2018-12-28 05:52:00 +08:00
jkmpNodeList ( JKQTPMathParser * p ) ;
2015-07-11 18:56:02 +08:00
/** \brief standard destructor, also destroy the children (recursively) */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpNodeList ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief add a jkmpNode n to the list */
void add ( jkmpNode * n ) ;
/** \brief evaluate the node */
2018-12-28 05:52:00 +08:00
virtual jkmpResult evaluate ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief get the number of nodes in the list */
2019-05-30 04:40:02 +08:00
int getCount ( ) ;
2015-07-11 18:56:02 +08:00
} ;
/*@}*/
public :
2019-01-13 01:53:16 +08:00
2015-07-11 18:56:02 +08:00
/** \brief error handling: exceptions of the type of this class will be thrown if an error occurs
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpErrorhandling
2015-07-11 18:56:02 +08:00
*
* \ attention If you do not want to use the exception handling which throws
* jkmpException exceptions , but want to write your own error handling , you should write your own
* error handler and assign it ( function pointer ) to the global variable jkmathparser_exception_function .
2018-11-18 18:59:30 +08:00
* If this is not nullptr this function will be called instead of throwing an exception .
2015-07-11 18:56:02 +08:00
*/
class jkmpException : public std : : exception {
private :
/** \brief the error message */
std : : string errormessage ;
public :
/** \brief class constructors */
2019-05-30 04:40:02 +08:00
jkmpException ( ) ;
2015-07-11 18:56:02 +08:00
/** \brief constructor with supplied error message */
2019-05-30 04:40:02 +08:00
jkmpException ( const std : : string & msg ) ;
2015-07-11 18:56:02 +08:00
/** \brief class destructors */
2018-12-28 05:52:00 +08:00
virtual ~ jkmpException ( ) override ;
2015-07-11 18:56:02 +08:00
/** \brief returns the assigned errormessage */
2019-05-30 04:40:02 +08:00
std : : string getMessage ( ) const ;
2015-07-11 18:56:02 +08:00
/** \brief returns the error description as C string */
2019-05-30 04:40:02 +08:00
virtual const char * what ( ) const noexcept override ;
2015-07-11 18:56:02 +08:00
} ;
2019-01-13 01:53:16 +08:00
/** \brief type for a custom error handler. This an alternative error handling
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpErrorhandling */
2015-07-11 18:56:02 +08:00
typedef void ( * jkmpexceptionf ) ( std : : string ) ;
2019-01-13 01:53:16 +08:00
/** \brief function that throws an exception or calls an error handler
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpErrorhandling */
2019-05-30 04:40:02 +08:00
void jkmpError ( const std : : string & st ) ;
2015-07-11 18:56:02 +08:00
private :
2019-01-13 01:53:16 +08:00
/** \brief if this is nullptr then an exception may be thrown otherwise this should point to an error handler that will be called.
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpErrorhandling */
2015-07-11 18:56:02 +08:00
jkmpexceptionf jkmathparser_exception_function ;
public :
2019-01-13 01:53:16 +08:00
/** \brief activate error handling by use of an exception function
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpErrorhandling */
2019-05-30 04:40:02 +08:00
void setException_function ( jkmpexceptionf exception_function ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief deactivate error handling by use of an exception function
2019-01-19 23:54:31 +08:00
* \ ingroup jkmpErrorhandling */
2019-05-30 04:40:02 +08:00
void resetException_function ( ) ;
2015-07-11 18:56:02 +08:00
protected :
/** \brief return the given token as human-readable string */
std : : string tokentostring ( jkmpTokenType token ) ;
/** \brief return the current token as human-readable string */
std : : string currenttokentostring ( ) ;
2019-01-19 23:54:31 +08:00
/** \brief Tokenizer: extract the next token from the input */
jkmpTokenType getToken ( ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief return a delimited text, i.e. extract the texte between the delimiters <code>"</code> in: of <code>"Hallo!"</code>, i.e. returns <code> Hallo!</code>
2015-07-11 18:56:02 +08:00
* This is used to parse string constants .
*
* This functions actually reads pascal style delimited string constants . So if you want to use the delimiter as part of the string you will have to
* write it as doubled character . So < code > ' Jan ' ' s Test ' < / code > stands for < code > Jan ' s Test < / code > .
*/
2019-01-19 23:54:31 +08:00
std : : string readDelim ( char delimiter ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief recognizes an compExpression while parsing. If \a get ist \c true, this function first retrieves a new token by calling getToken() */
jkmpNode * compExpression ( bool get ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief recognizes a logicalExpression while parsing. If \a get ist \c true, this function first retrieves a new token by calling getToken() */
jkmpNode * logicalExpression ( bool get ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief recognizes a logicalTerm while parsing. If \a get ist \c true, this function first retrieves a new token by calling getToken() */
jkmpNode * logicalTerm ( bool get ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief recognizes a mathExpression while parsing. If \a get ist \c true, this function first retrieves a new token by calling getToken() */
jkmpNode * mathExpression ( bool get ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief recognizes a term while parsing. If \a get ist \c true, this function first retrieves a new token by calling getToken() */
jkmpNode * mathTerm ( bool get ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief recognizes a primary while parsing. If \a get ist \c true, this function first retrieves a new token by calling getToken() */
jkmpNode * primary ( bool get ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief this stream is used to read in the program. An object is created and assigned
* ( and destroyed ) by the parse ( ) - function */
std : : istringstream * program ;
2015-07-11 18:56:02 +08:00
/** \brief vector containing all temporary variables */
std : : vector < jkmpTempVariable > tempvariables ;
/** \brief map to manage all currently defined variables */
std : : map < std : : string , jkmpVariable > variables ;
/** \brief map to manage all currently rtegistered functions */
std : : map < std : : string , jkmpFunctionDescriptor > functions ;
/** \brief the current token while parsing a string */
jkmpTokenType CurrentToken ;
/** \brief the string value of the current token (when applicable) during the parsing step */
std : : string StringValue ;
/** \brief the string value of the current token (when applicable) during the parsing step */
double NumberValue ;
/** \brief set the defining struct of the given variable */
2019-01-26 20:00:40 +08:00
void setVariable ( const std : : string & name , jkmpResult value ) ;
2015-07-11 18:56:02 +08:00
/** \brief set the defining struct of the given variable */
2019-01-26 20:00:40 +08:00
void setVariableDouble ( const std : : string & name , double value ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief adds a temporary variable */
2019-01-26 20:00:40 +08:00
void addTempVariable ( const std : : string & name , jkmpResult value ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
protected :
int argc ;
char * * argv ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
public :
/** \brief class constructor */
2015-07-11 18:56:02 +08:00
JKQTPMathParser ( ) ;
2019-01-19 23:54:31 +08:00
/** \brief class destructor */
2015-07-11 18:56:02 +08:00
virtual ~ JKQTPMathParser ( ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc data */
2019-05-30 04:40:02 +08:00
virtual void setData ( void * __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc data */
2019-05-30 04:40:02 +08:00
virtual void * getData ( ) const ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief register a new function
* \ param name name of the new function
* \ param function a pointer to the implementation
*/
2019-01-26 20:00:40 +08:00
void addFunction ( const std : : string & name , jkmpEvaluateFunc function ) ;
2019-01-19 23:54:31 +08:00
/** \brief register a new external variable of type double
* \ param name name of the new variable
* \ param v pointer to the variable memory
*/
2019-01-26 20:00:40 +08:00
void addVariableDouble ( const std : : string & name , double * v ) ;
2019-01-19 23:54:31 +08:00
/** \brief register a new external variable of type string
* \ param name name of the new variable
* \ param v pointer to the variable memory
*/
2019-01-26 20:00:40 +08:00
void addVariableString ( const std : : string & name , std : : string * v ) ;
2019-01-19 23:54:31 +08:00
/** \brief register a new external variable of type boolean
* \ param name name of the new variable
* \ param v pointer to the variable memory
*/
2019-01-26 20:00:40 +08:00
void addVariableBoolean ( const std : : string & name , bool * v ) ;
2019-01-19 23:54:31 +08:00
/** \brief register a new internal variable of type double
* \ param name name of the new variable
* \ param v initial value of this variable
*/
2019-01-26 20:00:40 +08:00
void addVariableDouble ( const std : : string & name , double v ) ;
2019-01-19 23:54:31 +08:00
/** \brief register a new internal variable of type string
* \ param name name of the new variable
* \ param v initial value of this variable
*/
2019-01-26 20:00:40 +08:00
void addVariableString ( const std : : string & name , const std : : string & v ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief register a new internal variable of type boolean
2015-07-11 18:56:02 +08:00
* \ param name name of the new variable
* \ param v initial value of this variable
*/
2019-01-26 20:00:40 +08:00
void addVariableBoolean ( const std : : string & name , bool v ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief register a new internal variable of type boolean
2015-07-11 18:56:02 +08:00
* \ param name name of the new variable
2019-05-18 02:46:52 +08:00
* \ param result initial value of this variable
2015-07-11 18:56:02 +08:00
*/
2019-01-26 20:00:40 +08:00
void addVariable ( const std : : string & name , jkmpResult result ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief returns the value of the given variable */
2019-01-26 20:00:40 +08:00
jkmpResult getVariable ( const std : : string & name ) ;
2019-01-13 01:53:16 +08:00
/** \brief returns the value of the given variable */
2019-01-26 20:00:40 +08:00
jkmpResult getVariableOrInvalid ( const std : : string & name ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief returns the defining structure of the given variable */
2019-01-26 20:00:40 +08:00
jkmpVariable getVariableDef ( const std : : string & name ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief evaluates a registered function
2015-07-11 18:56:02 +08:00
* \ param name name of the ( registered function ) to be evaluated
* \ param params array of the input parameters
* \ param n number of input parameters ( < = 8 )
*/
2019-01-26 20:00:40 +08:00
jkmpResult evaluateFunction ( const std : : string & name , jkmpResult * params , unsigned char n ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief returns the defining structure of the given function */
2019-01-26 20:00:40 +08:00
jkmpEvaluateFunc getFunctionDef ( const std : : string & name ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief tests whether a temporary variable exists */
2019-05-30 04:40:02 +08:00
bool tempvariableExists ( const std : : string & name ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief tests whether a variable exists */
2019-05-30 04:40:02 +08:00
bool variableExists ( const std : : string & name ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief tests whether a function exists */
2019-05-30 04:40:02 +08:00
bool functionExists ( const std : : string & name ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief deletes all defined variables. the memory of internal variables
2015-07-11 18:56:02 +08:00
* will be released . the external memory will not be released .
*/
void clearVariables ( ) ;
2019-01-13 01:53:16 +08:00
/** \brief delete the specified variabale and releases its internal memory.*/
2019-01-26 20:00:40 +08:00
void deleteVariable ( const std : : string & name ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief clears the list of internal functions*/
2019-05-30 04:40:02 +08:00
void clearFunctions ( ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief registers standard variables*/
2015-07-11 18:56:02 +08:00
void addStandardVariables ( ) ;
2019-01-13 01:53:16 +08:00
/** \brief registers standard functions*/
2015-07-11 18:56:02 +08:00
void addStandardFunctions ( ) ;
2019-01-13 01:53:16 +08:00
/** \brief parses the given expression*/
2019-01-26 20:00:40 +08:00
jkmpNode * parse ( const std : : string & prog ) ;
2015-07-11 18:56:02 +08:00
/** \brief evaluate the given expression */
2019-01-26 20:00:40 +08:00
jkmpResult evaluate ( const std : : string & prog ) ;
2015-07-11 18:56:02 +08:00
2019-01-13 01:53:16 +08:00
/** \brief prints a list of all registered variables */
2015-07-11 18:56:02 +08:00
void printVariables ( ) ;
2019-01-19 23:54:31 +08:00
/** \brief returns all registered variables */
2015-07-11 18:56:02 +08:00
std : : vector < std : : pair < std : : string , jkmpVariable > > getVariables ( ) ;
2019-01-19 23:54:31 +08:00
/** \brief store programs command-line arguments, so they are available in the parser */
void setArgCV ( int argc , char * * argv ) ;
2015-07-11 18:56:02 +08:00
2019-01-19 23:54:31 +08:00
/** \brief return one of programs command-line arguments, or \a defaultResult if it is not present */
2019-01-26 20:00:40 +08:00
std : : string getArgCVParam ( const std : : string & name , const std : : string & defaultResult ) ;
2015-07-11 18:56:02 +08:00
} ;
# endif // JKQTPMATHPARSER_H