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

View File

@ -41,21 +41,22 @@ void newton_sqrt()
compositor compositor
.add("newton_sqrt_impl", .add("newton_sqrt_impl",
"switch " "switch "
"{ " "{ "
" case x < 0 : -inf; " " case x < 0 : -inf; "
" case x == 0 : 0; " " case x == 0 : 0; "
" case x == 1 : 1; " " case x == 1 : 1; "
" default: " " default: "
" ~{ " " ~{ "
" z := 100; " " z := 100; "
" y := x / 2; " " y := x / 2; "
" repeat " " repeat "
" if (equal(y * y,x), z := 0, 0);" " y := (1 / 2) * (y + (x / y)); "
" y := (1 / 2) * (y + (x / y)); " " if (equal(y * y,x)) "
" until ((z -= 1) <= 0) " " break[y]; "
" }; " " until ((z -= 1) <= 0); "
"} ", " }; "
"} ",
"x","y","z"); "x","y","z");
compositor 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>("(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);) { 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); 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>); static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy<T>);
@ -4317,6 +4319,39 @@ inline bool run_test19()
"} ", "} ",
"x"); "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_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);
@ -4324,7 +4359,8 @@ inline bool run_test19()
const std::string expression_str[] = { const std::string expression_str[] = {
"is_prime1(x)", "is_prime1(x)",
"is_prime2(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); const std::size_t expression_count = sizeof(expression_str) / sizeof(std::string);
@ -4615,24 +4651,22 @@ inline bool run_test19()
compositor compositor
.add("newton_sqrt_impl", .add("newton_sqrt_impl",
"switch " "switch "
"{ " "{ "
" case x < 0 : -inf; " " case x < 0 : -inf; "
" case x == 0 : 0; " " case x == 0 : 0; "
" case x == 1 : 1; " " case x == 1 : 1; "
" default: " " default: "
" ~{ " " ~{ "
" z := 100; " " z := 100; "
" y := x / 2; " " y := x / 2; "
" while ((z := (z - 1)) > 0) " " repeat "
" { " " y := (1 / 2) * (y + (x / y)); "
" if (equal(y^2,x)) " " if (equal(y * y,x)) "
" y := y + (z := 0); " " break[y]; "
" else " " until ((z -= 1) <= 0); "
" y := (1 / 2) * (y + (x / y)); " " }; "
" } " "} ",
" }; "
"} ",
"x","y","z"); "x","y","z");
compositor compositor

View File

@ -33,7 +33,7 @@ arithmetic operations, functions and processes:
(5) Conditional, (5) Conditional,
Switch & Switch &
Loop statements: if-then-else, ternary conditional, switch-case, Loop statements: if-then-else, ternary conditional, switch-case,
while, for, repeat-until while, for, repeat-until, break, continue
(6) Assignment: :=, +=, -=, *=, /= (6) Assignment: :=, +=, -=, *=, /=
@ -456,6 +456,33 @@ include path (e.g: /usr/include/).
| | w := u + y; | | | 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 | | ?: | Ternary conditional statement, similar to that of the |
| | above denoted if-statement. | | | above denoted if-statement. |
| | eg: | | | eg: |