From e44540b0f4e31ef71211d386ba1d1599ca868ec1 Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Sat, 13 Apr 2013 18:26:57 +1000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 864 ++++++++++++++++++++++++++++++++++-------------- exprtk_test.cpp | 329 ++++++++++++++++-- readme.txt | 23 +- 3 files changed, 948 insertions(+), 268 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index ddcf1a7..3da79e0 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -74,7 +74,7 @@ namespace exprtk ('{' == c) || ('}' == c) || ('%' == c) || (':' == c) || ('?' == c) || ('&' == c) || - ('|' == c); + ('|' == c) || (';' == c); } inline bool is_letter(const char c) @@ -226,22 +226,23 @@ namespace exprtk static const std::string reserved_words[] = { - "and", "false", "for", "if", "ilike", "in", "like", "nand", "nor", "not", - "null", "or", "shl", "shr", "true", "while", "xnor", "xor", "&", "|" + "and", "default", "case", "false", "for", "if", "ilike", "in", "like", + "nand", "nor", "not", "null", "or", "shl", "shr", "switch", "true", + "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", "and", "asin", "atan", "atan2", "avg", "ceil", "clamp", - "cos", "cosh", "cot", "csc", "deg2grad", "deg2rad", "equal", "erf", "erfc", - "exp", "false", "floor", "for", "frac", "grad2deg", "hypot", "if", "ilike", - "in", "inrange", "like", "log", "log10", "log2", "logn", "log1p", "mand", - "max", "min", "mod", "mor", "mul", "nand", "nor", "not", "not_equal", "null", - "or", "pow", "rad2deg", "root", "round", "roundn", "sec", "sgn", "shl", "shr", - "sin", "sinh", "sqrt", "sum", "tan", "tanh", "true", "trunc", "while", "xnor", - "xor", "&", "|" + "abs", "acos", "and", "asin", "atan", "atan2", "avg", "case", "ceil", + "clamp", "cos", "cosh", "cot", "csc", "default", "deg2grad", "deg2rad", + "equal", "erf", "erfc", "exp", "false", "floor", "for", "frac", "grad2deg", + "hypot", "if", "ilike", "in", "inrange", "like", "log", "log10", "log2", + "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", "nand", "nor", + "not", "not_equal", "null", "or", "pow", "rad2deg", "root", "round", "roundn", + "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum", "switch", "tan", + "tanh", "true", "trunc", "while", "xnor", "xor", "&", "|" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); @@ -1709,9 +1710,11 @@ namespace exprtk } } if ('<' == *s_itr_) - t.set_operator(token_t::e_lt,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_); else if ('>' == *s_itr_) - t.set_operator(token_t::e_gt,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_); + else if (';' == *s_itr_) + t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_); else if ('&' == *s_itr_) t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); else if ('|' == *s_itr_) @@ -2459,11 +2462,7 @@ namespace exprtk add_invalid(lexer::token::e_string,lexer::token::e_string); add_invalid(lexer::token::e_number,lexer::token::e_string); add_invalid(lexer::token::e_string,lexer::token::e_number); - add_invalid(lexer::token::e_number,lexer::token::e_colon); - add_invalid(lexer::token::e_symbol,lexer::token::e_colon); add_invalid(lexer::token::e_string,lexer::token::e_colon); - add_invalid(lexer::token::e_colon,lexer::token::e_number); - add_invalid(lexer::token::e_colon,lexer::token::e_symbol); add_invalid(lexer::token::e_colon,lexer::token::e_string); add_invalid_set1(lexer::token::e_assign); add_invalid_set1(lexer::token::e_shr); @@ -2494,7 +2493,6 @@ namespace exprtk set_t::value_type p = std::make_pair(t0.type,t1.type); if (invalid_bracket_check(t0.type,t1.type)) { - invalid_bracket_check(t0.type,t1.type); error_list_.push_back(std::make_pair(t0,t1)); } else if (invalid_comb_.find(p) != invalid_comb_.end()) @@ -2555,17 +2553,11 @@ namespace exprtk { if (details::is_right_bracket(static_cast(base))) { - if (details::is_left_bracket(static_cast(t))) - return true; - else + switch (t) { - switch (t) - { - case lexer::token::e_string : return true; - case lexer::token::e_assign : return true; - case lexer::token::e_colon : return true; - default : return false; - } + case lexer::token::e_string : return true; + case lexer::token::e_assign : return true; + default : return false; } } else if (details::is_left_bracket(static_cast(base))) @@ -2594,6 +2586,7 @@ namespace exprtk case lexer::token::e_number : return false; case lexer::token::e_symbol : return false; case lexer::token::e_string : return false; + case lexer::token::e_eof : return false; default : return true; } } @@ -2605,7 +2598,6 @@ namespace exprtk case lexer::token::e_rbracket : return true; case lexer::token::e_rsqrbracket : return true; case lexer::token::e_rcrlbracket : return true; - case lexer::token::e_colon : return true; default : return false; } } @@ -2996,28 +2988,29 @@ namespace exprtk e_none , e_null , e_constant , e_unary , e_binary , e_binary_ext , e_trinary , e_quaternary , e_quinary , e_senary , e_vararg , e_conditional , - e_while , e_variable , e_stringvar , e_stringconst , - e_function , e_vafunction , e_add , e_sub , - e_mul , e_div , e_mod , e_pow , - e_lt , e_lte , e_gt , e_gte , - e_eq , e_ne , e_and , e_nand , - e_or , e_nor , e_xor , e_xnor , - e_in , e_like , e_ilike , e_inranges , - e_ipow , e_ipowinv , e_abs , e_acos , - e_asin , e_atan , e_ceil , e_cos , - e_cosh , e_exp , e_floor , e_log , - e_log10 , e_log2 , e_log1p , e_neg , - e_pos , e_round , e_sin , e_sinh , - e_sqrt , e_tan , e_tanh , e_cot , - e_sec , e_csc , e_r2d , e_d2r , - e_d2g , e_g2d , e_notl , e_sgn , - e_erf , e_erfc , e_frac , e_trunc , - e_uvouv , e_vov , e_cov , e_voc , - e_vob , e_bov , e_cob , e_boc , - e_vovov , e_vovoc , 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_while , e_switch , e_variable , e_stringvar , + e_stringconst , e_function , e_vafunction , e_add , + e_sub , e_mul , e_div , e_mod , + e_pow , e_lt , e_lte , e_gt , + e_gte , e_eq , e_ne , e_and , + e_nand , e_or , e_nor , e_xor , + e_xnor , e_in , e_like , e_ilike , + e_inranges , e_ipow , e_ipowinv , e_abs , + e_acos , e_asin , e_atan , e_ceil , + e_cos , e_cosh , e_exp , e_floor , + e_log , e_log10 , e_log2 , e_log1p , + e_neg , e_pos , e_round , e_sin , + e_sinh , e_sqrt , e_tan , e_tanh , + e_cot , e_sec , e_csc , e_r2d , + e_d2r , e_d2g , e_g2d , e_notl , + e_sgn , e_erf , e_erfc , e_frac , + e_trunc , e_uvouv , e_vov , e_cov , + e_voc , e_vob , e_bov , e_cob , + e_boc , e_vovov , e_vovoc , 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 }; typedef T value_type; @@ -3792,6 +3785,83 @@ namespace exprtk bool branch_deletable_; }; + template + class switch_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + switch_node(const Sequence& arglist) + { + if (1 != (arglist.size() & 1)) + return; + arg_list_.resize(arglist.size()); + delete_branch_.resize(arglist.size()); + for (std::size_t i = 0; i < arglist.size(); ++i) + { + if (arglist[i]) + { + arg_list_[i] = arglist[i]; + delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); + } + else + { + arg_list_.clear(); + delete_branch_.clear(); + return; + } + } + } + + ~switch_node() + { + for (std::size_t i = 0; i < arg_list_.size(); ++i) + { + if (arg_list_[i] && delete_branch_[i]) + { + delete arg_list_[i]; + arg_list_[i] = 0; + } + } + } + + inline T value() const + { + if (!arg_list_.empty()) + { + if (1 != (arg_list_.size() & 1)) + { + return std::numeric_limits::quiet_NaN(); + } + for (std::size_t i = 0; i < arg_list_.size() / 2; ++i) + { + expression_ptr condition = arg_list_[(2 * i) ]; + expression_ptr consequent = arg_list_[(2 * i) + 1]; + if (is_true(condition)) + { + return consequent->value(); + } + } + return arg_list_.back()->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_switch; + } + + private: + + std::vector arg_list_; + std::vector delete_branch_; + }; + template class variable_node : public expression_node { @@ -4054,7 +4124,6 @@ namespace exprtk template struct sfext42_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x + (y / (z * w)); } static inline std::string id() { return "t+(t/(t*t))";} }; template struct sfext43_op : public sf_base { typedef typename sf_base::Type Type; static inline T process(Type x, Type y, Type z, Type w) { return x - (y / (z * w)); } static inline std::string id() { return "t-(t/(t*t))";} }; - template class sf3_node : public trinary_node { @@ -6497,7 +6566,7 @@ namespace exprtk template inline bool is_sf3ext_node(const expression_node* n) { - switch(n->type()) + switch (n->type()) { case expression_node::e_vovov : return true; case expression_node::e_vovoc : return true; @@ -6678,7 +6747,7 @@ namespace exprtk template inline bool is_sf4ext_node(const expression_node* n) { - switch(n->type()) + switch (n->type()) { case expression_node::e_vovovov : return true; case expression_node::e_vovovoc : return true; @@ -9454,9 +9523,9 @@ namespace exprtk set_error( make_error(parser_error::e_token, error_token.first, - "ERR06 - Invalid token sequence: " + - error_token.first.value + " " + - error_token.second.value)); + "ERR06 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'")); } } } @@ -9846,7 +9915,6 @@ namespace exprtk scoped_vec_delete& operator=(const scoped_vec_delete&); }; - template inline expression_node_ptr parse_function_call(const details::operator_type& opt_type, bool& internal_error) { @@ -9954,8 +10022,8 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR11 - Expecting '()' to proceed: '" + function_name + "'")); + current_token_, + "ERR11 - Expecting '()' to proceed: '" + function_name + "'")); return error_node(); } else @@ -10109,6 +10177,104 @@ namespace exprtk return result; } + inline expression_node_ptr parse_switch_statement() + { + std::vector arg_list; + expression_node_ptr result = error_node(); + + const std::string symbol = current_token_.value; + + scoped_vec_delete sdd(*this,arg_list); + + next_token(); + if (!token_is(token_t::e_lcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR21 - Expected '{' for call to switch statement.")); + return error_node(); + } + + for (;;) + { + if (!details::imatch("case",current_token_.value)) + return error_node(); + + next_token(); + + expression_node_ptr condition = parse_expression(); + if (0 == condition) + return error_node(); + + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR22 - Expected ':' for case of switch statement.")); + return error_node(); + } + + expression_node_ptr consequent = parse_expression(); + if (0 == consequent) + return error_node(); + + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR23 - Expected ';' at end of case for switch statement.")); + return error_node(); + } + + arg_list.push_back(condition); + arg_list.push_back(consequent); + + if (details::imatch("default",current_token_.value)) + { + next_token(); + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR24 - Expected ':' for default of switch statement.")); + return error_node(); + } + + expression_node_ptr default_statement = parse_expression(); + if (0 == default_statement) + return error_node(); + else if (!token_is(token_t::e_eof)) + { + set_error(make_error(parser_error::e_syntax, + current_token_, + "ERR25 - Expected ';' at end of default for switch statement.")); + return error_node(); + } + + arg_list.push_back(default_statement); + break; + } + } + + if (!token_is(token_t::e_rcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR26 - Expected '}' at end of switch statement.")); + return error_node(); + } + + result = expression_generator_.switch_statement(arg_list); + + sdd.delete_ptr = (0 == result); + return result; + } + inline expression_node_ptr parse_vararg_function() { std::deque arg_list; @@ -10129,7 +10295,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR21 - Unsupported vararg function: " + symbol)); + "ERR26 - Unsupported vararg function: " + symbol)); return error_node(); } @@ -10141,7 +10307,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR22 - Expected '(' for call to vararg function: " + symbol)); + "ERR28 - Expected '(' for call to vararg function: " + symbol)); return error_node(); } @@ -10159,7 +10325,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR23 - Expected ',' for call to vararg function: " + symbol)); + "ERR29 - Expected ',' for call to vararg function: " + symbol)); return error_node(); } } @@ -10185,7 +10351,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR24 - Expected '(' for call to vararg function: " + vararg_function_name)); + "ERR30 - Expected '(' for call to vararg function: " + vararg_function_name)); return error_node(); } @@ -10203,7 +10369,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR25 - Expected ',' for call to vararg function: " + vararg_function_name)); + "ERR31 - Expected ',' for call to vararg function: " + vararg_function_name)); return error_node(); } } @@ -10264,7 +10430,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token_, - "ERR26 - Invalid special function[1]: " + current_token_.value)); + "ERR32 - Invalid special function[1]: " + current_token_.value)); return error_node(); } @@ -10275,7 +10441,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token_, - "ERR27 - Invalid special function[2]: " + current_token_.value)); + "ERR33 - Invalid special function[2]: " + current_token_.value)); return error_node(); } @@ -10367,7 +10533,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR28 - Invalid number of parameters for function: " + symbol)); + "ERR34 - Invalid number of parameters for function: " + symbol)); return error_node(); } } @@ -10379,7 +10545,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR29 - Failed to generate node for function: '" + symbol + "'")); + "ERR35 - Failed to generate node for function: '" + symbol + "'")); return error_node(); } } @@ -10399,7 +10565,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR30 - Failed to generate node for vararg function: '" + symbol + "'")); + "ERR36 - Failed to generate node for vararg function: '" + symbol + "'")); return error_node(); } } @@ -10408,16 +10574,17 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR31 - Undefined variable or function: '" + symbol + "'")); + "ERR37 - 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_null = "null"; + static const std::string symbol_if = "if"; + static const std::string symbol_while = "while"; + static const std::string symbol_switch = "switch"; + static const std::string symbol_null = "null"; if (valid_vararg_operation(current_token_.value)) { @@ -10435,6 +10602,10 @@ namespace exprtk { return parse_while_loop(); } + else if (details::imatch(current_token_.value,symbol_switch)) + { + return parse_switch_statement(); + } else if (details::is_valid_sf_symbol(current_token_.value)) { return parse_special_function(); @@ -10452,7 +10623,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token_, - "ERR32 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); + "ERR38 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); return error_node(); } } @@ -10527,7 +10698,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR33 - Premature end of expression.[1]")); + "ERR39 - Premature end of expression.[1]")); return error_node(); } else @@ -10535,7 +10706,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR34 - Premature end of expression.[2]")); + "ERR40 - Premature end of expression.[2]")); return error_node(); } } @@ -11156,6 +11327,52 @@ namespace exprtk return node_allocator_->allocate(condition,branch); } + template class Sequence> + inline expression_node_ptr const_optimize_switch(Sequence& arglist) + { + expression_node_ptr result = error_node(); + for (std::size_t i = 0; i < (arglist.size() / 2); ++i) + { + expression_node_ptr condition = arglist[(2 * i) ]; + expression_node_ptr consequent = arglist[(2 * i) + 1]; + if ((0 == result) && details::is_true(condition)) + { + result = consequent; + free_node(*node_allocator_,arglist[2 * i]); + break; + } + else + { + free_node(*node_allocator_,arglist[(2 * i) ]); + free_node(*node_allocator_,arglist[(2 * i) + 1]); + } + } + + if (result) + { + free_node(*node_allocator_,arglist.back()); + return result; + } + else + return arglist.back(); + } + + template class Sequence> + inline expression_node_ptr switch_statement(Sequence& arglist) + { + if (!all_nodes_valid(arglist)) + { + details::free_all_nodes(*node_allocator_,arglist); + return error_node(); + } + else if (is_constant_foldable(arglist)) + return const_optimize_switch(arglist); + else + return node_allocator_->allocate >(arglist); + } + #define unary_opr_switch_statements \ case_stmt(details:: e_abs,details:: abs_op) \ case_stmt(details:: e_acos,details:: acos_op) \ @@ -11455,7 +11672,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr const_optimize_varargfunc(const details::operator_type& operation, Sequence& arglist) { expression_node_ptr temp_node = error_node(); @@ -11692,7 +11909,7 @@ namespace exprtk template