C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html
This commit is contained in:
parent
b8e8b9502b
commit
187456164e
328
exprtk.hpp
328
exprtk.hpp
|
@ -57,7 +57,7 @@
|
||||||
|
|
||||||
namespace exprtk
|
namespace exprtk
|
||||||
{
|
{
|
||||||
#if exprtk_enable_debugging
|
#ifdef exprtk_enable_debugging
|
||||||
#define exprtk_debug(params) printf params
|
#define exprtk_debug(params) printf params
|
||||||
#else
|
#else
|
||||||
#define exprtk_debug(params) (void)0
|
#define exprtk_debug(params) (void)0
|
||||||
|
@ -678,16 +678,16 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
namespace constant
|
namespace constant
|
||||||
{
|
{
|
||||||
static const double e = 2.718281828459045235360;
|
static const double e = 2.71828182845904523536028747135266249775724709369996;
|
||||||
static const double pi = 3.141592653589793238462;
|
static const double pi = 3.14159265358979323846264338327950288419716939937510;
|
||||||
static const double pi_2 = 1.570796326794896619231;
|
static const double pi_2 = 1.57079632679489661923132169163975144209858469968755;
|
||||||
static const double pi_4 = 0.785398163397448309616;
|
static const double pi_4 = 0.78539816339744830961566084581987572104929234984378;
|
||||||
static const double pi_180 = 0.017453292519943295769;
|
static const double pi_180 = 0.01745329251994329576923690768488612713442871888542;
|
||||||
static const double _1_pi = 0.318309886183790671538;
|
static const double _1_pi = 0.31830988618379067153776752674502872406891929148091;
|
||||||
static const double _2_pi = 0.636619772367581343076;
|
static const double _2_pi = 0.63661977236758134307553505349005744813783858296183;
|
||||||
static const double _180_pi = 57.295779513082320876798;
|
static const double _180_pi = 57.29577951308232087679815481410517033240547246656443;
|
||||||
static const double log2 = 0.693147180559945309417;
|
static const double log2 = 0.69314718055994530941723212145817656807550013436026;
|
||||||
static const double sqrt2 = 1.414213562373095048801;
|
static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace details
|
namespace details
|
||||||
|
@ -1760,7 +1760,7 @@ namespace exprtk
|
||||||
if (curr != itr)
|
if (curr != itr)
|
||||||
{
|
{
|
||||||
instate = true;
|
instate = true;
|
||||||
d += compute_pow10(tmp_d,-std::distance(curr,itr));
|
d += compute_pow10(tmp_d,static_cast<int>(-std::distance(curr,itr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef parse_digit_1
|
#undef parse_digit_1
|
||||||
|
@ -6733,9 +6733,9 @@ namespace exprtk
|
||||||
std::string stringvar_node<T>::null_value = std::string("");
|
std::string stringvar_node<T>::null_value = std::string("");
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class string_range_node : public expression_node <T>,
|
class string_range_node : public expression_node <T>,
|
||||||
public string_base_node<T>,
|
public string_base_node<T>,
|
||||||
public range_interface <T>
|
public range_interface <T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -11600,7 +11600,7 @@ namespace exprtk
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~boc_base_node()
|
virtual ~boc_base_node()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
inline virtual operator_type operation() const
|
inline virtual operator_type operation() const
|
||||||
{
|
{
|
||||||
|
@ -13554,6 +13554,43 @@ namespace exprtk
|
||||||
const T& v_;
|
const T& v_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, typename PowOp>
|
||||||
|
class bipow_node : public expression_node<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef expression_node<T>* expression_ptr;
|
||||||
|
typedef std::pair<expression_ptr, bool> branch_t;
|
||||||
|
typedef PowOp operation_t;
|
||||||
|
|
||||||
|
explicit bipow_node(expression_ptr brnch)
|
||||||
|
{
|
||||||
|
init_branches<1>(branch_, brnch);
|
||||||
|
}
|
||||||
|
|
||||||
|
~bipow_node()
|
||||||
|
{
|
||||||
|
cleanup_branches::execute<T,1>(branch_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T value() const
|
||||||
|
{
|
||||||
|
return PowOp::result(branch_[0].first->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline typename expression_node<T>::node_type type() const
|
||||||
|
{
|
||||||
|
return expression_node<T>::e_ipow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bipow_node(const bipow_node<T,PowOp>&);
|
||||||
|
bipow_node<T,PowOp>& operator=(const bipow_node<T,PowOp>&);
|
||||||
|
|
||||||
|
branch_t branch_[1];
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, typename PowOp>
|
template <typename T, typename PowOp>
|
||||||
class ipowinv_node : public expression_node<T>
|
class ipowinv_node : public expression_node<T>
|
||||||
{
|
{
|
||||||
|
@ -13584,6 +13621,43 @@ namespace exprtk
|
||||||
const T& v_;
|
const T& v_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, typename PowOp>
|
||||||
|
class bipowninv_node : public expression_node<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef expression_node<T>* expression_ptr;
|
||||||
|
typedef std::pair<expression_ptr, bool> branch_t;
|
||||||
|
typedef PowOp operation_t;
|
||||||
|
|
||||||
|
explicit bipowninv_node(expression_ptr brnch)
|
||||||
|
{
|
||||||
|
init_branches<1>(branch_, brnch);
|
||||||
|
}
|
||||||
|
|
||||||
|
~bipowninv_node()
|
||||||
|
{
|
||||||
|
cleanup_branches::execute<T,1>(branch_);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline T value() const
|
||||||
|
{
|
||||||
|
return (T(1) / PowOp::result(branch_[0].first->value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline typename expression_node<T>::node_type type() const
|
||||||
|
{
|
||||||
|
return expression_node<T>::e_ipowinv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bipowninv_node(const bipowninv_node<T,PowOp>&);
|
||||||
|
bipowninv_node<T,PowOp>& operator=(const bipowninv_node<T,PowOp>&);
|
||||||
|
|
||||||
|
branch_t branch_[1];
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline bool is_vov_node(const expression_node<T>* node)
|
inline bool is_vov_node(const expression_node<T>* node)
|
||||||
{
|
{
|
||||||
|
@ -17139,7 +17213,7 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
st = e_usr_variable_type;
|
st = e_usr_variable_type;
|
||||||
default_value = T(0);
|
default_value = T(0);
|
||||||
error_message = "";
|
error_message.clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -17698,7 +17772,7 @@ namespace exprtk
|
||||||
settings_store& disable_inequality_operation(settings_inequality_opr inequality)
|
settings_store& disable_inequality_operation(settings_inequality_opr inequality)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(e_assign_unknown != inequality) &&
|
(e_ineq_unknown != inequality) &&
|
||||||
(static_cast<std::size_t>(inequality) < details::inequality_ops_list_size)
|
(static_cast<std::size_t>(inequality) < details::inequality_ops_list_size)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -20039,7 +20113,7 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can we optimize away the case statement?
|
// Can we optimise away the case statement?
|
||||||
if (is_constant_node(condition) && is_false(condition))
|
if (is_constant_node(condition) && is_false(condition))
|
||||||
{
|
{
|
||||||
free_node(node_allocator_, condition);
|
free_node(node_allocator_, condition);
|
||||||
|
@ -20183,7 +20257,7 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can we optimize away the case statement?
|
// Can we optimise away the case statement?
|
||||||
if (is_constant_node(condition) && is_false(condition))
|
if (is_constant_node(condition) && is_false(condition))
|
||||||
{
|
{
|
||||||
free_node(node_allocator_, condition);
|
free_node(node_allocator_, condition);
|
||||||
|
@ -23259,7 +23333,7 @@ namespace exprtk
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline bool unary_optimizable(const details::operator_type& operation) const
|
inline bool unary_optimisable(const details::operator_type& operation) const
|
||||||
{
|
{
|
||||||
return (details::e_abs == operation) || (details::e_acos == operation) ||
|
return (details::e_abs == operation) || (details::e_acos == operation) ||
|
||||||
(details::e_acosh == operation) || (details::e_asin == operation) ||
|
(details::e_acosh == operation) || (details::e_asin == operation) ||
|
||||||
|
@ -23283,7 +23357,7 @@ namespace exprtk
|
||||||
(details::e_frac == operation) || (details::e_trunc == operation);
|
(details::e_frac == operation) || (details::e_trunc == operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool sf3_optimizable(const std::string& sf3id, trinary_functor_t& tfunc)
|
inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc)
|
||||||
{
|
{
|
||||||
typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
|
typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
|
||||||
|
|
||||||
|
@ -23295,7 +23369,7 @@ namespace exprtk
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool sf4_optimizable(const std::string& sf4id, quaternary_functor_t& qfunc)
|
inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc)
|
||||||
{
|
{
|
||||||
typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
|
typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
|
||||||
|
|
||||||
|
@ -23307,7 +23381,7 @@ namespace exprtk
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool sf3_optimizable(const std::string& sf3id, details::operator_type& operation)
|
inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation)
|
||||||
{
|
{
|
||||||
typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
|
typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
|
||||||
|
|
||||||
|
@ -23319,7 +23393,7 @@ namespace exprtk
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool sf4_optimizable(const std::string& sf4id, details::operator_type& operation)
|
inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation)
|
||||||
{
|
{
|
||||||
typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
|
typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
|
||||||
|
|
||||||
|
@ -23343,9 +23417,9 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
else if (details::is_constant_node(branch[0]))
|
else if (details::is_constant_node(branch[0]))
|
||||||
return synthesize_expression<unary_node_t,1>(operation,branch);
|
return synthesize_expression<unary_node_t,1>(operation,branch);
|
||||||
else if (unary_optimizable(operation) && details::is_variable_node(branch[0]))
|
else if (unary_optimisable(operation) && details::is_variable_node(branch[0]))
|
||||||
return synthesize_uv_expression(operation,branch);
|
return synthesize_uv_expression(operation,branch);
|
||||||
else if (unary_optimizable(operation) && details::is_ivector_node(branch[0]))
|
else if (unary_optimisable(operation) && details::is_ivector_node(branch[0]))
|
||||||
return synthesize_uvec_expression(operation,branch);
|
return synthesize_uvec_expression(operation,branch);
|
||||||
else
|
else
|
||||||
return synthesize_unary_expression(operation,branch);
|
return synthesize_unary_expression(operation,branch);
|
||||||
|
@ -23413,7 +23487,7 @@ namespace exprtk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operation_optimizable(const details::operator_type& operation) const
|
inline bool operation_optimisable(const details::operator_type& operation) const
|
||||||
{
|
{
|
||||||
return (details::e_add == operation) ||
|
return (details::e_add == operation) ||
|
||||||
(details::e_sub == operation) ||
|
(details::e_sub == operation) ||
|
||||||
|
@ -23481,47 +23555,47 @@ namespace exprtk
|
||||||
return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]);
|
return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool cov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1]));
|
return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool voc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1]));
|
return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool vov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]));
|
return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool cob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1]));
|
return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool boc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1]));
|
return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool cocob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(details::e_add == operation) ||
|
(details::e_add == operation) ||
|
||||||
|
@ -23537,7 +23611,7 @@ namespace exprtk
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool coboc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(details::e_add == operation) ||
|
(details::e_add == operation) ||
|
||||||
|
@ -23553,33 +23627,33 @@ namespace exprtk
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool uvouv_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1]));
|
return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool vob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1]));
|
return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool bov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]));
|
return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool binext_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
||||||
{
|
{
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1]));
|
return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1]));
|
||||||
|
@ -23605,6 +23679,22 @@ namespace exprtk
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2])
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
!is_constant_node(branch[1]) ||
|
||||||
|
is_constant_node(branch[0]) ||
|
||||||
|
is_variable_node(branch[0]) ||
|
||||||
|
is_vector_node (branch[0]) ||
|
||||||
|
is_generally_string_node(branch[0])
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value();
|
||||||
|
|
||||||
|
return cardinal_pow_optimisable(operation, c);
|
||||||
|
}
|
||||||
|
|
||||||
inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2])
|
inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2])
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
|
@ -23750,7 +23840,11 @@ namespace exprtk
|
||||||
else if (is_string_operation(operation,branch))
|
else if (is_string_operation(operation,branch))
|
||||||
return synthesize_string_expression(operation,branch);
|
return synthesize_string_expression(operation,branch);
|
||||||
else if (is_null_present(branch))
|
else if (is_null_present(branch))
|
||||||
return synthesize_null_expression(operation,branch);
|
return synthesize_null_expression(operation, branch);
|
||||||
|
#ifndef exprtk_disable_cardinal_pow_optimisation
|
||||||
|
else if (is_constpow_operation(operation, branch))
|
||||||
|
return cardinal_pow_optimisation(branch);
|
||||||
|
#endif
|
||||||
|
|
||||||
expression_node_ptr result = error_node();
|
expression_node_ptr result = error_node();
|
||||||
|
|
||||||
|
@ -23770,30 +23864,30 @@ namespace exprtk
|
||||||
*/
|
*/
|
||||||
result = error_node();
|
result = error_node();
|
||||||
|
|
||||||
if (cocob_optimizable(operation,branch))
|
if (cocob_optimisable(operation,branch))
|
||||||
result = synthesize_cocob_expression::process(*this,operation,branch);
|
result = synthesize_cocob_expression::process(*this,operation,branch);
|
||||||
else if (coboc_optimizable(operation,branch) && (0 == result))
|
else if (coboc_optimisable(operation,branch) && (0 == result))
|
||||||
result = synthesize_coboc_expression::process(*this,operation,branch);
|
result = synthesize_coboc_expression::process(*this,operation,branch);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uvouv_optimizable(operation,branch))
|
if (uvouv_optimisable(operation,branch))
|
||||||
return synthesize_uvouv_expression(operation,branch);
|
return synthesize_uvouv_expression(operation,branch);
|
||||||
else if (vob_optimizable(operation,branch))
|
else if (vob_optimisable(operation,branch))
|
||||||
return synthesize_vob_expression::process(*this,operation,branch);
|
return synthesize_vob_expression::process(*this,operation,branch);
|
||||||
else if (bov_optimizable(operation,branch))
|
else if (bov_optimisable(operation,branch))
|
||||||
return synthesize_bov_expression::process(*this,operation,branch);
|
return synthesize_bov_expression::process(*this,operation,branch);
|
||||||
else if (cob_optimizable(operation,branch))
|
else if (cob_optimisable(operation,branch))
|
||||||
return synthesize_cob_expression::process(*this,operation,branch);
|
return synthesize_cob_expression::process(*this,operation,branch);
|
||||||
else if (boc_optimizable(operation,branch))
|
else if (boc_optimisable(operation,branch))
|
||||||
return synthesize_boc_expression::process(*this,operation,branch);
|
return synthesize_boc_expression::process(*this,operation,branch);
|
||||||
#ifndef exprtk_disable_enhanced_features
|
#ifndef exprtk_disable_enhanced_features
|
||||||
else if (cov_optimizable(operation,branch))
|
else if (cov_optimisable(operation,branch))
|
||||||
return synthesize_cov_expression::process(*this,operation,branch);
|
return synthesize_cov_expression::process(*this,operation,branch);
|
||||||
#endif
|
#endif
|
||||||
else if (binext_optimizable(operation,branch))
|
else if (binext_optimisable(operation,branch))
|
||||||
return synthesize_binary_ext_expression::process(*this,operation,branch);
|
return synthesize_binary_ext_expression::process(*this,operation,branch);
|
||||||
else
|
else
|
||||||
return synthesize_expression<binary_node_t,2>(operation,branch);
|
return synthesize_expression<binary_node_t,2>(operation,branch);
|
||||||
|
@ -23853,7 +23947,7 @@ namespace exprtk
|
||||||
|
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
// Can the condition be immediately evaluated? if so optimize.
|
// Can the condition be immediately evaluated? if so optimise.
|
||||||
else if (details::is_constant_node(condition))
|
else if (details::is_constant_node(condition))
|
||||||
{
|
{
|
||||||
// True branch
|
// True branch
|
||||||
|
@ -23899,7 +23993,7 @@ namespace exprtk
|
||||||
|
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
// Can the condition be immediately evaluated? if so optimize.
|
// Can the condition be immediately evaluated? if so optimise.
|
||||||
else if (details::is_constant_node(condition))
|
else if (details::is_constant_node(condition))
|
||||||
{
|
{
|
||||||
// True branch
|
// True branch
|
||||||
|
@ -23930,9 +24024,9 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
inline expression_node_ptr conditional_string(expression_node_ptr ,
|
inline expression_node_ptr conditional_string(expression_node_ptr,
|
||||||
expression_node_ptr ,
|
expression_node_ptr,
|
||||||
expression_node_ptr ) const
|
expression_node_ptr) const
|
||||||
{
|
{
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
|
@ -24055,7 +24149,7 @@ namespace exprtk
|
||||||
|
|
||||||
template <typename Allocator,
|
template <typename Allocator,
|
||||||
template <typename,typename> class Sequence>
|
template <typename,typename> class Sequence>
|
||||||
inline expression_node_ptr const_optimize_switch(Sequence<expression_node_ptr,Allocator>& arg_list)
|
inline expression_node_ptr const_optimise_switch(Sequence<expression_node_ptr,Allocator>& arg_list)
|
||||||
{
|
{
|
||||||
expression_node_ptr result = error_node();
|
expression_node_ptr result = error_node();
|
||||||
|
|
||||||
|
@ -24091,7 +24185,7 @@ namespace exprtk
|
||||||
|
|
||||||
template <typename Allocator,
|
template <typename Allocator,
|
||||||
template <typename,typename> class Sequence>
|
template <typename,typename> class Sequence>
|
||||||
inline expression_node_ptr const_optimize_mswitch(Sequence<expression_node_ptr,Allocator>& arg_list)
|
inline expression_node_ptr const_optimise_mswitch(Sequence<expression_node_ptr,Allocator>& arg_list)
|
||||||
{
|
{
|
||||||
expression_node_ptr result = error_node();
|
expression_node_ptr result = error_node();
|
||||||
|
|
||||||
|
@ -24224,7 +24318,7 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
else if (is_constant_foldable(arg_list))
|
else if (is_constant_foldable(arg_list))
|
||||||
return const_optimize_switch(arg_list);
|
return const_optimise_switch(arg_list);
|
||||||
|
|
||||||
switch ((arg_list.size() - 1) / 2)
|
switch ((arg_list.size() - 1) / 2)
|
||||||
{
|
{
|
||||||
|
@ -24258,7 +24352,7 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
else if (is_constant_foldable(arg_list))
|
else if (is_constant_foldable(arg_list))
|
||||||
return const_optimize_mswitch(arg_list);
|
return const_optimise_mswitch(arg_list);
|
||||||
else
|
else
|
||||||
return node_allocator_->allocate<details::multi_switch_node<Type> >(arg_list);
|
return node_allocator_->allocate<details::multi_switch_node<Type> >(arg_list);
|
||||||
}
|
}
|
||||||
|
@ -24353,7 +24447,7 @@ namespace exprtk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline expression_node_ptr const_optimize_sf3(const details::operator_type& operation,
|
inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation,
|
||||||
expression_node_ptr (&branch)[3])
|
expression_node_ptr (&branch)[3])
|
||||||
{
|
{
|
||||||
expression_node_ptr temp_node = error_node();
|
expression_node_ptr temp_node = error_node();
|
||||||
|
@ -24401,7 +24495,7 @@ namespace exprtk
|
||||||
return node_allocator_->allocate<literal_node_t>(v);
|
return node_allocator_->allocate<literal_node_t>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline expression_node_ptr varnode_optimize_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3])
|
inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3])
|
||||||
{
|
{
|
||||||
typedef details::variable_node<Type>* variable_ptr;
|
typedef details::variable_node<Type>* variable_ptr;
|
||||||
|
|
||||||
|
@ -24450,9 +24544,9 @@ namespace exprtk
|
||||||
if (!all_nodes_valid(branch))
|
if (!all_nodes_valid(branch))
|
||||||
return error_node();
|
return error_node();
|
||||||
else if (is_constant_foldable(branch))
|
else if (is_constant_foldable(branch))
|
||||||
return const_optimize_sf3(operation,branch);
|
return const_optimise_sf3(operation,branch);
|
||||||
else if (all_nodes_variables(branch))
|
else if (all_nodes_variables(branch))
|
||||||
return varnode_optimize_sf3(operation,branch);
|
return varnode_optimise_sf3(operation,branch);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (operation)
|
switch (operation)
|
||||||
|
@ -24491,7 +24585,7 @@ namespace exprtk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
||||||
{
|
{
|
||||||
expression_node_ptr temp_node = error_node();
|
expression_node_ptr temp_node = error_node();
|
||||||
|
|
||||||
|
@ -24538,7 +24632,7 @@ namespace exprtk
|
||||||
return node_allocator_->allocate<literal_node_t>(v);
|
return node_allocator_->allocate<literal_node_t>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline expression_node_ptr varnode_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
||||||
{
|
{
|
||||||
typedef details::variable_node<Type>* variable_ptr;
|
typedef details::variable_node<Type>* variable_ptr;
|
||||||
|
|
||||||
|
@ -24589,9 +24683,9 @@ namespace exprtk
|
||||||
if (!all_nodes_valid(branch))
|
if (!all_nodes_valid(branch))
|
||||||
return error_node();
|
return error_node();
|
||||||
else if (is_constant_foldable(branch))
|
else if (is_constant_foldable(branch))
|
||||||
return const_optimize_sf4(operation,branch);
|
return const_optimise_sf4(operation,branch);
|
||||||
else if (all_nodes_variables(branch))
|
else if (all_nodes_variables(branch))
|
||||||
return varnode_optimize_sf4(operation,branch);
|
return varnode_optimise_sf4(operation,branch);
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
#define case_stmt(op0,op1) \
|
#define case_stmt(op0,op1) \
|
||||||
|
@ -24631,7 +24725,7 @@ namespace exprtk
|
||||||
|
|
||||||
template <typename Allocator,
|
template <typename Allocator,
|
||||||
template <typename,typename> class Sequence>
|
template <typename,typename> class Sequence>
|
||||||
inline expression_node_ptr const_optimize_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
||||||
{
|
{
|
||||||
expression_node_ptr temp_node = error_node();
|
expression_node_ptr temp_node = error_node();
|
||||||
|
|
||||||
|
@ -24674,7 +24768,7 @@ namespace exprtk
|
||||||
|
|
||||||
template <typename Allocator,
|
template <typename Allocator,
|
||||||
template <typename,typename> class Sequence>
|
template <typename,typename> class Sequence>
|
||||||
inline expression_node_ptr varnode_optimize_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
||||||
{
|
{
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
|
@ -24731,13 +24825,13 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
else if (is_constant_foldable(arg_list))
|
else if (is_constant_foldable(arg_list))
|
||||||
return const_optimize_varargfunc(operation,arg_list);
|
return const_optimise_varargfunc(operation,arg_list);
|
||||||
else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0]))
|
else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0]))
|
||||||
return vectorize_func(operation,arg_list);
|
return vectorize_func(operation,arg_list);
|
||||||
else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation))
|
else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation))
|
||||||
return arg_list[0];
|
return arg_list[0];
|
||||||
else if (all_nodes_variables(arg_list))
|
else if (all_nodes_variables(arg_list))
|
||||||
return varnode_optimize_varargfunc(operation,arg_list);
|
return varnode_optimise_varargfunc(operation,arg_list);
|
||||||
|
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
|
@ -24768,7 +24862,7 @@ namespace exprtk
|
||||||
return error_node();
|
return error_node();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Can the function call be completely optimized?
|
// Can the function call be completely optimised?
|
||||||
if (details::is_constant_node(result))
|
if (details::is_constant_node(result))
|
||||||
return result;
|
return result;
|
||||||
else if (!all_nodes_valid(b))
|
else if (!all_nodes_valid(b))
|
||||||
|
@ -25519,8 +25613,8 @@ namespace exprtk
|
||||||
case_stmt(details::e_xnor,details::xnor_op) \
|
case_stmt(details::e_xnor,details::xnor_op) \
|
||||||
|
|
||||||
#ifndef exprtk_disable_cardinal_pow_optimisation
|
#ifndef exprtk_disable_cardinal_pow_optimisation
|
||||||
template <template <typename,typename> class IPowNode>
|
template <typename TType, template <typename,typename> class IPowNode>
|
||||||
inline expression_node_ptr cardinal_pow_optimization_impl(const T& v, const unsigned int& p)
|
inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p)
|
||||||
{
|
{
|
||||||
switch (p)
|
switch (p)
|
||||||
{
|
{
|
||||||
|
@ -25548,7 +25642,7 @@ namespace exprtk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline expression_node_ptr cardinal_pow_optimization(const T& v, const T& c)
|
inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c)
|
||||||
{
|
{
|
||||||
const bool not_recipricol = (c >= T(0));
|
const bool not_recipricol = (c >= T(0));
|
||||||
const int p = details::numeric::to_int32(details::numeric::abs(c));
|
const int p = details::numeric::to_int32(details::numeric::abs(c));
|
||||||
|
@ -25563,26 +25657,50 @@ namespace exprtk
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (not_recipricol)
|
if (not_recipricol)
|
||||||
return cardinal_pow_optimization_impl<details::ipow_node>(v,p);
|
return cardinal_pow_optimisation_impl<T,details::ipow_node>(v,p);
|
||||||
else
|
else
|
||||||
return cardinal_pow_optimization_impl<details::ipowinv_node>(v,p);
|
return cardinal_pow_optimisation_impl<T,details::ipowinv_node>(v,p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool cardinal_pow_optimizable(const details::operator_type& operation, const T& c)
|
inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c)
|
||||||
{
|
{
|
||||||
return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c);
|
return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2])
|
||||||
|
{
|
||||||
|
const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value();
|
||||||
|
const bool not_recipricol = (c >= T(0));
|
||||||
|
const int p = details::numeric::to_int32(details::numeric::abs(c));
|
||||||
|
|
||||||
|
node_allocator_->free(branch[1]);
|
||||||
|
|
||||||
|
if (0 == p)
|
||||||
|
{
|
||||||
|
details::free_all_nodes(*node_allocator_, branch);
|
||||||
|
return node_allocator_->allocate_c<literal_node_t>(T(1));
|
||||||
|
}
|
||||||
|
else if (not_recipricol)
|
||||||
|
return cardinal_pow_optimisation_impl<expression_node_ptr,details::bipow_node>(branch[0],p);
|
||||||
|
else
|
||||||
|
return cardinal_pow_optimisation_impl<expression_node_ptr,details::bipowninv_node>(branch[0],p);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
inline expression_node_ptr cardinal_pow_optimization(T&, const T&)
|
inline expression_node_ptr cardinal_pow_optimisation(T&, const T&)
|
||||||
{
|
{
|
||||||
return error_node();
|
return error_node();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool cardinal_pow_optimizable(const details::operator_type&, const T&)
|
inline bool cardinal_pow_optimisable(const details::operator_type&, const T&)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2])
|
||||||
|
{
|
||||||
|
return error_node();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct synthesize_binary_ext_expression
|
struct synthesize_binary_ext_expression
|
||||||
|
@ -26092,6 +26210,18 @@ namespace exprtk
|
||||||
return bocnode;
|
return bocnode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (operation == details::e_pow)
|
||||||
|
{
|
||||||
|
// (v ^ c0) ^ c1 --> v ^(c0 * c1)
|
||||||
|
details::boc_base_node<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]);
|
||||||
|
details::operator_type boc_opr = bocnode->operation();
|
||||||
|
|
||||||
|
if (details::e_pow == boc_opr)
|
||||||
|
{
|
||||||
|
bocnode->set_c(bocnode->c() * c);
|
||||||
|
return bocnode;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef exprtk_disable_enhanced_features
|
#ifndef exprtk_disable_enhanced_features
|
||||||
|
@ -26471,7 +26601,7 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
result = error_node();
|
result = error_node();
|
||||||
|
|
||||||
if (!operation_optimizable(operation))
|
if (!operation_optimisable(operation))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const std::string node_id = branch_to_id(branch);
|
const std::string node_id = branch_to_id(branch);
|
||||||
|
@ -26557,12 +26687,12 @@ namespace exprtk
|
||||||
|
|
||||||
details::free_node(*(expr_gen.node_allocator_),branch[1]);
|
details::free_node(*(expr_gen.node_allocator_),branch[1]);
|
||||||
|
|
||||||
if (expr_gen.cardinal_pow_optimizable(operation,c))
|
if (expr_gen.cardinal_pow_optimisable(operation,c))
|
||||||
{
|
{
|
||||||
if (std::equal_to<T>()(T(1),c))
|
if (std::equal_to<T>()(T(1),c))
|
||||||
return branch[0];
|
return branch[0];
|
||||||
else
|
else
|
||||||
return expr_gen.cardinal_pow_optimization(v,c);
|
return expr_gen.cardinal_pow_optimisation(v,c);
|
||||||
}
|
}
|
||||||
else if ((T(0) == c) && (details::e_mul == operation))
|
else if ((T(0) == c) && (details::e_mul == operation))
|
||||||
return expr_gen(T(0));
|
return expr_gen(T(0));
|
||||||
|
@ -26631,7 +26761,7 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
details::operator_type sf3opr;
|
details::operator_type sf3opr;
|
||||||
|
|
||||||
if (!expr_gen.sf3_optimizable(id,sf3opr))
|
if (!expr_gen.sf3_optimisable(id,sf3opr))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
result = synthesize_sf3ext_expression::template process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2);
|
result = synthesize_sf3ext_expression::template process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2);
|
||||||
|
@ -26715,7 +26845,7 @@ namespace exprtk
|
||||||
{
|
{
|
||||||
details::operator_type sf4opr;
|
details::operator_type sf4opr;
|
||||||
|
|
||||||
if (!expr_gen.sf4_optimizable(id,sf4opr))
|
if (!expr_gen.sf4_optimisable(id,sf4opr))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
result = synthesize_sf4ext_expression::template process<T0,T1,T2,T3>(expr_gen,sf4opr,t0,t1,t2,t3);
|
result = synthesize_sf4ext_expression::template process<T0,T1,T2,T3>(expr_gen,sf4opr,t0,t1,t2,t3);
|
||||||
|
@ -27731,6 +27861,14 @@ namespace exprtk
|
||||||
return expr_gen.node_allocator_->
|
return expr_gen.node_allocator_->
|
||||||
template allocate_rc<typename details::voc_node<Type,details::div_op<Type> > >(v,c0 * c1);
|
template allocate_rc<typename details::voc_node<Type,details::div_op<Type> > >(v,c0 * c1);
|
||||||
}
|
}
|
||||||
|
// (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)
|
||||||
|
else if ((details::e_pow == o0) && (details::e_pow == o1))
|
||||||
|
{
|
||||||
|
exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n"));
|
||||||
|
|
||||||
|
return expr_gen.node_allocator_->
|
||||||
|
template allocate_rc<typename details::voc_node<Type,details::pow_op<Type> > >(v,c0 * c1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (synthesize_sf3ext_expression::template compile<vtype,ctype,ctype>(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result))
|
if (synthesize_sf3ext_expression::template compile<vtype,ctype,ctype>(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result))
|
||||||
|
@ -31508,7 +31646,7 @@ namespace exprtk
|
||||||
}
|
}
|
||||||
else if ((details::e_default != operation))
|
else if ((details::e_default != operation))
|
||||||
{
|
{
|
||||||
// Attempt simple constant folding optimization.
|
// Attempt simple constant folding optimisation.
|
||||||
expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(operation,branch);
|
expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(operation,branch);
|
||||||
|
|
||||||
if (is_constant_foldable<N>(branch))
|
if (is_constant_foldable<N>(branch))
|
||||||
|
@ -31537,7 +31675,7 @@ namespace exprtk
|
||||||
|
|
||||||
typedef typename details::function_N_node<T,ifunction_t,N> function_N_node_t;
|
typedef typename details::function_N_node<T,ifunction_t,N> function_N_node_t;
|
||||||
|
|
||||||
// Attempt simple constant folding optimization.
|
// Attempt simple constant folding optimisation.
|
||||||
|
|
||||||
expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(f);
|
expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(f);
|
||||||
function_N_node_t* func_node_ptr = dynamic_cast<function_N_node_t*>(expression_point);
|
function_N_node_t* func_node_ptr = dynamic_cast<function_N_node_t*>(expression_point);
|
||||||
|
|
|
@ -2348,8 +2348,8 @@ inline bool run_test02()
|
||||||
if (!parser.compile(test.expr, expression))
|
if (!parser.compile(test.expr, expression))
|
||||||
{
|
{
|
||||||
printf("run_test02() - Error: %s Expression: %s\n",
|
printf("run_test02() - Error: %s Expression: %s\n",
|
||||||
parser.error().c_str(),
|
parser.error().c_str(),
|
||||||
test.expr.c_str());
|
test.expr.c_str());
|
||||||
|
|
||||||
result = false;
|
result = false;
|
||||||
continue;
|
continue;
|
||||||
|
@ -2365,13 +2365,13 @@ inline bool run_test02()
|
||||||
if (not_equal(expr_result, test.result))
|
if (not_equal(expr_result, test.result))
|
||||||
{
|
{
|
||||||
printf("run_test02() - Computation Error: Expression: [%s]\tExpected: %19.15f\tResult: %19.15f\t"
|
printf("run_test02() - Computation Error: Expression: [%s]\tExpected: %19.15f\tResult: %19.15f\t"
|
||||||
"a='%s'\tb='%s'\tc='%s'\n",
|
"a='%s'\tb='%s'\tc='%s'\n",
|
||||||
test.expr.c_str(),
|
test.expr.c_str(),
|
||||||
(double)test.result,
|
(double)test.result,
|
||||||
(double)expr_result,
|
(double)expr_result,
|
||||||
str_a.c_str(),
|
str_a.c_str(),
|
||||||
str_b.c_str(),
|
str_b.c_str(),
|
||||||
str_c.c_str());
|
str_c.c_str());
|
||||||
|
|
||||||
result = false;
|
result = false;
|
||||||
continue;
|
continue;
|
||||||
|
@ -6325,11 +6325,13 @@ inline bool run_test19()
|
||||||
104683, 104693, 104701, 104707, 104711, 104717, 104723, 104729,
|
104683, 104693, 104701, 104707, 104711, 104717, 104723, 104729,
|
||||||
1000621, 1000639, 1000651, 1000667, 1000669, 1001023, 1001027, 1001041
|
1000621, 1000639, 1000651, 1000667, 1000669, 1001023, 1001027, 1001041
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::size_t prime_list_size = sizeof(prime_list) / sizeof(std::size_t);
|
const std::size_t prime_list_size = sizeof(prime_list) / sizeof(std::size_t);
|
||||||
|
|
||||||
for (std::size_t i = 0; (i < prime_list_size) && (!failure); ++i)
|
for (std::size_t i = 0; (i < prime_list_size) && (!failure); ++i)
|
||||||
{
|
{
|
||||||
x = prime_list[i];
|
x = static_cast<T>(prime_list[i]);
|
||||||
|
|
||||||
std::vector<T> result(expression_count,T(0));
|
std::vector<T> result(expression_count,T(0));
|
||||||
|
|
||||||
for (std::size_t j = 0; j < expression_list.size(); ++j)
|
for (std::size_t j = 0; j < expression_list.size(); ++j)
|
||||||
|
@ -6467,6 +6469,7 @@ inline bool run_test19()
|
||||||
"x"));
|
"x"));
|
||||||
|
|
||||||
symbol_table_t& symbol_table = compositor.symbol_table();
|
symbol_table_t& symbol_table = compositor.symbol_table();
|
||||||
|
|
||||||
symbol_table.add_constants();
|
symbol_table.add_constants();
|
||||||
symbol_table.add_variable("x",x);
|
symbol_table.add_variable("x",x);
|
||||||
|
|
||||||
|
@ -6515,11 +6518,13 @@ inline bool run_test19()
|
||||||
46368, 75025, 121393, 196418,
|
46368, 75025, 121393, 196418,
|
||||||
317811, 514229, 832040, 1346269
|
317811, 514229, 832040, 1346269
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::size_t fibonacci_list_size = sizeof(fibonacci_list) / sizeof(std::size_t);
|
const std::size_t fibonacci_list_size = sizeof(fibonacci_list) / sizeof(std::size_t);
|
||||||
|
|
||||||
for (std::size_t i = 0; (i < fibonacci_list_size) && (!failure); ++i)
|
for (std::size_t i = 0; (i < fibonacci_list_size) && (!failure); ++i)
|
||||||
{
|
{
|
||||||
x = i;
|
x = static_cast<T>(i);
|
||||||
|
|
||||||
std::vector<T> result(expression_count,T(0));
|
std::vector<T> result(expression_count,T(0));
|
||||||
|
|
||||||
for (std::size_t j = 0; j < expression_list.size(); ++j)
|
for (std::size_t j = 0; j < expression_list.size(); ++j)
|
||||||
|
@ -6629,7 +6634,8 @@ inline bool run_test19()
|
||||||
|
|
||||||
for (std::size_t i = 0; i < 100; ++i)
|
for (std::size_t i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
x = i;
|
x = static_cast<T>(i);
|
||||||
|
|
||||||
T result = expression.value();
|
T result = expression.value();
|
||||||
|
|
||||||
if (not_equal(result,std::sqrt(x),T(0.0000001)))
|
if (not_equal(result,std::sqrt(x),T(0.0000001)))
|
||||||
|
@ -6757,7 +6763,9 @@ inline bool run_test19()
|
||||||
for (std::size_t i = 0; i < 100; ++i)
|
for (std::size_t i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
x = T(i);
|
x = T(i);
|
||||||
|
|
||||||
sum += x;
|
sum += x;
|
||||||
|
|
||||||
T result = expression.value();
|
T result = expression.value();
|
||||||
|
|
||||||
if (result != sum)
|
if (result != sum)
|
||||||
|
@ -6847,7 +6855,7 @@ struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
|
||||||
{
|
{
|
||||||
st = usr_t::e_usr_variable_type;
|
st = usr_t::e_usr_variable_type;
|
||||||
default_value = next_value();
|
default_value = next_value();
|
||||||
error_message = "";
|
error_message.clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -6855,7 +6863,7 @@ struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
|
||||||
{
|
{
|
||||||
st = usr_t::e_usr_constant_type;
|
st = usr_t::e_usr_constant_type;
|
||||||
default_value = next_value();
|
default_value = next_value();
|
||||||
error_message = "";
|
error_message.clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
56
readme.txt
56
readme.txt
|
@ -7,7 +7,7 @@ mathematical expression parsing and evaluation engine. The parsing
|
||||||
engine supports numerous forms of functional and logic processing
|
engine supports numerous forms of functional and logic processing
|
||||||
semantics and is easily extendible.
|
semantics and is easily extendible.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[01 - CAPABILITIES]
|
[01 - CAPABILITIES]
|
||||||
The ExprTk expression evaluator supports the following fundamental
|
The ExprTk expression evaluator supports the following fundamental
|
||||||
|
@ -49,7 +49,7 @@ arithmetic operations, functions and processes:
|
||||||
|
|
||||||
(11) Calculus: numerical integration and differentiation
|
(11) Calculus: numerical integration and differentiation
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[02 - EXAMPLE EXPRESSIONS]
|
[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
|
||||||
|
@ -76,7 +76,7 @@ expressions that can be parsed and evaluated using the ExprTk library.
|
||||||
(19) ((x + 'abc') like '*123*') or ('a123b' ilike y)
|
(19) ((x + 'abc') like '*123*') or ('a123b' ilike y)
|
||||||
(20) sgn(+1.2^3.4z / -5.6y) <= {-7.8^9 / -10.11x }
|
(20) sgn(+1.2^3.4z / -5.6y) <= {-7.8^9 / -10.11x }
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[03 - COPYRIGHT NOTICE]
|
[03 - COPYRIGHT NOTICE]
|
||||||
Free use of the C++ Mathematical Expression Toolkit Library is
|
Free use of the C++ Mathematical Expression Toolkit Library is
|
||||||
|
@ -85,7 +85,7 @@ version of the Common Public License.
|
||||||
|
|
||||||
http://www.opensource.org/licenses/cpl1.0.php
|
http://www.opensource.org/licenses/cpl1.0.php
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[04 - DOWNLOADS & UPDATES]
|
[04 - DOWNLOADS & UPDATES]
|
||||||
The most recent version of the C++ Mathematical Expression Toolkit
|
The most recent version of the C++ Mathematical Expression Toolkit
|
||||||
|
@ -95,13 +95,13 @@ locations:
|
||||||
(a) Download: http://www.partow.net/programming/exprtk/index.html
|
(a) Download: http://www.partow.net/programming/exprtk/index.html
|
||||||
(b) Repository: https://github.com/ArashPartow/exprtk
|
(b) Repository: https://github.com/ArashPartow/exprtk
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[05 - INSTALLATION]
|
[05 - INSTALLATION]
|
||||||
The header file exprtk.hpp should be placed in a project or system
|
The header file exprtk.hpp should be placed in a project or system
|
||||||
include path (e.g: /usr/include/).
|
include path (e.g: /usr/include/).
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[06 - COMPILATION]
|
[06 - COMPILATION]
|
||||||
(a) For a complete build: make clean all
|
(a) For a complete build: make clean all
|
||||||
|
@ -109,7 +109,7 @@ include path (e.g: /usr/include/).
|
||||||
(c) To strip executables: make strip_bin
|
(c) To strip executables: make strip_bin
|
||||||
(d) Execute valgrind check: make valgrind_check
|
(d) Execute valgrind check: make valgrind_check
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[07 - COMPILER COMPATIBILITY]
|
[07 - COMPILER COMPATIBILITY]
|
||||||
ExprTk has been built error and warning free using the following set
|
ExprTk has been built error and warning free using the following set
|
||||||
|
@ -120,11 +120,10 @@ of C++ compilers:
|
||||||
(*) Clang/LLVM (1.1+)
|
(*) Clang/LLVM (1.1+)
|
||||||
(*) PGI C++ (10.x+)
|
(*) PGI C++ (10.x+)
|
||||||
(*) Microsoft Visual Studio C++ Compiler (8.1+)
|
(*) Microsoft Visual Studio C++ Compiler (8.1+)
|
||||||
(*) Comeau C++ Compiler (4.3+)
|
|
||||||
(*) IBM XL C/C++ (9.x+)
|
(*) IBM XL C/C++ (9.x+)
|
||||||
(*) C++ Builder (XE4+)
|
(*) C++ Builder (XE4+)
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[08 - BUILT-IN OPERATIONS & FUNCTIONS]
|
[08 - BUILT-IN OPERATIONS & FUNCTIONS]
|
||||||
|
|
||||||
|
@ -604,7 +603,7 @@ appropriate may represent any of one the following:
|
||||||
5. A string
|
5. A string
|
||||||
6. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3])
|
6. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3])
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[09 - Fundamental Types]
|
[09 - Fundamental Types]
|
||||||
ExprTk supports three fundamental types which can be used freely in
|
ExprTk supports three fundamental types which can be used freely in
|
||||||
|
@ -635,7 +634,7 @@ can be assigned and concatenated to one another, they can also be
|
||||||
manipulated via sub-ranges using the range definition syntax. Strings
|
manipulated via sub-ranges using the range definition syntax. Strings
|
||||||
however can not interact with scalar or vector types.
|
however can not interact with scalar or vector types.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[10 - COMPONENTS]
|
[10 - COMPONENTS]
|
||||||
There are three primary components, that are specialized upon a given
|
There are three primary components, that are specialized upon a given
|
||||||
|
@ -794,7 +793,7 @@ The above denoted AST will be evaluated in the following order:
|
||||||
|
|
||||||
|
|
||||||
(3) Parser
|
(3) Parser
|
||||||
A structure which takes as input a string representation of an
|
A component which takes as input a string representation of an
|
||||||
expression and attempts to compile said input with the result being an
|
expression and attempts to compile said input with the result being an
|
||||||
instance of Expression. If an error is encountered during the
|
instance of Expression. If an error is encountered during the
|
||||||
compilation process, the parser will stop compiling and return an
|
compilation process, the parser will stop compiling and return an
|
||||||
|
@ -802,7 +801,7 @@ error status code, with a more detailed description of the error(s)
|
||||||
and its location within the input provided by the 'get_error'
|
and its location within the input provided by the 'get_error'
|
||||||
interface.
|
interface.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[11 - COMPILATION OPTIONS]
|
[11 - COMPILATION OPTIONS]
|
||||||
The exprtk::parser when being instantiated takes as input a set of
|
The exprtk::parser when being instantiated takes as input a set of
|
||||||
|
@ -937,7 +936,7 @@ desired over the strength reduced form. In these situations it is best
|
||||||
to turn off strength reduction optimisations or to use a type with a
|
to turn off strength reduction optimisations or to use a type with a
|
||||||
larger numerical bound.
|
larger numerical bound.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[12 - SPECIAL FUNCTIONS]
|
[12 - SPECIAL FUNCTIONS]
|
||||||
The purpose of special functions in ExprTk is to provide compiler
|
The purpose of special functions in ExprTk is to provide compiler
|
||||||
|
@ -1008,7 +1007,7 @@ correctly optimize such expressions for a given architecture.
|
||||||
$f98(x,y,z,w) | (x == y) ? z : w
|
$f98(x,y,z,w) | (x == y) ? z : w
|
||||||
$f99(x,y,z,w) | x*sin(y)+z*cos(w)
|
$f99(x,y,z,w) | x*sin(y)+z*cos(w)
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[13 - VARIABLE , VECTOR & STRING DEFINITION]
|
[13 - VARIABLE , VECTOR & STRING DEFINITION]
|
||||||
ExprTk supports the definition of expression local variables, vectors
|
ExprTk supports the definition of expression local variables, vectors
|
||||||
|
@ -1127,7 +1126,7 @@ based on the following priorities:
|
||||||
(e) Symbol table functions
|
(e) Symbol table functions
|
||||||
(f) Unknown symbol resolver based variables
|
(f) Unknown symbol resolver based variables
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[14 - VECTOR PROCESSING]
|
[14 - VECTOR PROCESSING]
|
||||||
ExprTk provides support for various forms of vector oriented
|
ExprTk provides support for various forms of vector oriented
|
||||||
|
@ -1203,7 +1202,7 @@ not a vector but rather a single value.
|
||||||
min(1 / x) == (1 / 3)
|
min(1 / x) == (1 / 3)
|
||||||
max(x / 2) == (3 / 2)
|
max(x / 2) == (3 / 2)
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[15 - USER DEFINED FUNCTIONS]
|
[15 - USER DEFINED FUNCTIONS]
|
||||||
ExprTk provides a means whereby custom functions can be defined and
|
ExprTk provides a means whereby custom functions can be defined and
|
||||||
|
@ -1310,6 +1309,7 @@ example defines a generic function called 'too':
|
||||||
{
|
{
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
return T(0);
|
return T(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1735,7 +1735,7 @@ carried out:
|
||||||
{ ... }
|
{ ... }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[16 - EXPRESSION DEPENDENTS]
|
[16 - EXPRESSION DEPENDENTS]
|
||||||
Any expression that is not a literal (aka constant) will have
|
Any expression that is not a literal (aka constant) will have
|
||||||
|
@ -1881,7 +1881,7 @@ of the DEC in determining the 'assignments' of the given expression:
|
||||||
Note: The assignments will only consist of variable types and as such
|
Note: The assignments will only consist of variable types and as such
|
||||||
will not contain symbols denoting functions.
|
will not contain symbols denoting functions.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[17 - ENABLING AND DISABLING FEATURES]
|
[17 - ENABLING AND DISABLING FEATURES]
|
||||||
The parser can be configured via its settings instance to either allow
|
The parser can be configured via its settings instance to either allow
|
||||||
|
@ -2239,7 +2239,7 @@ provided symbol names when calling the standard 'add_function' method.
|
||||||
Normally if a user specified symbol name conflicts with any of the
|
Normally if a user specified symbol name conflicts with any of the
|
||||||
ExprTk reserved words, the add_function call will fail.
|
ExprTk reserved words, the add_function call will fail.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[18 - EXPRESSION RETURN VALUES]
|
[18 - EXPRESSION RETURN VALUES]
|
||||||
ExprTk expressions can return immediately from any point by utilizing
|
ExprTk expressions can return immediately from any point by utilizing
|
||||||
|
@ -2291,7 +2291,7 @@ expression will return normally.
|
||||||
typedef typename type_t::vector_view vector_t;
|
typedef typename type_t::vector_view vector_t;
|
||||||
typedef typename type_t::string_view string_t;
|
typedef typename type_t::string_view string_t;
|
||||||
|
|
||||||
const results_context_t& result = expression.results();
|
const results_context_t& results = expression.results();
|
||||||
|
|
||||||
for (std::size_t i = 0; i < results.count(); ++i)
|
for (std::size_t i = 0; i < results.count(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -2313,10 +2313,10 @@ expression will return normally.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Note: Processing of the return results is very similar to that of the
|
Note: Processing of the return results is similar to that of the
|
||||||
generic function call parameters.
|
generic function call parameters.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[19 - COMPILATION ERRORS]
|
[19 - COMPILATION ERRORS]
|
||||||
When attempting to compile a malformed or otherwise erroneous ExprTk
|
When attempting to compile a malformed or otherwise erroneous ExprTk
|
||||||
|
@ -2426,7 +2426,7 @@ find, within the symbol_table, symbols representing variables or
|
||||||
functions, to being unable to create new variables in the symbol_table
|
functions, to being unable to create new variables in the symbol_table
|
||||||
via the 'unknown symbol resolver' mechanism.
|
via the 'unknown symbol resolver' mechanism.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[20 - EXPRTK NOTES]
|
[20 - EXPRTK NOTES]
|
||||||
The following is a list of facts and suggestions one may want to take
|
The following is a list of facts and suggestions one may want to take
|
||||||
|
@ -2604,7 +2604,7 @@ into account when using ExprTk:
|
||||||
(x + y) / (x - y);
|
(x + y) / (x - y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[21 - SIMPLE EXPRTK EXAMPLE]
|
[21 - SIMPLE EXPRTK EXAMPLE]
|
||||||
--- snip ---
|
--- snip ---
|
||||||
|
@ -2692,7 +2692,7 @@ int main()
|
||||||
}
|
}
|
||||||
--- snip ---
|
--- snip ---
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[22 - BUILD OPTIONS]
|
[22 - BUILD OPTIONS]
|
||||||
When building ExprTk there are a number of defines that will enable or
|
When building ExprTk there are a number of defines that will enable or
|
||||||
|
@ -2738,7 +2738,7 @@ This define will disable all string processing capabilities. Any
|
||||||
expression that contains a string or string related syntax will result
|
expression that contains a string or string related syntax will result
|
||||||
in a compilation failure.
|
in a compilation failure.
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[23 - FILES]
|
[23 - FILES]
|
||||||
The source distribution of ExprTk is comprised of the following set of
|
The source distribution of ExprTk is comprised of the following set of
|
||||||
|
@ -2766,7 +2766,7 @@ files:
|
||||||
(19) exprtk_simple_example_15.cpp
|
(19) exprtk_simple_example_15.cpp
|
||||||
(20) exprtk_simple_example_16.cpp
|
(20) exprtk_simple_example_16.cpp
|
||||||
|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
[24 - LANGUAGE STRUCTURE]
|
[24 - LANGUAGE STRUCTURE]
|
||||||
+-------------------------------------------------------------+
|
+-------------------------------------------------------------+
|
||||||
|
|
Loading…
Reference in New Issue