C++ Mathematical Expression Library (ExprTk) https://www.partow.net/programming/exprtk/index.html

This commit is contained in:
Arash Partow 2016-12-15 10:46:23 +11:00
parent f75c3934ed
commit 71bba0b6fa
3 changed files with 931 additions and 93 deletions

View File

@ -4333,7 +4333,7 @@ namespace exprtk
e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051,
e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055,
e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059,
e_sf4ext60 = 2060
e_sf4ext60 = 2060, e_sf4ext61 = 2061
};
inline std::string to_str(const operator_type opr)
@ -5422,6 +5422,7 @@ namespace exprtk
virtual const range_t& range_ref() const = 0;
};
#ifndef exprtk_disable_string_capabilities
template <typename T>
class string_base_node
{
@ -5505,6 +5506,7 @@ namespace exprtk
const std::string value_;
range_t rp_;
};
#endif
template <typename T>
class unary_node : public expression_node<T>
@ -5532,6 +5534,7 @@ namespace exprtk
inline T value() const
{
const T arg = branch_->value();
return numeric::process<T>(operation_,arg);
}
@ -5664,6 +5667,7 @@ namespace exprtk
{
const T arg0 = branch_[0].first->value();
const T arg1 = branch_[1].first->value();
return numeric::process<T>(operation_,arg0,arg1);
}
@ -6229,6 +6233,7 @@ namespace exprtk
inline T value() const
{
T result = T(0);
while (is_true(condition_))
{
try
@ -6242,6 +6247,7 @@ namespace exprtk
catch(const continue_exception&)
{}
}
return result;
}
@ -7375,6 +7381,7 @@ namespace exprtk
{
rp_.n1_c.second = (*value_).size() - 1;
rp_.cache.second = rp_.n1_c.second;
return std::numeric_limits<T>::quiet_NaN();
}
@ -8876,57 +8883,58 @@ namespace exprtk
define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)")
define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)")
define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)")
define_sfop4(ext10,((x + y) * (z - w)),"(t+t)*(t-t)")
define_sfop4(ext11,((x + y) / (z - w)),"(t+t)/(t-t)")
define_sfop4(ext12,((x - y) - (z + w)),"(t-t)-(t+t)")
define_sfop4(ext13,((x - y) + (z + w)),"(t-t)+(t+t)")
define_sfop4(ext14,((x - y) * (z + w)),"(t-t)*(t+t)")
define_sfop4(ext15,((x - y) / (z + w)),"(t-t)/(t+t)")
define_sfop4(ext16,((x * y) - (z + w)),"(t*t)-(t+t)")
define_sfop4(ext17,((x / y) - (z + w)),"(t/t)-(t+t)")
define_sfop4(ext18,((x * y) + (z + w)),"(t*t)+(t+t)")
define_sfop4(ext19,((x / y) + (z + w)),"(t/t)+(t+t)")
define_sfop4(ext20,((x * y) + (z - w)),"(t*t)+(t-t)")
define_sfop4(ext21,((x / y) + (z - w)),"(t/t)+(t-t)")
define_sfop4(ext22,((x * y) - (z - w)),"(t*t)-(t-t)")
define_sfop4(ext23,((x / y) - (z - w)),"(t/t)-(t-t)")
define_sfop4(ext24,((x + y) * (z * w)),"(t+t)*(t*t)")
define_sfop4(ext25,((x + y) * (z / w)),"(t+t)*(t/t)")
define_sfop4(ext26,((x + y) / (z * w)),"(t+t)/(t*t)")
define_sfop4(ext27,((x + y) / (z / w)),"(t+t)/(t/t)")
define_sfop4(ext28,((x - y) / (z * w)),"(t-t)/(t*t)")
define_sfop4(ext29,((x - y) / (z / w)),"(t-t)/(t/t)")
define_sfop4(ext30,((x - y) * (z * w)),"(t-t)*(t*t)")
define_sfop4(ext31,((x - y) * (z / w)),"(t-t)*(t/t)")
define_sfop4(ext32,((x * y) * (z + w)),"(t*t)*(t+t)")
define_sfop4(ext33,((x / y) * (z + w)),"(t/t)*(t+t)")
define_sfop4(ext34,((x * y) / (z + w)),"(t*t)/(t+t)")
define_sfop4(ext35,((x / y) / (z + w)),"(t/t)/(t+t)")
define_sfop4(ext36,((x * y) / (z - w)),"(t*t)/(t-t)")
define_sfop4(ext37,((x / y) / (z - w)),"(t/t)/(t-t)")
define_sfop4(ext38,((x * y) * (z - w)),"(t*t)*(t-t)")
define_sfop4(ext39,((x * y) / (z * w)),"(t*t)/(t*t)")
define_sfop4(ext40,((x / y) * (z / w)),"(t/t)*(t/t)")
define_sfop4(ext41,((x / y) * (z - w)),"(t/t)*(t-t)")
define_sfop4(ext42,((x * y) * (z * w)),"(t*t)*(t*t)")
define_sfop4(ext43,(x + (y * (z / w))),"t+(t*(t/t))")
define_sfop4(ext44,(x - (y * (z / w))),"t-(t*(t/t))")
define_sfop4(ext45,(x + (y / (z * w))),"t+(t/(t*t))")
define_sfop4(ext46,(x - (y / (z * w))),"t-(t/(t*t))")
define_sfop4(ext47,(((x - y) - z) * w),"((t-t)-t)*t")
define_sfop4(ext48,(((x - y) - z) / w),"((t-t)-t)/t")
define_sfop4(ext49,(((x - y) + z) * w),"((t-t)+t)*t")
define_sfop4(ext50,(((x - y) + z) / w),"((t-t)+t)/t")
define_sfop4(ext51,((x + (y - z)) * w),"(t+(t-t))*t")
define_sfop4(ext52,((x + (y - z)) / w),"(t+(t-t))/t")
define_sfop4(ext53,((x + y) / (z + w)),"(t+t)/(t+t)")
define_sfop4(ext54,((x - y) / (z - w)),"(t-t)/(t-t)")
define_sfop4(ext55,((x + y) * (z + w)),"(t+t)*(t+t)")
define_sfop4(ext56,((x - y) * (z - w)),"(t-t)*(t-t)")
define_sfop4(ext57,((x - y) + (z - w)),"(t-t)+(t-t)")
define_sfop4(ext58,((x - y) - (z - w)),"(t-t)-(t-t)")
define_sfop4(ext59,((x / y) + (z * w)),"(t/t)+(t*t)")
define_sfop4(ext60,(((x * y) * z) / w),"((t*t)*t)/t")
define_sfop4(ext10,((x + y) + (z + w)),"(t+t)+(t+t)")
define_sfop4(ext11,((x + y) * (z - w)),"(t+t)*(t-t)")
define_sfop4(ext12,((x + y) / (z - w)),"(t+t)/(t-t)")
define_sfop4(ext13,((x - y) - (z + w)),"(t-t)-(t+t)")
define_sfop4(ext14,((x - y) + (z + w)),"(t-t)+(t+t)")
define_sfop4(ext15,((x - y) * (z + w)),"(t-t)*(t+t)")
define_sfop4(ext16,((x - y) / (z + w)),"(t-t)/(t+t)")
define_sfop4(ext17,((x * y) - (z + w)),"(t*t)-(t+t)")
define_sfop4(ext18,((x / y) - (z + w)),"(t/t)-(t+t)")
define_sfop4(ext19,((x * y) + (z + w)),"(t*t)+(t+t)")
define_sfop4(ext20,((x / y) + (z + w)),"(t/t)+(t+t)")
define_sfop4(ext21,((x * y) + (z - w)),"(t*t)+(t-t)")
define_sfop4(ext22,((x / y) + (z - w)),"(t/t)+(t-t)")
define_sfop4(ext23,((x * y) - (z - w)),"(t*t)-(t-t)")
define_sfop4(ext24,((x / y) - (z - w)),"(t/t)-(t-t)")
define_sfop4(ext25,((x + y) * (z * w)),"(t+t)*(t*t)")
define_sfop4(ext26,((x + y) * (z / w)),"(t+t)*(t/t)")
define_sfop4(ext27,((x + y) / (z * w)),"(t+t)/(t*t)")
define_sfop4(ext28,((x + y) / (z / w)),"(t+t)/(t/t)")
define_sfop4(ext29,((x - y) / (z * w)),"(t-t)/(t*t)")
define_sfop4(ext30,((x - y) / (z / w)),"(t-t)/(t/t)")
define_sfop4(ext31,((x - y) * (z * w)),"(t-t)*(t*t)")
define_sfop4(ext32,((x - y) * (z / w)),"(t-t)*(t/t)")
define_sfop4(ext33,((x * y) * (z + w)),"(t*t)*(t+t)")
define_sfop4(ext34,((x / y) * (z + w)),"(t/t)*(t+t)")
define_sfop4(ext35,((x * y) / (z + w)),"(t*t)/(t+t)")
define_sfop4(ext36,((x / y) / (z + w)),"(t/t)/(t+t)")
define_sfop4(ext37,((x * y) / (z - w)),"(t*t)/(t-t)")
define_sfop4(ext38,((x / y) / (z - w)),"(t/t)/(t-t)")
define_sfop4(ext39,((x * y) * (z - w)),"(t*t)*(t-t)")
define_sfop4(ext40,((x * y) / (z * w)),"(t*t)/(t*t)")
define_sfop4(ext41,((x / y) * (z / w)),"(t/t)*(t/t)")
define_sfop4(ext42,((x / y) * (z - w)),"(t/t)*(t-t)")
define_sfop4(ext43,((x * y) * (z * w)),"(t*t)*(t*t)")
define_sfop4(ext44,(x + (y * (z / w))),"t+(t*(t/t))")
define_sfop4(ext45,(x - (y * (z / w))),"t-(t*(t/t))")
define_sfop4(ext46,(x + (y / (z * w))),"t+(t/(t*t))")
define_sfop4(ext47,(x - (y / (z * w))),"t-(t/(t*t))")
define_sfop4(ext48,(((x - y) - z) * w),"((t-t)-t)*t")
define_sfop4(ext49,(((x - y) - z) / w),"((t-t)-t)/t")
define_sfop4(ext50,(((x - y) + z) * w),"((t-t)+t)*t")
define_sfop4(ext51,(((x - y) + z) / w),"((t-t)+t)/t")
define_sfop4(ext52,((x + (y - z)) * w),"(t+(t-t))*t")
define_sfop4(ext53,((x + (y - z)) / w),"(t+(t-t))/t")
define_sfop4(ext54,((x + y) / (z + w)),"(t+t)/(t+t)")
define_sfop4(ext55,((x - y) / (z - w)),"(t-t)/(t-t)")
define_sfop4(ext56,((x + y) * (z + w)),"(t+t)*(t+t)")
define_sfop4(ext57,((x - y) * (z - w)),"(t-t)*(t-t)")
define_sfop4(ext58,((x - y) + (z - w)),"(t-t)+(t-t)")
define_sfop4(ext59,((x - y) - (z - w)),"(t-t)-(t-t)")
define_sfop4(ext60,((x / y) + (z * w)),"(t/t)+(t*t)")
define_sfop4(ext61,(((x * y) * z) / w),"((t*t)*t)/t")
#undef define_sfop3
#undef define_sfop4
@ -11174,6 +11182,7 @@ namespace exprtk
ts.data = vi->vds().data();
ts.type = type_store_t::e_vector;
}
#ifndef exprtk_disable_string_capabilities
else if (is_generally_string_node(arg_list_[i]))
{
string_base_node<T>* sbn = reinterpret_cast<string_base_node<T>*>(0);
@ -11209,6 +11218,7 @@ namespace exprtk
else
range_list_[i].range = &(ri->range_ref());
}
#endif
else if (is_variable_node(arg_list_[i]))
{
variable_node_ptr_t var = variable_node_ptr_t(0);
@ -11282,10 +11292,11 @@ namespace exprtk
type_store_t& ts = typestore_list_[i];
ts.size = rp.cache_size();
#ifndef exprtk_disable_string_capabilities
if (ts.type == type_store_t::e_string)
ts.data = const_cast<char*>(rdt.str_node->base()) + rp.cache.first;
else
#endif
ts.data = static_cast<char*>(rdt.data) + (rp.cache.first * rdt.type_size);
}
else
@ -11307,6 +11318,7 @@ namespace exprtk
mutable range_list_t range_list_;
};
#ifndef exprtk_disable_string_capabilities
template <typename T, typename StringFunction>
class string_function_node : public generic_function_node<T,StringFunction>,
public string_base_node<T>,
@ -11390,6 +11402,7 @@ namespace exprtk
mutable range_t range_;
mutable std::string ret_string_;
};
#endif
template <typename T, typename GenericFunction>
class multimode_genfunction_node : public generic_function_node<T,GenericFunction>
@ -11434,6 +11447,7 @@ namespace exprtk
std::size_t param_seq_index_;
};
#ifndef exprtk_disable_string_capabilities
template <typename T, typename StringFunction>
class multimode_strfunction_node : public string_function_node<T,StringFunction>
{
@ -11482,6 +11496,7 @@ namespace exprtk
std::size_t param_seq_index_;
};
#endif
class return_exception
{};
@ -16286,13 +16301,19 @@ namespace exprtk
local_data().vector_store.clear();
}
inline void clear_local_constants()
{
local_data().local_symbol_list_.clear();
}
inline void clear()
{
if (!valid()) return;
clear_variables();
clear_functions();
clear_strings ();
clear_vectors ();
clear_variables ();
clear_functions ();
clear_strings ();
clear_vectors ();
clear_local_constants();
}
inline std::size_t variable_count() const
@ -18711,11 +18732,13 @@ namespace exprtk
case e_st_string :
case e_st_local_variable :
case e_st_local_vector :
case e_st_local_string :
case e_st_function :
if (collect_variables_ || collect_functions_)
symbol_name_list_.push_back(std::make_pair(symbol,st));
break;
case e_st_local_string : if (collect_variables_)
symbol_name_list_.push_back(std::make_pair(symbol,st));
break;
case e_st_function : if (collect_functions_)
symbol_name_list_.push_back(std::make_pair(symbol,st));
break;
default : return;
}
@ -22776,6 +22799,7 @@ namespace exprtk
return result;
}
#ifndef exprtk_disable_string_capabilities
inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name)
{
std::vector<expression_node_ptr> arg_list;
@ -22856,6 +22880,7 @@ namespace exprtk
return result;
}
#endif
template <typename Type, std::size_t NumberOfParameters>
struct parse_special_function_impl
@ -24235,6 +24260,7 @@ namespace exprtk
}
}
#ifndef exprtk_disable_string_capabilities
{
// Are we dealing with a vararg string returning function?
igeneric_function<T>* string_function = symtab_store_.get_string_function(symbol);
@ -24259,6 +24285,7 @@ namespace exprtk
}
}
}
#endif
// Are we dealing with a vector?
if (symtab_store_.is_vector(symbol))
@ -26373,6 +26400,7 @@ namespace exprtk
}
}
#ifndef exprtk_disable_string_capabilities
inline expression_node_ptr string_function_call(igeneric_function_t* gf,
std::vector<expression_node_ptr>& arg_list,
const std::size_t& param_seq_index = std::numeric_limits<std::size_t>::max())
@ -26425,6 +26453,7 @@ namespace exprtk
return error_node();
}
}
#endif
inline expression_node_ptr return_call(std::vector<expression_node_ptr>& arg_list)
{
@ -28078,6 +28107,7 @@ namespace exprtk
return false;
const std::string node_id = branch_to_id(branch);
typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id);
if (synthesize_map_.end() != itr)
@ -28278,7 +28308,7 @@ namespace exprtk
case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51)
case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55)
case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59)
case_stmt1(60)
case_stmt1(60) case_stmt1(61)
#undef case_stmt0
#undef case_stmt1
@ -28357,6 +28387,7 @@ namespace exprtk
typedef details::T0oT1oT2_base_node<Type>* sf3ext_base_ptr;
sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node);
std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t";
switch (n->type())
@ -33404,7 +33435,7 @@ namespace exprtk
register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51)
register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55)
register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59)
register_sf4ext(60)
register_sf4ext(60) register_sf4ext(61)
#undef register_sf4ext
}
@ -33466,6 +33497,76 @@ namespace exprtk
lexer::helper::sequence_validator sequence_validator_;
};
template <typename Allocator,
template <typename, typename> class Sequence>
inline bool collect_variables(const std::string& expr_str,
Sequence<std::string, Allocator>& symbol_list)
{
typedef double T;
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
typedef parser_t::dependent_entity_collector::symbol_t symbol_t;
symbol_table_t symbol_table;
expression_t expression;
parser_t parser;
expression.register_symbol_table(symbol_table);
parser.enable_unknown_symbol_resolver();
parser.dec().collect_variables() = true;
if (!parser.compile(expr_str, expression))
return false;
std::deque<symbol_t> symb_list;
parser.dec().symbols(symb_list);
for (std::size_t i = 0; i < symb_list.size(); ++i)
{
symbol_list.push_back(symb_list[i].first);
}
return true;
}
template <typename Allocator,
template <typename, typename> class Sequence>
inline bool collect_functions(const std::string& expr_str,
Sequence<std::string, Allocator>& symbol_list)
{
typedef double T;
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
typedef parser_t::dependent_entity_collector::symbol_t symbol_t;
symbol_table_t symbol_table;
expression_t expression;
parser_t parser;
expression.register_symbol_table(symbol_table);
parser.enable_unknown_symbol_resolver();
parser.dec().collect_functions() = true;
if (!parser.compile(expr_str, expression))
return false;
std::deque<symbol_t> symb_list;
parser.dec().symbols(symb_list);
for (std::size_t i = 0; i < symb_list.size(); ++i)
{
symbol_list.push_back(symb_list[i].first);
}
return true;
}
template <typename T>
inline T integrate(const expression<T>& e,
T& x,
@ -33673,6 +33774,8 @@ namespace exprtk
symbol_table.add_constants();
expression<T> expression;
expression.register_symbol_table(symbol_table);
parser<T> parser;
if (parser.compile(expression_string,expression))
@ -33695,9 +33798,11 @@ namespace exprtk
symbol_table<T> symbol_table;
symbol_table.add_constants();
symbol_table.add_variable(x_var,x);
symbol_table.add_constant(x_var,x);
expression<T> expression;
expression.register_symbol_table(symbol_table);
parser<T> parser;
if (parser.compile(expression_string,expression))
@ -33721,10 +33826,12 @@ namespace exprtk
symbol_table<T> symbol_table;
symbol_table.add_constants();
symbol_table.add_variable(x_var,x);
symbol_table.add_variable(y_var,y);
symbol_table.add_constant(x_var,x);
symbol_table.add_constant(y_var,y);
expression<T> expression;
expression.register_symbol_table(symbol_table);
parser<T> parser;
if (parser.compile(expression_string,expression))
@ -33749,11 +33856,13 @@ namespace exprtk
symbol_table<T> symbol_table;
symbol_table.add_constants();
symbol_table.add_variable(x_var,x);
symbol_table.add_variable(y_var,y);
symbol_table.add_variable(z_var,z);
symbol_table.add_constant(x_var,x);
symbol_table.add_constant(y_var,y);
symbol_table.add_constant(z_var,z);
expression<T> expression;
expression.register_symbol_table(symbol_table);
parser<T> parser;
if (parser.compile(expression_string,expression))
@ -34948,7 +35057,7 @@ namespace exprtk
else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49)
else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53)
else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57)
else_stmt(58) else_stmt(59) else_stmt(60)
else_stmt(58) else_stmt(59) else_stmt(60) else_stmt(61)
}
}
@ -36831,9 +36940,9 @@ namespace exprtk
namespace information
{
static const char* library = "Mathematical Expression Toolkit";
static const char* version = "2.71828182845904523536028747135266249775"
"7247093699959574966967627724076630353547";
static const char* date = "20161010";
static const char* version = "2.7182818284590452353602874713526624977572"
"470936999595749669676277240766303535475945";
static const char* date = "20161212";
static inline std::string data()
{

View File

@ -4029,6 +4029,42 @@ inline bool run_test10()
}
}
{
T a = T(1);
T b = T(2);
T c = T(3);
T d = T(4);
std::string e = "a string";
exprtk::symbol_table<T> symbol_table0;
exprtk::symbol_table<T> symbol_table1;
expression_t expression;
for (std::size_t i = 0; i < 10000; ++i)
{
symbol_table0.clear();
symbol_table1.clear();
symbol_table0.add_variable ("a",a);
symbol_table0.add_variable ("b",b);
symbol_table0.add_variable ("c",c);
symbol_table0.add_variable ("d",d);
symbol_table0.add_stringvar("e",e);
symbol_table0.add_constants( );
symbol_table1.add_variable ("a",a);
symbol_table1.add_variable ("b",b);
symbol_table1.add_variable ("c",c);
symbol_table1.add_variable ("d",d);
symbol_table1.add_stringvar("e",e);
symbol_table1.add_constants( );
expression.register_symbol_table(symbol_table0);
expression.register_symbol_table(symbol_table1);
}
}
{
std::string expression_list[] =
{

View File

@ -1,11 +1,42 @@
C++ Mathematical Expression Toolkit Library
C++ Mathematical Expression Toolkit Library Documentation
Section 00 - Introduction
Section 01 - Capabilities
Section 02 - Example Expressions
Section 03 - Copyright Notice
Section 04 - Downloads & Updates
Section 05 - Installation
Section 06 - Compilation
Section 07 - Compiler Compatibility
Section 08 - Built-In Operations & Functions
Section 09 - Fundamental Types
Section 10 - Components
Section 11 - Compilation Options
Section 12 - Special Functions
Section 13 - Variable, Vector & String Definition
Section 14 - Vector Processing
Section 15 - User Defined Functions
Section 16 - Expression Dependents
Section 17 - Hierarchies Of Symbol Tables
Section 18 - Unknown Unknowns
Section 19 - Enabling & Disabling Features
Section 20 - Expression Return Values
Section 21 - Compilation Errors
Section 22 - Runtime Library Packages
Section 23 - Helpers & Utils
Section 24 - Exprtk Notes
Section 25 - Simple Exprtk Example
Section 26 - Build Options
Section 27 - Files
Section 28 - Language Structure
[00 - INTRODUCTION]
The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple
to use, easy to integrate and extremely efficient run-time
mathematical expression parsing and evaluation engine. The parsing
engine supports numerous forms of functional and logic processing
semantics and is easily extendible.
semantics and is easily extensible.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -116,7 +147,7 @@ include path (e.g: /usr/include/).
ExprTk has been built error and warning free using the following set
of C++ compilers:
(*) GNU Compiler Collection (3.3+)
(*) GNU Compiler Collection (3.5+)
(*) Intel C++ Compiler (8.x+)
(*) Clang/LLVM (1.1+)
(*) PGI C++ (10.x+)
@ -608,7 +639,7 @@ appropriate may represent any of one the following:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[09 - Fundamental Types]
[09 - FUNDAMENTAL TYPES]
ExprTk supports three fundamental types which can be used freely in
expressions. The types are as follows:
@ -719,7 +750,9 @@ Note: It is possible to register multiple symbol_tables with a single
expression object. In the event an expression has multiple symbol
tables, and where there exists conflicts between symbols, the
compilation stage will resolve the conflicts based on the order of
registration of the symbol_tables to the expression.
registration of the symbol_tables to the expression. For a more
expansive discussion please review section [17 - Hierarchies Of
Symbol Tables]
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
@ -1144,7 +1177,7 @@ correctly optimize such expressions for a given architecture.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[13 - VARIABLE , VECTOR & STRING DEFINITION]
[13 - VARIABLE, VECTOR & STRING DEFINITION]
ExprTk supports the definition of expression local variables, vectors
and strings. The definitions must be unique as shadowing is not
allowed and object life-times are based on scope. Definitions use the
@ -1964,7 +1997,7 @@ carried out:
Note: For the igeneric_function type, there also needs to be a 'Z'
parameter sequence defined inorder for the zero parameter trait to
parameter sequence defined in order for the zero parameter trait to
properly take effect otherwise a compilation error will occur.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -2115,7 +2148,410 @@ will not contain symbols denoting functions.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[17 - ENABLING AND DISABLING FEATURES]
[17 - HIERARCHIES OF SYMBOL TABLES]
Most situations will only require a single symbol_table instance to be
associated with a given expression instance.
However as an expression can have more than one symbol table instance
associated with itself, when building more complex systems that
utilize many expressions where each can in turn utilize one or more
variables from a large set of potential variables, functions or
constants, it becomes evident that grouping variables into layers of
symbol_tables will simplify and streamline the overall process.
A suggested hierarchy of symbol tables is as follows:
(a) Global constant value symbol table
(b) Global non side-effect functions symbol table
(c) Global variable symbol table
(d) Expression specific variable symbol table
(a) Global constant value symbol table
This symbol table will contain constant variables denoting immutable
values. These variables can be made available to all expressions, and
in turn expressions will assume the values themselves will never be
modified for the duration of the process run-time. Examples of such
variables are:
(1) pi or e
(2) speed_of_light
(3) avogadro_number
(4) num_cpus
(b) Global non side-effect functions symbol table
This symbol table will contain only user defined functions that will
not incur any side-effects that are visible to any of the expressions
that invoke them. These functions will be thread-safe or threading
invariant and will not maintain any form of state between invocations.
Examples of such functions are:
(1) calc_volume_of_sphere(r)
(2) distance(x0,y0,x1,y1)
(c) Global variable symbol table
This symbol table will contain variables that will be accessible to
all associated expressions and will not be specific to exclusive to
any one expression. This variant differs from (a) in that the values
of the variables can change (or be updated) between evaluations of
expressions - but through properly scheduled evaluations are
guaranteed to never change during the evaluation of any dependent
expressions. Furthermore it is assumed that these variables will be
used in a read-only context and that no expressions will attempt to
modify these variables via assignments or other means.
(1) price_of_stock_xyz
(2) outside_temperature or inside_temperature
(3) fuel_in_tank
(4) num_customers_in_store
(5) num_items_on_shelf
(d) Expression specific variable symbol table
This symbol_table is the most common form, and is used to store
variables that are specific and exclusive to a particular expression.
That is to say references to variables in this symbol_table will not
be part of another expression. Though it may be possible to have
expressions that contain the variables with the same name, in that
case those variables will be distinct different. Which would mean if a
particular expression were to be compiled twice, that each expression
would have it's own unique symbol_table which in turn would have it's
own instances of those variables. Examples of such variables could be:
(1) x or y
(2) customer_name
The following is a diagram depicting the possible version of the
denoted symbol table hierarchies. In the diagram there are two unique
expressions, each of which have a reference to the Global constant,
functions and variables symbol tables and an exclusive reference to a
local symbol table.
+-------------------------+ +-------------------------+
| Global Constants | | Global Functions |
| Symbol Table | | Symbol Table |
+----o--o-----------------+ +--------------------o----+
| | |
| | +-------+
| +------------------->----------------------------+ |
| +----------------------------+ | |
| | Global Variables | | |
| +------o Symbol Table o-----+ | V
| | +----------------------------+ | | |
| | | | |
| | +----------------+ +----------------+ | | |
| | | Symbol Table 0 | | Symbol Table 1 | | V |
| | +--o-------------+ +--o-------------+ | | |
| | | | | | |
| | | | | | |
+--V--V----V---------+ +-V---------------V--+ | |
| Expression 0 | | Expression 1 |<--+--+
| '2 * sin(x) - y' | | 'k + abs(x - y)' |
+--------------------+ +--------------------+
Bringing all of the above together, in the following example the
hierarchy of symbol tables are instantiated and initialised. An
expression that makes use of various elements of each symbol table is
then compiled and later on evaluated:
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
// Setup global constants symbol table
symbol_table_t glbl_const_symbol_table;
glbl_const_symbtab.add_constants(); // pi, epsilon and inf
glbl_const_symbtab.add_constant("speed_of_light",299e6);
glbl_const_symbtab.add_constant("avogadro_number",6e23);
// Setup global function symbol table
symbol_table_t glbl_funcs_symbol_table;
glbl_func_symbtab.add_function('distance',distance);
glbl_func_symbtab.add_function('calc_spherevol',calc_sphrvol);
......
// Setup global variable symbol table
symbol_table_t glbl_variable_symbol_table;
glbl_variable_symbtab.add_variable('temp_outside',thermo.outside);
glbl_variable_symbtab.add_variable('temp_inside' ,thermo.inside );
glbl_variable_symbtab.add_variable('num_cstmrs',store.num_cstmrs);
......
double x,y,z;
// Setup expression specific symbol table
symbol_table_t symbol_table;
symbol_table.add_variable('x',x);
symbol_table.add_variable('y',y);
symbol_table.add_variable('z',z);
expression_t expression;
// Register the various symbol tables
expression
.register_symbol_table(symbol_table);
expression
.register_symbol_table(glbl_funcs_symbol_table);
expression
.register_symbol_table(glbl_const_symbol_table);
expression
.register_symbol_table(glbl_variable_symbol_table);
std::string expression_str =
"abs(temp_inside - temp_outside) + 2 * speed_of_light / x";
parser_t parser;
parser.compile(expression_str,expression);
......
while (keep_evaluating)
{
....
T result = expression.value();
....
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[18 - UNKNOWN UNKNOWNS]
In this section we will discuss the process of handling expressions
with a mix of known and unknown variables. Initially a discussion into
the types of expressions that exist will be provided, then a series of
possible solutions will be presented for each scenario.
When parsing an expression, there may be situations where one is not
fully aware of what if any variables will be used prior to the
expression being compiled.
This can become problematic, as in the default scenario it is assumed
the symbol_table that is registered with the expression instance will
already posses the externally available variables, functions and
constants needed during the compilation of the expression.
In the event there are symbols in the expression that can't be mapped
to either a reserved word, or located in the associated
symbol_table(s), an "Undefined symbol" error will be raised and the
compilation process will fail.
The numerous scenarios that can occur when compiling an expression
with ExprTk generally fall into one of the following three categories:
(a) No external variables
(b) Predetermined set of external variables
(c) Unknown set of variables
(a) No external variables
These are expressions that contain no external variables but may
contain local variables. As local variables cannot be accessed
externally from the expression, it is assumed that such expressions
will not have a need for a symbol_table and furthermore expressions
which don't make use of functions that have side-effects will be
evaluated completely at compile time resulting in a constant return
value. The following are examples of such expressions:
(1) 1 + 2
(2) var x := 3; 2 * x - 3
(3) var x := 3; var y := abs(x - 8); x - y / 7
(b) Predetermined set of external variables
These are expressions that are comprised of externally available
variables and functions and will only compile successfully if the
symbols that correspond to the variables and functions are already
defined in their associated symbol_table(s). This is by far the most
common scenario when using ExprTk.
As an example, one may have three external variables: x, y and z which
have been registered with the associated symbol_table, and will then
need to compile and evaluate expressions comprised of any subset of
these three variables. The following are a few examples of such
expressions:
(1) 1 + x
(2) x / y
(3) 2 * x * y / z
In this scenario one can use the 'dependent_entity_collector'
component as described in [Section 16] to further determine which of
the registered variables were actually used in the given expression.
As an example once the set of utilized variables are known, any
further 'attention' can be restricted to only those variables when
evaluating the expression. This can be quite useful when dealing with
expressions that can draw from a set of hundreds or even thousands of
variables.
(c) Unknown set of variables
These are expressions that are comprised of symbols other than the
standard ExprTk reserved words or what has been registered with their
associated symbol_table, and will normally fail compilation due to the
associated symbol_table not having a reference to them. As such this
scenario can be seen as a combination of scenario B, where one may
have a symbol_table with registered variables, but would also like to
handle the situation of variables that aren't present in said
symbol_table.
When dealing with expressions of category (c), one must perform all of
the following:
(1) Determine the variables used in the expression
(2) Populate a symbol_table(s) with the entities from (1)
(3) Compile the expression
(4) Provide a means by which the entities from (1) can be modified
Depending on the nature of processing, steps (1) and (2) can be done
either independently of each other or combined into one. The following
example will initially look at solving the problem of unknown
variables with the latter method using the 'unknown_symbol_resolver'
component.
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
symbol_table_t unknown_var_symbol_table;
symbol_table_t symbol_table;
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);
expression_t expression;
expression.register_symbol_table(unknown_var_symbol_table);
expression.register_symbol_table(symbol_table);
parser_t parser;
parser.enable_unknown_symbol_resolver();
std::string expression_str = "x + abs(y / 3k) * z + 2";
parser.compile(expression_str,expression);
In the example above, the symbols 'k' and 'z' will be treated as
unknown symbols. The parser in the example is set to handle unknown
symbols using the built-in default unknown_symbol_resolver (USR). The
default USR will automatically resolve any unknown symbols as a
variable (scalar type). The new variables will be added to the primary
symbol_table, which in this case is the 'unknown_var_symbol_table'
instance. Once the compilation has completed successfully, the
variables that were resolved during compilation can be accessed from
the primary symbol_table using the 'get_variable_list' and
'variable_ref' methods and then if needed can be modified accordingly
after which the expression itself can be evaluated.
std::vector<std::string> variable_list;
unknown_var_symbol_table.get_variable_list(variable_list);
for (auto& var_name : variable_list)
{
T& v = symbol_table.variable_ref(var_name);
v = ...;
}
...
expression.value();
Note: As previously mentioned the default USR will automatically
assume any unknown symbol to be a valid scalar variable, and will then
proceed to add said symbol as a variable to the primary symbol_table
of the associated expression during the compilation process. However a
problem that may arise, is that expressions that are parsed with the
USR enabled, but contain 'typos' or otherwise syntactic errors may
inadvertently compile successfully due to the simplistic nature of the
default USR. The following are some example expressions:
(1) 1 + abz(x + 1)
(2) sine(y / 2) - coz(3x)
The two expression above contain misspelt symbols (abz, sine, coz)
which if implied multiplications and default USR are enabled during
compilation will result in them being assumed to be valid 'variables',
which obviously is not the intended outcome by the user. A possible
solution to this problem is for one to implement their own specific
USR that will perform a user defined business logic in determining if
an encountered unknown symbol should be treated as a variable or if it
should raise a compilation error. The following example demonstrated a
simple user defined USR:
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t;
template <typename T>
struct my_usr : public parser_t::unknown_symbol_resolver
{
typedef typename parser_t::unknown_symbol_resolver usr_t;
bool process(const std::string& unknown_symbol,
typename usr_t::usr_symbol_type& st,
T& default_value,
std::string& error_message)
{
if (0 != unknown_symbol.find('var_'))
{
error_message = "Invalid symbol: " + unknown_symbol;
return false;
}
st = usr_t::e_usr_variable_type;
default_value = T(123.123);
return true;
}
};
...
symbol_table_t unknown_var_symbol_table;
symbol_table_t symbol_table;
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);
expression_t expression;
expression.register_symbol_table(unknown_var_symbol_table);
expression.register_symbol_table(symbol_table);
my_usr<T> musr;
parser_t parser;
parser.enable_unknown_symbol_resolver(&musr);
std::string expression_str = "var_x + abs(var_y - 3) * var_z";
parser.compile(expression_str,expression);
In the example above, a user specified USR is defined, and is
registered with the parser enabling the USR functionality. The when an
unknown symbol is encountered during the compilation process, the
USR's process method will be invoked. The USR in the example will only
'accept' unknown symbols that have a prefix of 'var_' as being valid
variables, all other unknown symbols will result in a compilation
error being raised.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[19 - ENABLING & DISABLING FEATURES]
The parser can be configured via its settings instance to either allow
or disallow certain features that are available within the ExprTk
grammar. The features fall into one of the following six categories:
@ -2438,9 +2874,7 @@ redefined as a function taking degree input.
}
};
.
.
.
...
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::expression<T> expression_t;
@ -2473,7 +2907,7 @@ ExprTk reserved words, the add_function call will fail.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[18 - EXPRESSION RETURN VALUES]
[20 - EXPRESSION RETURN VALUES]
ExprTk expressions can return immediately from any point by utilizing
the return call. Furthermore the return call can be used to transfer
out multiple return values from within the expression.
@ -2550,7 +2984,7 @@ generic function call parameters.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[19 - COMPILATION ERRORS]
[21 - COMPILATION ERRORS]
When attempting to compile a malformed or otherwise erroneous ExprTk
expression, the compilation process will result in an error, as is
indicated by the 'compile' method returning a false value. A
@ -2670,7 +3104,7 @@ via the 'unknown symbol resolver' mechanism.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[20 - RUNTIME LIBRARY PACKAGES]
[22 - RUNTIME LIBRARY PACKAGES]
ExprTk contains a set of simple extensions, that provide
functionalities beyond basic numerical calculations. Currently the
available packages are:
@ -2745,7 +3179,266 @@ file I/O package is made available for the given expression:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[21 - EXPRTK NOTES]
[23 - HELPERS & UTILS]
The ExprTk library provides a series of usage simplifications via
helper routines that combine various processes into a single 'function
call' making certain actions easier to carry out though not
necessarily in the most efficient way possible. A list of the routines
are as follows:
(a) collect_variables
(b) collect_functions
(c) compute
(d) integrate
(e) derivative
(f) second_derivative
(g) third_derivative
(a) collect_variables
This function will collect all the variable symbols in a given string
representation of an expression and return them in an STL compatible
sequence data structure (eg: std::vector, dequeue etc) specialised
upon a std::string type. An example use of the routine is as follows:
std::string expression = "x + abs(y / z)";
std::vector<std::string> variable_list;
exprtk::collect_variables(expression,variable_list);
for (auto var : variable_list)
{
...
}
(b) collect_functions
This function will collect all the function symbols in a given string
representation of an expression and return them in an STL compatible
sequence data structure (eg: std::vector, dequeue etc) specialised
upon a std::string type. An example use of the routine is as follows:
std::string expression = "x + abs(y / cos(1 + z))";
std::deque<std::string> variable_list;
exprtk::collect_functions(expression,function_list);
for (auto func : function_list)
{
...
}
(c) compute
This free function will compute the value of an expression from its
string form. If an invalid expression is passed, the result of the
function will be false indicating an error, otherwise the return value
will be true indicating success. The compute function has three
overloads, the definitions of which are:
(1) No variables
(2) One variable called x
(3) Two variable called x and y
(3) Three variable called x, y and z
An example use of each of the three overloads for the compute routine
is as follows:
T result = T(0);
// No variables overload
std::string no_vars = "abs(1 - (3 / pi)) * 5";
if (!exprtk::compute(no_vars,result))
printf("Failed to compute: %s",no_vars.c_str());
else
printf("Result: %15.5f\n",result);
// One variable 'x' overload
T x = 123.456;
std::string one_var = "abs(x - (3 / pi)) * 5";
if (!exprtk::compute(one_var, x, result))
printf("Failed to compute: %s",one_var.c_str());
else
printf("Result: %15.5f\n",result);
// Two variables 'x' and 'y' overload
T y = 789.012;
std::string two_var = "abs(x - (y / pi)) * 5";
if (!exprtk::compute(two_var, x, y, result))
printf("Failed to compute: %s",two_var.c_str());
else
printf("Result: %15.5f\n",result);
// Three variables 'x', 'y' and 'z' overload
T z = 345.678;
std::string three_var = "abs(x - (y / pi)) * z";
if (!exprtk::compute(three_var, x, y, z, result))
printf("Failed to compute: %s",three_var.c_str());
else
printf("Result: %15.5f\n",result);
(d) integrate
This free function will attempt to perform a numerical integration of
a single variable compiled expression over a defined range and given
step size. The numerical integration is based on the three point form
of the Simpson's rule. The integrate function has two overloads, where
the variable of integration can either be passed as a reference or as
a name in string form. Example usage of the function is as follows:
typedef exprtk::parser<T> parser_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::symbol_table<T> symbol_table_t;
std::string expression_string = "sqrt(1 - (x^2))";
T x = T(0);
symbol_table_t symbol_table;
symbol_table.add_variable("x",x);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
parser.compile(expression_string,expression);
....
// Integrate in domain [-1,1] using a reference to x variable
T area1 = exprtk::integrate(expression, x, T(-1), T(1));
// Integrate in domain [-1,1] using name of x variable
T area2 = exprtk::integrate(expression, "x", T(-1), T(1));
(e) derivative
This free function will attempt to perform a numerical differentiation
of a single variable compiled expression at a given point for a given
epsilon, using a variant of Newton's difference quotient called the
five-point stencil method. The derivative function has two overloads,
where the variable of differentiation can either be passed as a
reference or as a name in string form. A example usage of the function
is as follows:
typedef exprtk::parser<T> parser_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::symbol_table<T> symbol_table_t;
std::string expression_string = "sqrt(1 - (x^2))";
T x = T(0);
symbol_table_t symbol_table;
symbol_table.add_variable("x",x);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
parser.compile(expression_string,expression);
....
// Differentiate expression where value of x = 12.3 using a reference
// to x variable
x = T(12.3);
T derivative1 = exprtk::derivative(expression,x);
// Differentiate expression where value x = 45.6 using name
// of x variable
x = T(45.6);
T derivative2 = exprtk::derivative(expression, "x");
(f) second_derivative
This free function will attempt to perform a numerical second
derivative of a single variable compiled expression at a given point
for a given epsilon, using a variant of Newton's difference quotient
method. The second_derivative function has two overloads, where the
variable of differentiation can either be passed as a reference or as
a name in string form. Example usage of the function is as follows:
typedef exprtk::parser<T> parser_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::symbol_table<T> symbol_table_t;
std::string expression_string = "sqrt(1 - (x^2))";
T x = T(0);
symbol_table_t symbol_table;
symbol_table.add_variable("x",x);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
parser.compile(expression_string,expression);
....
// Second derivative of expression where value of x = 12.3 using a
// reference to x variable
x = T(12.3);
T derivative1 = exprtk::second_derivative(expression,x);
// Second derivative of expression where value of x = 45.6 using
// name of x variable
x = T(45.6);
T derivative2 = exprtk::second_derivative(expression, "x");
(g) third_derivative
This free function will attempt to perform a numerical third
derivative of a single variable compiled expression at a given point
for a given epsilon, using a variant of Newton's difference quotient
method. The third_derivative function has two overloads, where the
variable of differentiation can either be passed as a reference or as
a name in string form. Example usage of the function is as follows:
typedef exprtk::parser<T> parser_t;
typedef exprtk::expression<T> expression_t;
typedef exprtk::symbol_table<T> symbol_table_t;
std::string expression_string = "sqrt(1 - (x^2))";
T x = T(0);
symbol_table_t symbol_table;
symbol_table.add_variable("x",x);
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
parser.compile(expression_string,expression);
....
// Third derivative of expression where value of x = 12.3 using a
// reference to x variable
x = T(12.3);
T derivative1 = exprtk::third_derivative(expression,x);
// Third derivative of expression where value of x = 45.6 using
// name of x variable
x = T(45.6);
T derivative2 = exprtk::third_derivative(expression, "x");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[24 - EXPRTK NOTES]
The following is a list of facts and suggestions one may want to take
into account when using ExprTk:
@ -2946,7 +3639,7 @@ into account when using ExprTk:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[22 - SIMPLE EXPRTK EXAMPLE]
[25 - SIMPLE EXPRTK EXAMPLE]
The following is a simple yet complete example demonstrating typical
usage of the ExprTk Library. The example instantiates a symbol table
object, adding to it three variables named x, y and z, and a custom
@ -3051,7 +3744,7 @@ int main()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[23 - BUILD OPTIONS]
[26 - BUILD OPTIONS]
When building ExprTk there are a number of defines that will enable or
disable certain features and capabilities. The defines can either be
part of a compiler command line switch or scoped around the include to
@ -3118,7 +3811,7 @@ error.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[24 - FILES]
[27 - FILES]
The source distribution of ExprTk is comprised of the following set of
files:
@ -3149,7 +3842,7 @@ files:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[25 - LANGUAGE STRUCTURE]
[28 - LANGUAGE STRUCTURE]
+-------------------------------------------------------------+
|00 - If Statement |
| |