C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html
This commit is contained in:
parent
ebf3f14ca6
commit
e105e6278c
758
exprtk.hpp
758
exprtk.hpp
File diff suppressed because it is too large
Load Diff
165
exprtk_test.cpp
165
exprtk_test.cpp
|
@ -4617,6 +4617,11 @@ struct gen_func2 : public exprtk::igeneric_function<T>
|
|||
{
|
||||
return T(0);
|
||||
}
|
||||
|
||||
inline T operator()(const std::size_t&, parameter_list_t params)
|
||||
{
|
||||
return this->operator()(params);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -4670,6 +4675,11 @@ struct inc_func : public exprtk::igeneric_function<T>
|
|||
|
||||
return T(0);
|
||||
}
|
||||
|
||||
inline T operator()(const std::size_t&, parameter_list_t params)
|
||||
{
|
||||
return this->operator()(params);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -4700,6 +4710,14 @@ struct rem_space_and_uppercase : public exprtk::igeneric_function<T>
|
|||
|
||||
return T(0);
|
||||
}
|
||||
|
||||
inline T operator()(const std::size_t& param_seq_index, std::string& result, parameter_list_t params)
|
||||
{
|
||||
if (1 == param_seq_index)
|
||||
return this->operator()(result,params);
|
||||
else
|
||||
return T(0);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -4849,7 +4867,7 @@ inline bool run_test18()
|
|||
|
||||
if (!parser.compile(expression_list[i],expression))
|
||||
{
|
||||
printf("run_test18() - GenFunc Error: %s Expression: %s\n",
|
||||
printf("run_test18() - GenFunc Error: %s Expression: %s [2]\n",
|
||||
parser.error().c_str(),
|
||||
expression_list[i].c_str());
|
||||
|
||||
|
@ -4925,7 +4943,18 @@ inline bool run_test18()
|
|||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(2w / 3, 'abc123',s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo('abc123', s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0[2:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3, 'abc123');",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0[2:3]+s0[4:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3, 'abc123');"
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0[2:3]+s0[4:5],v0, v1 + v2, v0[2], x, 2x + y, z,2w / 3, 'abc123');",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
|
||||
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
|
||||
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);"
|
||||
|
||||
|
||||
};
|
||||
|
||||
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
|
||||
|
@ -4942,6 +4971,14 @@ inline bool run_test18()
|
|||
"SSVVTTTTV",
|
||||
"SVVTTTTVS",
|
||||
"SVVTTTTVS",
|
||||
"V*T*VS*" ,
|
||||
"V*TTTTVSS",
|
||||
"VVT*VSS" ,
|
||||
"VVTTTTVS*",
|
||||
"TTTTTTT|STSTSTS|V*T*VS*" ,
|
||||
"TTTTTTT|STSTSTS|V*TTTTVSS",
|
||||
"TTTTTTT|STSTSTS|VVT*VSS" ,
|
||||
"TTTTTTT|STSTSTS|VVTTTTVS*"
|
||||
};
|
||||
|
||||
bool failure = false;
|
||||
|
@ -4958,7 +4995,7 @@ inline bool run_test18()
|
|||
|
||||
if (!parser.compile(expression_list[i],expression))
|
||||
{
|
||||
printf("run_test18() - GenFunc2 Error: %s Expression: %s Parameter Sequence: %s\n",
|
||||
printf("run_test18() - GenFunc2 Error: %s Expression: %s Parameter Sequence: %s [3]\n",
|
||||
parser.error().c_str(),
|
||||
expression_list[i].c_str(),
|
||||
parameter_type_list[i].c_str());
|
||||
|
@ -5049,7 +5086,7 @@ inline bool run_test18()
|
|||
|
||||
if (!parser.compile(expression_list[i],expression))
|
||||
{
|
||||
printf("run_test18() - IncFunc Error: %s Expression: %s Parameter Sequence: %s\n",
|
||||
printf("run_test18() - IncFunc Error: %s Expression: %s Parameter Sequence: %s [4]\n",
|
||||
parser.error().c_str(),
|
||||
expression_list[i].c_str(),
|
||||
parameter_type_list[i].c_str());
|
||||
|
@ -5141,70 +5178,88 @@ inline bool run_test18()
|
|||
" s4 := s0 + remspc_uc(s1); "
|
||||
" remspc_uc(s0 + s1) == remspc_uc(s0) + remspc_uc(s1);";
|
||||
|
||||
expression_t expression;
|
||||
std::string parameter_type_list[] =
|
||||
{
|
||||
"VVVTTT|S",
|
||||
"VVTTTV|S",
|
||||
"VTTTVV|S",
|
||||
"TTTVVV|S",
|
||||
"TTVVVT|S",
|
||||
"TVVVTT|S"
|
||||
};
|
||||
|
||||
expression.register_symbol_table(symbol_table);
|
||||
std::size_t parameter_type_list_size = sizeof(parameter_type_list) / sizeof(std::string);
|
||||
|
||||
parser_t parser;
|
||||
|
||||
if (!parser.compile(program,expression))
|
||||
for (std::size_t i = 0; i < parameter_type_list_size; ++i)
|
||||
{
|
||||
printf("Error: %s\tExpression: %s\n",
|
||||
parser.error().c_str(),
|
||||
program.c_str());
|
||||
expression_t expression;
|
||||
|
||||
return false;
|
||||
}
|
||||
expression.register_symbol_table(symbol_table);
|
||||
|
||||
T result = expression.value();
|
||||
parser_t parser;
|
||||
|
||||
if (result != T(1))
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Result <> 1\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
rsauc.parameter_sequence = parameter_type_list[i];
|
||||
|
||||
if (result != T(1))
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s0\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
if (!parser.compile(program,expression))
|
||||
{
|
||||
printf("Error: %s\tExpression: %s\n",
|
||||
parser.error().c_str(),
|
||||
program.c_str());
|
||||
|
||||
if ("How now " != s0)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s0\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("brown cow?" != s1)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s1\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
T result = expression.value();
|
||||
|
||||
if ("HOWNOWBROWNCOW?" != s2)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s2\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
if (result != T(1))
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Result <> 1\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if ("HOWNOWbrown cow?" != s3)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s3\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
if (result != T(1))
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s0\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if ("How now BROWNCOW?" != s4)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s4\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
if ("How now " != s0)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s0\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if ("brown cow?" != s1)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s1\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if ("HOWNOWBROWNCOW?" != s2)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s2\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if ("HOWNOWbrown cow?" != s3)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s3\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
|
||||
if ("How now BROWNCOW?" != s4)
|
||||
{
|
||||
printf("run_test18() - Error in evaluation! (4) Expression: %s Check: s4\n",
|
||||
program.c_str());
|
||||
failure = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (failure)
|
||||
|
|
184
readme.txt
184
readme.txt
|
@ -50,7 +50,7 @@ arithmetic operations, functions and processes:
|
|||
|
||||
|
||||
[02 - EXAMPLE EXPRESSIONS]
|
||||
The following is a short listing of the types of mathematical
|
||||
The following is a short listing of the types of mathematical
|
||||
expressions that can be parsed and evaluated using the ExprTk library.
|
||||
|
||||
(01) sqrt(1 - (3 / x^2))
|
||||
|
@ -1253,16 +1253,37 @@ Compile-time type checking of input parameters can be requested by
|
|||
passing a string to the constructor of the igeneric_function that
|
||||
represents the required sequence of parameter types. When no parameter
|
||||
sequence is provided, it is implied the function can accept a variable
|
||||
number of parameters comprised of any of the fundemental types. The
|
||||
following example demonstrates how this can be achieved:
|
||||
number of parameters comprised of any of the fundamental types.
|
||||
|
||||
Each fundamental type has an associated character. The following is a
|
||||
listing of said characters and their meanings:
|
||||
|
||||
(1) T - Scalar
|
||||
(2) V - Vector
|
||||
(3) S - String
|
||||
(4) ? - Any type (Scalar, Vector or String)
|
||||
(5) * - Wildcard operator
|
||||
(6) | - Parameter sequence delimiter
|
||||
|
||||
|
||||
No other characters other than the six denoted above may be included
|
||||
in the parameter sequence definition. If any such invalid characters
|
||||
do exist, registration of the associated generic function to a symbol
|
||||
table ('add_function' method) will fail. If the parameter sequence is
|
||||
modified resulting in it becoming invalid after having been added to
|
||||
the symbol table but before the compilation step, a compilation error
|
||||
will be incurred.
|
||||
|
||||
The following example demonstrates a simple generic function
|
||||
implementation with a user specified parameter sequence:
|
||||
|
||||
template <typename T>
|
||||
struct too : public exprtk::igeneric_function<T>
|
||||
struct moo : public exprtk::igeneric_function<T>
|
||||
{
|
||||
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||
parameter_list_t;
|
||||
|
||||
too()
|
||||
moo()
|
||||
: exprtk::igeneric_function<T>("SVTT")
|
||||
{}
|
||||
|
||||
|
@ -1273,45 +1294,13 @@ following example demonstrates how this can be achieved:
|
|||
};
|
||||
|
||||
|
||||
In the example above the custom generic function 'too' expects
|
||||
exactly four parameters in the following sequence:
|
||||
|
||||
(a) String
|
||||
(b) Vector
|
||||
(c) Scalar
|
||||
(d) Scalar
|
||||
|
||||
|
||||
One further refinement to the type checking facility is the
|
||||
possibility of a variable number of trailing common types which can be
|
||||
accomplished by using a wildcard '*' at the end of the sequence
|
||||
definition.
|
||||
|
||||
template <typename T>
|
||||
struct too : public exprtk::igeneric_function<T>
|
||||
{
|
||||
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||
parameter_list_t;
|
||||
|
||||
too()
|
||||
: exprtk::igeneric_function<T>("SVTTV*")
|
||||
{}
|
||||
|
||||
inline T operator()(parameter_list_t parameters)
|
||||
{
|
||||
...
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
In the example above the generic function 'too' expects at least five
|
||||
In the example above the generic function 'moo' expects exactly four
|
||||
parameters in the following sequence:
|
||||
|
||||
(a) String
|
||||
(b) Vector
|
||||
(c) Scalar
|
||||
(d) Scalar
|
||||
(e) One or more Vectors
|
||||
(1) String
|
||||
(2) Vector
|
||||
(3) Scalar
|
||||
(4) Scalar
|
||||
|
||||
|
||||
(4) igeneric_function II
|
||||
|
@ -1326,7 +1315,7 @@ situations such as concatenation and equality operations.
|
|||
|
||||
|
||||
The following example defines an generic function named 'toupper' with
|
||||
the string return type function operator being explicitly overriden:
|
||||
the string return type function operator being explicitly overridden:
|
||||
|
||||
template <typename T>
|
||||
struct toupper : public exprtk::igeneric_function<T>
|
||||
|
@ -1354,12 +1343,16 @@ the string return type function operator being explicitly overriden:
|
|||
|
||||
|
||||
In the example above the generic function 'toupper' expects only one
|
||||
input parameter of type string, as noted by the parameter sequence
|
||||
input parameter of type string, as noted by the parameter sequence
|
||||
string passed during the constructor. When executed, the function will
|
||||
return as a result a copy of the input string converted to uppercase
|
||||
form.
|
||||
form. An example expression using the toupper function registered as
|
||||
the symbol 'toupper' is as follows:
|
||||
|
||||
When adding a string type returning generic function to a symbol
|
||||
"'ABCDEF' == toupper('aBc') + toupper('DeF')"
|
||||
|
||||
|
||||
Note: When adding a string type returning generic function to a symbol
|
||||
table, the 'add_function' is invoked with an extra parameter
|
||||
(e_ft_strfunc) that denotes the function should be treated as a string
|
||||
returning function type. The following example demonstrates how this
|
||||
|
@ -1374,6 +1367,99 @@ is done:
|
|||
symbol_table_t::e_ft_strfunc);
|
||||
|
||||
|
||||
Note: There are two further refinements to the type checking facility
|
||||
are the possibilities of a variable number of common types which can
|
||||
be accomplished by using a wildcard '*' and a special 'any type' which
|
||||
is done using the '?' character. It should be noted that the wildcard
|
||||
operator is associated with the previous type in the sequence and
|
||||
implies one or more of that type.
|
||||
|
||||
template <typename T>
|
||||
struct zoo : public exprtk::igeneric_function<T>
|
||||
{
|
||||
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||
parameter_list_t;
|
||||
|
||||
zoo()
|
||||
: exprtk::igeneric_function<T>("SVT*V?")
|
||||
{}
|
||||
|
||||
inline T operator()(parameter_list_t parameters)
|
||||
{
|
||||
...
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
In the example above the generic function 'zoo' expects at least five
|
||||
parameters in the following sequence:
|
||||
|
||||
(1) String
|
||||
(2) Vector
|
||||
(3) One or more Scalars
|
||||
(4) Vector
|
||||
(5) Any type (one type of either a scalar, vector or string)
|
||||
|
||||
|
||||
A final piece of type checking functionality is available for the
|
||||
scenarios where a single function name is intended to be used for
|
||||
multiple distinct parameter sequences. Two specific overrides of the
|
||||
function operator are provided one for standard generic functions and
|
||||
one for string returning functions. The overrides are as follows:
|
||||
|
||||
// f(psi,i_0,i_1,....,i_N) --> Scalar
|
||||
inline T operator()(const std::size_t& ps_index,
|
||||
parameter_list_t parameters)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
// f(psi,i_0,i_1,....,i_N) --> String
|
||||
inline T operator()(const std::size_t& ps_index,
|
||||
std::string& result,
|
||||
parameter_list_t parameters)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
When the function operator is invoked the 'ps_index' parameter will
|
||||
have as its value the index of the parameter sequence that matches the
|
||||
specific invocation. This way complex and time consuming type checking
|
||||
conditions need not be executed in the function itself but rather a
|
||||
simple and efficient dispatch to a specific implementation for that
|
||||
particular parameter sequence can be performed.
|
||||
|
||||
template <typename T>
|
||||
struct roo : public exprtk::igeneric_function<T>
|
||||
{
|
||||
typedef typename exprtk::igeneric_function<T>::parameter_list_t
|
||||
parameter_list_t;
|
||||
|
||||
moo()
|
||||
: exprtk::igeneric_function<T>("SVTT|SS|TTV|S?V*S")
|
||||
{}
|
||||
|
||||
inline T operator()(parameter_list_t parameters)
|
||||
{
|
||||
...
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
In the above example there are four distinct parameter sequences that
|
||||
can be processed by the generic function 'roo'. Any other parameter
|
||||
sequences will cause a compilation error. The valid four sequences are
|
||||
as follows:
|
||||
|
||||
Sequence-0 Sequence-1 Sequence-2 Sequence-3
|
||||
'SVTT' 'SS' 'TTV' 'S?V*S'
|
||||
(1) String (1) String (1) Scalar (1) String
|
||||
(2) Vector (2) String (2) Scalar (2) Any Type
|
||||
(3) Scalar (3) Vector (3) One or more Vectors
|
||||
(4) Scalar (4) String
|
||||
|
||||
|
||||
(5) function_compositor
|
||||
The function compositor interface allows a user to define a function
|
||||
using ExprTk syntax. The functions are limited to returning a single
|
||||
|
@ -1745,7 +1831,7 @@ into account when using Exprtk:
|
|||
(28) Every valid ExprTk statement is a "value returning" expression.
|
||||
Unlike some languages that limit the types of expressions that
|
||||
can be performed in certain situations, in ExprTk any valid
|
||||
expression can be used in any "value consuming" context. Eg:
|
||||
expression can be used in any "value consuming" context. eg:
|
||||
|
||||
var y := 3;
|
||||
for (var x := switch
|
||||
|
@ -2045,7 +2131,9 @@ files:
|
|||
+-------------------------------------------------------------+
|
||||
|09 - Variable Definition Statement |
|
||||
| |
|
||||
| [var] ---> [symbol] -+-> [:=] ---> [expression] -+-> [;] |
|
||||
| [var] ---> [symbol] -+-> [:=] -+-> [expression] -+-> [;] |
|
||||
| | | | |
|
||||
| | +-----> [{}] -->--+ |
|
||||
| | | |
|
||||
| +------------->-------------+ |
|
||||
| |
|
||||
|
|
Loading…
Reference in New Issue