C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html
This commit is contained in:
parent
e10cdcffcd
commit
9f5db27235
6
Makefile
6
Makefile
|
@ -33,6 +33,7 @@ BUILD_LIST+=exprtk_simple_example_06
|
|||
BUILD_LIST+=exprtk_simple_example_07
|
||||
BUILD_LIST+=exprtk_simple_example_08
|
||||
BUILD_LIST+=exprtk_simple_example_09
|
||||
BUILD_LIST+=exprtk_simple_example_10
|
||||
|
||||
all: $(BUILD_LIST)
|
||||
|
||||
|
@ -69,6 +70,9 @@ exprtk_simple_example_08: exprtk_simple_example_08.cpp exprtk.hpp
|
|||
exprtk_simple_example_09: exprtk_simple_example_09.cpp exprtk.hpp
|
||||
$(COMPILER) $(OPTIONS) exprtk_simple_example_09 exprtk_simple_example_09.cpp $(LINKER_OPT)
|
||||
|
||||
exprtk_simple_example_10: exprtk_simple_example_10.cpp exprtk.hpp
|
||||
$(COMPILER) $(OPTIONS) exprtk_simple_example_10 exprtk_simple_example_10.cpp $(LINKER_OPT)
|
||||
|
||||
pgo: exprtk_test.cpp exprtk_benchmark.cpp exprtk.hpp
|
||||
$(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT)
|
||||
./exprtk_benchmark
|
||||
|
@ -86,6 +90,7 @@ strip_bin:
|
|||
strip -s exprtk_simple_example_07
|
||||
strip -s exprtk_simple_example_08
|
||||
strip -s exprtk_simple_example_09
|
||||
strip -s exprtk_simple_example_10
|
||||
|
||||
valgrind_check:
|
||||
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_test
|
||||
|
@ -99,6 +104,7 @@ valgrind_check:
|
|||
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_07
|
||||
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_08
|
||||
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_09
|
||||
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_10
|
||||
|
||||
clean:
|
||||
rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch
|
||||
|
|
161
exprtk.hpp
161
exprtk.hpp
|
@ -1,32 +1,32 @@
|
|||
/*
|
||||
****************************************************************
|
||||
* C++ Mathematical Expression Toolkit Library *
|
||||
* *
|
||||
* Author: Arash Partow (1999-2013) *
|
||||
* URL: http://www.partow.net/programming/exprtk/index.html *
|
||||
* *
|
||||
* Copyright notice: *
|
||||
* Free use of the C++ Mathematical Expression Toolkit Library *
|
||||
* is permitted under the guidelines and in accordance with the *
|
||||
* most current version of the Common Public License. *
|
||||
* http://www.opensource.org/licenses/cpl1.0.php *
|
||||
* *
|
||||
* Example expressions: *
|
||||
* (00) (y+x/y)*(x-y/x) *
|
||||
* (01) (x^2/sin(2*pi/y))-x/2 *
|
||||
* (02) sqrt(1-(x^2)) *
|
||||
* (03) 1-sin(2*x)+cos(pi/y) *
|
||||
* (04) a*exp(2*t)+c *
|
||||
* (05) if(((x+2)==3)and((y+5)<=9),1+w,2/z) *
|
||||
* (06) if(avg(x,y)<=x+y,x-y,x*y)+2*pi/x *
|
||||
* (07) z:=x+sin(2*pi/y) *
|
||||
* (08) u:=2*(pi*z)/(w:=x+cos(y/pi)) *
|
||||
* (09) clamp(-1,sin(2*pi*x)+cos(y/2*pi),+1) *
|
||||
* (10) inrange(-2,m,+2)==if(({-2<=m} and [m<=+2]),1,0) *
|
||||
* (11) (12.34sin(x)cos(2y)7+1)==(12.34*sin(x)*cos(2*y)*7+1) *
|
||||
* (12) (x ilike 's*ri?g') and [y<(3z^7+w)] *
|
||||
* *
|
||||
****************************************************************
|
||||
******************************************************************
|
||||
* C++ Mathematical Expression Toolkit Library *
|
||||
* *
|
||||
* Author: Arash Partow (1999-2013) *
|
||||
* URL: http://www.partow.net/programming/exprtk/index.html *
|
||||
* *
|
||||
* Copyright notice: *
|
||||
* Free use of the C++ Mathematical Expression Toolkit Library is *
|
||||
* permitted under the guidelines and in accordance with the most *
|
||||
* current version of the Common Public License. *
|
||||
* http://www.opensource.org/licenses/cpl1.0.php *
|
||||
* *
|
||||
* Example expressions: *
|
||||
* (00) (y+x/y)*(x-y/x) *
|
||||
* (01) (x^2/sin(2*pi/y))-x/2 *
|
||||
* (02) sqrt(1-(x^2)) *
|
||||
* (03) 1-sin(2*x)+cos(pi/y) *
|
||||
* (04) a*exp(2*t)+c *
|
||||
* (05) if(((x+2)==3)and((y+5)<=9),1+w,2/z) *
|
||||
* (06) if(avg(x,y)<=x+y,x-y,x*y)+2*pi/x *
|
||||
* (07) z:=x+sin(2*pi/y) *
|
||||
* (08) u:=2*(pi*z)/(w:=x+cos(y/pi)) *
|
||||
* (09) clamp(-1,sin(2*pi*x)+cos(y/2*pi),+1) *
|
||||
* (10) inrange(-2,m,+2)==if(({-2<=m} and [m<=+2]),1,0) *
|
||||
* (11) (12.34sin(x)cos(2y)7+1)==(12.34*sin(x)*cos(2*y)*7+1) *
|
||||
* (12) (x ilike 's*ri?g') and [y<(3z^7+w)] *
|
||||
* *
|
||||
******************************************************************
|
||||
*/
|
||||
|
||||
|
||||
|
@ -2304,7 +2304,7 @@ namespace exprtk
|
|||
|
||||
void reset()
|
||||
{
|
||||
//msvc doesn't support swap properly.
|
||||
//why? because msvc doesn't support swap properly.
|
||||
stack_ = std::stack<char>();
|
||||
state_ = true;
|
||||
error_token_.clear();
|
||||
|
@ -9400,6 +9400,27 @@ namespace exprtk
|
|||
e_commutative_check = 32
|
||||
};
|
||||
|
||||
struct unknown_symbol_resolver
|
||||
{
|
||||
|
||||
enum symbol_type
|
||||
{
|
||||
e_variable_type = 0,
|
||||
e_constant_type = 1
|
||||
};
|
||||
|
||||
virtual ~unknown_symbol_resolver()
|
||||
{}
|
||||
|
||||
virtual bool process(const std::string& /*unknown_symbol*/, symbol_type& st, T& default_value, std::string& error_message)
|
||||
{
|
||||
st = e_variable_type;
|
||||
default_value = T(0);
|
||||
error_message = "";
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static const std::size_t precompile_all_opts = e_replacer +
|
||||
e_joiner +
|
||||
e_numeric_check +
|
||||
|
@ -9409,7 +9430,9 @@ namespace exprtk
|
|||
|
||||
parser(const std::size_t precompile_options = precompile_all_opts)
|
||||
: symbol_name_caching_(false),
|
||||
precompile_options_(precompile_options)
|
||||
precompile_options_(precompile_options),
|
||||
resolve_unknown_symbol_(false),
|
||||
unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0))
|
||||
{
|
||||
init_precompilation();
|
||||
load_operations_map(base_ops_map_);
|
||||
|
@ -9729,6 +9752,21 @@ namespace exprtk
|
|||
return symbol_replacer_.remove(symbol);
|
||||
}
|
||||
|
||||
inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast<unknown_symbol_resolver*>(0))
|
||||
{
|
||||
resolve_unknown_symbol_ = true;
|
||||
if (usr)
|
||||
unknown_symbol_resolver_ = usr;
|
||||
else
|
||||
unknown_symbol_resolver_ = &default_usr_;
|
||||
}
|
||||
|
||||
inline void disable_unknown_symbol_resolver()
|
||||
{
|
||||
resolve_unknown_symbol_ = false;
|
||||
unknown_symbol_resolver_ = &default_usr_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline bool valid_base_operation(const std::string& symbol)
|
||||
|
@ -10799,14 +10837,60 @@ namespace exprtk
|
|||
return error_node();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// Should we handle unknown symbols?
|
||||
if (resolve_unknown_symbol_ && unknown_symbol_resolver_)
|
||||
{
|
||||
set_error(
|
||||
make_error(parser_error::e_syntax,
|
||||
current_token_,
|
||||
"ERR40 - Undefined variable or function: '" + symbol + "'"));
|
||||
return error_node();
|
||||
T default_value = T(0);
|
||||
std::string error_message;
|
||||
typename unknown_symbol_resolver::symbol_type symbol_type;
|
||||
|
||||
if (unknown_symbol_resolver_->process(symbol,symbol_type,default_value,error_message))
|
||||
{
|
||||
bool create_result = false;
|
||||
switch (symbol_type)
|
||||
{
|
||||
case unknown_symbol_resolver::e_variable_type : create_result = symbol_table_.create_variable(symbol,default_value);
|
||||
break;
|
||||
|
||||
case unknown_symbol_resolver::e_constant_type : create_result = symbol_table_.add_constant(symbol,default_value);
|
||||
break;
|
||||
|
||||
default : create_result = false;
|
||||
}
|
||||
|
||||
if (create_result)
|
||||
{
|
||||
expression_node_ptr variable = symbol_table_.get_variable(symbol);
|
||||
if (variable)
|
||||
{
|
||||
if (symbol_name_caching_)
|
||||
{
|
||||
symbol_name_cache_.push_back(symbol);
|
||||
}
|
||||
if (symbol_table_.is_constant_node(symbol))
|
||||
{
|
||||
variable = expression_generator_(variable->value());
|
||||
}
|
||||
next_token();
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
set_error(
|
||||
make_error(parser_error::e_symtab,
|
||||
current_token_,
|
||||
"ERR40 - Failed to create variable: '" + symbol + "'"));
|
||||
|
||||
return error_node();
|
||||
}
|
||||
}
|
||||
|
||||
set_error(
|
||||
make_error(parser_error::e_syntax,
|
||||
current_token_,
|
||||
"ERR41 - Undefined variable or function: '" + symbol + "'"));
|
||||
return error_node();
|
||||
}
|
||||
|
||||
inline expression_node_ptr parse_symbol()
|
||||
|
@ -11747,6 +11831,7 @@ namespace exprtk
|
|||
else if (all_nodes_variables(branch))
|
||||
return varnode_optimize_sf3(operation,branch);
|
||||
else
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
#define case_stmt(op0,op1) case op0 : return node_allocator_->allocate<details::sf3_node<Type,op1<Type> > >(operation,branch);
|
||||
|
@ -11777,6 +11862,7 @@ namespace exprtk
|
|||
#undef case_stmt
|
||||
default : return error_node();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
||||
|
@ -15524,6 +15610,9 @@ namespace exprtk
|
|||
std::size_t precompile_options_;
|
||||
std::deque<std::string> symbol_name_cache_;
|
||||
std::deque<parser_error::type> error_list_;
|
||||
bool resolve_unknown_symbol_;
|
||||
unknown_symbol_resolver* unknown_symbol_resolver_;
|
||||
unknown_symbol_resolver default_usr_;
|
||||
base_ops_map_t base_ops_map_;
|
||||
unary_op_map_t unary_op_map_;
|
||||
binary_op_map_t binary_op_map_;
|
||||
|
|
160
exprtk_test.cpp
160
exprtk_test.cpp
|
@ -3830,6 +3830,165 @@ inline bool run_test19()
|
|||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
T x = T(0);
|
||||
|
||||
exprtk::symbol_table<T> symbol_table;
|
||||
|
||||
symbol_table.add_constants();
|
||||
symbol_table.add_variable("x",x);
|
||||
|
||||
compositor_t compositor(symbol_table);
|
||||
|
||||
compositor
|
||||
.add("newton_sqrt_impl",
|
||||
"switch "
|
||||
"{ "
|
||||
" case x < 0 : -inf; "
|
||||
" case x == 0 : 0; "
|
||||
" case x == 1 : 1; "
|
||||
" default: "
|
||||
" ~{ "
|
||||
" z := 100; "
|
||||
" y := x / 2; "
|
||||
" while ((z := (z - 1)) > 0) "
|
||||
" { "
|
||||
" if (equal(y * y,x), z := 0, 0);"
|
||||
" y := (1 / 2) * (y + (x / y)) "
|
||||
" } "
|
||||
" }; "
|
||||
"} ",
|
||||
"x","y","z");
|
||||
|
||||
compositor
|
||||
.add("newton_sqrt",
|
||||
"newton_sqrt_impl(x,0,0)","x");
|
||||
|
||||
std::string expression_str = "newton_sqrt(x)";
|
||||
|
||||
expression_t expression;
|
||||
|
||||
expression.register_symbol_table(symbol_table);
|
||||
|
||||
exprtk::parser<T> parser;
|
||||
|
||||
if (!parser.compile(expression_str,expression))
|
||||
{
|
||||
printf("run_test19() - Error: %s Expression: %s\n",
|
||||
parser.error().c_str(),
|
||||
expression_str.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool failure = false;
|
||||
|
||||
for (std::size_t i = 0; i < 100; ++i)
|
||||
{
|
||||
x = i;
|
||||
T result = expression.value();
|
||||
|
||||
if (not_equal(result,std::sqrt(x),T(0.0000001)))
|
||||
{
|
||||
printf("run_test19() - Computation Error "
|
||||
"Expression: [%s]\tExpected: %12.8f\tResult: %12.8f\n",
|
||||
expression_str.c_str(),
|
||||
std::sqrt(x),
|
||||
result);
|
||||
failure = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (failure)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
|
||||
{
|
||||
|
||||
typedef typename exprtk::parser<T>::unknown_symbol_resolver usr_t;
|
||||
|
||||
bool process(const std::string& unknown_symbol,
|
||||
typename usr_t::symbol_type& st,
|
||||
T& default_value,
|
||||
std::string& error_message)
|
||||
{
|
||||
if (unknown_symbol[0] == 'v')
|
||||
{
|
||||
st = usr_t::e_variable_type;
|
||||
default_value = next_value();
|
||||
error_message = "";
|
||||
return true;
|
||||
}
|
||||
else if (unknown_symbol[0] == 'w')
|
||||
{
|
||||
st = usr_t::e_constant_type;
|
||||
default_value = next_value();
|
||||
error_message = "";
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_message = "Unknown symbol...";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
T next_value(const bool reset = false)
|
||||
{
|
||||
static T value = 0;
|
||||
if (reset)
|
||||
return (value = 0);
|
||||
else
|
||||
return ++value;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline bool run_test20()
|
||||
{
|
||||
typedef exprtk::expression<T> expression_t;
|
||||
|
||||
for (std::size_t i = 0; i < 400; ++i)
|
||||
{
|
||||
exprtk::symbol_table<T> symbol_table;
|
||||
symbol_table.add_constants();
|
||||
|
||||
expression_t expression;
|
||||
expression.register_symbol_table(symbol_table);
|
||||
|
||||
exprtk::parser<T> parser;
|
||||
|
||||
my_usr<T> musr;
|
||||
musr.next_value(true);
|
||||
parser.enable_unknown_symbol_resolver(&musr);
|
||||
|
||||
std::string expr_str = "v01+w02+v03+w04+v05+w06+v07+w08+v09+w10+"
|
||||
"v11+w12+v13+w14+v15+w16+v17+w18+v19+w20+"
|
||||
"v21+w22+v23+w24+v25+w26+v27+w28+v29+w30";
|
||||
|
||||
if (!parser.compile(expr_str,expression))
|
||||
{
|
||||
printf("run_test18() - Error: %s Expression: %s\n",
|
||||
parser.error().c_str(),
|
||||
expr_str.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
T sum_1_30 = T((1 + 30) * 15);
|
||||
T result = expression.value();
|
||||
|
||||
if (sum_1_30 != result)
|
||||
{
|
||||
printf("run_test20() - Error in evaluation! (1) Expression: %s\n",
|
||||
expr_str.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3870,6 +4029,7 @@ int main()
|
|||
perform_test(double,17)
|
||||
perform_test(double,18)
|
||||
perform_test(double,19)
|
||||
perform_test(double,20)
|
||||
|
||||
#undef perform_test
|
||||
|
||||
|
|
36
readme.txt
36
readme.txt
|
@ -1,6 +1,6 @@
|
|||
C++ Mathematical Expression Toolkit Library
|
||||
|
||||
[INTRODUCTION]
|
||||
[00 - INTRODUCTION]
|
||||
The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple
|
||||
to use, easy to integrate and extremely efficient mathematical
|
||||
expression parsing and evaluation engine. The parsing engine supports
|
||||
|
@ -9,7 +9,7 @@ very easily extendible.
|
|||
|
||||
|
||||
|
||||
[CAPABILITIES]
|
||||
[01 - CAPABILITIES]
|
||||
The ExprTk evaluator supports the following fundamental mathematical
|
||||
operations, functions and processes:
|
||||
|
||||
|
@ -42,7 +42,7 @@ operations, functions and processes:
|
|||
|
||||
|
||||
|
||||
[EXAMPLE EXPRESSIONS]
|
||||
[02 - EXAMPLE EXPRESSIONS]
|
||||
The following is a short sample of the types of mathematical
|
||||
expressions that can be parsed and evaluated using the ExprTk library.
|
||||
|
||||
|
@ -69,7 +69,7 @@ expressions that can be parsed and evaluated using the ExprTk library.
|
|||
|
||||
|
||||
|
||||
[COPYRIGHT NOTICE]
|
||||
[03 - COPYRIGHT NOTICE]
|
||||
Free use of the C++ Mathematical Expression Toolkit Library is
|
||||
permitted under the guidelines and in accordance with the most current
|
||||
version of the Common Public License.
|
||||
|
@ -78,7 +78,7 @@ http://www.opensource.org/licenses/cpl1.0.php
|
|||
|
||||
|
||||
|
||||
[DOWNLOADS & UPDATES]
|
||||
[04 - DOWNLOADS & UPDATES]
|
||||
The most recent version of the C++ Mathematical Expression Toolkit
|
||||
Library including all updates and tests can be found at the following
|
||||
locations:
|
||||
|
@ -88,20 +88,20 @@ locations:
|
|||
|
||||
|
||||
|
||||
[INSTALLATION]
|
||||
[05 - INSTALLATION]
|
||||
The header file exprtk.hpp should be placed in a project or system
|
||||
include path (e.g: /usr/include/).
|
||||
|
||||
|
||||
|
||||
[COMPILATION]
|
||||
[06 - COMPILATION]
|
||||
(1) For a complete build: make clean all
|
||||
(2) For a PGO build: make clean pgo
|
||||
(3) To strip executables: make strip_bin
|
||||
|
||||
|
||||
|
||||
[COMPILER COMPATIBILITY]
|
||||
[07 - COMPILER COMPATIBILITY]
|
||||
(*) GNU Compiler Collection (4.3+)
|
||||
(*) Intel® C++ Compiler (9.x+)
|
||||
(*) Clang/LLVM (1.1+)
|
||||
|
@ -112,7 +112,7 @@ include path (e.g: /usr/include/).
|
|||
|
||||
|
||||
|
||||
[BUILT-IN OPERATIONS & FUNCTIONS]
|
||||
[08 - BUILT-IN OPERATIONS & FUNCTIONS]
|
||||
|
||||
(0) Basic Operators
|
||||
+-----------+--------------------------------------------------------+
|
||||
|
@ -344,7 +344,7 @@ include path (e.g: /usr/include/).
|
|||
|
||||
|
||||
|
||||
[SPECIAL FUNCTIONS]
|
||||
[09 - SPECIAL FUNCTIONS]
|
||||
The purpose of special functions in ExprTk is to provide compiler
|
||||
generated equivalents of common mathematical expressions which can be
|
||||
invoked by using the 'special function' syntax (eg: $f12(x,y,z) or
|
||||
|
@ -415,7 +415,7 @@ correctly optimize such expressions for a given architecture.
|
|||
|
||||
|
||||
|
||||
[EXPRTK NOTES]
|
||||
[10 - EXPRTK NOTES]
|
||||
(00) Precision and performance of expression evaluations are the
|
||||
dominant principles of the ExprTk library.
|
||||
|
||||
|
@ -478,7 +478,7 @@ correctly optimize such expressions for a given architecture.
|
|||
|
||||
|
||||
|
||||
[SIMPLE EXPRTK EXAMPLE]
|
||||
[11 - SIMPLE EXPRTK EXAMPLE]
|
||||
--- snip ---
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
@ -553,9 +553,19 @@ int main()
|
|||
|
||||
|
||||
|
||||
[FILES]
|
||||
[12 - FILES]
|
||||
(00) Makefile
|
||||
(01) readme.txt
|
||||
(02) exprtk.hpp
|
||||
(03) exprtk_test.cpp
|
||||
(04) exprtk_benchmark.cpp
|
||||
(05) exprtk_simple_example_01.cpp
|
||||
(06) exprtk_simple_example_02.cpp
|
||||
(07) exprtk_simple_example_03.cpp
|
||||
(08) exprtk_simple_example_04.cpp
|
||||
(09) exprtk_simple_example_05.cpp
|
||||
(10) exprtk_simple_example_06.cpp
|
||||
(11) exprtk_simple_example_07.cpp
|
||||
(12) exprtk_simple_example_08.cpp
|
||||
(13) exprtk_simple_example_09.cpp
|
||||
(14) exprtk_simple_example_10.cpp
|
||||
|
|
Loading…
Reference in New Issue