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

This commit is contained in:
Arash Partow 2014-04-27 14:15:43 +10:00
parent 86514b460f
commit ab7c1677e5
4 changed files with 654 additions and 105 deletions

View File

@ -40,6 +40,7 @@
#include <cstdio>
#include <cstdlib>
#include <deque>
#include <exception>
#include <iterator>
#include <limits>
#include <list>
@ -272,24 +273,23 @@ namespace exprtk
static const std::string reserved_words[] =
{
"default", "case", "false", "for", "if", "else", "ilike", "in", "like",
"and", "nand", "nor", "not", "null", "or", "repeat", "shl", "shr", "switch",
"true", "until", "while", "xnor", "xor", "&", "|"
"break", "case", "continue", "default", "false", "for", "if", "else",
"ilike", "in", "like", "and", "nand", "nor", "not", "null", "or", "repeat",
"shl", "shr", "switch", "true", "until", "while", "xnor", "xor", "&", "|"
};
static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string);
static const std::string reserved_symbols[] =
{
"abs", "acos", "acosh", "and", "asin", "asinh", "atan", "atanh", "atan2",
"avg", "case", "ceil", "clamp", "cos", "cosh", "cot", "csc", "default",
"deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", "expm1", "false",
"floor", "for", "frac", "grad2deg", "hypot", "iclamp", "if", "else", "ilike",
"in", "inrange", "like", "log", "log10", "log2", "logn", "log1p", "mand", "max",
"min", "mod", "mor", "mul", "nand", "nor", "not", "not_equal", "null", "or",
"pow", "rad2deg", "repeat", "root", "round", "roundn", "sec", "sgn", "shl",
"shr", "sin", "sinh", "sqrt", "sum", "switch", "tan", "tanh", "true", "trunc",
"until", "while", "xnor", "xor", "&", "|"
"abs", "acos", "acosh", "and", "asin", "asinh", "atan", "atanh", "atan2", "avg",
"break", "case", "ceil", "clamp", "continue", "cos", "cosh", "cot", "csc", "default",
"deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", "expm1", "false", "floor",
"for", "frac", "grad2deg", "hypot", "iclamp", "if", "else", "ilike", "in", "inrange",
"like", "log", "log10", "log2", "logn", "log1p", "mand", "max", "min", "mod", "mor",
"mul", "nand", "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", "repeat",
"root", "round", "roundn", "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum",
"switch", "tan", "tanh", "true", "trunc", "until", "while", "xnor", "xor", "&", "|"
};
static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string);
@ -3386,7 +3386,8 @@ namespace exprtk
e_vocov , e_covov , e_covoc , e_vovovov ,
e_vovovoc , e_vovocov , e_vocovov , e_covovov ,
e_covocov , e_vocovoc , e_covovoc , e_vococov ,
e_sf3ext , e_sf4ext , e_nulleq , e_vecelem
e_sf3ext , e_sf4ext , e_nulleq , e_vecelem ,
e_break , e_continue
};
typedef T value_type;
@ -3479,6 +3480,18 @@ namespace exprtk
return node && (details::expression_node<T>::e_null == node->type());
}
template <typename T>
inline bool is_break_node(const expression_node<T>* node)
{
return node && (details::expression_node<T>::e_break == node->type());
}
template <typename T>
inline bool is_continue_node(const expression_node<T>* node)
{
return node && (details::expression_node<T>::e_continue == node->type());
}
template <typename T>
inline bool is_function(const expression_node<T>* node)
{
@ -4232,6 +4245,77 @@ namespace exprtk
bool consequent_deletable_;
};
#ifndef exprtk_disable_break_continue
template <typename T>
class break_exception : public std::exception
{
public:
break_exception(const T& v)
: value(v)
{}
T value;
};
class continue_exception : public std::exception
{};
template <typename T>
class break_node : public expression_node<T>
{
public:
typedef expression_node<T>* expression_ptr;
break_node(expression_ptr ret = expression_ptr(0))
: return_(ret),
return_deletable_(branch_deletable(return_))
{}
~break_node()
{
if (return_deletable_)
{
delete return_;
}
}
inline T value() const
{
throw break_exception<T>(return_ ? return_->value() : std::numeric_limits<T>::quiet_NaN());
return std::numeric_limits<T>::quiet_NaN();
}
inline typename expression_node<T>::node_type type() const
{
return expression_node<T>::e_break;
}
private:
expression_ptr return_;
bool return_deletable_;
};
template <typename T>
class continue_node : public expression_node<T>
{
public:
inline T value() const
{
throw continue_exception();
return std::numeric_limits<T>::quiet_NaN();
}
inline typename expression_node<T>::node_type type() const
{
return expression_node<T>::e_break;
}
};
#endif
template <typename T>
class while_loop_node : public expression_node<T>
{
@ -4436,6 +4520,248 @@ namespace exprtk
T* loop_counter_var_;
};
#ifndef exprtk_disable_break_continue
template <typename T>
class while_loop_bc_node : public expression_node<T>
{
public:
typedef expression_node<T>* expression_ptr;
while_loop_bc_node(expression_ptr condition, expression_ptr loop_body)
: condition_(condition),
loop_body_(loop_body),
condition_deletable_(branch_deletable(condition_)),
loop_body_deletable_(branch_deletable(loop_body_))
{}
~while_loop_bc_node()
{
if (condition_ && condition_deletable_)
{
delete condition_;
}
if (loop_body_ && loop_body_deletable_)
{
delete loop_body_;
}
}
inline T value() const
{
T result = T(0);
while (is_true(condition_))
{
try
{
result = loop_body_->value();
}
catch(const break_exception<T>& e)
{
return e.value;
}
catch(const continue_exception&)
{}
}
return result;
}
inline typename expression_node<T>::node_type type() const
{
return expression_node<T>::e_while;
}
private:
expression_ptr condition_;
expression_ptr loop_body_;
bool condition_deletable_;
bool loop_body_deletable_;
};
template <typename T>
class repeat_until_loop_bc_node : public expression_node<T>
{
public:
typedef expression_node<T>* expression_ptr;
repeat_until_loop_bc_node(expression_ptr condition, expression_ptr loop_body)
: condition_(condition),
loop_body_(loop_body),
condition_deletable_(branch_deletable(condition_)),
loop_body_deletable_(branch_deletable(loop_body_))
{}
~repeat_until_loop_bc_node()
{
if (condition_ && condition_deletable_)
{
delete condition_;
}
if (loop_body_ && loop_body_deletable_)
{
delete loop_body_;
}
}
inline T value() const
{
T result = T(0);
do
{
try
{
result = loop_body_->value();
}
catch(const break_exception<T>& e)
{
return e.value;
}
catch(const continue_exception&)
{}
}
while (is_false(condition_));
return result;
}
inline typename expression_node<T>::node_type type() const
{
return expression_node<T>::e_repeat;
}
private:
expression_ptr condition_;
expression_ptr loop_body_;
bool condition_deletable_;
bool loop_body_deletable_;
};
template <typename T>
class for_loop_bc_node : public expression_node<T>
{
public:
typedef expression_node<T>* expression_ptr;
for_loop_bc_node(expression_ptr initializer,
expression_ptr condition,
expression_ptr incrementor,
expression_ptr loop_body,
expression_ptr loop_var,
T* loop_counter_var = 0)
: initializer_(initializer),
condition_ (condition),
incrementor_(incrementor),
loop_body_ (loop_body),
loop_var_ (loop_var),
initializer_deletable_(branch_deletable(initializer_)),
condition_deletable_ (branch_deletable(condition_ )),
incrementor_deletable_(branch_deletable(incrementor_)),
loop_body_deletable_ (branch_deletable(loop_body_ )),
loop_counter_var_(loop_counter_var)
{}
~for_loop_bc_node()
{
if (initializer_ && initializer_deletable_)
{
delete initializer_;
}
if (condition_ && condition_deletable_)
{
delete condition_;
}
if (incrementor_ && incrementor_deletable_)
{
delete incrementor_;
}
if (loop_body_ && loop_body_deletable_)
{
delete loop_body_;
}
if (loop_var_)
{
delete loop_var_;
}
if (loop_counter_var_)
{
delete loop_counter_var_;
}
}
inline T value() const
{
T result = T(0);
if (initializer_)
initializer_->value();
if (incrementor_)
{
while (is_true(condition_))
{
try
{
result = loop_body_->value();
}
catch(const break_exception<T>& e)
{
return e.value;
}
catch(const continue_exception&)
{}
incrementor_->value();
}
}
else
{
while (is_true(condition_))
{
try
{
result = loop_body_->value();
}
catch(const break_exception<T>& e)
{
return e.value;
}
catch(const continue_exception&)
{}
}
}
return result;
}
inline typename expression_node<T>::node_type type() const
{
return expression_node<T>::e_for;
}
private:
expression_ptr initializer_;
expression_ptr condition_ ;
expression_ptr incrementor_;
expression_ptr loop_body_ ;
expression_ptr loop_var_ ;
bool initializer_deletable_;
bool condition_deletable_ ;
bool incrementor_deletable_;
bool loop_body_deletable_ ;
T* loop_counter_var_;
};
#endif
template <typename T>
class switch_node : public expression_node<T>
{
@ -10575,7 +10901,6 @@ namespace exprtk
exprtk::parser_error::to_str(error.mode).c_str(),
error.diagnostic.c_str());
}
}
template <typename T>
@ -10624,6 +10949,11 @@ namespace exprtk
typedef details::while_loop_node <T> while_loop_node_t;
typedef details::repeat_until_loop_node<T> repeat_until_loop_node_t;
typedef details::for_loop_node<T> for_loop_node_t;
#ifndef exprtk_disable_break_continue
typedef details::while_loop_bc_node <T> while_loop_bc_node_t;
typedef details::repeat_until_loop_bc_node<T> repeat_until_loop_bc_node_t;
typedef details::for_loop_bc_node<T> for_loop_bc_node_t;
#endif
typedef details::switch_node<T> switch_node_t;
typedef details::variable_node<T> variable_node_t;
typedef details::vector_node<T> vector_node_t;
@ -10808,6 +11138,7 @@ namespace exprtk
{
error_list_.clear();
synthesis_error_.clear();
brkcnt_list_.clear();
local_symbol_table_.clear_variables(false);
expression_generator_.set_allocator(node_allocator_);
@ -11743,7 +12074,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR22 - Failed to parse body of consequent for if-statement."));
"ERR22 - Failed to parse body of consequent for if-statement"));
result = false;
}
}
@ -11764,7 +12095,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR23 - Expected ';' at the end of the consequent for if-statement."));
"ERR23 - Expected ';' at the end of the consequent for if-statement"));
result = false;
}
}
@ -11773,7 +12104,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR24 - Failed to parse body of consequent for if-statement."));
"ERR24 - Failed to parse body of consequent for if-statement"));
result = false;
}
}
@ -11792,7 +12123,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR25 - Failed to parse body of the 'else' for if-statement."));
"ERR25 - Failed to parse body of the 'else' for if-statement"));
result = false;
}
}
@ -11803,7 +12134,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR26 - Failed to parse body of if-else statement."));
"ERR26 - Failed to parse body of if-else statement"));
result = false;
}
}
@ -11814,7 +12145,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR27 - Expected ';' at the end of the 'else-if' for the if-statement."));
"ERR27 - Expected ';' at the end of the 'else-if' for the if-statement"));
result = false;
}
}
@ -11823,7 +12154,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR28 - Failed to parse body of the 'else' for if-statement."));
"ERR28 - Failed to parse body of the 'else' for if-statement"));
result = false;
}
}
@ -11959,8 +12290,11 @@ namespace exprtk
inline expression_node_ptr parse_while_loop()
{
// Parse: [while][(][test expr][)][{][expression][}]
expression_node_ptr condition = error_node();
expression_node_ptr branch = error_node();
expression_node_ptr condition = error_node();
expression_node_ptr branch = error_node();
expression_node_ptr result_node = error_node();
bool result = true;
next_token();
@ -11986,30 +12320,43 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR39 - Expected ')' at end of while-statement condition"));
return error_node();
}
if (0 == (branch = parse_multi_sequence("while-loop")))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR40 - Failed to parse body of while-loop"));
free_node(node_allocator_,condition);
return error_node();
result = false;
}
expression_node_ptr result;
brkcnt_list_.push_front(false);
if (0 == (result = expression_generator_.while_loop(condition,branch)))
if (result)
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR41 - Failed to synthesize while-loop"));
if (0 == (branch = parse_multi_sequence("while-loop")))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR40 - Failed to parse body of while-loop"));
result = false;
}
else if (0 == (result_node = expression_generator_.while_loop(condition,
branch,
brkcnt_list_.front())))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR41 - Failed to synthesize while-loop"));
result = false;
}
}
if (!result)
{
free_node(node_allocator_,condition );
free_node(node_allocator_,branch );
free_node(node_allocator_,result_node);
brkcnt_list_.pop_front();
return error_node();
}
else
return result;
return result_node;
}
inline expression_node_ptr parse_repeat_until_loop()
@ -12025,6 +12372,8 @@ namespace exprtk
{
token_t::token_type seperator = token_t::e_eof;
brkcnt_list_.push_front(false);
for (;;)
{
expression_node_ptr arg = parse_expression();
@ -12065,6 +12414,7 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR43 - Failed to parse body of repeat until loop"));
brkcnt_list_.pop_front();
return error_node();
}
}
@ -12075,6 +12425,7 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR44 - Expected '(' before condition of repeat until loop"));
brkcnt_list_.pop_front();
return error_node();
}
else if (0 == (condition = parse_expression()))
@ -12083,6 +12434,7 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR45 - Failed to parse condition for repeat until loop"));
brkcnt_list_.pop_front();
return error_node();
}
else if (!token_is(token_t::e_rbracket))
@ -12091,21 +12443,28 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR46 - Expected ')' after condition of repeat until loop"));
free_node(node_allocator_,condition);
brkcnt_list_.pop_front();
return error_node();
}
expression_node_ptr result;
if (0 == (result = expression_generator_.repeat_until_loop(condition,branch)))
if (0 == (result = expression_generator_.repeat_until_loop(condition,branch,brkcnt_list_.front())))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR47 - Failed to synthesize repeat until loop"));
free_node(node_allocator_,condition);
brkcnt_list_.pop_front();
return error_node();
}
else
{
brkcnt_list_.pop_front();
return result;
}
}
inline expression_node_ptr parse_for_loop()
@ -12156,7 +12515,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR51 - For-loop variable '" +loop_counter_symbol+ "' is being shadowed by a previous declaration."));
"ERR51 - For-loop variable '" +loop_counter_symbol+ "' is being shadowed by a previous declaration"));
return error_node();
}
else if (!symbol_table_.is_variable(loop_counter_symbol))
@ -12227,6 +12586,7 @@ namespace exprtk
if (result)
{
brkcnt_list_.push_front(false);
if (0 == (loop_body = parse_multi_sequence("for-loop")))
{
set_error(
@ -12245,6 +12605,7 @@ namespace exprtk
free_node(node_allocator_,incrementor);
free_node(node_allocator_,loop_body );
delete loop_counter;
brkcnt_list_.pop_front();
return error_node();
}
else
@ -12254,12 +12615,16 @@ namespace exprtk
local_symbol_table_.remove_variable(loop_counter_symbol,false);
}
return expression_generator_.for_loop(initializer,
expression_node_ptr result_node =
expression_generator_.for_loop(initializer,
condition,
incrementor,
loop_body,
loop_var,
loop_counter);
loop_counter,
brkcnt_list_.front());
brkcnt_list_.pop_front();
return result_node;
}
}
@ -12427,7 +12792,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR69 - Expected a 'case' statement for multi-switch."));
"ERR69 - Expected a 'case' statement for multi-switch"));
return error_node();
}
@ -13172,6 +13537,64 @@ namespace exprtk
return node_allocator_.allocate<details::null_node<T> >();
}
#ifndef exprtk_disable_break_continue
inline expression_node_ptr parse_break_statement()
{
if (!brkcnt_list_.empty())
{
next_token();
brkcnt_list_.front() = true;
expression_node_ptr ret = error_node();
if (token_is(token_t::e_lsqrbracket))
{
if (0 == (ret = parse_expression()))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR97 - Failed to parse return expression for 'break' statement"));
return error_node();
}
else if (!token_is(token_t::e_rsqrbracket))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR98 - Expected ']' at the completed of break's return expression"));
return error_node();
}
}
return node_allocator_.allocate<details::break_node<T> >(ret);
}
else
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR99 - Invalid use of 'break', allowed only in the scope of a loop"));
}
return error_node();
}
inline expression_node_ptr parse_continue_statement()
{
if (!brkcnt_list_.empty())
{
next_token();
brkcnt_list_.front() = true;
return node_allocator_.allocate<details::continue_node<T> >();
}
else
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR100 - Invalid use of 'continue', allowed only in the scope of a loop"));
return error_node();
}
}
#endif
inline expression_node_ptr parse_symtab_symbol()
{
const std::string symbol = current_token_.value;
@ -13242,7 +13665,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR97 - Invalid number of parameters for function: " + symbol));
"ERR101 - Invalid number of parameters for function: " + symbol));
return error_node();
}
}
@ -13254,7 +13677,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR98 - Failed to generate node for function: '" + symbol + "'"));
"ERR102 - Failed to generate node for function: '" + symbol + "'"));
return error_node();
}
}
@ -13274,7 +13697,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR99 - Failed to generate node for vararg function: '" + symbol + "'"));
"ERR103 - Failed to generate node for vararg function: '" + symbol + "'"));
return error_node();
}
}
@ -13285,6 +13708,15 @@ namespace exprtk
return parse_vector();
}
if (details::is_reserved_symbol(symbol))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR104 - Invalid use of reserved symbol '" + symbol + "'"));
return error_node();
}
// Should we handle unknown symbols?
if (resolve_unknown_symbol_ && unknown_symbol_resolver_)
{
@ -13324,7 +13756,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR100 - Failed to create variable: '" + symbol + "'"));
"ERR105 - Failed to create variable: '" + symbol + "'"));
return error_node();
}
@ -13333,18 +13765,20 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR101 - Undefined variable or function: '" + symbol + "'"));
"ERR106 - Undefined variable or function: '" + symbol + "'"));
return error_node();
}
inline expression_node_ptr parse_symbol()
{
static const std::string symbol_if = "if" ;
static const std::string symbol_while = "while" ;
static const std::string symbol_repeat = "repeat";
static const std::string symbol_for = "for" ;
static const std::string symbol_switch = "switch";
static const std::string symbol_null = "null" ;
static const std::string symbol_if = "if" ;
static const std::string symbol_while = "while" ;
static const std::string symbol_repeat = "repeat" ;
static const std::string symbol_for = "for" ;
static const std::string symbol_switch = "switch" ;
static const std::string symbol_null = "null" ;
static const std::string symbol_break = "break" ;
static const std::string symbol_continue = "continue";
if (valid_vararg_operation(current_token_.value))
{
@ -13382,6 +13816,16 @@ namespace exprtk
{
return parse_null_statement();
}
#ifndef exprtk_disable_break_continue
else if (details::imatch(current_token_.value,symbol_break))
{
return parse_break_statement();
}
else if (details::imatch(current_token_.value,symbol_continue))
{
return parse_continue_statement();
}
#endif
else if (symbol_table_.valid())
{
return parse_symtab_symbol();
@ -13391,7 +13835,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR102 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
"ERR107 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
return error_node();
}
}
@ -13415,7 +13859,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_numeric,
current_token_,
"ERR103 - Failed to convert '" + current_token_.value + "' to a number."));
"ERR108 - Failed to convert '" + current_token_.value + "' to a number"));
return error_node();
}
}
@ -13439,7 +13883,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR104 - Expected ')' instead of: '" + current_token_.value + "'"));
"ERR109 - Expected ')' instead of: '" + current_token_.value + "'"));
return error_node();
}
}
@ -13453,7 +13897,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR105 - Expected ']' instead of: '" + current_token_.value + "'"));
"ERR110 - Expected ']' instead of: '" + current_token_.value + "'"));
return error_node();
}
}
@ -13467,7 +13911,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR106 - Expected '}' instead of: '" + current_token_.value + "'"));
"ERR111 - Expected '}' instead of: '" + current_token_.value + "'"));
return error_node();
}
}
@ -13490,7 +13934,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR107 - Premature end of expression[1]"));
"ERR112 - Premature end of expression[1]"));
return error_node();
}
else
@ -13498,7 +13942,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR108 - Premature end of expression[2]"));
"ERR113 - Premature end of expression[2]"));
return error_node();
}
@ -13774,6 +14218,10 @@ namespace exprtk
return error_node();
else if (details::is_null_node(branch[0]))
return branch[0];
else if (details::is_break_node(branch[0]))
return error_node();
else if (details::is_continue_node(branch[0]))
return error_node();
else if (details::is_constant_node(branch[0]))
return synthesize_expression<unary_node_t,1>(operation,branch);
else if (unary_optimizable(operation) && details::is_variable_node(branch[0]))
@ -13990,6 +14438,16 @@ namespace exprtk
);
}
inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2])
{
return (
details::is_break_node (branch[0]) ||
details::is_break_node (branch[1]) ||
details::is_continue_node(branch[0]) ||
details::is_continue_node(branch[1])
);
}
inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2])
{
const bool b0_string = is_generally_string_node(branch[0]);
@ -14064,6 +14522,8 @@ namespace exprtk
return error_node();
else if (is_invalid_assignment_op(operation,branch))
return error_node();
else if (is_invalid_break_continue_op(branch))
return error_node();
else if (details::e_assign == operation)
return synthesize_assignment_expression(operation,branch);
else if (is_assignment_operation(operation))
@ -14185,7 +14645,8 @@ namespace exprtk
}
inline expression_node_ptr while_loop(expression_node_ptr condition,
expression_node_ptr branch) const
expression_node_ptr branch,
const bool brkcont = false) const
{
if (details::is_constant_node(condition))
{
@ -14204,12 +14665,19 @@ namespace exprtk
free_node(*node_allocator_,condition);
return branch;
}
else
else if (!brkcont)
return node_allocator_->allocate<while_loop_node_t>(condition,branch);
#ifndef exprtk_disable_break_continue
else
return node_allocator_->allocate<while_loop_bc_node_t>(condition,branch);
#else
return error_node();
#endif
}
inline expression_node_ptr repeat_until_loop(expression_node_ptr condition,
expression_node_ptr branch) const
expression_node_ptr branch,
const bool brkcont = false) const
{
if (details::is_constant_node(condition))
{
@ -14228,8 +14696,14 @@ namespace exprtk
free_node(*node_allocator_,condition);
return branch;
}
else
else if (!brkcont)
return node_allocator_->allocate<repeat_until_loop_node_t>(condition,branch);
#ifndef exprtk_disable_break_continue
else
return node_allocator_->allocate<repeat_until_loop_bc_node_t>(condition,branch);
#else
return error_node();
#endif
}
inline expression_node_ptr for_loop(expression_node_ptr initializer,
@ -14237,7 +14711,8 @@ namespace exprtk
expression_node_ptr incrementor,
expression_node_ptr loop_body,
expression_node_ptr loop_var,
T* loop_counter) const
T* loop_counter,
bool brkcont = false) const
{
if (details::is_constant_node(condition))
{
@ -14262,13 +14737,24 @@ namespace exprtk
free_node(*node_allocator_,incrementor);
return loop_body;
}
else
else if (!brkcont)
return node_allocator_->allocate<for_loop_node_t>(initializer,
condition,
incrementor,
loop_body,
loop_var,
loop_counter);
#ifndef exprtk_disable_break_continue
else
return node_allocator_->allocate<for_loop_bc_node_t>(initializer,
condition,
incrementor,
loop_body,
loop_var,
loop_counter);
#else
return error_node();
#endif
}
template <typename Allocator,
@ -19581,6 +20067,7 @@ namespace exprtk
std::set<expression_node_ptr> local_var_set_;
std::deque<std::string> symbol_name_cache_;
std::deque<parser_error::type> error_list_;
std::deque<bool> brkcnt_list_;
bool resolve_unknown_symbol_;
unknown_symbol_resolver* unknown_symbol_resolver_;
unknown_symbol_resolver default_usr_;

View File

@ -41,21 +41,22 @@ void newton_sqrt()
compositor
.add("newton_sqrt_impl",
"switch "
"{ "
" case x < 0 : -inf; "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default: "
" ~{ "
" z := 100; "
" y := x / 2; "
" repeat "
" if (equal(y * y,x), z := 0, 0);"
" y := (1 / 2) * (y + (x / y)); "
" until ((z -= 1) <= 0) "
" }; "
"} ",
"switch "
"{ "
" case x < 0 : -inf; "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default: "
" ~{ "
" z := 100; "
" y := x / 2; "
" repeat "
" y := (1 / 2) * (y + (x / y)); "
" if (equal(y * y,x)) "
" break[y]; "
" until ((z -= 1) <= 0); "
" }; "
"} ",
"x","y","z");
compositor

View File

@ -1521,7 +1521,9 @@ inline bool run_test01()
test_xy<T>("(x /= 2y) == (1/6)" ,T(1),T(3),T(1)),
test_xy<T>("for(i := 0; (i < 10);) { i += 1; }; x;" ,T(1),T(20),T( 1)),
test_xy<T>("for(i := 0; (i < 10) and (i != y); i+=2) { x += i; }; x;" ,T(1),T(20),T(21)),
test_xy<T>("for(i := 0; (i < 10) and (i != y);) { x += i; i+=2; }; x;",T(1),T(20),T(21))
test_xy<T>("for(i := 0; (i < 10) and (i != y);) { x += i; i+=2; }; x;",T(1),T(20),T(21)),
test_xy<T>("for(i := 0; (i < y); i += 1) { if (i <= (y / 2)) x += i; else break; }; x;" ,T(0),T(10),T(15)),
test_xy<T>("for(i := 0; (i < y); i += 1) { if (i <= (y / 2)) continue; else x += i; }; x;" ,T(0),T(10),T(30))
};
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy<T>);
@ -4317,6 +4319,39 @@ inline bool run_test19()
"} ",
"x");
compositor
.add("is_prime_impl4",
"switch "
"{ "
" case 1 == x : false; "
" case 2 == x : true; "
" case 3 == x : true; "
" case 5 == x : true; "
" case 7 == x : true; "
" case 0 == x % 2 : false; "
" default : "
" { "
" for (i := 3; i < y; i += 2) "
" { "
" if ((x % i) == 0) "
" break[false]; "
" else "
" true; "
" } "
" }; "
"} ",
"x","y");
compositor
.add("is_prime4",
"switch "
"{ "
" case x <= 0 : false; "
" case frac(x) != 0 : false; "
" default : is_prime_impl4(x,min(x - 1,trunc(sqrt(x)) + 1));"
"} ",
"x");
symbol_table_t& symbol_table = compositor.symbol_table();
symbol_table.add_constants();
symbol_table.add_variable("x",x);
@ -4324,7 +4359,8 @@ inline bool run_test19()
const std::string expression_str[] = {
"is_prime1(x)",
"is_prime2(x)",
"is_prime3(x)"
"is_prime3(x)",
"is_prime4(x)"
};
const std::size_t expression_count = sizeof(expression_str) / sizeof(std::string);
@ -4615,24 +4651,22 @@ inline bool run_test19()
compositor
.add("newton_sqrt_impl",
"switch "
"{ "
" case x < 0 : -inf; "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default: "
" ~{ "
" z := 100; "
" y := x / 2; "
" while ((z := (z - 1)) > 0) "
" { "
" if (equal(y^2,x)) "
" y := y + (z := 0); "
" else "
" y := (1 / 2) * (y + (x / y)); "
" } "
" }; "
"} ",
"switch "
"{ "
" case x < 0 : -inf; "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default: "
" ~{ "
" z := 100; "
" y := x / 2; "
" repeat "
" y := (1 / 2) * (y + (x / y)); "
" if (equal(y * y,x)) "
" break[y]; "
" until ((z -= 1) <= 0); "
" }; "
"} ",
"x","y","z");
compositor

View File

@ -33,7 +33,7 @@ arithmetic operations, functions and processes:
(5) Conditional,
Switch &
Loop statements: if-then-else, ternary conditional, switch-case,
while, for, repeat-until
while, for, repeat-until, break, continue
(6) Assignment: :=, +=, -=, *=, /=
@ -456,6 +456,33 @@ include path (e.g: /usr/include/).
| | w := u + y; |
| | } |
+----------+---------------------------------------------------------+
| break | Break terminates the execution of the nearest enclosed |
| break[] | loop, allowing for the execution to continue on external|
| | to the loop. The default break statement will set the |
| | return value of the loop to NaN, where as the return |
| | based form will set the value to that of the break |
| | expression. |
| | eg: |
| | while ((i += 1) < 10) |
| | { |
| | if (i < 5) |
| | j -= i + 2; |
| | else if (i % 2 == 0) |
| | break; |
| | else |
| | break[2i + 3]; |
| | } |
+----------+---------------------------------------------------------+
| continue | Continue results in the remaining portion of the nearest|
| | enclosing loop body to be skipped. |
| | eg: |
| | for (i := 0; i < 10; i+= 1) |
| | { |
| | if (i < 5) |
| | continue; |
| | j -= i + 2; |
| | } |
+----------+---------------------------------------------------------+
| ?: | Ternary conditional statement, similar to that of the |
| | above denoted if-statement. |
| | eg: |