diff --git a/Makefile b/Makefile index 458f8ce..d2b94e6 100644 --- a/Makefile +++ b/Makefile @@ -103,20 +103,20 @@ strip_bin: strip -s exprtk_simple_example_12 valgrind_check: - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_test - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_benchmark - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_01 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_02 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_03 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_04 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_05 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_06 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_07 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_08 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_09 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_10 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_11 - valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_12 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_test_valgrind.log -v ./exprtk_test + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_benchmark_valgrind.log -v ./exprtk_benchmark + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_01_valgrind.log -v ./exprtk_simple_example_01 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_02_valgrind.log -v ./exprtk_simple_example_02 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_03_valgrind.log -v ./exprtk_simple_example_03 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_04_valgrind.log -v ./exprtk_simple_example_04 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_05_valgrind.log -v ./exprtk_simple_example_05 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_06_valgrind.log -v ./exprtk_simple_example_06 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_07_valgrind.log -v ./exprtk_simple_example_07 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_08_valgrind.log -v ./exprtk_simple_example_08 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_09_valgrind.log -v ./exprtk_simple_example_09 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_10_valgrind.log -v ./exprtk_simple_example_10 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_11_valgrind.log -v ./exprtk_simple_example_11 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_12_valgrind.log -v ./exprtk_simple_example_12 clean: rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch diff --git a/exprtk.hpp b/exprtk.hpp index 32f3307..ab4b646 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -181,14 +181,13 @@ namespace exprtk { std::string::iterator itr1 = s.begin(); std::string::iterator itr2 = s.begin(); - std::string::iterator end = s.end(); - std::size_t removal_count = 0; + std::string::iterator end = s.end (); + std::size_t removal_count = 0; + while (end != itr1) { - bool bypass = false; if ('\\' == (*itr1)) { - bypass = true; ++removal_count; if (end == ++itr1) break; @@ -202,20 +201,17 @@ namespace exprtk } continue; } - else - bypass = false; } - if (!bypass) + if (itr1 != itr2) { - if (itr1 != itr2) - { - (*itr2) = (*itr1); - } - ++itr1; - ++itr2; + (*itr2) = (*itr1); } + + ++itr1; + ++itr2; } + s.resize(s.size() - removal_count); } @@ -262,9 +258,11 @@ namespace exprtk const std::size_t length = std::min(s1.size(),s2.size()); for (std::size_t i = 0; i < length; ++i) { - if (std::tolower(s1[i]) > std::tolower(s2[i])) + const char c1 = std::tolower(s1[i]); + const char c2 = std::tolower(s2[i]); + if (c1 > c2) return false; - else if (std::tolower(s1[i]) < std::tolower(s2[i])) + else if (c1 < c2) return true; } return s1.size() < s2.size(); @@ -275,7 +273,8 @@ namespace exprtk { "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", "&", "|" + "shl", "shr", "swap", "switch", "true", "until", "var", "while", "xnor", + "xor", "&", "|" }; static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); @@ -289,8 +288,8 @@ namespace exprtk "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", "sinc", "sinh", "sqrt", - "sum", "switch", "tan", "tanh", "true", "trunc", "until", "while", "xnor", "xor", - "&", "|" + "sum", "swap", "switch", "tan", "tanh", "true", "trunc", "until", "var", "while", + "xnor", "xor", "&", "|" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); @@ -1084,6 +1083,7 @@ namespace exprtk { unsigned int k = N; T l = T(1); + while (k) { if (k & 1) @@ -1091,9 +1091,11 @@ namespace exprtk l *= v; --k; } + v *= v; k >>= 1; } + return l; } }; @@ -1224,12 +1226,18 @@ namespace exprtk return false; if (static_cast('n') == (*itr)) { - if ((static_cast('a') != *(itr + 1)) || (static_cast('n') != *(itr + 2))) + if ( + (static_cast('a') != *(itr + 1)) || + (static_cast('n') != *(itr + 2)) + ) { return false; } } - else if ((static_cast('A') != *(itr + 1)) || (static_cast('N') != *(itr + 2))) + else if ( + (static_cast('A') != *(itr + 1)) || + (static_cast('N') != *(itr + 2)) + ) { return false; } @@ -1457,6 +1465,8 @@ namespace exprtk 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, + 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, + 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, @@ -1525,14 +1535,15 @@ namespace exprtk e_eof = 6, e_number = 7, e_symbol = 8, e_string = 9, e_assign = 10, e_addass = 11, e_subass = 12, e_mulass = 13, e_divass = 14, - e_shr = 15, e_shl = 16, e_lte = 17, - e_ne = 18, e_gte = 19, e_lt = '<', - e_gt = '>', e_eq = '=', e_rbracket = ')', - e_lbracket = '(', e_rsqrbracket = ']', e_lsqrbracket = '[', - e_rcrlbracket = '}', e_lcrlbracket = '{', e_comma = ',', - e_add = '+', e_sub = '-', e_div = '/', - e_mul = '*', e_mod = '%', e_pow = '^', - e_colon = ':', e_ternary = '?' + e_modass = 15, e_shr = 16, e_shl = 17, + e_lte = 18, e_ne = 19, e_gte = 20, + e_swap = 21, e_lt = '<', e_gt = '>', + e_eq = '=', e_rbracket = ')', e_lbracket = '(', + e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}', + e_lcrlbracket = '{', e_comma = ',', e_add = '+', + e_sub = '-', e_div = '/', e_mul = '*', + e_mod = '%', e_pow = '^', e_colon = ':', + e_ternary = '?' }; token() @@ -1635,6 +1646,7 @@ namespace exprtk case e_subass : return "-="; case e_mulass : return "*="; case e_divass : return "/="; + case e_modass : return "%="; case e_shr : return ">>"; case e_shl : return "<<"; case e_lte : return "<="; @@ -1658,6 +1670,7 @@ namespace exprtk case e_pow : return "^"; case e_colon : return ":"; case e_ternary : return "?"; + case e_swap : return "<=>"; default : return "UNKNOWN"; } } @@ -1683,8 +1696,8 @@ namespace exprtk public: typedef token token_t; - typedef std::deque token_list_t; - typedef std::deque::iterator token_list_itr_t; + typedef std::vector token_list_t; + typedef std::vector::iterator token_list_itr_t; generator() : base_itr_(0), @@ -1912,11 +1925,27 @@ namespace exprtk { token_t t; + const char c0 = s_itr_[0]; + if (!is_end(s_itr_ + 1)) { + const char c1 = s_itr_[1]; + + if (!is_end(s_itr_ + 2)) + { + const char c2 = s_itr_[2]; + + if ((c0 == '<') && (c1 == '=') && (c2 == '>')) + { + t.set_operator(token_t::e_swap,s_itr_,s_itr_ + 3,base_itr_); + token_list_.push_back(t); + s_itr_ += 3; + return; + } + } + token_t::token_type ttype = token_t::e_none; - char c0 = s_itr_[0]; - char c1 = s_itr_[1]; + if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; @@ -1929,6 +1958,7 @@ namespace exprtk else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; + else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; if (token_t::e_none != ttype) { @@ -1938,18 +1968,19 @@ namespace exprtk return; } } - if ('<' == *s_itr_) + + if ('<' == c0) t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_); - else if ('>' == *s_itr_) + else if ('>' == c0) t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_); - else if (';' == *s_itr_) + else if (';' == c0) t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_); - else if ('&' == *s_itr_) + else if ('&' == c0) t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); - else if ('|' == *s_itr_) + else if ('|' == c0) t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); else - t.set_operator(token_t::token_type(*s_itr_),s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::token_type(c0),s_itr_,s_itr_ + 1,base_itr_); token_list_.push_back(t); ++s_itr_; } @@ -2401,7 +2432,7 @@ namespace exprtk for (std::size_t i = 0; i < g.token_list_.size() - 1; ++i) { token t; - if (join(g.token_list_[i],g.token_list_[i + 1],t)) + while (join(g.token_list_[i],g.token_list_[i + 1],t)) { g.token_list_[i] = t; g.token_list_.erase(g.token_list_.begin() + (i + 1)); @@ -2420,7 +2451,7 @@ namespace exprtk for (std::size_t i = 0; i < g.token_list_.size() - 2; ++i) { token t; - if (join(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t)) + while (join(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t)) { g.token_list_[i] = t; g.token_list_.erase(g.token_list_.begin() + (i + 1), @@ -2560,6 +2591,14 @@ namespace exprtk t.position = t0.position; return true; } + // '% =' --> '%=' + else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq)) + { + t.type = lexer::token::e_modass; + t.value = "%="; + t.position = t0.position; + return true; + } // '> =' --> '>=' else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq)) { @@ -2600,12 +2639,21 @@ namespace exprtk t.position = t0.position; return true; } + // '<= >' --> '<=>' + else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt)) + { + t.type = lexer::token::e_swap; + t.value = "<=>"; + t.position = t0.position; + return true; + } else return false; } inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t) { + // '[ * ]' --> '[*]' if ( (t0.type == lexer::token::e_lsqrbracket) && (t1.type == lexer::token::e_mul ) && @@ -2751,7 +2799,7 @@ namespace exprtk private: std::size_t current_index_; - std::deque error_list_; + std::vector error_list_; }; class symbol_replacer : public lexer::token_modifier @@ -2797,7 +2845,9 @@ namespace exprtk { if (replace_map_.empty()) return false; + replace_map_t::iterator itr = replace_map_.find(t.value); + if (replace_map_.end() != itr) { t.value = itr->second.first; @@ -2925,8 +2975,8 @@ namespace exprtk { switch (t) { - case lexer::token::e_string : return true; case lexer::token::e_assign : return (']' != base); + case lexer::token::e_string : return true; default : return false; } } @@ -2979,7 +3029,7 @@ namespace exprtk } set_t invalid_comb_; - std::deque > error_list_; + std::vector > error_list_; }; @@ -3019,6 +3069,7 @@ namespace exprtk { return false; } + token_joiner_list.push_back(joiner); return true; } @@ -3031,6 +3082,7 @@ namespace exprtk { return false; } + token_inserter_list.push_back(inserter); return true; } @@ -3043,8 +3095,10 @@ namespace exprtk for (std::size_t i = 0; i < token_modifier_list.size(); ++i) { lexer::token_modifier& modifier = (*token_modifier_list[i]); + modifier.reset(); modifier.process(g); + if (!modifier.result()) { error_token_modifier = token_modifier_list[i]; @@ -3063,8 +3117,10 @@ namespace exprtk for (std::size_t i = 0; i < token_joiner_list.size(); ++i) { lexer::token_joiner& joiner = (*token_joiner_list[i]); + joiner.reset(); joiner.process(g); + if (!joiner.result()) { error_token_joiner = token_joiner_list[i]; @@ -3083,8 +3139,10 @@ namespace exprtk for (std::size_t i = 0; i < token_inserter_list.size(); ++i) { lexer::token_inserter& inserter = (*token_inserter_list[i]); + inserter.reset(); inserter.process(g); + if (!inserter.result()) { error_token_inserter = token_inserter_list[i]; @@ -3103,8 +3161,10 @@ namespace exprtk for (std::size_t i = 0; i < token_scanner_list.size(); ++i) { lexer::token_scanner& scanner = (*token_scanner_list[i]); + scanner.reset(); scanner.process(g); + if (!scanner.result()) { error_token_scanner = token_scanner_list[i]; @@ -3115,10 +3175,10 @@ namespace exprtk return result; } - std::deque token_scanner_list; - std::deque token_modifier_list; - std::deque token_joiner_list; - std::deque token_inserter_list; + std::vector token_scanner_list; + std::vector token_modifier_list; + std::vector token_joiner_list; + std::vector token_inserter_list; lexer::token_scanner* error_token_scanner; lexer::token_modifier* error_token_modifier; @@ -3153,8 +3213,8 @@ namespace exprtk e_d2g , e_g2d , e_hypot , e_notl , e_erf , e_erfc , e_frac , e_trunc , e_assign , e_addass , e_subass , e_mulass , - e_divass , e_in , e_like , e_ilike , - e_multi , + e_divass , e_modass , e_in , e_like , + e_ilike , e_multi , e_swap , // Do not add new functions/operators after this point. e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, @@ -3182,7 +3242,7 @@ namespace exprtk e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, - e_sffinal = 1100, + e_sffinal = 1100, e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, @@ -3406,7 +3466,8 @@ namespace exprtk 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_break , e_continue + e_vecelem , e_vecass , e_break , e_continue , + e_swap }; typedef T value_type; @@ -3443,7 +3504,7 @@ namespace exprtk inline bool is_true(const long double v) { - return (0.0 != v); + return (0.0L != v); } inline bool is_true(const float v) @@ -3481,6 +3542,16 @@ namespace exprtk return node && (details::expression_node::e_variable == node->type()); } + template + inline bool is_ivariable_node(const expression_node* node) + { + return node && + ( + details::expression_node::e_variable == node->type() || + details::expression_node::e_vecelem == node->type() + ); + } + template inline bool is_vector_node(const expression_node* node) { @@ -3511,6 +3582,12 @@ namespace exprtk return node && (details::expression_node::e_continue == node->type()); } + template + inline bool is_swap_node(const expression_node* node) + { + return node && (details::expression_node::e_swap == node->type()); + } + template inline bool is_function(const expression_node* node) { @@ -4226,6 +4303,7 @@ namespace exprtk class cons_conditional_node : public expression_node { public: + // Consequent only conditional statement node typedef expression_node* expression_ptr; @@ -4443,29 +4521,25 @@ namespace exprtk typedef expression_node* expression_ptr; - for_loop_node(expression_ptr initializer, + for_loop_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, - expression_ptr loop_body, - expression_ptr loop_var, - T* loop_counter_var = 0) - : initializer_(initializer), + expression_ptr loop_body) + : initialiser_(initialiser), condition_ (condition), incrementor_(incrementor), loop_body_ (loop_body), - loop_var_ (loop_var), - initializer_deletable_(branch_deletable(initializer_)), + initialiser_deletable_(branch_deletable(initialiser_)), condition_deletable_ (branch_deletable(condition_ )), incrementor_deletable_(branch_deletable(incrementor_)), - loop_body_deletable_ (branch_deletable(loop_body_ )), - loop_counter_var_(loop_counter_var) + loop_body_deletable_ (branch_deletable(loop_body_ )) {} ~for_loop_node() { - if (initializer_ && initializer_deletable_) + if (initialiser_ && initialiser_deletable_) { - delete initializer_; + delete initialiser_; } if (condition_ && condition_deletable_) @@ -4482,24 +4556,14 @@ namespace exprtk { 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 (initialiser_) + initialiser_->value(); if (incrementor_) { @@ -4527,16 +4591,14 @@ namespace exprtk private: - expression_ptr initializer_; + expression_ptr initialiser_; expression_ptr condition_ ; expression_ptr incrementor_; expression_ptr loop_body_ ; - expression_ptr loop_var_ ; - bool initializer_deletable_; + bool initialiser_deletable_; bool condition_deletable_ ; bool incrementor_deletable_; bool loop_body_deletable_ ; - T* loop_counter_var_; }; #ifndef exprtk_disable_break_continue @@ -4666,29 +4728,25 @@ namespace exprtk typedef expression_node* expression_ptr; - for_loop_bc_node(expression_ptr initializer, + for_loop_bc_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, - expression_ptr loop_body, - expression_ptr loop_var, - T* loop_counter_var = 0) - : initializer_(initializer), + expression_ptr loop_body) + : initialiser_(initialiser), condition_ (condition), incrementor_(incrementor), loop_body_ (loop_body), - loop_var_ (loop_var), - initializer_deletable_(branch_deletable(initializer_)), + initialiser_deletable_(branch_deletable(initialiser_)), condition_deletable_ (branch_deletable(condition_ )), incrementor_deletable_(branch_deletable(incrementor_)), - loop_body_deletable_ (branch_deletable(loop_body_ )), - loop_counter_var_(loop_counter_var) + loop_body_deletable_ (branch_deletable(loop_body_ )) {} ~for_loop_bc_node() { - if (initializer_ && initializer_deletable_) + if (initialiser_ && initialiser_deletable_) { - delete initializer_; + delete initialiser_; } if (condition_ && condition_deletable_) @@ -4705,24 +4763,14 @@ namespace exprtk { 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 (initialiser_) + initialiser_->value(); if (incrementor_) { @@ -4768,16 +4816,14 @@ namespace exprtk private: - expression_ptr initializer_; + expression_ptr initialiser_; expression_ptr condition_ ; expression_ptr incrementor_; expression_ptr loop_body_ ; - expression_ptr loop_var_ ; - bool initializer_deletable_; + bool initialiser_deletable_; bool condition_deletable_ ; bool incrementor_deletable_; bool loop_body_deletable_ ; - T* loop_counter_var_; }; #endif @@ -4790,17 +4836,17 @@ namespace exprtk template class Sequence> - switch_node(const Sequence& arglist) + switch_node(const Sequence& arg_list) { - if (1 != (arglist.size() & 1)) + if (1 != (arg_list.size() & 1)) return; - arg_list_.resize(arglist.size()); - delete_branch_.resize(arglist.size()); - for (std::size_t i = 0; i < arglist.size(); ++i) + arg_list_.resize(arg_list.size()); + delete_branch_.resize(arg_list.size()); + for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arglist[i]) + if (arg_list[i]) { - arg_list_[i] = arglist[i]; + arg_list_[i] = arg_list[i]; delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); } else @@ -4869,17 +4915,17 @@ namespace exprtk template class Sequence> - multi_switch_node(const Sequence& arglist) + multi_switch_node(const Sequence& arg_list) { - if (0 != (arglist.size() & 1)) + if (0 != (arg_list.size() & 1)) return; - arg_list_.resize(arglist.size()); - delete_branch_.resize(arglist.size()); - for (std::size_t i = 0; i < arglist.size(); ++i) + arg_list_.resize(arg_list.size()); + delete_branch_.resize(arg_list.size()); + for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arglist[i]) + if (arg_list[i]) { - arg_list_[i] = arglist[i]; + arg_list_[i] = arg_list[i]; delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); } else @@ -4940,20 +4986,40 @@ namespace exprtk }; template - class variable_node : public expression_node + class ivariable + { + public: + + virtual T& ref() = 0; + virtual const T& ref() const = 0; + }; + + template + class variable_node : public expression_node, + public ivariable { public: static T null_value; explicit variable_node() - : value_(&null_value) + : value_(&null_value), + delete_value_(false) {} - explicit variable_node(T& value) - : value_(&value) + variable_node(T& value) + : value_(&value), + delete_value_(false) {} + ~variable_node() + { + if (delete_value_) + { + delete value_; + } + } + inline bool operator <(const variable_node& v) const { return this < (&v); @@ -4979,13 +5045,23 @@ namespace exprtk return expression_node::e_variable; } + inline bool& delete_value() + { + return delete_value_; + } + private: T* value_; + bool delete_value_; }; template - class vector_node : public expression_node + T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); + + template + class vector_node : public expression_node, + public ivariable { public: @@ -4993,12 +5069,13 @@ namespace exprtk vector_node(expression_ptr index, T* vector_base) : index_(index), - vector_base_(vector_base) + vector_base_(vector_base), + index_deletable_(branch_deletable(index_)) {} ~vector_node() { - if (index_ && !details::is_variable_node(index_)) + if (index_ && index_deletable_) { delete index_; } @@ -5028,10 +5105,158 @@ namespace exprtk expression_ptr index_; T* vector_base_; + bool index_deletable_; }; template - T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); + class vector_assignment_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_assignment_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list, + const bool single_value_initialse) + : vector_base_(vector_base), + initialiser_list_(initialiser_list), + size_(size), + single_value_initialse_(single_value_initialse) + {} + + ~vector_assignment_node() + { + for (std::size_t i = 0; i < initialiser_list_.size(); ++i) + { + if (branch_deletable(initialiser_list_[i])) + { + delete initialiser_list_[i]; + } + } + } + + inline T value() const + { + if (single_value_initialse_) + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = initialiser_list_[0]->value(); + } + } + else + { + for (std::size_t i = 0; i < initialiser_list_.size(); ++i) + { + *(vector_base_ + i) = initialiser_list_[i]->value(); + } + + if (initialiser_list_.size() < size_) + { + for (std::size_t i = initialiser_list_.size() - 1; i < size_; ++i) + { + *(vector_base_ + i) = T(0); + } + } + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecass; + } + + private: + + mutable T* vector_base_; + std::vector initialiser_list_; + const std::size_t size_; + const bool single_value_initialse_; + }; + + template + class swap_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef variable_node* variable_node_ptr; + + swap_node(variable_node_ptr var0, variable_node_ptr var1) + : var0_(var0), + var1_(var1) + {} + + inline T value() const + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_swap; + } + + private: + + variable_node_ptr var0_; + variable_node_ptr var1_; + }; + + template + class swap_generic_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef ivariable* ivariable_ptr; + + swap_generic_node(expression_ptr var0, expression_ptr var1) + : var0_(dynamic_cast(var0)), + var1_(dynamic_cast(var1)), + v0_ (var0), + v1_ (var1), + var0_deletable_(branch_deletable(v0_)), + var1_deletable_(branch_deletable(v1_)) + {} + + ~swap_generic_node() + { + if (var0_deletable_) + { + delete v0_; + } + + if (var1_deletable_) + { + delete v1_; + } + } + + inline T value() const + { + std::swap(var0_->ref(),var1_->ref()); + return var1_->ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_swap; + } + + private: + + ivariable_ptr var0_; + ivariable_ptr var1_; + expression_ptr v0_; + expression_ptr v1_; + bool var0_deletable_; + bool var1_deletable_; + }; #ifndef exprtk_disable_string_capabilities template @@ -5499,15 +5724,15 @@ namespace exprtk template class Sequence> - vararg_node(const Sequence& arglist) + vararg_node(const Sequence& arg_list) { - arg_list_.resize(arglist.size()); - delete_branch_.resize(arglist.size()); - for (std::size_t i = 0; i < arglist.size(); ++i) + arg_list_.resize(arg_list.size()); + delete_branch_.resize(arg_list.size()); + for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arglist[i]) + if (arg_list[i]) { - arg_list_[i] = arglist[i]; + arg_list_[i] = arg_list[i]; delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); } else @@ -5559,14 +5784,14 @@ namespace exprtk template class Sequence> - vararg_varnode(const Sequence& arglist) + vararg_varnode(const Sequence& arg_list) { - arg_list_.resize(arglist.size()); - for (std::size_t i = 0; i < arglist.size(); ++i) + arg_list_.resize(arg_list.size()); + for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (arglist[i] && is_variable_node(arglist[i])) + if (arg_list[i] && is_variable_node(arg_list[i])) { - variable_node* var_node_ptr = dynamic_cast*>(arglist[i]); + variable_node* var_node_ptr = dynamic_cast*>(arg_list[i]); arg_list_[i] = (&var_node_ptr->ref()); } else @@ -6472,22 +6697,22 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { case 0 : return T(0); - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); default : { T result = T(0); - for (std::size_t i = 0; i < arglist.size(); ++i) + for (std::size_t i = 0; i < arg_list.size(); ++i) { - result += value(arglist[i]); + result += value(arg_list[i]); } return result; } @@ -6495,37 +6720,37 @@ namespace exprtk } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return value(arglist[0]); + return value(arg_list[0]); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { - return value(arglist[0]) + value(arglist[1]); + return value(arg_list[0]) + value(arg_list[1]); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { - return value(arglist[0]) + value(arglist[1]) + - value(arglist[2]); + return value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { - return value(arglist[0]) + value(arglist[1]) + - value(arglist[2]) + value(arglist[3]); + return value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3]); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { - return value(arglist[0]) + value(arglist[1]) + - value(arglist[2]) + value(arglist[3]) + - value(arglist[4]); + return value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3]) + + value(arg_list[4]); } }; @@ -6537,22 +6762,22 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { case 0 : return T(0); - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); default : { - T result = T(value(arglist[0])); - for (std::size_t i = 1; i < arglist.size(); ++i) + T result = T(value(arg_list[0])); + for (std::size_t i = 1; i < arg_list.size(); ++i) { - result *= value(arglist[i]); + result *= value(arg_list[i]); } return result; } @@ -6560,37 +6785,37 @@ namespace exprtk } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return value(arglist[0]); + return value(arg_list[0]); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { - return value(arglist[0]) * value(arglist[1]); + return value(arg_list[0]) * value(arg_list[1]); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { - return value(arglist[0]) * value(arglist[1]) * - value(arglist[2]); + return value(arg_list[0]) * value(arg_list[1]) * + value(arg_list[2]); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { - return value(arglist[0]) * value(arglist[1]) * - value(arglist[2]) * value(arglist[3]); + return value(arg_list[0]) * value(arg_list[1]) * + value(arg_list[2]) * value(arg_list[3]); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { - return value(arglist[0]) * value(arglist[1]) * - value(arglist[2]) * value(arglist[3]) * - value(arglist[4]); + return value(arg_list[0]) * value(arg_list[1]) * + value(arg_list[2]) * value(arg_list[3]) * + value(arg_list[4]); } }; @@ -6602,51 +6827,51 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { case 0 : return T(0); - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); - default : return vararg_add_op::process(arglist) / arglist.size(); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + default : return vararg_add_op::process(arg_list) / arg_list.size(); } } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return value(arglist[0]); + return value(arg_list[0]); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { - return (value(arglist[0]) + value(arglist[1])) / T(2); + return (value(arg_list[0]) + value(arg_list[1])) / T(2); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { - return (value(arglist[0]) + value(arglist[1]) + value(arglist[2])) / T(3); + return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2])) / T(3); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { - return (value(arglist[0]) + value(arglist[1]) + - value(arglist[2]) + value(arglist[3])) / T(4); + return (value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3])) / T(4); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { - return (value(arglist[0]) + value(arglist[1]) + - value(arglist[2]) + value(arglist[3]) + - value(arglist[4])) / T(5); + return (value(arg_list[0]) + value(arg_list[1]) + + value(arg_list[2]) + value(arg_list[3]) + + value(arg_list[4])) / T(5); } }; @@ -6658,22 +6883,22 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { case 0 : return T(0); - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); default : { - T result = T(value(arglist[0])); - for (std::size_t i = 1; i < arglist.size(); ++i) + T result = T(value(arg_list[0])); + for (std::size_t i = 1; i < arg_list.size(); ++i) { - const T v = value(arglist[i]); + const T v = value(arg_list[i]); if (v < result) result = v; } @@ -6683,38 +6908,38 @@ namespace exprtk } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return value(arglist[0]); + return value(arg_list[0]); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { - return std::min(value(arglist[0]),value(arglist[1])); + return std::min(value(arg_list[0]),value(arg_list[1])); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { - return std::min(std::min(value(arglist[0]),value(arglist[1])),value(arglist[2])); + return std::min(std::min(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { return std::min( - std::min(value(arglist[0]),value(arglist[1])), - std::min(value(arglist[2]),value(arglist[3]))); + std::min(value(arg_list[0]),value(arg_list[1])), + std::min(value(arg_list[2]),value(arg_list[3]))); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { return std::min( - std::min(std::min(value(arglist[0]),value(arglist[1])), - std::min(value(arglist[2]),value(arglist[3]))), - value(arglist[4])); + std::min(std::min(value(arg_list[0]),value(arg_list[1])), + std::min(value(arg_list[2]),value(arg_list[3]))), + value(arg_list[4])); } }; @@ -6726,22 +6951,22 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { case 0 : return T(0); - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); default : { - T result = T(value(arglist[0])); - for (std::size_t i = 1; i < arglist.size(); ++i) + T result = T(value(arg_list[0])); + for (std::size_t i = 1; i < arg_list.size(); ++i) { - const T v = value(arglist[i]); + const T v = value(arg_list[i]); if (v > result) result = v; } @@ -6751,38 +6976,38 @@ namespace exprtk } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return value(arglist[0]); + return value(arg_list[0]); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { - return std::max(value(arglist[0]),value(arglist[1])); + return std::max(value(arg_list[0]),value(arg_list[1])); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { - return std::max(std::max(value(arglist[0]),value(arglist[1])),value(arglist[2])); + return std::max(std::max(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { return std::max( - std::max(value(arglist[0]),value(arglist[1])), - std::max(value(arglist[2]),value(arglist[3]))); + std::max(value(arg_list[0]),value(arg_list[1])), + std::max(value(arg_list[2]),value(arg_list[3]))); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { return std::max( - std::max(std::max(value(arglist[0]),value(arglist[1])), - std::max(value(arglist[2]),value(arglist[3]))), - value(arglist[4])); + std::max(std::max(value(arg_list[0]),value(arg_list[1])), + std::max(value(arg_list[2]),value(arg_list[3]))), + value(arg_list[4])); } }; @@ -6794,20 +7019,20 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); default : { - for (std::size_t i = 0; i < arglist.size(); ++i) + for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (T(0) == value(arglist[i])) + if (T(0) == value(arg_list[i])) return T(0); } return T(1); @@ -6816,50 +7041,50 @@ namespace exprtk } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return (T(0) != value(arglist[0])) ? T(1) : T(0); + return (T(0) != value(arg_list[0])) ? T(1) : T(0); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) && - (T(0) != value(arglist[1])) + (T(0) != value(arg_list[0])) && + (T(0) != value(arg_list[1])) ) ? T(1) : T(0); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) && - (T(0) != value(arglist[1])) && - (T(0) != value(arglist[2])) + (T(0) != value(arg_list[0])) && + (T(0) != value(arg_list[1])) && + (T(0) != value(arg_list[2])) ) ? T(1) : T(0); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) && - (T(0) != value(arglist[1])) && - (T(0) != value(arglist[2])) && - (T(0) != value(arglist[3])) + (T(0) != value(arg_list[0])) && + (T(0) != value(arg_list[1])) && + (T(0) != value(arg_list[2])) && + (T(0) != value(arg_list[3])) ) ? T(1) : T(0); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) && - (T(0) != value(arglist[1])) && - (T(0) != value(arglist[2])) && - (T(0) != value(arglist[3])) && - (T(0) != value(arglist[4])) + (T(0) != value(arg_list[0])) && + (T(0) != value(arg_list[1])) && + (T(0) != value(arg_list[2])) && + (T(0) != value(arg_list[3])) && + (T(0) != value(arg_list[4])) ) ? T(1) : T(0); } }; @@ -6872,20 +7097,20 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); default : { - for (std::size_t i = 0; i < arglist.size(); ++i) + for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (T(0) != value(arglist[i])) + if (T(0) != value(arg_list[i])) return T(1); } return T(0); @@ -6894,50 +7119,50 @@ namespace exprtk } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return (T(0) != value(arglist[0])) ? T(1) : T(0); + return (T(0) != value(arg_list[0])) ? T(1) : T(0); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) || - (T(0) != value(arglist[1])) + (T(0) != value(arg_list[0])) || + (T(0) != value(arg_list[1])) ) ? T(1) : T(0); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) || - (T(0) != value(arglist[1])) || - (T(0) != value(arglist[2])) + (T(0) != value(arg_list[0])) || + (T(0) != value(arg_list[1])) || + (T(0) != value(arg_list[2])) ) ? T(1) : T(0); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) || - (T(0) != value(arglist[1])) || - (T(0) != value(arglist[2])) || - (T(0) != value(arglist[3])) + (T(0) != value(arg_list[0])) || + (T(0) != value(arg_list[1])) || + (T(0) != value(arg_list[2])) || + (T(0) != value(arg_list[3])) ) ? T(1) : T(0); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { return ( - (T(0) != value(arglist[0])) || - (T(0) != value(arglist[1])) || - (T(0) != value(arglist[2])) || - (T(0) != value(arglist[3])) || - (T(0) != value(arglist[4])) + (T(0) != value(arg_list[0])) || + (T(0) != value(arg_list[1])) || + (T(0) != value(arg_list[2])) || + (T(0) != value(arg_list[3])) || + (T(0) != value(arg_list[4])) ) ? T(1) : T(0); } }; @@ -6950,104 +7175,104 @@ namespace exprtk template class Sequence> - static inline T process(const Sequence& arglist) + static inline T process(const Sequence& arg_list) { - switch (arglist.size()) + switch (arg_list.size()) { case 0 : return std::numeric_limits::quiet_NaN(); - case 1 : return process_1(arglist); - case 2 : return process_2(arglist); - case 3 : return process_3(arglist); - case 4 : return process_4(arglist); - case 5 : return process_5(arglist); - case 6 : return process_6(arglist); - case 7 : return process_7(arglist); - case 8 : return process_8(arglist); + case 1 : return process_1(arg_list); + case 2 : return process_2(arg_list); + case 3 : return process_3(arg_list); + case 4 : return process_4(arg_list); + case 5 : return process_5(arg_list); + case 6 : return process_6(arg_list); + case 7 : return process_7(arg_list); + case 8 : return process_8(arg_list); default : { - for (std::size_t i = 0; i < (arglist.size() - 1); ++i) + for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) { - value(arglist[i]); + value(arg_list[i]); } - return value(arglist.back()); + return value(arg_list.back()); } } } template - static inline T process_1(const Sequence& arglist) + static inline T process_1(const Sequence& arg_list) { - return value(arglist[0]); + return value(arg_list[0]); } template - static inline T process_2(const Sequence& arglist) + static inline T process_2(const Sequence& arg_list) { - value(arglist[0]); - return value(arglist[1]); + value(arg_list[0]); + return value(arg_list[1]); } template - static inline T process_3(const Sequence& arglist) + static inline T process_3(const Sequence& arg_list) { - value(arglist[0]); - value(arglist[1]); - return value(arglist[2]); + value(arg_list[0]); + value(arg_list[1]); + return value(arg_list[2]); } template - static inline T process_4(const Sequence& arglist) + static inline T process_4(const Sequence& arg_list) { - value(arglist[0]); - value(arglist[1]); - value(arglist[2]); - return value(arglist[3]); + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + return value(arg_list[3]); } template - static inline T process_5(const Sequence& arglist) + static inline T process_5(const Sequence& arg_list) { - value(arglist[0]); - value(arglist[1]); - value(arglist[2]); - value(arglist[3]); - return value(arglist[4]); + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + return value(arg_list[4]); } template - static inline T process_6(const Sequence& arglist) + static inline T process_6(const Sequence& arg_list) { - value(arglist[0]); - value(arglist[1]); - value(arglist[2]); - value(arglist[3]); - value(arglist[4]); - return value(arglist[5]); + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + return value(arg_list[5]); } template - static inline T process_7(const Sequence& arglist) + static inline T process_7(const Sequence& arg_list) { - value(arglist[0]); - value(arglist[1]); - value(arglist[2]); - value(arglist[3]); - value(arglist[4]); - value(arglist[5]); - return value(arglist[6]); + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + value(arg_list[5]); + return value(arg_list[6]); } template - static inline T process_8(const Sequence& arglist) + static inline T process_8(const Sequence& arg_list) { - value(arglist[0]); - value(arglist[1]); - value(arglist[2]); - value(arglist[3]); - value(arglist[4]); - value(arglist[5]); - value(arglist[6]); - return value(arglist[7]); + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + value(arg_list[5]); + value(arg_list[6]); + return value(arg_list[7]); } }; @@ -7526,73 +7751,73 @@ namespace exprtk template const typename expression_node::node_type nodetype_T0oT1::result = expression_node::e_none; - #define synthnode_type_define(T0_,T1_,v_) \ + #define synthesis_node_type_define(T0_,T1_,v_) \ template \ struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; \ template \ const typename expression_node::node_type nodetype_T0oT1::result = expression_node:: v_; \ - synthnode_type_define(const T0&,const T1&, e_vov) - synthnode_type_define(const T0&,const T1 , e_voc) - synthnode_type_define(const T0 ,const T1&, e_cov) - synthnode_type_define( T0&, T1&,e_none) - synthnode_type_define(const T0 ,const T1 ,e_none) - synthnode_type_define( T0&,const T1 ,e_none) - synthnode_type_define(const T0 , T1&,e_none) - synthnode_type_define(const T0&, T1&,e_none) - synthnode_type_define( T0&,const T1&,e_none) - #undef synthnode_type_define + synthesis_node_type_define(const T0&,const T1&, e_vov) + synthesis_node_type_define(const T0&,const T1 , e_voc) + synthesis_node_type_define(const T0 ,const T1&, e_cov) + synthesis_node_type_define( T0&, T1&,e_none) + synthesis_node_type_define(const T0 ,const T1 ,e_none) + synthesis_node_type_define( T0&,const T1 ,e_none) + synthesis_node_type_define(const T0 , T1&,e_none) + synthesis_node_type_define(const T0&, T1&,e_none) + synthesis_node_type_define( T0&,const T1&,e_none) + #undef synthesis_node_type_define template struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; template const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node::e_none; - #define synthnode_type_define(T0_,T1_,T2_,v_) \ + #define synthesis_node_type_define(T0_,T1_,T2_,v_) \ template \ struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; \ template \ const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node:: v_; \ - synthnode_type_define(const T0&,const T1&,const T2&, e_vovov) - synthnode_type_define(const T0&,const T1&,const T2 , e_vovoc) - synthnode_type_define(const T0&,const T1 ,const T2&, e_vocov) - synthnode_type_define(const T0 ,const T1&,const T2&, e_covov) - synthnode_type_define(const T0 ,const T1&,const T2 , e_covoc) - synthnode_type_define(const T0 ,const T1 ,const T2 , e_none ) - synthnode_type_define(const T0 ,const T1 ,const T2&, e_none ) - synthnode_type_define(const T0&,const T1 ,const T2 , e_none ) - synthnode_type_define( T0&, T1&, T2&, e_none ) - #undef synthnode_type_define + synthesis_node_type_define(const T0&,const T1&,const T2&, e_vovov) + synthesis_node_type_define(const T0&,const T1&,const T2 , e_vovoc) + synthesis_node_type_define(const T0&,const T1 ,const T2&, e_vocov) + synthesis_node_type_define(const T0 ,const T1&,const T2&, e_covov) + synthesis_node_type_define(const T0 ,const T1&,const T2 , e_covoc) + synthesis_node_type_define(const T0 ,const T1 ,const T2 , e_none ) + synthesis_node_type_define(const T0 ,const T1 ,const T2&, e_none ) + synthesis_node_type_define(const T0&,const T1 ,const T2 , e_none ) + synthesis_node_type_define( T0&, T1&, T2&, e_none ) + #undef synthesis_node_type_define template struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; template const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node::e_none; - #define synthnode_type_define(T0_,T1_,T2_,T3_,v_) \ + #define synthesis_node_type_define(T0_,T1_,T2_,T3_,v_) \ template \ struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; \ template \ const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node:: v_; \ - synthnode_type_define(const T0&,const T1&,const T2&, const T3&,e_vovovov) - synthnode_type_define(const T0&,const T1&,const T2&, const T3 ,e_vovovoc) - synthnode_type_define(const T0&,const T1&,const T2 , const T3&,e_vovocov) - synthnode_type_define(const T0&,const T1 ,const T2&, const T3&,e_vocovov) - synthnode_type_define(const T0 ,const T1&,const T2&, const T3&,e_covovov) - synthnode_type_define(const T0 ,const T1&,const T2 , const T3&,e_covocov) - synthnode_type_define(const T0&,const T1 ,const T2&, const T3 ,e_vocovoc) - synthnode_type_define(const T0 ,const T1&,const T2&, const T3 ,e_covovoc) - synthnode_type_define(const T0&,const T1 ,const T2 , const T3&,e_vococov) - synthnode_type_define(const T0 ,const T1 ,const T2 , const T3 ,e_none ) - synthnode_type_define(const T0 ,const T1 ,const T2 , const T3&,e_none ) - synthnode_type_define(const T0 ,const T1 ,const T2&, const T3 ,e_none ) - synthnode_type_define(const T0 ,const T1&,const T2 , const T3 ,e_none ) - synthnode_type_define(const T0&,const T1 ,const T2 , const T3 ,e_none ) - synthnode_type_define(const T0 ,const T1 ,const T2&, const T3&,e_none ) - synthnode_type_define(const T0&,const T1&,const T2 , const T3 ,e_none ) - #undef synthnode_type_define + synthesis_node_type_define(const T0&,const T1&,const T2&, const T3&,e_vovovov) + synthesis_node_type_define(const T0&,const T1&,const T2&, const T3 ,e_vovovoc) + synthesis_node_type_define(const T0&,const T1&,const T2 , const T3&,e_vovocov) + synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3&,e_vocovov) + synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3&,e_covovov) + synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3&,e_covocov) + synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3 ,e_vocovoc) + synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3 ,e_covovoc) + synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3&,e_vococov) + synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3 ,e_none ) + synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3&,e_none ) + synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3 ,e_none ) + synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3 ,e_none ) + synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3 ,e_none ) + synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3&,e_none ) + synthesis_node_type_define(const T0&,const T1&,const T2 , const T3 ,e_none ) + #undef synthesis_node_type_define template class T0oT1 : public expression_node @@ -8798,9 +9023,16 @@ namespace exprtk std::size_t r0_1 = 0; std::size_t r1_0 = 0; std::size_t r1_1 = 0; - if (rp0_(r0_0,r1_0,s0_.size()) && rp1_(r0_1,r1_1,s1_.size())) - return Operation::process(s0_.substr(r0_0,(r1_0 - r0_0) + 1), - s1_.substr(r0_1,(r1_1 - r0_1) + 1)); + if ( + rp0_(r0_0,r1_0,s0_.size()) && + rp1_(r0_1,r1_1,s1_.size()) + ) + { + return Operation::process( + s0_.substr(r0_0,(r1_0 - r0_0) + 1), + s1_.substr(r0_1,(r1_1 - r0_1) + 1) + ); + } else return T(0); } @@ -9510,6 +9742,12 @@ namespace exprtk { public: + ivararg_function(const bool hse = true) + : has_side_effects(hse) + {} + + bool has_side_effects; + virtual ~ivararg_function() {} @@ -9764,6 +10002,11 @@ namespace exprtk return add_impl >(symbol_name,std::make_pair(v,v_size),is_constant); } + inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_constant = false) + { + return add_impl >(symbol_name,std::make_pair(v,v_size),is_constant); + } + template inline bool add(const std::string& symbol_name, std::vector& v, const bool is_constant = false) { @@ -9863,6 +10106,7 @@ namespace exprtk { struct init_type { + static inline double set(double) { return (0.0); } static inline double set(long double) { return (0.0); } static inline float set(float) { return (0.0f); } static inline std::string set(std::string) { return std::string(""); } @@ -10055,16 +10299,19 @@ namespace exprtk { delete holder_; } + holder_ = 0; } + holder_ = st.holder_; holder_->ref_count++; + return *this; } inline bool operator==(const symbol_table& st) { - return (this == *st); + return (this == &st) || (holder_ == st.holder_); } inline void clear_variables(const bool delete_node = true) @@ -10174,7 +10421,8 @@ namespace exprtk return local_data().vararg_function_store.get(vararg_function_name); } - typedef vector_holder* vector_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_ptr; inline vector_ptr get_vector(const std::string& vector_name) { @@ -10628,9 +10876,19 @@ namespace exprtk private: typedef details::expression_node* expression_ptr; + typedef typename symbol_table::vector_ptr vector_ptr; struct expression_holder { + enum data_type + { + e_unknown, + e_expr, + e_vecholder, + e_data, + e_vecdata + }; + expression_holder() : ref_count(0), expr(0) @@ -10647,18 +10905,34 @@ namespace exprtk { delete expr; } - if (!local_var_list.empty()) + + if (!local_data_list.empty()) { - for (std::size_t i = 0; i < local_var_list.size(); ++i) + for (std::size_t i = 0; i < local_data_list.size(); ++i) { - delete local_var_list[i]; + switch (local_data_list[i].second) + { + case e_expr : delete reinterpret_cast(local_data_list[i].first); + break; + + case e_vecholder : delete reinterpret_cast(local_data_list[i].first); + break; + + case e_data : delete (T*)(local_data_list[i].first); + break; + + case e_vecdata : delete [] (T*)(local_data_list[i].first); + break; + + default : break; + } } } } std::size_t ref_count; expression_ptr expr; - std::vector local_var_list; + std::vector > local_data_list; }; public: @@ -10702,7 +10976,10 @@ namespace exprtk inline bool operator!() const { - return ((0 == expression_holder_) || (0 == expression_holder_->expr)); + return ( + (0 == expression_holder_) || + (0 == expression_holder_->expr) + ); } inline expression& release() @@ -10787,7 +11064,39 @@ namespace exprtk { if (expression_holder_) { - expression_holder_->local_var_list.push_back(expr); + expression_holder_-> + local_data_list.push_back( + std::make_pair(reinterpret_cast(expr), + expression_holder::e_expr)); + } + } + } + + inline void register_local_var(vector_ptr vec_holder) + { + if (vec_holder) + { + if (expression_holder_) + { + expression_holder_-> + local_data_list.push_back( + std::make_pair(reinterpret_cast(vec_holder), + expression_holder::e_vecholder)); + } + } + } + + inline void register_local_data(void* data, const bool vectype = false) + { + if (data) + { + if (expression_holder_) + { + expression_holder_-> + local_data_list.push_back( + std::make_pair(reinterpret_cast(data), + vectype ? expression_holder::e_vecdata : + expression_holder::e_data)); } } } @@ -10804,27 +11113,27 @@ namespace exprtk { public: - static inline bool is_head_constant(const expression& expr) + static inline bool is_constant(const expression& expr) { return details::is_constant_node(expr.expression_holder_->expr); } - static inline bool is_head_variable(const expression& expr) + static inline bool is_variable(const expression& expr) { return details::is_variable_node(expr.expression_holder_->expr); } - static inline bool is_head_unary(const expression& expr) + static inline bool is_unary(const expression& expr) { return details::is_unary_node(expr.expression_holder_->expr); } - static inline bool is_head_binary(const expression& expr) + static inline bool is_binary(const expression& expr) { return details::is_binary_node(expr.expression_holder_->expr); } - static inline bool is_head_function(const expression& expr) + static inline bool is_function(const expression& expr) { return details::is_function(expr.expression_holder_->expr); } @@ -10891,8 +11200,8 @@ namespace exprtk inline bool update_error(type& error, const std::string& expression) { if ( - expression.empty() || - (error.token.position >= expression.size()) || + expression.empty() || + (error.token.position > expression.size()) || (std::numeric_limits::max() == error.token.position) ) { @@ -11040,18 +11349,215 @@ namespace exprtk typedef details::T0oT1oT2oT3_define covovoc_t; typedef details::T0oT1oT2oT3_define vococov_t; + struct scope_element + { + enum element_type + { + e_none, + e_variable, + e_vector, + e_vecelem + }; + + typedef variable_node_t* variable_node_ptr; + typedef typename symbol_table_t::vector_ptr vector_ptr; + typedef typename symbol_table_t::vector_holder_t vector_holder_t; + + scope_element() + : name("???"), + size (std::numeric_limits::max()), + index(std::numeric_limits::max()), + depth(std::numeric_limits::max()), + ref_count(0), + type (e_none), + active(false), + data(0), + var_node(0), + vec_node(0) + {} + + bool operator < (const scope_element& se) const + { + if (depth < se.depth) + return true; + else if (depth > se.depth) + return false; + else if (index < se.index) + return true; + else if (index > se.index) + return false; + else + return (name < se.name); + } + + std::string name; + std::size_t size; + std::size_t index; + std::size_t depth; + std::size_t ref_count; + element_type type; + bool active; + void* data; + variable_node_ptr var_node; + vector_ptr vec_node; + }; + + class scope_element_manager + { + public: + + typedef variable_node_t* variable_node_ptr; + typedef parser parser_t; + + scope_element_manager(parser& p) + : parser_(p) + {} + + inline std::size_t size() const + { + return element_.size(); + } + + inline bool empty() const + { + return element_.empty(); + } + + inline scope_element& get_element(const std::size_t& index) + { + if (index < element_.size()) + return element_[index]; + else + return null_element_; + } + + inline scope_element& get_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + if (element_[i].depth > parser_.scope_depth_) + return null_element_; + else if ( + (element_[i].name == var_name) && + (element_[i].index == index) + ) + return element_[i]; + } + + return null_element_; + } + + inline bool add_element(const scope_element& se) + { + for (std::size_t j = 0; j < element_.size(); ++j) + { + if ( + (element_[j].name == se.name ) && + (element_[j].depth <= se.depth) && + (element_[j].index == se.index) + ) + return false; + } + + element_.push_back(se); + std::sort(element_.begin(),element_.end()); + return true; + } + + inline void deactivate(const std::size_t scope_depth) + { + for (std::size_t j = 0; j < element_.size(); ++j) + { + if (element_[j].depth >= scope_depth) + { + element_[j].active = false; + } + } + } + + void cleanup(const bool purge = false) + { + std::vector tmp_element_(element_.size()); + for (std::size_t i = 0; i < element_.size(); ++i) + { + if (purge) + element_[i].ref_count = 0; + + if (element_[i].ref_count) + tmp_element_.push_back(element_[i]); + else + { + delete element_[i].var_node; + T* data = (T*)(element_[i].data); + switch(element_[i].type) + { + case scope_element::e_variable : delete data; + break; + + case scope_element::e_vector : delete [] data; + break; + + default : break; + } + } + } + + element_ = tmp_element_; + } + + private: + + parser_t& parser_; + std::vector element_; + scope_element null_element_; + }; + + class scope_handler + { + public: + + typedef parser parser_t; + + scope_handler(parser& p) + : parser_(p) + { + parser_.scope_depth_++; + #ifdef exprtk_enable_debugging + std::string depth(2 * parser_.scope_depth_,'-'); + printf("%s> Scope Depth: %02d\n",depth.c_str(),static_cast(parser_.scope_depth_)); + #endif + } + + ~scope_handler() + { + parser_.sem_.deactivate(parser_.scope_depth_); + parser_.scope_depth_--; + #ifdef exprtk_enable_debugging + std::string depth(2 * parser_.scope_depth_,'-'); + printf("<%s Scope Depth: %02d\n",depth.c_str(),static_cast(parser_.scope_depth_)); + #endif + } + + private: + + parser_t& parser_; + }; + + public: - enum precompilation_step + enum compilation_options { - e_unknown = 0, - e_replacer = 1, - e_joiner = 2, - e_numeric_check = 4, - e_bracket_check = 8, - e_sequence_check = 16, - e_commutative_check = 32, - e_strength_reduction = 64 + e_unknown = 0, + e_replacer = 1, + e_joiner = 2, + e_numeric_check = 4, + e_bracket_check = 8, + e_sequence_check = 16, + e_commutative_check = 32, + e_strength_reduction = 64, + e_disable_vardef = 128 }; struct unknown_symbol_resolver @@ -11087,7 +11593,16 @@ namespace exprtk : symbol_name_caching_(false), compile_options_(compile_options), resolve_unknown_symbol_(false), + vardef_disabled_((compile_options & e_disable_vardef) == e_disable_vardef), unknown_symbol_resolver_(reinterpret_cast(0)), + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning (disable:4355) + #endif + sem_(*this), + #ifdef _MSC_VER + #pragma warning(pop) + #endif operator_joiner_2_(2), operator_joiner_3_(3) { @@ -11109,9 +11624,7 @@ namespace exprtk } ~parser() - { - local_symbol_table_.clear_variables(false); - } + {} inline void init_precompilation() { @@ -11143,8 +11656,8 @@ namespace exprtk } if ( - numeric_check_enabled() || - bracket_check_enabled() || + numeric_check_enabled () || + bracket_check_enabled () || sequence_check_enabled() ) { @@ -11169,11 +11682,12 @@ namespace exprtk inline bool compile(const std::string& expression_string, expression& expr) { - error_list_.clear(); + error_list_ .clear(); + brkcnt_list_ .clear(); synthesis_error_.clear(); - brkcnt_list_.clear(); - local_symbol_table_.clear_variables(false); + sem_ .cleanup(true); expression_generator_.set_allocator(node_allocator_); + scope_depth_ = 0; if (expression_string.empty()) { @@ -11218,13 +11732,16 @@ namespace exprtk } else { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR02 - Incomplete expression due to unexpected token: '" + current_token_.value + "'")); + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR02 - Invalid expression encountered")); + } symbol_name_cache_.clear(); - clear_local_vars(); + sem_.cleanup(true); if (0 != e) { @@ -11380,7 +11897,7 @@ namespace exprtk if (index < error_list_.size()) return error_list_[index]; else - throw std::invalid_argument("parser::get_error() - Invalid error index specificed."); + throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); } inline std::string error() const @@ -11514,7 +12031,10 @@ namespace exprtk { std::string ct_str = current_token_.value; current_token_ = lexer_.next_token(); - printf("prev[%s] --> curr[%s]\n", + std::string depth(2 * scope_depth_,' '); + printf("%s" + "prev[%s] --> curr[%s]\n", + depth.c_str(), ct_str.c_str(), current_token_.value.c_str()); } @@ -11527,27 +12047,32 @@ namespace exprtk inline expression_node_ptr parse_corpus() { - std::deque arg_list; + std::vector arg_list; expression_node_ptr result = error_node(); - scoped_deq_delete sdd(*this,arg_list); + scoped_vec_delete sdd(*this,arg_list); do { expression_node_ptr arg = parse_expression(); + if (0 == arg) + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR07 - Invalid expression encountered")); + } + return error_node(); + } else arg_list.push_back(arg); if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR07 - Expected ';' at end of sub-expression, instead got: '" + current_token_.value + "'")); - return error_node(); - } + continue; } while (!lexer_.finished()); @@ -11605,6 +12130,8 @@ namespace exprtk case token_t::e_subass : current_state.set(e_level00,e_level00,details::e_subass); break; case token_t::e_mulass : current_state.set(e_level00,e_level00,details::e_mulass); break; case token_t::e_divass : current_state.set(e_level00,e_level00,details::e_divass); break; + case token_t::e_modass : current_state.set(e_level00,e_level00,details::e_modass); break; + case token_t::e_swap : current_state.set(e_level00,e_level00,details::e_swap ); break; case token_t::e_lt : current_state.set(e_level05,e_level06,details:: e_lt); break; case token_t::e_lte : current_state.set(e_level05,e_level06,details:: e_lte); break; case token_t::e_eq : current_state.set(e_level05,e_level06,details:: e_eq); break; @@ -11778,11 +12305,7 @@ namespace exprtk { for (std::size_t i = 0; i < N; ++i) { - if (p_[i] && !is_variable_node(p_[i])) - { - parser_.node_allocator_.free(p_[i]); - p_[i] = 0; - } + free_node(parser_.node_allocator_,p_[i]); } } } @@ -11860,47 +12383,53 @@ 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) + inline expression_node_ptr parse_function_invocation(ifunction* function, const std::string& function_name) { - expression_node_ptr branch[NumberofParameters]; - expression_node_ptr result = 0; - - std::fill_n(branch,NumberofParameters,reinterpret_cast(0)); - scoped_delete sd(*this,branch); - - next_token(); - - if (!token_is(token_t::e_lbracket)) + expression_node_ptr func_node = reinterpret_cast(0); + switch (function->param_count) { - return error_node(); + case 0 : func_node = parse_function_call_0 (function,function_name); break; + case 1 : func_node = parse_function_call< 1>(function,function_name); break; + case 2 : func_node = parse_function_call< 2>(function,function_name); break; + case 3 : func_node = parse_function_call< 3>(function,function_name); break; + case 4 : func_node = parse_function_call< 4>(function,function_name); break; + case 5 : func_node = parse_function_call< 5>(function,function_name); break; + case 6 : func_node = parse_function_call< 6>(function,function_name); break; + case 7 : func_node = parse_function_call< 7>(function,function_name); break; + case 8 : func_node = parse_function_call< 8>(function,function_name); break; + case 9 : func_node = parse_function_call< 9>(function,function_name); break; + case 10 : func_node = parse_function_call<10>(function,function_name); break; + case 11 : func_node = parse_function_call<11>(function,function_name); break; + case 12 : func_node = parse_function_call<12>(function,function_name); break; + case 13 : func_node = parse_function_call<13>(function,function_name); break; + case 14 : func_node = parse_function_call<14>(function,function_name); break; + case 15 : func_node = parse_function_call<15>(function,function_name); break; + case 16 : func_node = parse_function_call<16>(function,function_name); break; + case 17 : func_node = parse_function_call<17>(function,function_name); break; + case 18 : func_node = parse_function_call<18>(function,function_name); break; + case 19 : func_node = parse_function_call<19>(function,function_name); break; + case 20 : func_node = parse_function_call<20>(function,function_name); break; + default : { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR09 - Invalid number of parameters for function: '" + function_name + "'")); + + return error_node(); + } } - for (int i = 0; i < static_cast(NumberofParameters); ++i) - { - branch[i] = parse_expression(); - if (0 == branch[i]) - { - internal_error = true; - return error_node(); - } - else if (i < static_cast(NumberofParameters - 1)) - { - if (!token_is(token_t::e_comma)) - { - return error_node(); - } - } - } - - if (!token_is(token_t::e_rbracket)) - { - return error_node(); - } + if (func_node) + return func_node; else - result = expression_generator_(opt_type,branch); - sd.delete_ptr = false; - return result; + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR10 - Failed to generate call to function: '" + function_name + "'")); + + return error_node(); + } } template @@ -11916,19 +12445,22 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR09 - Expecting argument list for function: '" + function_name + "'")); + "ERR11 - Expecting argument list for function: '" + function_name + "'")); + return error_node(); } for (int i = 0; i < static_cast(NumberofParameters); ++i) { branch[i] = parse_expression(); + if (0 == branch[i]) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR10 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); + "ERR12 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); + return error_node(); } else if (i < static_cast(NumberofParameters - 1)) @@ -11938,7 +12470,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR11 - Invalid number of arguments for function: '" + function_name + "'")); + "ERR13 - Invalid number of arguments for function: '" + function_name + "'")); + return error_node(); } } @@ -11949,7 +12482,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR12 - Invalid number of arguments for function: '" + function_name + "'")); + "ERR14 - Invalid number of arguments for function: '" + function_name + "'")); + return error_node(); } else @@ -11971,13 +12505,61 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR13 - Expecting '()' to proceed: '" + function_name + "'")); + "ERR15 - Expecting '()' to proceed: '" + function_name + "'")); + return error_node(); } else return result; } + template + inline int parse_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters]) + { + std::fill_n(param_list,MaxNumberofParameters,reinterpret_cast(0)); + scoped_delete sd(*this,param_list); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR16 - Expected a '(' at start of function call, instead got: '" + current_token_.value + "'")); + + return 0; + } + + int param_index = 0; + + for (; param_index < static_cast(MaxNumberofParameters); ++param_index) + { + param_list[param_index] = parse_expression(); + + if (0 == param_list[param_index]) + { + return 0; + } + else if (token_is(token_t::e_rbracket)) + break; + else if (token_is(token_t::e_comma)) + continue; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR17 - Expected a ',' between function input parameters, instead got: '" + current_token_.value + "'")); + + return 0; + } + } + + sd.delete_ptr = false; + return (param_index + 1); + } + inline expression_node_ptr parse_base_operation() { typedef std::pair map_range_t; @@ -11988,50 +12570,68 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR14 - No entries found for base operation: " + operation_name)); + "ERR18 - No entries found for base operation: " + operation_name)); + return error_node(); } - for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) - { - store_token(); - expression_node_ptr branch = reinterpret_cast(0); - details::base_operation_t& operation = itr->second; - bool internal_error = false; // Any error other than incorrect number of params. - switch (operation.num_params) - { - case 1 : branch = parse_function_call<1>(operation.type,internal_error); break; - case 2 : branch = parse_function_call<2>(operation.type,internal_error); break; - case 3 : branch = parse_function_call<3>(operation.type,internal_error); break; - case 4 : branch = parse_function_call<4>(operation.type,internal_error); break; - case 5 : branch = parse_function_call<5>(operation.type,internal_error); break; - case 6 : branch = parse_function_call<6>(operation.type,internal_error); break; - default : - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR15 - Impossible argument count for base function: " + operation_name)); - return error_node(); - } - } + const std::size_t MaxNumberofParameters = 6; + expression_node_ptr param_list[MaxNumberofParameters] = {0}; - if (branch) + std::size_t parameter_count = parse_function_call(param_list); + + if (0 == parameter_count) + { + return error_node(); + } + else if (parameter_count <= 6) + { + for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) { - return branch; + details::base_operation_t& operation = itr->second; + + if (operation.num_params == parameter_count) + { + expression_node_ptr pl1[1] = {0}; + expression_node_ptr pl2[2] = {0}; + expression_node_ptr pl3[3] = {0}; + expression_node_ptr pl4[4] = {0}; + expression_node_ptr pl5[5] = {0}; + expression_node_ptr pl6[6] = {0}; + + switch (parameter_count) + { + case 1 : std::copy(param_list,param_list + 1,pl1); break; + case 2 : std::copy(param_list,param_list + 2,pl2); break; + case 3 : std::copy(param_list,param_list + 3,pl3); break; + case 4 : std::copy(param_list,param_list + 4,pl4); break; + case 5 : std::copy(param_list,param_list + 5,pl5); break; + case 6 : std::copy(param_list,param_list + 6,pl6); break; + } + + switch (parameter_count) + { + case 1 : return expression_generator_(operation.type,pl1); + case 2 : return expression_generator_(operation.type,pl2); + case 3 : return expression_generator_(operation.type,pl3); + case 4 : return expression_generator_(operation.type,pl4); + case 5 : return expression_generator_(operation.type,pl5); + case 6 : return expression_generator_(operation.type,pl6); + } + } } - else if (internal_error) - { - return error_node(); - } - remove_last_error(); - restore_token(); + } + + for (std::size_t i = 0; i < MaxNumberofParameters; ++i) + { + free_node(node_allocator_,param_list[i]); } set_error( make_error(parser_error::e_syntax, current_token_, - "ERR16 - Invalid parameter count for function: " + operation_name)); + "ERR19 - Invalid number of parameters for call to function: '" + operation_name + "'")); + return error_node(); } @@ -12049,7 +12649,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR17 - Expected ',' between if-statement condition and consequent")); + "ERR20 - Expected ',' between if-statement condition and consequent")); result = false; } else if (0 == (consequent = parse_expression())) @@ -12057,7 +12657,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR18 - Failed to parse consequent for if-statement")); + "ERR21 - Failed to parse consequent for if-statement")); result = false; } else if (!token_is(token_t::e_comma)) @@ -12065,7 +12665,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR19 - Expected ',' between if-statement consequent and alternative")); + "ERR22 - Expected ',' between if-statement consequent and alternative")); result = false; } else if (0 == (alternative = parse_expression())) @@ -12073,7 +12673,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR20 - Failed to parse alternative for if-statement")); + "ERR23 - Failed to parse alternative for if-statement")); result = false; } else if (!token_is(token_t::e_rbracket)) @@ -12081,7 +12681,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR21 - Expected ')' at end of if-statement")); + "ERR24 - Expected ')' at end of if-statement")); result = false; } @@ -12110,7 +12710,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR22 - Failed to parse body of consequent for if-statement")); + "ERR25 - Failed to parse body of consequent for if-statement")); result = false; } } @@ -12131,7 +12731,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR23 - Expected ';' at the end of the consequent for if-statement")); + "ERR26 - Expected ';' at the end of the consequent for if-statement")); result = false; } } @@ -12140,7 +12740,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR24 - Failed to parse body of consequent for if-statement")); + "ERR27 - Failed to parse body of consequent for if-statement")); result = false; } } @@ -12159,7 +12759,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR25 - Failed to parse body of the 'else' for if-statement")); + "ERR28 - Failed to parse body of the 'else' for if-statement")); result = false; } } @@ -12170,7 +12770,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR26 - Failed to parse body of if-else statement")); + "ERR29 - Failed to parse body of if-else statement")); result = false; } } @@ -12181,7 +12781,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")); + "ERR30 - Expected ';' at the end of the 'else-if' for the if-statement")); result = false; } } @@ -12190,7 +12790,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR28 - Failed to parse body of the 'else' for if-statement")); + "ERR31 - Failed to parse body of the 'else' for if-statement")); result = false; } } @@ -12218,7 +12818,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR29 - Expected '(' at start of if-statement, instead got: '" + current_token_.value + "'")); + "ERR32 - Expected '(' at start of if-statement, instead got: '" + current_token_.value + "'")); + return error_node(); } else if (0 == (condition = parse_expression())) @@ -12226,7 +12827,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR30 - Failed to parse condition for if-statement")); + "ERR33 - Failed to parse condition for if-statement")); + return error_node(); } else if (token_is(token_t::e_comma,false)) @@ -12256,7 +12858,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR31 - Invalid if-statement")); + "ERR34 - Invalid if-statement")); free_node(node_allocator_,condition); @@ -12276,7 +12878,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR32 - Encountered invalid condition branch for ternary if-statement")); + "ERR35 - Encountered invalid condition branch for ternary if-statement")); + return error_node(); } else if (!token_is(token_t::e_ternary)) @@ -12284,7 +12887,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR33 - Expected '?' after condition of ternary if-statement")); + "ERR36 - Expected '?' after condition of ternary if-statement")); result = false; } else if (0 == (consequent = parse_expression())) @@ -12292,7 +12895,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR34 - Failed to parse consequent for if-statement")); + "ERR37 - Failed to parse consequent for if-statement")); result = false; } else if (!token_is(token_t::e_colon)) @@ -12300,7 +12903,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR35 - Expected ':' between ternary if-statement consequent and alternative")); + "ERR38 - Expected ':' between ternary if-statement consequent and alternative")); result = false; } else if (0 == (alternative = parse_expression())) @@ -12308,7 +12911,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR36 - Failed to parse alternative for if-statement")); + "ERR39 - Failed to parse alternative for if-statement")); result = false; } @@ -12339,7 +12942,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR37 - Expected '(' at start of while-statement condition")); + "ERR40 - Expected '(' at start of while-statement condition")); + return error_node(); } else if (0 == (condition = parse_expression())) @@ -12347,7 +12951,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR38 - Failed to parse condition for while-loop")); + "ERR41 - Failed to parse condition for while-loop")); + return error_node(); } else if (!token_is(token_t::e_rbracket)) @@ -12355,7 +12960,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR39 - Expected ')' at end of while-statement condition")); + "ERR42 - Expected ')' at end of while-statement condition")); result = false; } @@ -12368,7 +12973,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR40 - Failed to parse body of while-loop")); + "ERR43 - Failed to parse body of while-loop")); result = false; } else if (0 == (result_node = expression_generator_.while_loop(condition, @@ -12378,7 +12983,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR41 - Failed to synthesize while-loop")); + "ERR44 - Failed to synthesize while-loop")); result = false; } } @@ -12402,14 +13007,16 @@ namespace exprtk expression_node_ptr branch = error_node(); next_token(); - std::deque arg_list; - scoped_deq_delete sdd(*this,arg_list); + std::vector arg_list; + scoped_vec_delete sdd(*this,arg_list); { token_t::token_type seperator = token_t::e_eof; brkcnt_list_.push_front(false); + scope_handler sh(*this); + for (;;) { expression_node_ptr arg = parse_expression(); @@ -12429,7 +13036,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR42 - Expected '" + token_t::to_str(seperator) + "' for body of repeat until loop")); + "ERR45 - Expected '" + token_t::to_str(seperator) + "' for body of repeat until loop")); + return error_node(); } @@ -12446,31 +13054,37 @@ namespace exprtk if (0 == branch) { + brkcnt_list_.pop_front(); + set_error( make_error(parser_error::e_syntax, current_token_, - "ERR43 - Failed to parse body of repeat until loop")); - brkcnt_list_.pop_front(); + "ERR46 - Failed to parse body of repeat until loop")); + return error_node(); } } if (!token_is(token_t::e_lbracket)) { + brkcnt_list_.pop_front(); + set_error( make_error(parser_error::e_syntax, current_token_, - "ERR44 - Expected '(' before condition of repeat until loop")); - brkcnt_list_.pop_front(); + "ERR47 - Expected '(' before condition of repeat until loop")); + return error_node(); } else if (0 == (condition = parse_expression())) { + brkcnt_list_.pop_front(); + set_error( make_error(parser_error::e_syntax, current_token_, - "ERR45 - Failed to parse condition for repeat until loop")); - brkcnt_list_.pop_front(); + "ERR48 - Failed to parse condition for repeat until loop")); + return error_node(); } else if (!token_is(token_t::e_rbracket)) @@ -12478,9 +13092,11 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR46 - Expected ')' after condition of repeat until loop")); + "ERR49 - Expected ')' after condition of repeat until loop")); + free_node(node_allocator_,condition); brkcnt_list_.pop_front(); + return error_node(); } @@ -12491,9 +13107,11 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR47 - Failed to synthesize repeat until loop")); + "ERR50 - Failed to synthesize repeat until loop")); + free_node(node_allocator_,condition); brkcnt_list_.pop_front(); + return error_node(); } else @@ -12505,23 +13123,26 @@ namespace exprtk inline expression_node_ptr parse_for_loop() { - expression_node_ptr initializer = error_node(); + expression_node_ptr initialiser = error_node(); expression_node_ptr condition = error_node(); expression_node_ptr incrementor = error_node(); expression_node_ptr loop_body = error_node(); - expression_node_ptr loop_var = error_node(); - T* loop_counter = 0; - bool result = true; + + scope_element* se = 0; + bool result = true; std::string loop_counter_symbol; next_token(); + scope_handler sh(*this); + if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR48 - Expected '(' at start of for-loop")); + "ERR51 - Expected '(' at start of for-loop")); + return error_node(); } @@ -12532,7 +13153,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR49 - Expected a variable at the start of initializer section of for-loop")); + "ERR52 - Expected a variable at the start of initialiser section of for-loop")); + return error_node(); } else if (!peek_token_is(token_t::e_assign)) @@ -12540,33 +13162,67 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR50 - Expected variable assignment of initializer section of for-loop")); + "ERR53 - Expected variable assignment of initialiser section of for-loop")); + return error_node(); } loop_counter_symbol = current_token_.value; - if (local_symbol_table_.is_variable(loop_counter_symbol)) + se = &sem_.get_element(loop_counter_symbol); + + if ((se->name == loop_counter_symbol) && se->active) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR51 - For-loop variable '" +loop_counter_symbol+ "' is being shadowed by a previous declaration")); + "ERR54 - 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)) { - loop_counter = new T(T(0)); - local_symbol_table_.add_variable(loop_counter_symbol,*loop_counter); - loop_var = local_symbol_table_.get_variable(loop_counter_symbol); + if ( + !se->active && + (se->name == loop_counter_symbol) && + (se->type == scope_element::e_variable) + ) + { + se->active = true; + se->ref_count++; + } + else + { + scope_element nse; + nse.name = loop_counter_symbol; + nse.type = scope_element::e_variable; + nse.depth = scope_depth_; + nse.data = new T(T(0)); + nse.var_node = new variable_node_t(*(T*)(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR55 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); + + result = false; + + } + #ifdef exprtk_enable_debugging + else + printf("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str()); + #endif + } } - if (0 == (initializer = parse_expression())) + if (0 == (initialiser = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR52 - Failed to parse initializer of for-loop")); + "ERR56 - Failed to parse initialiser of for-loop")); result = false; } @@ -12575,7 +13231,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR53 - Expected ';' after initializer of for-loop")); + "ERR57 - Expected ';' after initialiser of for-loop")); result = false; } } @@ -12587,7 +13243,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR54 - Failed to parse condition of for-loop")); + "ERR58 - Failed to parse condition of for-loop")); result = false; } else if (!token_is(token_t::e_eof)) @@ -12595,7 +13251,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR55 - Expected ';' after condition section of for-loop")); + "ERR59 - Expected ';' after condition section of for-loop")); result = false; } } @@ -12607,7 +13263,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR56 - Failed to parse incrementor of for-loop")); + "ERR60 - Failed to parse incrementor of for-loop")); result = false; } else if (!token_is(token_t::e_rbracket)) @@ -12615,7 +13271,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR57 - Expected ')' after incrementor section of for-loop")); + "ERR61 - Expected ')' after incrementor section of for-loop")); result = false; } } @@ -12628,36 +13284,34 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR58 - Failed to parse body of for-loop")); + "ERR62 - Failed to parse body of for-loop")); result = false; } } if (!result) { - local_symbol_table_.remove_variable(loop_counter_symbol); - free_node(node_allocator_,initializer); + se->ref_count--; + sem_.cleanup(); + free_node(node_allocator_,initialiser); free_node(node_allocator_,condition ); free_node(node_allocator_,incrementor); free_node(node_allocator_,loop_body ); - delete loop_counter; - brkcnt_list_.pop_front(); + + if (!brkcnt_list_.empty()) + { + brkcnt_list_.pop_front(); + } + return error_node(); } else { - if (loop_counter && !loop_counter_symbol.empty()) - { - local_symbol_table_.remove_variable(loop_counter_symbol,false); - } - expression_node_ptr result_node = - expression_generator_.for_loop(initializer, + expression_generator_.for_loop(initialiser, condition, incrementor, loop_body, - loop_var, - loop_counter, brkcnt_list_.front()); brkcnt_list_.pop_front(); return result_node; @@ -12676,11 +13330,12 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR59 - Expected keyword 'switch'")); + "ERR63 - Expected keyword 'switch'")); + return error_node(); } - scoped_vec_delete sdd(*this,arg_list); + scoped_vec_delete svd(*this,arg_list); next_token(); @@ -12689,7 +13344,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR60 - Expected '{' for call to switch statement")); + "ERR64 - Expected '{' for call to switch statement")); + return error_node(); } @@ -12700,7 +13356,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR61 - Expected either a 'case' or 'default' statement")); + "ERR65 - Expected either a 'case' or 'default' statement")); + return error_node(); } @@ -12710,13 +13367,13 @@ namespace exprtk if (0 == condition) return error_node(); - - if (!token_is(token_t::e_colon)) + else if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR62 - Expected ':' for case of switch statement")); + "ERR66 - Expected ':' for case of switch statement")); + return error_node(); } @@ -12724,13 +13381,13 @@ namespace exprtk if (0 == consequent) return error_node(); - - if (!token_is(token_t::e_eof)) + else if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR63 - Expected ';' at end of case for switch statement")); + "ERR67 - Expected ';' at end of case for switch statement")); + return error_node(); } @@ -12756,11 +13413,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR64 - Expected ':' for default of switch statement")); + "ERR68 - 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)) @@ -12768,7 +13427,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR65 - Expected ';' at end of default for switch statement")); + "ERR69 - Expected ';' at end of default for switch statement")); + return error_node(); } @@ -12782,13 +13442,14 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR66 - Expected '}' at end of switch statement")); + "ERR70 - Expected '}' at end of switch statement")); + return error_node(); } result = expression_generator_.switch_statement(arg_list); - sdd.delete_ptr = (0 == result); + svd.delete_ptr = (0 == result); return result; } @@ -12804,11 +13465,12 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR67 - Expected token '[*]'")); + "ERR71 - Expected token '[*]'")); + return error_node(); } - scoped_vec_delete sdd(*this,arg_list); + scoped_vec_delete svd(*this,arg_list); next_token(); @@ -12817,7 +13479,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR68 - Expected '{' for call to [*] statement")); + "ERR72 - Expected '{' for call to [*] statement")); + return error_node(); } @@ -12828,13 +13491,15 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR69 - Expected a 'case' statement for multi-switch")); + "ERR73 - Expected a 'case' statement for multi-switch")); + return error_node(); } next_token(); expression_node_ptr condition = parse_expression(); + if (0 == condition) return error_node(); @@ -12843,11 +13508,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR70 - Expected ':' for case of [*] statement")); + "ERR74 - Expected ':' for case of [*] statement")); + return error_node(); } expression_node_ptr consequent = parse_expression(); + if (0 == consequent) return error_node(); @@ -12856,7 +13523,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR71 - Expected ';' at end of case for [*] statement")); + "ERR75 - Expected ';' at end of case for [*] statement")); + return error_node(); } @@ -12885,19 +13553,20 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR72 - Expected '}' at end of [*] statement")); + "ERR76 - Expected '}' at end of [*] statement")); + return error_node(); } result = expression_generator_.multi_switch_statement(arg_list); - sdd.delete_ptr = (0 == result); + svd.delete_ptr = (0 == result); return result; } inline expression_node_ptr parse_vararg_function() { - std::deque arg_list; + std::vector arg_list; expression_node_ptr result = error_node(); details::operator_type opt_type = details::e_default; @@ -12912,23 +13581,24 @@ namespace exprtk { return parse_multi_switch_statement(); } - else if (details::imatch(symbol,"sum" )) opt_type = details::e_sum; - else if (details::imatch(symbol,"mul" )) opt_type = details::e_prod; else if (details::imatch(symbol,"avg" )) opt_type = details::e_avg; - else if (details::imatch(symbol,"min" )) opt_type = details::e_min; - else if (details::imatch(symbol,"max" )) opt_type = details::e_max; else if (details::imatch(symbol,"mand")) opt_type = details::e_mand; + else if (details::imatch(symbol,"max" )) opt_type = details::e_max; + else if (details::imatch(symbol,"min" )) opt_type = details::e_min; else if (details::imatch(symbol,"mor" )) opt_type = details::e_mor; + else if (details::imatch(symbol,"mul" )) opt_type = details::e_prod; + else if (details::imatch(symbol,"sum" )) opt_type = details::e_sum; else { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR73 - Unsupported vararg function: " + symbol)); + "ERR77 - Unsupported vararg function: " + symbol)); + return error_node(); } - scoped_deq_delete sdd(*this,arg_list); + scoped_vec_delete sdd(*this,arg_list); next_token(); if (!token_is(token_t::e_lbracket)) @@ -12936,13 +13606,15 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR74 - Expected '(' for call to vararg function: " + symbol)); + "ERR78 - Expected '(' for call to vararg function: " + symbol)); + return error_node(); } for ( ; ; ) { expression_node_ptr arg = parse_expression(); + if (0 == arg) return error_node(); else @@ -12955,7 +13627,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR75 - Expected ',' for call to vararg function: " + symbol)); + "ERR79 - Expected ',' for call to vararg function: " + symbol)); + return error_node(); } } @@ -12981,7 +13654,10 @@ namespace exprtk { if (is_variable_node(expression_list[i])) continue; - else if (is_constant_node(expression_list[i])) + else if ( + is_constant_node(expression_list[i]) || + is_null_node (expression_list[i]) + ) { free_node(node_allocator_,expression_list[i]); continue; @@ -13012,24 +13688,29 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR76 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + + "ERR80 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + ((!source.empty()) ? std::string(" section of " + source): ""))); + return error_node(); } } - std::deque arg_list; + std::vector arg_list; expression_node_ptr result = error_node(); - scoped_deq_delete sdd(*this,arg_list); + scoped_vec_delete sdd(*this,arg_list); + + scope_handler sh(*this); for (;;) { expression_node_ptr arg = parse_expression(); + if (0 == arg) return error_node(); else arg_list.push_back(arg); + if (token_is(close_bracket)) break; @@ -13040,7 +13721,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR77 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source)); + "ERR81 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source)); + return error_node(); } @@ -13081,6 +13763,7 @@ namespace exprtk delete n0_e.second; } } + if (n1_e.first && n1_e.second) { n1_e.first = false; @@ -13166,7 +13849,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR78 - Expected '[' for start of range")); + "ERR82 - Expected '[' for start of range")); + return false; } @@ -13184,25 +13868,30 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR79 - Failed parse begin section of range")); + "ERR83 - Failed parse begin section of range")); + return false; } else if (is_constant_node(r0)) { T r0_value = r0->value(); + if (r0_value >= T(0)) { rp.n0_c.first = true; rp.n0_c.second = static_cast(r0_value); } + free_node(node_allocator_,r0); + if (r0_value < T(0)) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR80 - Range lower bound less than zero! Constraint: r0 >= 0")); + "ERR84 - Range lower bound less than zero! Constraint: r0 >= 0")); + return false; } } @@ -13217,7 +13906,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR81 - Expected ':' for break in range")); + "ERR85 - Expected ':' for break in range")); + rp.free(); return false; } @@ -13237,7 +13927,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR82 - Failed parse end section of range")); + "ERR86 - Failed parse end section of range")); + rp.free(); return false; @@ -13245,18 +13936,22 @@ namespace exprtk else if (is_constant_node(r1)) { T r1_value = r1->value(); + if (r1_value >= T(0)) { rp.n1_c.first = true; rp.n1_c.second = static_cast(r1_value); } + free_node(node_allocator_,r1); + if (r1_value < T(0)) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR83 - Range upper bound less than zero! Constraint: r1 >= 0")); + "ERR87 - Range upper bound less than zero! Constraint: r1 >= 0")); + return false; } } @@ -13271,7 +13966,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR84 - Expected ']' for start of range")); + "ERR88 - Expected ']' for start of range")); + rp.free(); return false; } @@ -13287,7 +13983,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR85 - Invalid range, Constraint: r0 <= r1")); + "ERR89 - Invalid range, Constraint: r0 <= r1")); + return false; } } @@ -13312,7 +14009,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR86 - Unknown string symbol")); + "ERR90 - Unknown string symbol")); + return error_node(); } @@ -13328,13 +14026,17 @@ namespace exprtk if (peek_token_is(token_t::e_lsqrbracket)) { next_token(); + range_pack rp; + if (!parse_range(rp)) { free_node(node_allocator_,result); return error_node(); } + result = expression_generator_(dynamic_cast*>(result)->ref(),rp); + if (result) rp.clear(); } @@ -13368,16 +14070,17 @@ namespace exprtk } if ( - (rp.n0_c.first && rp.n0_c.second >= const_str.size()) || - (rp.n1_c.first && rp.n1_c.second >= const_str.size()) + (rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || + (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) ) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR87 - Overflow in range for string: '" + const_str + "'[" + + "ERR91 - Overflow in range for string: '" + const_str + "'[" + (rp.n0_c.first ? details::to_str(rp.n0_c.second) : "?") + ":" + (rp.n1_c.first ? details::to_str(rp.n1_c.second) : "?") + "]")); + return error_node(); } @@ -13394,17 +14097,42 @@ namespace exprtk inline expression_node_ptr parse_vector() { - const std::string symbol = current_token_.value; - typename symbol_table_t::vector_ptr vec = symbol_table_.get_vector(symbol); + const std::string symbol = current_token_.value; + + typename symbol_table_t::vector_ptr vec = typename symbol_table_t::vector_ptr(0); + + const scope_element& se = sem_.get_element(symbol); + + if ( + (se.name != symbol) || + (scope_element::e_vector != se.type) || + (se.depth > scope_depth_) + ) + { + if (0 == (vec = symbol_table_.get_vector(symbol))) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR92 - Symbol '" + symbol+ " not a vector")); + + return error_node(); + } + } + else + vec = se.vec_node; + expression_node_ptr index_expr = error_node(); next_token(); + if (!token_is(token_t::e_lsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR88 - Expected '[' for index of vector: '" + symbol + "'")); + "ERR93 - Expected '[' for index of vector: '" + symbol + "'")); + return error_node(); } else if (token_is(token_t::e_rsqrbracket)) @@ -13416,7 +14144,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR89 - Failed to parse index for vector: '" + symbol + "'")); + "ERR94 - Failed to parse index for vector: '" + symbol + "'")); + return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) @@ -13424,7 +14153,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR90 - Expected ']' for index of vector: '" + symbol + "'")); + "ERR95 - Expected ']' for index of vector: '" + symbol + "'")); + + free_node(node_allocator_,index_expr); + return error_node(); } @@ -13441,34 +14173,31 @@ namespace exprtk scoped_vec_delete sdd(*this,arg_list); next_token(); - if (!token_is(token_t::e_lbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR91 - Expected '(' for call to vararg function: " + vararg_function_name)); - return error_node(); - } - if (!token_is(token_t::e_rbracket)) + if (token_is(token_t::e_lbracket)) { - for ( ; ; ) + if (!token_is(token_t::e_rbracket)) { - expression_node_ptr arg = parse_expression(); - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) + for ( ; ; ) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR92 - Expected ',' for call to vararg function: " + vararg_function_name)); - return error_node(); + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR96 - Expected ',' for call to vararg function: " + vararg_function_name)); + + return error_node(); + } } } } @@ -13491,12 +14220,14 @@ namespace exprtk scoped_delete sd(p,branch); p.next_token(); + if (!p.token_is(token_t::e_lbracket)) { p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR93 - Expected '(' for special function")); + "ERR97 - Expected '(' for special function")); + return error_node(); } @@ -13514,7 +14245,8 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR94 - Expected ',' before next parameter of special function")); + "ERR98 - Expected ',' before next parameter of special function")); + return p.error_node(); } } @@ -13524,7 +14256,9 @@ namespace exprtk return p.error_node(); else result = p.expression_generator_.special_function(opt_type,branch); + sd.delete_ptr = (0 == result); + return result; } }; @@ -13540,7 +14274,8 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token_, - "ERR95 - Invalid special function[1]: " + current_token_.value)); + "ERR99 - Invalid special function[1]: " + current_token_.value)); + return error_node(); } @@ -13551,7 +14286,8 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token_, - "ERR96 - Invalid special function[2]: " + current_token_.value)); + "ERR100 - Invalid special function[2]: " + current_token_.value)); + return error_node(); } @@ -13579,16 +14315,20 @@ namespace exprtk if (!brkcnt_list_.empty()) { next_token(); + brkcnt_list_.front() = true; - expression_node_ptr ret = error_node(); + + expression_node_ptr return_expr = error_node(); + if (token_is(token_t::e_lsqrbracket)) { - if (0 == (ret = parse_expression())) + if (0 == (return_expr = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR97 - Failed to parse return expression for 'break' statement")); + "ERR101 - Failed to parse return expression for 'break' statement")); + return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) @@ -13596,19 +14336,24 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR98 - Expected ']' at the completed of break's return expression")); + "ERR102 - Expected ']' at the completed of break's return expression")); + + free_node(node_allocator_,return_expr); + return error_node(); } } - return node_allocator_.allocate >(ret); + + return node_allocator_.allocate >(return_expr); } else { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR99 - Invalid use of 'break', allowed only in the scope of a loop")); + "ERR103 - Invalid use of 'break', allowed only in the scope of a loop")); } + return error_node(); } @@ -13625,12 +14370,571 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR100 - Invalid use of 'continue', allowed only in the scope of a loop")); + "ERR104 - Invalid use of 'continue', allowed only in the scope of a loop")); + return error_node(); } } #endif + inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) + { + expression_node_ptr size_expr = error_node(); + + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR105 - Expected '[' as part of vector size definition")); + + return error_node(); + } + else if (0 == (size_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR106 - Failed to determine size of vector '" + vec_name + "'")); + + return error_node(); + } + else if (!is_constant_node(size_expr)) + { + free_node(node_allocator_,size_expr); + + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR107 - Expected a literal number as size of vector '" + vec_name + "'")); + + return error_node(); + } + + T vector_size = size_expr->value(); + + free_node(node_allocator_,size_expr); + + if ( + (vector_size <= T(0)) || + (0 != (vector_size - details::numeric::trunc(vector_size))) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR108 - Invalid vector size. Must be an integer greater than zero, size: " + + details::to_str((int)vector_size))); + + return error_node(); + } + + std::vector vec_initilizer_list; + + scoped_vec_delete svd(*this,vec_initilizer_list); + + bool single_value_initialiser = false; + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR109 - Expected ']' as part of vector size definition")); + + return error_node(); + } + else if (!token_is(token_t::e_assign)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR110 - Expected ':=' as part of vector definition")); + + return error_node(); + } + else if (!token_is(token_t::e_eof)) + { + if (token_is(token_t::e_lsqrbracket)) + { + expression_node_ptr initialiser = parse_expression(); + + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR111 - Failed to parse single vector initialiser")); + + return error_node(); + } + + vec_initilizer_list.push_back(initialiser); + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR112 - Expected ']' to close single value vector initialiszer")); + + return error_node(); + } + + single_value_initialiser = true; + } + else if (!token_is(token_t::e_lcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR113 - Expected '{' as part of vector initialiser list")); + + return error_node(); + } + else if (!token_is(token_t::e_rcrlbracket)) + { + for (;;) + { + expression_node_ptr initialiser = parse_expression(); + + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR114 - Expected '{' as part of vector initialiser list")); + + return error_node(); + } + else + vec_initilizer_list.push_back(initialiser); + + if (token_is(token_t::e_rcrlbracket)) + break; + + bool is_next_close = peek_token_is(token_t::e_rcrlbracket); + + if (!token_is(token_t::e_comma) && is_next_close) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR115 - Expected ',' between vector initialisers")); + + return error_node(); + } + + if (token_is(token_t::e_rcrlbracket)) + break; + } + } + + if ( + !token_is(token_t::e_rbracket ,false) && + !token_is(token_t::e_rcrlbracket,false) && + !token_is(token_t::e_rsqrbracket,false) + ) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR116 - Expected ';' at end of vector definition")); + + return error_node(); + } + } + + if (vec_initilizer_list.size() > vector_size) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR117 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'")); + + return error_node(); + } + } + + typename symbol_table_t::vector_ptr vec_holder = typename symbol_table_t::vector_ptr(0); + + std::size_t vec_size = static_cast(vector_size); + + scope_element& se = sem_.get_element(vec_name,vec_size); + + if ((se.name == vec_name) && se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR118 - Illegal redefinition of local vector: '" + vec_name + "'")); + + return error_node(); + } + + if (0 == vec_holder) + { + scope_element nse; + nse.name = vec_name; + nse.type = scope_element::e_vector; + nse.depth = scope_depth_; + nse.size = vec_size; + nse.data = new T[vec_size]; + nse.vec_node = new typename scope_element::vector_holder_t((T*)(nse.data),nse.size); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR119 - Failed to add new local variable to SEM")); + + return error_node(); + } + + vec_holder = nse.vec_node; + + #ifdef exprtk_enable_debugging + printf("parse_define_vector_statement() - INFO - Added new local vector: %s\n",nse.name.c_str()); + #endif + } + + expression_node_ptr result = + node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list, + single_value_initialiser); + + svd.delete_ptr = (0 == result); + + return result; + } + + inline bool local_variable_is_shadowed(const std::string& symbol) + { + const scope_element& se = sem_.get_element(symbol); + return (se.name == symbol); + } + + inline expression_node_ptr parse_define_var_statement() + { + if (vardef_disabled_) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR120 - Illegal variable definition")); + + return error_node(); + } + else if (!details::imatch(current_token_.value,"var")) + { + return error_node(); + } + else + next_token(); + + const std::string var_name = current_token_.value; + + expression_node_ptr initialisation_expression = error_node(); + + if (!token_is(token_t::e_symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR121 - Expected a symbol for variable definition")); + + return error_node(); + } + else if (details::is_reserved_symbol(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR122 - Illegal redefinition of reserved keyword: '" + var_name + "'")); + + return error_node(); + } + else if (symbol_table_.symbol_exists(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR123 - Illegal redefinition of variable '" + var_name + "'")); + + return error_node(); + } + else if (local_variable_is_shadowed(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR124 - Illegal redefinition of local variable: '" + var_name + "'")); + + return error_node(); + } + else if (token_is(token_t::e_lsqrbracket,false)) + { + return parse_define_vector_statement(var_name); + } + else if (token_is(token_t::e_assign)) + { + if (0 == (initialisation_expression = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR125 - Failed to parse initialisation expression")); + + return error_node(); + } + } + + if ( + !token_is(token_t::e_rbracket ,false) && + !token_is(token_t::e_rcrlbracket,false) && + !token_is(token_t::e_rsqrbracket,false) + ) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR126 - Expected ';' after variable definition")); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + } + + variable_node_t* var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR127 - Illegal redefinition of local variable: '" + var_name + "'")); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + else if (scope_element::e_variable == se.type) + var_node = se.var_node; + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.type = scope_element::e_variable; + nse.depth = scope_depth_; + nse.data = new T(T(0)); + nse.var_node = new variable_node_t(*(T*)(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR128 - Failed to add new local variable '" + var_name + "' to SEM")); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + + var_node = nse.var_node; + + #ifdef exprtk_enable_debugging + printf("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str()); + #endif + } + + expression_node_ptr branch[2] = {0}; + branch[0] = var_node; + branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); + return expression_generator_(details::e_assign,branch); + } + + inline expression_node_ptr parse_swap_statement() + { + if (!details::imatch(current_token_.value,"swap")) + { + return error_node(); + } + else + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR129 - Expected '(' at start of swap statement")); + + return error_node(); + } + + expression_node_ptr variable0 = error_node(); + expression_node_ptr variable1 = error_node(); + + const std::string var0_name = current_token_.value; + + if (!token_is(token_t::e_symbol,false)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR130 - Expected a symbol for variable or vector element definition")); + + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable0 = parse_vector())) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR131 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); + + return error_node(); + } + } + else + { + if (symbol_table_.is_variable(var0_name)) + { + variable0 = symbol_table_.get_variable(var0_name); + } + + scope_element& se = sem_.get_element(var0_name); + + if ( + (se.active) && + (se.name == var0_name) && + (scope_element::e_variable == se.type) + ) + { + variable0 = se.var_node; + } + + if (0 == variable0) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR132 - First parameter to swap is an invalid variable: '" + var0_name + "'")); + + return error_node(); + } + else + next_token(); + } + + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR133 - Expected ',' between parameters to swap")); + + return error_node(); + } + + const std::string var1_name = current_token_.value; + + if (!token_is(token_t::e_symbol,false)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR134 - Expected a symbol for variable or vector element definition")); + + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable1 = parse_vector())) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR135 - Second parameter to swap is an invalid vector element: '" + var1_name + "'")); + + return error_node(); + } + } + else + { + if (symbol_table_.is_variable(var1_name)) + { + variable1 = symbol_table_.get_variable(var1_name); + } + + scope_element& se = sem_.get_element(var1_name); + + if ( + (se.active) && + (se.name == var1_name) && + (scope_element::e_variable == se.type) + ) + { + variable1 = se.var_node; + } + + if (0 == variable1) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR136 - Second parameter to swap is an invalid variable: '" + var1_name + "'")); + + return error_node(); + } + else + next_token(); + } + + if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR137 - Expected ')' at end of swap statement")); + + return error_node(); + } + + typedef details::variable_node* variable_node_ptr; + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + if ( + (0 != (v0 = dynamic_cast(variable0))) && + (0 != (v1 = dynamic_cast(variable1))) + ) + { + return node_allocator_.allocate >(v0,v1); + } + else + return node_allocator_.allocate >(variable0,variable1); + } + inline expression_node_ptr parse_symtab_symbol() { const std::string symbol = current_token_.value; @@ -13647,17 +14951,24 @@ namespace exprtk return variable; } - // Are we dealing with a local variable? - variable = local_symbol_table_.get_variable(symbol); - if (variable) + // Are we dealing with a locally defined variable or vector? + if (!sem_.empty()) { - cache_symbol(symbol); - if (local_symbol_table_.is_constant_node(symbol)) + scope_element& se = sem_.get_element(symbol); + if (se.name == symbol) { - variable = expression_generator_(variable->value()); + if (scope_element::e_variable == se.type) + { + se.active = true; + cache_symbol(symbol); + next_token(); + return se.var_node; + } + else if (scope_element::e_vector == se.type) + { + return parse_vector(); + } } - next_token(); - return variable; } #ifndef exprtk_disable_string_capabilities @@ -13673,49 +14984,7 @@ namespace exprtk if (function) { - expression_node_ptr func_node = reinterpret_cast(0); - switch (function->param_count) - { - case 0 : func_node = parse_function_call_0 (function,symbol); break; - case 1 : func_node = parse_function_call< 1>(function,symbol); break; - case 2 : func_node = parse_function_call< 2>(function,symbol); break; - case 3 : func_node = parse_function_call< 3>(function,symbol); break; - case 4 : func_node = parse_function_call< 4>(function,symbol); break; - case 5 : func_node = parse_function_call< 5>(function,symbol); break; - case 6 : func_node = parse_function_call< 6>(function,symbol); break; - case 7 : func_node = parse_function_call< 7>(function,symbol); break; - case 8 : func_node = parse_function_call< 8>(function,symbol); break; - case 9 : func_node = parse_function_call< 9>(function,symbol); break; - case 10 : func_node = parse_function_call<10>(function,symbol); break; - case 11 : func_node = parse_function_call<11>(function,symbol); break; - case 12 : func_node = parse_function_call<12>(function,symbol); break; - case 13 : func_node = parse_function_call<13>(function,symbol); break; - case 14 : func_node = parse_function_call<14>(function,symbol); break; - case 15 : func_node = parse_function_call<15>(function,symbol); break; - case 16 : func_node = parse_function_call<16>(function,symbol); break; - case 17 : func_node = parse_function_call<17>(function,symbol); break; - case 18 : func_node = parse_function_call<18>(function,symbol); break; - case 19 : func_node = parse_function_call<19>(function,symbol); break; - case 20 : func_node = parse_function_call<20>(function,symbol); break; - default : { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR101 - Invalid number of parameters for function: " + symbol)); - return error_node(); - } - } - - if (func_node) - return func_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR102 - Failed to generate node for function: '" + symbol + "'")); - return error_node(); - } + return parse_function_invocation(function,symbol); } // Are we dealing with a vararg function? @@ -13733,7 +15002,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR103 - Failed to generate node for vararg function: '" + symbol + "'")); + "ERR138 - Failed to generate node for vararg function: '" + symbol + "'")); + return error_node(); } } @@ -13749,7 +15019,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR104 - Invalid use of reserved symbol '" + symbol + "'")); + "ERR139 - Invalid use of reserved symbol '" + symbol + "'")); + return error_node(); } @@ -13777,6 +15048,7 @@ namespace exprtk if (create_result) { expression_node_ptr variable = symbol_table_.get_variable(symbol); + if (variable) { cache_symbol(symbol); @@ -13784,7 +15056,9 @@ namespace exprtk { variable = expression_generator_(variable->value()); } + next_token(); + return variable; } } @@ -13792,7 +15066,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token_, - "ERR105 - Failed to create variable: '" + symbol + "'")); + "ERR140 - Failed to create variable: '" + symbol + "'")); return error_node(); } @@ -13801,7 +15075,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR106 - Undefined variable or function: '" + symbol + "'")); + "ERR141 - Undefined variable or function: '" + symbol + "'")); + return error_node(); } @@ -13815,6 +15090,8 @@ namespace exprtk static const std::string symbol_null = "null" ; static const std::string symbol_break = "break" ; static const std::string symbol_continue = "continue"; + static const std::string symbol_var = "var" ; + static const std::string symbol_swap = "swap" ; if (valid_vararg_operation(current_token_.value)) { @@ -13862,7 +15139,15 @@ namespace exprtk return parse_continue_statement(); } #endif - else if (symbol_table_.valid()) + else if (details::imatch(current_token_.value,symbol_var)) + { + return parse_define_var_statement(); + } + else if (details::imatch(current_token_.value,symbol_swap)) + { + return parse_swap_statement(); + } + else if (symbol_table_.valid() || !sem_.empty()) { return parse_symtab_symbol(); } @@ -13871,7 +15156,8 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token_, - "ERR107 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); + "ERR142 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); + return error_node(); } } @@ -13895,7 +15181,8 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token_, - "ERR108 - Failed to convert '" + current_token_.value + "' to a number")); + "ERR143 - Failed to convert '" + current_token_.value + "' to a number")); + return error_node(); } } @@ -13919,7 +15206,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR109 - Expected ')' instead of: '" + current_token_.value + "'")); + "ERR144 - Expected ')' instead of: '" + current_token_.value + "'")); + return error_node(); } } @@ -13933,7 +15221,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR110 - Expected ']' instead of: '" + current_token_.value + "'")); + "ERR145 - Expected ']' instead of: '" + current_token_.value + "'")); + return error_node(); } } @@ -13947,7 +15236,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR111 - Expected '}' instead of: '" + current_token_.value + "'")); + "ERR146 - Expected '}' instead of: '" + current_token_.value + "'")); + return error_node(); } } @@ -13970,7 +15260,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR112 - Premature end of expression[1]")); + "ERR147 - Premature end of expression[1]")); + return error_node(); } else @@ -13978,7 +15269,8 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR113 - Premature end of expression[2]")); + "ERR148 - Premature end of expression[2]")); + return error_node(); } @@ -14272,7 +15564,8 @@ namespace exprtk return (details::e_addass == operation) || (details::e_subass == operation) || (details::e_mulass == operation) || - (details::e_divass == operation); + (details::e_divass == operation) || + (details::e_modass == operation); } #ifndef exprtk_disable_string_capabilities @@ -14496,7 +15789,7 @@ namespace exprtk result = true; if (result) { - parser_->set_synthesis_error("Invalid string operation."); + parser_->set_synthesis_error("Invalid string operation"); } return result; } @@ -14513,7 +15806,7 @@ namespace exprtk result = true; if (result) { - parser_->set_synthesis_error("Invalid string operation."); + parser_->set_synthesis_error("Invalid string operation"); } return result; } @@ -14563,6 +15856,8 @@ namespace exprtk return error_node(); else if (details::e_assign == operation) return synthesize_assignment_expression(operation,branch); + else if (details::e_swap == operation) + return synthesize_swap_expression(branch); else if (is_assignment_operation(operation)) return synthesize_assignment_operation_expression(operation,branch); else if (is_shortcircuit_expression(operation)) @@ -14693,6 +15988,7 @@ namespace exprtk result = error_node(); else result = node_allocator_->allocate >(); + free_node(*node_allocator_,condition); free_node(*node_allocator_,branch); return result; @@ -14723,9 +16019,11 @@ namespace exprtk free_node(*node_allocator_,condition); return branch; } + expression_node_ptr result = error_node(); free_node(*node_allocator_,condition); free_node(*node_allocator_,branch); + return result; } else if (details::is_null_node(condition)) @@ -14743,52 +16041,48 @@ namespace exprtk #endif } - inline expression_node_ptr for_loop(expression_node_ptr initializer, + inline expression_node_ptr for_loop(expression_node_ptr initialiser, expression_node_ptr condition, expression_node_ptr incrementor, expression_node_ptr loop_body, - expression_node_ptr loop_var, - T* loop_counter, bool brkcont = false) const { if (details::is_constant_node(condition)) { expression_node_ptr result = error_node(); + if (details::is_true(condition)) // Infinite loops are not allowed. result = error_node(); else result = node_allocator_->allocate >(); - free_node(*node_allocator_,initializer ); + + free_node(*node_allocator_,initialiser ); free_node(*node_allocator_,condition ); free_node(*node_allocator_,incrementor ); free_node(*node_allocator_,loop_body ); - free_node(*node_allocator_,loop_var ,true); - delete loop_counter; + return result; } else if (details::is_null_node(condition)) { - free_node(*node_allocator_,initializer); - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,incrementor); + free_node(*node_allocator_,initialiser ); + free_node(*node_allocator_,condition ); + free_node(*node_allocator_,incrementor ); + return loop_body; } else if (!brkcont) - return node_allocator_->allocate(initializer, + return node_allocator_->allocate(initialiser, condition, incrementor, - loop_body, - loop_var, - loop_counter); + loop_body); #ifndef exprtk_disable_break_continue else - return node_allocator_->allocate(initializer, + return node_allocator_->allocate(initialiser, condition, incrementor, - loop_body, - loop_var, - loop_counter); + loop_body); #else return error_node(); #endif @@ -14796,14 +16090,14 @@ namespace exprtk template class Sequence> - inline expression_node_ptr const_optimize_switch(Sequence& arglist) + inline expression_node_ptr const_optimize_switch(Sequence& arg_list) { expression_node_ptr result = error_node(); - for (std::size_t i = 0; i < (arglist.size() / 2); ++i) + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) { - expression_node_ptr condition = arglist[(2 * i) ]; - expression_node_ptr consequent = arglist[(2 * i) + 1]; + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; if ((0 == result) && details::is_true(condition)) { @@ -14814,12 +16108,12 @@ namespace exprtk if (0 == result) { - result = arglist.back(); + result = arg_list.back(); } - for (std::size_t i = 0; i < arglist.size(); ++i) + for (std::size_t i = 0; i < arg_list.size(); ++i) { - expression_node_ptr current_expr = arglist[i]; + expression_node_ptr current_expr = arg_list[i]; if (current_expr && (current_expr != result)) { @@ -14832,14 +16126,14 @@ namespace exprtk template class Sequence> - inline expression_node_ptr const_optimize_mswitch(Sequence& arglist) + inline expression_node_ptr const_optimize_mswitch(Sequence& arg_list) { expression_node_ptr result = error_node(); - for (std::size_t i = 0; i < (arglist.size() / 2); ++i) + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) { - expression_node_ptr condition = arglist[(2 * i) ]; - expression_node_ptr consequent = arglist[(2 * i) + 1]; + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; if (details::is_true(condition)) { @@ -14853,9 +16147,9 @@ namespace exprtk result = node_allocator_->allocate(zero); } - for (std::size_t i = 0; i < arglist.size(); ++i) + for (std::size_t i = 0; i < arg_list.size(); ++i) { - expression_node_ptr current_expr = arglist[i]; + expression_node_ptr current_expr = arg_list[i]; if (current_expr && (current_expr != result)) { @@ -14868,32 +16162,32 @@ namespace exprtk template class Sequence> - inline expression_node_ptr switch_statement(Sequence& arglist) + inline expression_node_ptr switch_statement(Sequence& arg_list) { - if (!all_nodes_valid(arglist)) + if (!all_nodes_valid(arg_list)) { - details::free_all_nodes(*node_allocator_,arglist); + details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } - else if (is_constant_foldable(arglist)) - return const_optimize_switch(arglist); + else if (is_constant_foldable(arg_list)) + return const_optimize_switch(arg_list); else - return node_allocator_->allocate >(arglist); + return node_allocator_->allocate >(arg_list); } template class Sequence> - inline expression_node_ptr multi_switch_statement(Sequence& arglist) + inline expression_node_ptr multi_switch_statement(Sequence& arg_list) { - if (!all_nodes_valid(arglist)) + if (!all_nodes_valid(arg_list)) { - details::free_all_nodes(*node_allocator_,arglist); + details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } - else if (is_constant_foldable(arglist)) - return const_optimize_mswitch(arglist); + else if (is_constant_foldable(arg_list)) + return const_optimize_mswitch(arg_list); else - return node_allocator_->allocate >(arglist); + return node_allocator_->allocate >(arg_list); } #define unary_opr_switch_statements \ @@ -15235,7 +16529,7 @@ namespace exprtk template class Sequence> - inline expression_node_ptr const_optimize_varargfunc(const details::operator_type& operation, Sequence& arglist) + inline expression_node_ptr const_optimize_varargfunc(const details::operator_type& operation, Sequence& arg_list) { expression_node_ptr temp_node = error_node(); switch (operation) @@ -15243,7 +16537,7 @@ namespace exprtk #define case_stmt(op0,op1) \ case op0 : temp_node = node_allocator_-> \ allocate > > \ - (arglist); \ + (arg_list); \ break; \ case_stmt(details::e_sum, details::vararg_add_op ) @@ -15275,13 +16569,13 @@ namespace exprtk template class Sequence> - inline expression_node_ptr varnode_optimize_varargfunc(const details::operator_type& operation, Sequence& arglist) + inline expression_node_ptr varnode_optimize_varargfunc(const details::operator_type& operation, Sequence& arg_list) { switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arglist); \ + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ case_stmt(details::e_sum, details::vararg_add_op ) case_stmt(details::e_prod, details::vararg_mul_op ) @@ -15298,25 +16592,25 @@ namespace exprtk template class Sequence> - inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arglist) + inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) { - if (!all_nodes_valid(arglist)) + if (!all_nodes_valid(arg_list)) { - details::free_all_nodes(*node_allocator_,arglist); + details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } - else if (is_constant_foldable(arglist)) - return const_optimize_varargfunc(operation,arglist); - else if ((arglist.size() == 1) && special_one_parameter_vararg(operation)) - return arglist[0]; - else if (all_nodes_variables(arglist)) - return varnode_optimize_varargfunc(operation,arglist); + else if (is_constant_foldable(arg_list)) + return const_optimize_varargfunc(operation,arg_list); + else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) + return arg_list[0]; + else if (all_nodes_variables(arg_list)) + return varnode_optimize_varargfunc(operation,arg_list); switch (operation) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arglist); \ + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ case_stmt(details::e_sum, details::vararg_add_op ) case_stmt(details::e_prod, details::vararg_mul_op ) @@ -15378,17 +16672,23 @@ namespace exprtk } inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, - std::vector& arglist) + std::vector& arg_list) { - if (!all_nodes_valid(arglist)) + if (!all_nodes_valid(arg_list)) { - details::free_all_nodes(*node_allocator_,arglist); + details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } - expression_node_ptr result = node_allocator_->allocate > >(vaf,arglist); + typedef details::vararg_function_node alloc_type; - if (!arglist.empty() && is_constant_foldable(arglist)) + expression_node_ptr result = node_allocator_->allocate(vaf,arg_list); + + if ( + !arg_list.empty() && + !vaf->has_side_effects && + is_constant_foldable(arg_list) + ) { Type v = result->value(); details::free_node(*node_allocator_,result); @@ -15409,20 +16709,32 @@ namespace exprtk std::size_t i = static_cast(index->value()); details::free_node(*node_allocator_,index); Type* v = (*vector_base)[i]; - const std::string vec_symbol = symbol + "__" + details::to_str(i); - bool created_var = false; - if (!parser_->local_symbol_table_.symbol_exists(vec_symbol)) + scope_element& se = parser_->sem_.get_element(symbol,i); + + if (se.index == i) { - parser_->local_symbol_table_.add_variable(vec_symbol,(*v)); - created_var = true; + result = se.var_node; } - - result = parser_->local_symbol_table_.get_variable(vec_symbol); - - if (created_var) + else { - parser_->register_local_var(result); + scope_element nse; + nse.name = symbol; + nse.type = scope_element::e_vecelem; + nse.index = i; + nse.depth = parser_->scope_depth_; + nse.data = 0; + nse.var_node = new variable_node_t((*v)); + if (!parser_->sem_.add_element(nse)) + { + parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); + result = error_node(); + } + #ifdef exprtk_enable_debugging + else + printf("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str()); + #endif + result = nse.var_node; } } else @@ -15492,6 +16804,7 @@ namespace exprtk case_stmt(details:: e_subass,details:: sub_op) case_stmt(details:: e_mulass,details:: mul_op) case_stmt(details:: e_divass,details:: div_op) + case_stmt(details:: e_modass,details:: mod_op) #undef case_stmt default : return error_node(); } @@ -15509,17 +16822,44 @@ namespace exprtk case_stmt(details:: e_subass,details:: sub_op) case_stmt(details:: e_mulass,details:: mul_op) case_stmt(details:: e_divass,details:: div_op) + case_stmt(details:: e_modass,details:: mod_op) #undef case_stmt default : return error_node(); } } else { - parser_->set_synthesis_error("Invalid assignment operation[2]."); + parser_->set_synthesis_error("Invalid assignment operation[2]"); return error_node(); } } + inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) + { + const bool v0_is_ivar = details::is_ivariable_node(branch[0]); + const bool v1_is_ivar = details::is_ivariable_node(branch[1]); + + if (!v0_is_ivar || !v1_is_ivar) + { + parser_->set_synthesis_error("Only variables or vector elements can be swapped"); + return error_node(); + } + + typedef details::variable_node* variable_node_ptr; + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + if ( + (0 != (v0 = dynamic_cast(branch[0]))) && + (0 != (v1 = dynamic_cast(branch[1]))) + ) + { + return node_allocator_->allocate >(v0,v1); + } + else + return node_allocator_->allocate >(branch[0],branch[1]); + } + #ifndef exprtk_disable_sc_andor inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { @@ -15746,8 +17086,8 @@ namespace exprtk if (details::is_cob_node(branch[1])) { // Simplify expressions of the form: - // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) - // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) + // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) ---> 40320 * (9 + x) + // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) ---> 45 + x if ( (operation == details::e_mul) || (operation == details::e_add) @@ -15852,8 +17192,8 @@ namespace exprtk if (details::is_boc_node(branch[0])) { // Simplify expressions of the form: - // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) - // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) + // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) ---> (x + 9) * 40320 + // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) ---> x + 45 if ( (operation == details::e_mul) || (operation == details::e_add) @@ -15917,7 +17257,9 @@ namespace exprtk } }; - inline bool synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2], expression_node_ptr& result) + inline bool synthesize_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2], + expression_node_ptr& result) { result = error_node(); if (!operation_optimizable(operation)) @@ -17083,7 +18425,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; struct synthesize_vovovoc_expression0 @@ -17129,7 +18471,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17176,7 +18518,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17223,7 +18565,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17270,7 +18612,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17371,8 +18713,13 @@ namespace exprtk } // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) else if ( - (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && - ((details::e_add == o1) || (details::e_sub == o1)) + (c0 == c1) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) ) { std::string specfunc; @@ -17405,7 +18752,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17506,8 +18853,13 @@ namespace exprtk } // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) else if ( - (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && - ((details::e_add == o1) || (details::e_sub == o1)) + (c0 == c1) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) ) { std::string specfunc; @@ -17540,7 +18892,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17641,8 +18993,13 @@ namespace exprtk } // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) else if ( - (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && - ((details::e_add == o1) || (details::e_sub == o1)) + (c0 == c1) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) ) { std::string specfunc; @@ -17675,7 +19032,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17776,8 +19133,12 @@ namespace exprtk } // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) else if ( - (details::e_mul == o0) && (details::e_mul == o2) && (c0 == c1) && - ((details::e_add == o1) || (details::e_sub == o1)) + (c0 == c1) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || (details::e_sub == o1) + ) ) { std::string specfunc; @@ -17810,7 +19171,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); } }; @@ -17852,7 +19213,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -17894,7 +19255,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -17936,7 +19297,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -17978,7 +19339,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -18021,7 +19382,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -18064,7 +19425,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -18106,7 +19467,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -18149,7 +19510,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -18191,7 +19552,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); } }; @@ -18233,7 +19594,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18275,7 +19636,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18317,7 +19678,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18359,7 +19720,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18402,7 +19763,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18445,7 +19806,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18487,7 +19848,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18530,7 +19891,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); } }; @@ -18588,7 +19949,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18631,7 +19992,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18673,7 +20034,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18715,7 +20076,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18757,7 +20118,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18799,7 +20160,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18842,7 +20203,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18885,7 +20246,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18927,7 +20288,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -18969,7 +20330,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19012,7 +20373,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19054,7 +20415,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19096,7 +20457,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19138,7 +20499,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19180,7 +20541,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19223,7 +20584,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19266,7 +20627,7 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t"<< expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); } }; @@ -19418,7 +20779,6 @@ namespace exprtk return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); } - inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { std::string& s0 = dynamic_cast*>(branch[0])->ref(); @@ -19902,38 +21262,45 @@ namespace exprtk } } - inline void register_local_var(expression_node_ptr var) - { - local_var_set_.insert(var); - } - - inline void clear_local_vars() - { - if (!local_var_set_.empty()) - { - typedef std::set set_t; - typename set_t::iterator itr = local_var_set_.begin(); - while (local_var_set_.end() != itr) - { - delete *itr; - ++itr; - } - local_var_set_.clear(); - } - } - inline void register_local_vars(expression& e) { - if (!local_var_set_.empty()) + for (std::size_t i = 0; i < sem_.size(); ++i) { - typedef std::set set_t; - typename set_t::iterator itr = local_var_set_.begin(); - while (local_var_set_.end() != itr) + scope_element& se = sem_.get_element(i); + + if ( + (scope_element::e_variable == se.type) || + (scope_element::e_vecelem == se.type) + ) { - e.register_local_var(*itr); - ++itr; + if (se.var_node) + { + e.register_local_var (se.var_node); + } + + if (se.data) + { + e.register_local_data(se.data); + } } - local_var_set_.clear(); + else if (scope_element::e_vector == se.type) + { + if (se.vec_node) + { + e.register_local_var (se.vec_node ); + } + + if (se.data) + { + e.register_local_data(se.data,true); + } + } + + se.var_node = 0; + se.vec_node = 0; + se.data = 0; + se.ref_count = 0; + se.active = false; } } @@ -20100,14 +21467,14 @@ namespace exprtk expression_generator expression_generator_; details::node_allocator node_allocator_; symbol_table_t symbol_table_; - symbol_table_t local_symbol_table_; bool symbol_name_caching_; std::size_t compile_options_; - std::set local_var_set_; std::deque symbol_name_cache_; std::deque error_list_; std::deque brkcnt_list_; bool resolve_unknown_symbol_; + bool vardef_disabled_; + std::size_t scope_depth_; unknown_symbol_resolver* unknown_symbol_resolver_; unknown_symbol_resolver default_usr_; base_ops_map_t base_ops_map_; @@ -20117,6 +21484,7 @@ namespace exprtk sf3_map_t sf3_map_; sf4_map_t sf4_map_; std::string synthesis_error_; + scope_element_manager sem_; lexer::helper::helper_assembly helper_assembly_; @@ -20135,9 +21503,12 @@ namespace exprtk const T& r0, const T& r1, const std::size_t number_of_intervals = 1000000) { - if (r0 > r1) return T(0); + if (r0 > r1) + return T(0); + T h = (r1 - r0) / (T(2) * number_of_intervals); T total_area = T(0); + for (std::size_t i = 0; i < number_of_intervals; ++i) { x = r0 + T(2) * i * h; @@ -20146,6 +21517,7 @@ namespace exprtk T y2 = e.value(); x += h; total_area += h * (y0 + T(4) * y1 + y2) / T(3); } + return total_area; } @@ -20156,9 +21528,12 @@ namespace exprtk const std::size_t number_of_intervals = 1000000) { symbol_table& sym_table = e.get_symbol_table(); + if (!sym_table.valid()) return std::numeric_limits::quiet_NaN(); + details::variable_node* var = sym_table.get_variable(variable_name); + if (var) { T& x = var->ref(); @@ -20253,9 +21628,12 @@ namespace exprtk const T& h = T(0.00001)) { symbol_table& sym_table = e.get_symbol_table(); + if (!sym_table.valid()) return std::numeric_limits::quiet_NaN(); + details::variable_node* var = sym_table.get_variable(variable_name); + if (var) { T& x = var->ref(); @@ -20274,9 +21652,12 @@ namespace exprtk const T& h = T(0.0001)) { symbol_table& sym_table = e.get_symbol_table(); + if (!sym_table.valid()) return std::numeric_limits::quiet_NaN(); + details::variable_node* var = sym_table.get_variable(variable_name); + if (var) { T& x = var->ref(); @@ -20670,6 +22051,9 @@ namespace exprtk v.resize(param_count); } + virtual ~base_func() + {} + inline void update(const T& v0) { (*v[0]) = v0; @@ -20706,66 +22090,19 @@ namespace exprtk (*v[4]) = v4; (*v[5]) = v5; } - inline function_t& setup(expression_t& expr, T& v0, T& v1, T& v2, T& v3, T& v4, T& v5) + template class Sequence> + inline function_t& setup(expression_t& expr, Sequence vd) { expression = expr; - v[0] = &v0; v[1] = &v1; - v[2] = &v2; v[3] = &v3; - v[4] = &v4; v[5] = &v5; + for (std::size_t i = 0; i < vd.size(); ++i) + { + v[i] = vd[i]; + } clear_stack(); return (*this); } - inline function_t& setup(expression_t& expr, T& v0, T& v1, T& v2, T& v3, T& v4) - { - expression = expr; - v[0] = &v0; v[1] = &v1; - v[2] = &v2; v[3] = &v3; - v[4] = &v4; - clear_stack(); - return (*this); - } - - inline function_t& setup(expression_t& expr, T& v0, T& v1, T& v2, T& v3) - { - expression = expr; - v[0] = &v0; v[1] = &v1; - v[2] = &v2; v[3] = &v3; - clear_stack(); - return (*this); - } - - inline function_t& setup(expression_t& expr, T& v0, T& v1, T& v2) - { - expression = expr; - v[0] = &v0; v[1] = &v1; - v[2] = &v2; - clear_stack(); - return (*this); - } - - inline function_t& setup(expression_t& expr, T& v0, T& v1) - { - expression = expr; - v[0] = &v0; v[1] = &v1; - clear_stack(); - return (*this); - } - - inline function_t& setup(expression_t& expr, T& v0) - { - expression = expr; - v[0] = &v0; - clear_stack(); - return (*this); - } - - inline function_t& setup(expression_t& expr) - { - expression = expr; - return (*this); - } - inline void pre() { if (stack_depth++) @@ -20815,6 +22152,8 @@ namespace exprtk std::deque stack; }; + typedef std::map funcparam_t; + struct func_0param : public base_func { func_0param() : base_func(0) {} @@ -20911,19 +22250,72 @@ namespace exprtk } }; + template class Sequence> + inline bool add(const std::string& name, + const std::string& expression, + const Sequence& var_list) + { + const std::size_t n = var_list.size(); + std::vector v(n,0); + std::vector sv(n); + if (expr_map_.end() != expr_map_.find(name)) + return false; + else if (!forward(name,n)) + return false; + + std::vector > var_transform_list; + for (std::size_t i = 0; i < var_list.size(); ++i) + { + if (!add_variable(var_list[i],v[i],sv[i])) + { + for (std::size_t j = 0; j <= i; ++j) + { + delete v[j]; + } + remove(name,n); + return false; + } + else + var_transform_list.push_back(std::make_pair(var_list[i],sv[i])); + } + + if (compile_expression(name,expression,var_transform_list)) + { + fp_map_[n][name]->setup(expr_map_[name],v); + return true; + } + else + { + remove(name,sv); + for (std::size_t i = 0; i < v.size(); ++i) + { + delete v[i]; + } + return false; + } + } + public: function_compositor() - : suffix_index_(1), + : fp_map_(7), + suffix_index_(1), id_(get_id()) {} function_compositor(const symbol_table_t& st) : symbol_table_(st), + fp_map_(7), suffix_index_(1), id_(get_id()) {} + ~function_compositor() + { + clear(); + } + inline symbol_table_t& symbol_table() { return symbol_table_; @@ -20933,49 +22325,35 @@ namespace exprtk { symbol_table_.clear(); expr_map_.clear(); - f0p_map_.clear(); - f1p_map_.clear(); - f2p_map_.clear(); - f3p_map_.clear(); - f4p_map_.clear(); - f5p_map_.clear(); - f6p_map_.clear(); + + for (std::size_t i = 0; i < fp_map_.size(); ++i) + { + typename funcparam_t::iterator itr = fp_map_[i].begin(); + typename funcparam_t::iterator end = fp_map_[i].end(); + + while (itr != end) + { + delete itr->second; + ++itr; + } + + fp_map_[i].clear(); + } + suffix_index_ = 1; } inline bool add(const function& f) { - switch (f.v_.size()) - { - case 0 : return add(f.name_,f.expression_); - case 1 : return add(f.name_,f.expression_,f.v_[0]); - case 2 : return add(f.name_,f.expression_,f.v_[0],f.v_[1]); - case 3 : return add(f.name_,f.expression_,f.v_[0],f.v_[1],f.v_[2]); - case 4 : return add(f.name_,f.expression_,f.v_[0],f.v_[1],f.v_[2],f.v_[3]); - case 5 : return add(f.name_,f.expression_,f.v_[0],f.v_[1],f.v_[2],f.v_[3],f.v_[4]); - case 6 : return add(f.name_,f.expression_,f.v_[0],f.v_[1],f.v_[2],f.v_[3],f.v_[4],f.v_[5]); - default : return false; - } + return add(f.name_,f.expression_,f.v_); } inline bool add(const std::string& name, const std::string& expression) { - if (expr_map_.end() != expr_map_.find(name)) - return false; - else if (!forward(name,0)) - return false; - std::vector > var_transform_list; - if (compile_expression(name,expression,var_transform_list)) - { - f0p_map_[name].setup(expr_map_[name]); - return true; - } - else - { - remove(name,0); - return false; - } + const std::size_t n = 0; + std::vector v(n); + return add(name,expression,v); } inline bool add(const std::string& name, @@ -20983,26 +22361,9 @@ namespace exprtk const std::string& v0) { const std::size_t n = 1; - T* v[n] = { 0 }; - std::string sv[n]; - if (expr_map_.end() != expr_map_.find(name)) - return false; - else if (!forward(name,1)) - return false; - else if (!add_variable(v0,v[0],sv[0])) - return false; - std::vector > var_transform_list; - var_transform_list.push_back(std::make_pair(v0,sv[0])); - if (compile_expression(name,expression,var_transform_list)) - { - f1p_map_[name].setup(expr_map_[name],(*v[0])); - return true; - } - else - { - remove(name,sv); - return false; - } + std::vector v(n); + v[0] = v0; + return add(name,expression,v); } inline bool add(const std::string& name, @@ -21010,27 +22371,9 @@ namespace exprtk const std::string& v0, const std::string& v1) { const std::size_t n = 2; - T* v[n] = { 0 }; - std::string sv[n]; - if (expr_map_.end() != expr_map_.find(name)) - return false; - else if (!forward(name,2)) - return false; - else if (!add_variable(v0,v[0],sv[0])) return false; - else if (!add_variable(v1,v[1],sv[1])) return false; - std::vector > var_transform_list; - var_transform_list.push_back(std::make_pair(v0,sv[0])); - var_transform_list.push_back(std::make_pair(v1,sv[1])); - if (compile_expression(name,expression,var_transform_list)) - { - f2p_map_[name].setup(expr_map_[name],(*v[0]),(*v[1])); - return true; - } - else - { - remove(name,sv); - return false; - } + std::vector v(n); + v[0] = v0; v[1] = v1; + return add(name,expression,v); } inline bool add(const std::string& name, @@ -21038,29 +22381,9 @@ namespace exprtk const std::string& v0, const std::string& v1, const std::string& v2) { const std::size_t n = 3; - T* v[n] = { 0 }; - std::string sv[n]; - if (expr_map_.end() != expr_map_.find(name)) - return false; - else if (!forward(name,3)) - return false; - else if (!add_variable(v0,v[0],sv[0])) return false; - else if (!add_variable(v1,v[1],sv[1])) return false; - else if (!add_variable(v2,v[2],sv[2])) return false; - std::vector > var_transform_list; - var_transform_list.push_back(std::make_pair(v0,sv[0])); - var_transform_list.push_back(std::make_pair(v1,sv[1])); - var_transform_list.push_back(std::make_pair(v2,sv[2])); - if (compile_expression(name,expression,var_transform_list)) - { - f3p_map_[name].setup(expr_map_[name],(*v[0]),(*v[1]),(*v[2])); - return true; - } - else - { - remove(name,sv); - return false; - } + std::vector v(n); + v[0] = v0; v[1] = v1; v[2] = v2; + return add(name,expression,v); } inline bool add(const std::string& name, @@ -21069,31 +22392,10 @@ namespace exprtk const std::string& v3) { const std::size_t n = 4; - T* v[n] = { 0 }; - std::string sv[n]; - if (expr_map_.end() != expr_map_.find(name)) - return false; - else if (!forward(name,4)) - return false; - else if (!add_variable(v0,v[0],sv[0])) return false; - else if (!add_variable(v1,v[1],sv[1])) return false; - else if (!add_variable(v2,v[2],sv[2])) return false; - else if (!add_variable(v3,v[3],sv[3])) return false; - std::vector > var_transform_list; - var_transform_list.push_back(std::make_pair(v0,sv[0])); - var_transform_list.push_back(std::make_pair(v1,sv[1])); - var_transform_list.push_back(std::make_pair(v2,sv[2])); - var_transform_list.push_back(std::make_pair(v3,sv[3])); - if (compile_expression(name,expression,var_transform_list)) - { - f4p_map_[name].setup(expr_map_[name],(*v[0]),(*v[1]),(*v[2]),(*v[3])); - return true; - } - else - { - remove(name,sv); - return false; - } + std::vector v(n); + v[0] = v0; v[1] = v1; + v[2] = v2; v[3] = v3; + return add(name,expression,v); } inline bool add(const std::string& name, @@ -21102,33 +22404,11 @@ namespace exprtk const std::string& v3, const std::string& v4) { const std::size_t n = 5; - T* v[n] = { 0 }; - std::string sv[n]; - if (expr_map_.end() != expr_map_.find(name)) - return false; - else if (!forward(name,5)) - return false; - else if (!add_variable(v0,v[0],sv[0])) return false; - else if (!add_variable(v1,v[1],sv[1])) return false; - else if (!add_variable(v2,v[2],sv[2])) return false; - else if (!add_variable(v3,v[3],sv[3])) return false; - else if (!add_variable(v3,v[4],sv[4])) return false; - std::vector > var_transform_list; - var_transform_list.push_back(std::make_pair(v0,sv[0])); - var_transform_list.push_back(std::make_pair(v1,sv[1])); - var_transform_list.push_back(std::make_pair(v2,sv[2])); - var_transform_list.push_back(std::make_pair(v3,sv[3])); - var_transform_list.push_back(std::make_pair(v4,sv[4])); - if (compile_expression(name,expression,var_transform_list)) - { - f5p_map_[name].setup(expr_map_[name],(*v[0]),(*v[1]),(*v[2]),(*v[3]),(*v[4])); - return true; - } - else - { - remove(name,sv); - return false; - } + std::vector v(n); + v[0] = v0; v[1] = v1; + v[2] = v2; v[3] = v3; + v[4] = v4; + return add(name,expression,v); } inline bool add(const std::string& name, @@ -21136,36 +22416,12 @@ namespace exprtk const std::string& v0, const std::string& v1, const std::string& v2, const std::string& v3, const std::string& v4, const std::string& v5) { - const std::size_t n = 6; - T* v[n] = { 0 }; - std::string sv[n]; - if (expr_map_.end() != expr_map_.find(name)) - return false; - else if (!forward(name,6)) - return false; - else if (!add_variable(v0,v[0],sv[0])) return false; - else if (!add_variable(v1,v[1],sv[1])) return false; - else if (!add_variable(v2,v[2],sv[2])) return false; - else if (!add_variable(v3,v[3],sv[3])) return false; - else if (!add_variable(v4,v[4],sv[4])) return false; - else if (!add_variable(v5,v[5],sv[5])) return false; - std::vector > var_transform_list; - var_transform_list.push_back(std::make_pair(v0,sv[0])); - var_transform_list.push_back(std::make_pair(v1,sv[1])); - var_transform_list.push_back(std::make_pair(v2,sv[2])); - var_transform_list.push_back(std::make_pair(v3,sv[3])); - var_transform_list.push_back(std::make_pair(v4,sv[4])); - var_transform_list.push_back(std::make_pair(v5,sv[5])); - if (compile_expression(name,expression,var_transform_list)) - { - f6p_map_[name].setup(expr_map_[name],(*v[0]),(*v[1]),(*v[2]),(*v[3]),(*v[4]),(*v[5])); - return true; - } - else - { - remove(name,sv); - return false; - } + const std::size_t n = 5; + std::vector v(n); + v[0] = v0; v[1] = v1; + v[2] = v2; v[3] = v3; + v[4] = v4; v[5] = v5; + return add(name,expression,v); } private: @@ -21216,6 +22472,7 @@ namespace exprtk else ++suffix_index_; } + return false; } @@ -21239,81 +22496,66 @@ namespace exprtk symbol_table_.is_variable (symbol) || symbol_table_.is_stringvar (symbol) || symbol_table_.is_function (symbol) || + symbol_table_.is_vector (symbol) || symbol_table_.is_vararg_function(symbol) ); } inline bool forward(const std::string& name, const std::size_t& arg_count) { - if (symbol_used(name)) + if (arg_count > 6) + return false; + else if (symbol_used(name)) return false; else { + if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) + return false; switch (arg_count) { - case 0 : { if (f0p_map_.end() != f0p_map_.find(name)) return false; } break; - case 1 : { if (f1p_map_.end() != f1p_map_.find(name)) return false; } break; - case 2 : { if (f2p_map_.end() != f2p_map_.find(name)) return false; } break; - case 3 : { if (f3p_map_.end() != f3p_map_.find(name)) return false; } break; - case 4 : { if (f4p_map_.end() != f4p_map_.find(name)) return false; } break; - case 5 : { if (f5p_map_.end() != f5p_map_.find(name)) return false; } break; - case 6 : { if (f6p_map_.end() != f6p_map_.find(name)) return false; } break; - } - - switch (arg_count) - { - case 0 : { f0p_map_[name] = func_0param(); return symbol_table_.add_function(name,f0p_map_[name]); } - case 1 : { f1p_map_[name] = func_1param(); return symbol_table_.add_function(name,f1p_map_[name]); } - case 2 : { f2p_map_[name] = func_2param(); return symbol_table_.add_function(name,f2p_map_[name]); } - case 3 : { f3p_map_[name] = func_3param(); return symbol_table_.add_function(name,f3p_map_[name]); } - case 4 : { f4p_map_[name] = func_4param(); return symbol_table_.add_function(name,f4p_map_[name]); } - case 5 : { f5p_map_[name] = func_5param(); return symbol_table_.add_function(name,f5p_map_[name]); } - case 6 : { f6p_map_[name] = func_6param(); return symbol_table_.add_function(name,f6p_map_[name]); } - default : return false; + case 0 : (fp_map_[arg_count])[name] = new func_0param(); break; + case 1 : (fp_map_[arg_count])[name] = new func_1param(); break; + case 2 : (fp_map_[arg_count])[name] = new func_2param(); break; + case 3 : (fp_map_[arg_count])[name] = new func_3param(); break; + case 4 : (fp_map_[arg_count])[name] = new func_4param(); break; + case 5 : (fp_map_[arg_count])[name] = new func_5param(); break; + case 6 : (fp_map_[arg_count])[name] = new func_6param(); break; } + exprtk::ifunction& ifunc = (*(fp_map_[arg_count])[name]); + return symbol_table_.add_function(name,ifunc); } } - template - inline void remove(const std::string& name, const std::string (&v)[N]) + template class Sequence> + inline void remove(const std::string& name, const Sequence& v) { symbol_table_.remove_function(name); - for (std::size_t i = 0; i < N; ++i) + for (std::size_t i = 0; i < v.size(); ++i) { symbol_table_.remove_variable(v[i]); } - remove(name,N); + remove(name,v.size()); } inline void remove(const std::string& name, const std::size_t& arg_count) { + if (arg_count > 6) + return; + typename std::map::iterator em_itr = expr_map_.find(name); if (expr_map_.end() != em_itr) { expr_map_.erase(em_itr); } - switch (arg_count) - { - case 0 : { if (f0p_map_.end() == f0p_map_.find(name)) return; } - case 1 : { if (f1p_map_.end() == f1p_map_.find(name)) return; } - case 2 : { if (f2p_map_.end() == f2p_map_.find(name)) return; } - case 3 : { if (f3p_map_.end() == f3p_map_.find(name)) return; } - case 4 : { if (f4p_map_.end() == f4p_map_.find(name)) return; } - case 5 : { if (f5p_map_.end() == f5p_map_.find(name)) return; } - case 6 : { if (f6p_map_.end() == f6p_map_.find(name)) return; } - } + typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); - switch (arg_count) - { - case 0 : { f0p_map_.erase(f0p_map_.find(name)); return; } - case 1 : { f1p_map_.erase(f1p_map_.find(name)); return; } - case 2 : { f2p_map_.erase(f2p_map_.find(name)); return; } - case 3 : { f3p_map_.erase(f3p_map_.find(name)); return; } - case 4 : { f4p_map_.erase(f4p_map_.find(name)); return; } - case 5 : { f5p_map_.erase(f5p_map_.find(name)); return; } - case 6 : { f6p_map_.erase(f6p_map_.find(name)); return; } - } + if (fp_map_[arg_count].end() != fp_itr) + return; + else + delete fp_itr->second; + fp_map_[arg_count].erase(fp_itr); } private: @@ -21321,13 +22563,7 @@ namespace exprtk symbol_table_t symbol_table_; parser_t parser_; std::map expr_map_; - std::map f0p_map_; - std::map f1p_map_; - std::map f2p_map_; - std::map f3p_map_; - std::map f4p_map_; - std::map f5p_map_; - std::map f6p_map_; + std::vector fp_map_; unsigned int suffix_index_; unsigned int id_; }; @@ -21569,7 +22805,9 @@ namespace exprtk # define WIN32_LEAN_AND_MEAN # endif # include +# include #else +# include # include # include #endif @@ -21651,14 +22889,14 @@ namespace exprtk #endif - inline bool in_use() const - { - return in_use_; - } + inline bool in_use() const + { + return in_use_; + } private: - bool in_use_; + bool in_use_; #ifdef WIN32 LARGE_INTEGER start_time_; diff --git a/exprtk_simple_example_11.cpp b/exprtk_simple_example_11.cpp index c7e1170..ceb5f69 100644 --- a/exprtk_simple_example_11.cpp +++ b/exprtk_simple_example_11.cpp @@ -28,12 +28,13 @@ void square_wave2() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expr_string = " r := 0; " - " for(i := 0; i < 1000; i += 1) " - " { " - " r += (1/(2i+1))*sin((4i+2)*pi*f*t); " - " }; " - " r *= a*(4 / pi); "; + std::string wave_program = + " r := 0; " + " for(i := 0; i < 1000; i += 1) " + " { " + " r += (1 / (2i + 1)) * sin((4i + 2) * pi * f * t); " + " }; " + " r *= a * (4 / pi); "; static const T pi = T(3.14159265358979323846); @@ -53,7 +54,7 @@ void square_wave2() parser_t parser; parser.enable_unknown_symbol_resolver(); - parser.compile(expr_string,expression); + parser.compile(wave_program,expression); const T delta = (T(4) * pi) / T(1000); diff --git a/exprtk_simple_example_12.cpp b/exprtk_simple_example_12.cpp index bdf4cdd..81ada05 100644 --- a/exprtk_simple_example_12.cpp +++ b/exprtk_simple_example_12.cpp @@ -28,25 +28,23 @@ void bubble_sort() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expr_string = - " upper_bound := v[]; " - " repeat " - " swapped := false; " - " for(i := 0; i < upper_bound; i += 1) " - " { " - " for(j := i + 1; j < upper_bound; j += 1) " - " { " - " if (v[i] > v[j]) " - " { " - " temp := v[i]; " - " v[i] := v[j]; " - " v[j] := temp; " - " swapped := true; " - " }; " - " }; " - " }; " - " upper_bound -= 1; " - " until (not(swapped) or (upper_bound == 0)); "; + std::string bubblesort_program = + " upper_bound := v[]; " + " repeat " + " swapped := false; " + " for(i := 0; i < upper_bound; i += 1) " + " { " + " for(j := i + 1; j < upper_bound; j += 1) " + " { " + " if (v[i] > v[j]) " + " { " + " v[i] <=> v[j]; " + " swapped := true; " + " }; " + " }; " + " }; " + " upper_bound -= 1; " + " until (not(swapped) or (upper_bound == 0)); "; T v[] = { T(2.2), T(1.1), T(5.5), T(4.4), T(3.3) }; @@ -59,7 +57,7 @@ void bubble_sort() parser_t parser; parser.enable_unknown_symbol_resolver(); - parser.compile(expr_string,expression); + parser.compile(bubblesort_program,expression); expression.value(); } diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 1ebe66a..3f680c1 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -27,6 +27,7 @@ #include "exprtk.hpp" + typedef double numeric_type; typedef std::pair test_t; @@ -1128,7 +1129,7 @@ inline bool test_expression(const std::string& expression_string, const T& expec } } - if (!exprtk::expression_helper::is_head_constant(expression)) + if (!exprtk::expression_helper::is_constant(expression)) { printf("test_expression() - Error: Expression did not compile to a constant! Expression: %s\n", expression_string.c_str()); @@ -2736,6 +2737,8 @@ inline bool run_test09() template inline bool run_test10() { + typedef exprtk::expression expression_t; + T x = T(1.1); T y = T(2.2); T xx = T(3.3); @@ -2748,8 +2751,6 @@ inline bool run_test10() exprtk::symbol_table symbol_table; - typedef exprtk::expression expression_t; - struct test { static inline bool variable(exprtk::symbol_table& symbol_table, const std::string& variable_name, const T& value) @@ -3241,6 +3242,96 @@ inline bool run_test10() } } + { + exprtk::symbol_table symbol_table0; + exprtk::symbol_table symbol_table1; + + if (symbol_table0 == symbol_table1) + { + printf("run_test10() - Error symbol_table0 and symbol_table1 are equal\n"); + return false; + } + + symbol_table0 = symbol_table1; + symbol_table1 = symbol_table0; + + if (!(symbol_table0 == symbol_table1)) + { + printf("run_test10() - Error symbol_table0 and symbol_table1 are not equal\n"); + return false; + } + } + + { + std::string expression_list[] = + { + "var x := 1; var y := 2; swap(x,y); (x == 2) and (y == 1)", + "var x := 1; var y := 2; x <=> y ; (x == 2) and (y == 1)", + "var v[2] := {1,2}; swap(v[0],v[1]); (v[0] == 2) and (v[1] == 1)", + "var v[2] := {1,2}; v[0] <=> v[1] ; (v[0] == 2) and (v[1] == 1)", + "var x := 1; var y := 2; ~(swap(x,y),(x == 2) and (y == 1))", + "var x := 1; var y := 2; ~(x <=> y , (x == 2) and (y == 1))", + "var v[2] := {1,2}; ~(swap(v[0],v[1]), (v[0] == 2) and (v[1] == 1))", + "var v[2] := {1,2}; ~(v[0] <=> v[1] , (v[0] == 2) and (v[1] == 1))", + "var v[2] := {1,2}; swap(v[zero],v[one]); (v[zero] == 2) and (v[one] == 1)", + "var v[2] := {1,2}; v[zero] <=> v[one] ; (v[zero] == 2) and (v[one] == 1)", + "var v[2] := {1,2}; ~(swap(v[zero],v[one]), (v[zero] == 2) and (v[one] == 1))", + "var v[2] := {1,2}; ~(v[zero] <=> v[one] , (v[zero] == 2) and (v[one] == 1))", + "var v[2] := {1,2}; swap(v[2 * zero],v[(2 * one) / (1 + 1)]); (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1)", + "var v[2] := {1,2}; v[2 * zero] <=> v[(2*one)/(1+1)] ; (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1)", + "var v[2] := {1,2}; ~(swap(v[2 * zero],v[(2 * one) / (1 + 1)]), (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1))", + "var v[2] := {1,2}; ~(v[2 * zero] <=> v[(2 * one) / (1 + 1)] , (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1))", + "var x := 1; var y := 2; var v[2] := {3,4}; swap(x,v[0]); swap(v[1],y); (x == 3) and (y == 4)", + "var x := 1; var y := 2; var v[2] := {3,4}; x <=> v[0]; v[1] <=> y; (x == 3) and (y == 4)", + "var x := 1; var y := 2; var v[2] := {3,4}; swap(x,v[zero]); swap(v[one],y); (x == 3) and (y == 4)", + "var x := 1; var y := 2; var v[2] := {3,4}; x <=> v[zero]; v[one] <=> y; (x == 3) and (y == 4)", + "var x := 1; var y := 2; var v[2] := {3,4}; swap(x,v[2 * zero]); swap(v[(2 * one) / (1 + 1)],y); (x == 3) and (y == 4)", + "var x := 1; var y := 2; var v[2] := {3,4}; x <=> v[zero / 3]; v[(2 * one)/(1 + 1)] <=> y; (x == 3) and (y == 4)" + }; + + const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); + + exprtk::symbol_table symbol_table; + + T zero = T(0); + T one = T(1); + + symbol_table.add_variable("zero",zero); + symbol_table.add_variable("one" , one); + + bool failed = false; + + for (std::size_t i = 0; i < expression_list_size; ++i) + { + expression_t expression; + expression.register_symbol_table(symbol_table); + + { + exprtk::parser parser; + if (!parser.compile(expression_list[i],expression)) + { + printf("run_test10() - swaps Error: %s Expression: %s\n", + parser.error().c_str(), + expression_list[i].c_str()); + return false; + } + } + + T result = expression.value(); + + if (T(1) != result) + { + printf("run_test10() - swaps evaluation error Expression: %s\n", + expression_list[i].c_str()); + + failed = true; + } + } + + if (failed) + return false; + } + return true; } @@ -4035,6 +4126,8 @@ inline bool run_test18() static const std::string expr_str_list[] = { + "equal(va_func,(0))", + "equal(va_func(),(0))", "equal(va_func(1,2,3,4,5,6,7,8,9),(1+2+3+4+5+6+7+8+9))", "equal(va_func(1,x,3,y,5,z,7,w,9),(1+x+3+y+5+z+7+w+9))", "equal(va_func(x,2,y,4,z,6,w,8,u),(x+2+y+4+z+6+w+8+u))", @@ -4201,7 +4294,7 @@ inline bool run_test19() compositor .add("f2","7 * (f1(x) + f1(y))","x","y"); - // f3(x,y,z) = 9 * (2(x,y) + f2(y,z) + f2(x,z)) + // f3(x,y,z) = 9 * (f2(x,y) + f2(y,z) + f2(x,z)) compositor .add("f3","9 * (f2(x,y) + f2(y,z) + f2(x,z))","x","y","z"); @@ -4711,6 +4804,70 @@ inline bool run_test19() return false; } + { + symbol_table_t symbol_table; + + symbol_table.add_constants(); + + compositor_t compositor(symbol_table); + + compositor + .add("mandelbrot", + " var width := 118; " + " var height := 41; " + " var imag_max := +1; " + " var imag_min := -1; " + " var real_max := +1; " + " var real_min := -2.5; " + " var x_step := (real_max - real_min) / width; " + " var y_step := (imag_max - imag_min) / height; " + " for (y := 0; y < height; y += 1) " + " { " + " var imag := imag_min + (y_step * y); " + " for (x := 0; x < width; x += 1) " + " { " + " var real := real_min + x_step * x; " + " var z_real := real; " + " var z_imag := imag; " + " var plot_value; " + " for (n := 0; n < 30; n += 1) " + " { " + " var a := z_real^2; " + " var b := z_imag^2; " + " plot_value := n; " + " if ((a + b) < 4) " + " { " + " z_imag := 2 * z_real * z_imag + imag; " + " z_real := a - b + real; " + " } " + " else " + " break; " + " }; " + " }; " + " } "); + + std::string expression_str = "mandelbrot()"; + + expression_t expression; + + expression.register_symbol_table(symbol_table); + + parser_t parser; + + if (!parser.compile(expression_str,expression)) + { + printf("run_test19() - Error: %s Expression: %s\n", + parser.error().c_str(), + expression_str.c_str()); + return false; + } + + for (std::size_t i = 0; i < 100; ++i) + { + expression.value(); + } + } + return true; } diff --git a/readme.txt b/readme.txt index db8c32e..14e26b6 100644 --- a/readme.txt +++ b/readme.txt @@ -18,11 +18,11 @@ arithmetic operations, functions and processes: (01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp, expm1, floor, frac, log, log10, log1p, log2, logn, max, min, mul, nequal, root, round, - roundn, sgn, sqrt, sum, trunc + roundn, sgn, sqrt, sum, swap, trunc (02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2, - cos, cosh, cot, csc, sec, sin, sinc, sinh, tan, - tanh, hypot, rad2deg, deg2grad, deg2rad, + cos, cosh, cot, csc, sec, sin, sinc, sinh, + tan, tanh, hypot, rad2deg, deg2grad, deg2rad, grad2deg (03) Equalities & @@ -36,7 +36,7 @@ arithmetic operations, functions and processes: (06) Loop statements: while, for, repeat-until, break, continue - (07) Assignment: :=, +=, -=, *=, /= + (07) Assignment: :=, +=, -=, *=, /=, %= (08) String processing: in, like, ilike @@ -108,6 +108,9 @@ include path (e.g: /usr/include/). [07 - COMPILER COMPATIBILITY] +ExprTk has been built error and warning free using the following set +of C++ compilers: + (*) GNU Compiler Collection (3.3+) (*) Intel C++ Compiler (8.x+) (*) Clang/LLVM (1.1+) @@ -150,13 +153,17 @@ include path (e.g: /usr/include/). +----------+---------------------------------------------------------+ | *= | Assign the multiplication of x by the value of the | | | expression on the righthand side to x. Where x is either| -| | variable or vector type. | +| | a variable or vector type. | | | (eg: x *= abs(y / z)) | +----------+---------------------------------------------------------+ | /= | Assign the division of x by the value of the expression | | | on the right-hand side to x. Where x is either a | | | variable or vector type. (eg: x[i+j] /= abs(y * z)) | +----------+---------------------------------------------------------+ +| %= | Assign x modulo the value of the expression on the right| +| | hand side to x. Where x is either a variable or vector | +| | type. (eg: x[2] %= y ^ 2) | ++----------+---------------------------------------------------------+ (1) Equalities & Inequalities +----------+---------------------------------------------------------+ @@ -292,6 +299,9 @@ include path (e.g: /usr/include/). | sum | Sum of all the inputs. | | | (eg: sum(x,y,z,w,u,v,t) == (x + y + z + w + u + v + t)) | +----------+---------------------------------------------------------+ +| swap | Swap the values of the variables x and y and return the | +| <=> | current value of y. (eg: swap(x,y) or x <=> y) | ++----------+---------------------------------------------------------+ | trunc | Integer portion of x. (eg: trunc(x)) | +----------+---------------------------------------------------------+ @@ -453,7 +463,7 @@ include path (e.g: /usr/include/). | | The conditional is mandatory whereas the initializer | | | and incrementing expressions are optional. | | | eg: | -| | for (x := 0; x < n && (x != y); x += 1) | +| | for (x := 0; (x < n) and (x != y); x += 1) | | | { | | | y := y + x / 2 - z; | | | w := u + y; | @@ -479,7 +489,7 @@ include path (e.g: /usr/include/). | continue | Continue results in the remaining portion of the nearest| | | enclosing loop body to be skipped. | | | eg: | -| | for (i := 0; i < 10; i+= 1) | +| | for (i := 0; i < 10; i += 1) | | | { | | | if (i < 5) | | | continue; | @@ -511,6 +521,12 @@ include path (e.g: /usr/include/). | | case (x + 3) = (y * 4) : y := abs(z / 6) + 7y; | | | } | +----------+---------------------------------------------------------+ +| [] | The vector size operator returns the size of the vector | +| | being actioned. | +| | eg: | +| | 1. v[] | +| | 2. max_size := max(v0[],v1[],v2[],v3[]) | ++----------+---------------------------------------------------------+ Note: In the above tables, the symbols x, y, z, w, u and v where appropriate may represent any of one the following: @@ -518,7 +534,7 @@ appropriate may represent any of one the following: 1. Literal numeric/string value 2. A variable 3. A vector element - 3. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3]) + 4. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3]) @@ -582,11 +598,19 @@ current values assigned to the variables will be used. x = 1.0; y = 2.0; - parser.value(); // 1 * 2 + 3 + expression.value(); // 1 * 2 + 3 + x = 3.7; - parser.value(); // 3.7 * 2 + 3 + expression.value(); // 3.7 * 2 + 3 + y = -9.0; - parser.value(); // 3.7 * -9 + 3 + expression.value(); // 3.7 * -9 + 3 + + // 'x * -9 + 3' for x in range of [0,100] in steps of 0.0001 + for (x = 0; x < 100; x += 0.0001) + { + expression.value(); // x * -9 + 3 + } (2) Expression @@ -680,8 +704,7 @@ handle: (h) '-' '=' ---> '-=' (subtraction assignment) (i) '*' '=' ---> '*=' (multiplication assignment) (j) '/' '=' ---> '/=' (division assignment) - - + (j) '%' '=' ---> '%=' (modulo assignment) An example of the transformation that takes place is as follows: @@ -825,108 +848,295 @@ correctly optimize such expressions for a given architecture. -[12 - EXPRTK NOTES] +[12 - VARIABLE & VECTOR DEFINITION] +ExprTk supports the definition of expression local variables and +vectors. The definitions must be unique as shadowing is not allowed +and object life-times are based on scope. Definitions use the +following general form: + + var := ; + +(1) Variable Definition +Variables are of numeric type denoting a single value. They can be +explicitly initialised to a value, otherwise they will be defaulted to +zero. The following are examples of variable definitions: + + (a) Initialise x to zero + var x; + + (b) Initialise y to three + var y := 3; + + (c) Initialise z to the expression + var z := if(max(1,x + y) > 2,w,v); + + +(2) Vector Definition +Vectors are arrays of a common numeric type. The elements in a vector +can be explicitly initialised, otherwise they will all be defaulted to +zero. The following are examples of vector definitions: + + (a) Initialise all values to zero + var x[3]; + + (b) Initialise all values to zero + var x[3] := {}; + + (c) Initialise all values to given expression + var x[3] := [123 + 3y + sin(w/z)]; + + (d) Initialise the first two values, other elements to zero + var x[3] := {1 + x[2], sin(y[0] / x[]) + 3}; + + (e) Initialise the first three (all) values + var x[3] := {1,2,3}; + + (f) Error as there are too many initializers + var x[3] := {1,2,3,4}; + + (g) Error as a vector of size zero is not allowed. + var x[0]; + + +(3) Return Value +Variable and vector definitions have a return value. In the case of +variable definitions, the value to which the variable is initialized +will be returned. Where as for vectors, the value of the first element +(eg: v[0]) will be returned. + + + +[13 - USER DEFINED FUNCTIONS] +ExprTk provides a means whereby custom functions can be defined and +utilized within expressions. The concept requires the user to +provide a reference to the function coupled with an associated name +that will be invoked within expressions. Function can take in numerous +inputs but will always return one value. + +During expression compilation when required the reference to the +function will be obtained from the associated symbol_table and be +embedded into the expression. + +There are two types of function interface: + + (1) ifunction + (2) ivararg_function + + +(1) ifunction +This interface supports zero to 20 input parameters. The usage +requires a custom function be derived from ifunction and to override +one of the 21 function operators. As part of the constructor the +custom function will define how many parameters it expects to handle. +The following example defines a 3 parameter function called 'foo': + + template + struct foo : public exprtk::ifunction + { + foo() : exprtk::ifunction(3) + {} + + T operator()(const T& v1, const T& v2, const T& v3) + { + return T(1) + (v1 * v2) / T(v3); + } + }; + + +(2) ivararg_function +This interface supports a variable number of arguments as input into +the function. The function operator interface uses a std::vector +specialized upon type T to facilitate parameter passing. The following +example defines a vararg function called 'boo': + + template + struct boo : public exprtk::ivararg_function + { + inline T operator()(const std::vector& arglist) + { + T result = T(0); + for (std::size_t i = 0; i < arglist.size(); ++i) + { + result += arglist[i] / arglist[i > 0 ? (i - 1) : 0]; + } + return result; + } + }; + + +(3) Using Functions In Expressions +For the above denoted custom functions to be used in an expression, an +instance of each function needs to be registered with a symbol_table +that has been associated with the expression instance. The following +demonstrations how all the pieces are put together: + + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + foo f; + boo b; + + symbol_table_t symbol_table; + symbol_table.add_function("foo",f); + symbol_table.add_function("boo",b); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + std::string expression_str = + "foo(1,2,3) + boo(1) / boo(1/2,2/3,3/4,4/5,5/6)"; + + parser_t parser; + parser.compile(expression_str,expression); + + expression.value(); + + +(4) Function Side-Effects +All function calls are assumed to have side-effects by default. What +that means is that a certain type of optimisation will not be carried +out when the function is being called. The optimisation in question +is: constant folding. Normally during compilation this optimisation +would be invoked when all the parameters being passed into the +function are literals, the function will be evaluated at that point +and a new literal will replace the function call node in the AST. + +If it is certain that the function being registered does not have any +side effects and can be correctly constant folded where appropriate, +then during the construction of the function a 'false' can be passed +to the constructor to denote the lack of side-effects. + + template + struct foo : public exprtk::ifunction + { + foo() : exprtk::ifunction(3,false) + {} + + T operator()(const T& v1, const T& v2, const T& v3) + { ... } + }; + + +(5) Zero Parameter Functions +When an ifunction derived type is defined with zero number of +parameters, there are two calling conventions within expressions that +are allowed. For a function named 'foo' with zero input parameters the +calling styles are as follows: + + (1) x + sin(foo()- 2) / y + (2) x + sin(foo - 2) / y + + + +[14 - EXPRTK NOTES] +The following is a list of facts and suggestions one may want to take +into account when using Exprtk: + (00) Precision and performance of expression evaluations are the dominant principles of the ExprTk library. - (01) Supported types are float, double and long double. + (01) ExprTk uses a rudimentary imperative programming model with + syntax based on languages such as Pascal and C. - (02) Standard mathematical operator precedence is applied (BEDMAS). + (02) Supported types are float, double and long double. - (03) Results of expressions that are deemed as being 'valid' are to + (03) Standard mathematical operator precedence is applied (BEDMAS). + + (04) Results of expressions that are deemed as being 'valid' are to exist within the set of Real numbers. All other results will be of the value: Not-A-Number (NaN). - (04) Supported user defined types are numeric and string variables + (05) Supported user defined types are numeric and string variables and functions. - (05) All variable and function names are case-insensitive. + (06) All variable and function names are case-insensitive. - (06) Variable and function names must begin with a letter + (07) Variable and function names must begin with a letter (A-Z or a-z), then can be comprised of any combination of letters, digits and underscores. (eg: x, var1 or power_func99) - (07) Expression lengths and sub-expression lists are limited only by + (08) Expression lengths and sub-expression lists are limited only by storage capacity. - (08) The life-time of objects registered with or created from a + (09) The life-time of objects registered with or created from a specific symbol-table must span at least the life-time of the compiled expressions which utilize objects, such as variables, of that symbol-table, otherwise the result will be undefined behavior. - (09) Equal/Nequal are normalized equality routines, which use + (10) Equal/Nequal are normalized equality routines, which use epsilons of 0.0000000001 and 0.000001 for double and float types respectively. - (10) All trigonometric functions assume radian input unless + (11) All trigonometric functions assume radian input unless stated otherwise. - (11) Expressions may contain white-space characters such as + (12) Expressions may contain white-space characters such as space, tabs, new-lines, control-feed et al. ('\n', '\r', '\t', '\b', '\v', '\f') - (12) Strings may be constructed from any letters, digits or special + (13) Strings may be constructed from any letters, digits or special characters such as (~!@#$%^&*()[]|=+ ,./?<>;:"`~_), and must be enclosed with single-quotes. eg: 'Frankly my dear, I do not give a damn!' - (13) User defined normal functions can have up to 20 parameters, + (14) User defined normal functions can have up to 20 parameters, where as user defined vararg-functions can have an unlimited number of parameters. - (14) The inbuilt polynomial functions can be at most of degree 12. + (15) The inbuilt polynomial functions can be at most of degree 12. - (15) Where appropriate constant folding optimisations may be + (16) Where appropriate constant folding optimisations may be applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)') - (16) If the strength reduction compilation option has been enabled, + (17) If the strength reduction compilation option has been enabled, then where applicable strength reduction optimisations may be applied. - (17) String processing capabilities are available by default. + (18) String processing capabilities are available by default. To turn them off, the following needs to be defined at compile time: exprtk_disable_string_capabilities - (18) Composited functions can call themselves or any other functions + (19) Composited functions can call themselves or any other functions that have been defined prior to their own definition. - (19) Recursive calls made from within composited functions will have + (20) Recursive calls made from within composited functions will have a stack size bound by the stack of the executing architecture. - (20) User defined functions by default are assumed to have side + (21) User defined functions by default are assumed to have side effects. As such an "all constant parameter" invocation of such functions wont result in constant folding. If the function has no side effects then that can be noted during the constructor of the ifunction allowing it to be constant folded where appropriate. - (21) The entity relationship between symbol_table and an expression + (22) The entity relationship between symbol_table and an expression is one-to-many. Hence the intended use case is to have a single symbol table manage the variable and function requirements of multiple expressions. - (22) The common use-case for an expression is to have it compiled + (23) The common use-case for an expression is to have it compiled only ONCE and then subsequently have it evaluated multiple times. An extremely inefficient and suboptimal approach would be to recompile an expression from its string form every time it requires evaluating. - (23) The following are examples of compliant floating point value + (24) The following are examples of compliant floating point value representations: - (a) 12345 (b) -123.456 - (c) +123.456e+12 (d) 123.456E-12 - (e) +012.045e+07 (f) .1234 - (g) 123.456f (h) -321.654E+3L + (a) 12345 (e) -123.456 + (b) +123.456e+12 (f) 123.456E-12 + (c) +012.045e+07 (g) .1234 + (d) 123.456f (h) -321.654E+3L - (24) Expressions may contain any of the following comment styles: + (25) Expressions may contain any of the following comment styles: 1. // .... \n 2. # .... \n 3. /* .... */ -[13 - SIMPLE EXPRTK EXAMPLE] +[15 - SIMPLE EXPRTK EXAMPLE] --- snip --- #include #include @@ -974,8 +1184,8 @@ int main() if (!parser.compile(expression_str,expression)) { - // A compilation error has occured. Attempt to - // print all errors to the stdout. + // A compilation error has occurred. Attempt to + // print all errors to stdout. printf("Error: %s\tExpression: %s\n", parser.error().c_str(), @@ -1014,7 +1224,7 @@ int main() -[14 - FILES] +[16 - FILES] (00) Makefile (01) readme.txt (02) exprtk.hpp @@ -1032,3 +1242,149 @@ int main() (14) exprtk_simple_example_10.cpp (15) exprtk_simple_example_11.cpp (16) exprtk_simple_example_12.cpp + + + +[17 - LANGUAGE STRUCTURE] ++-------------------------------------------------------------+ +|00 - If Statement | +| | +| [if] ---> [(] ---> [condition] -+-> [,] -+ | +| | | | +| +---------------<---------------+ | | +| | | | +| | +------------------<------------------+ | +| | | | +| | +--> [consequent] ---> [,] ---> [alternative] ---> [)] | +| | | +| +--> [)] --+-> [{] ---> [expression*] ---> [}] --+ | +| | | | +| | +---------<----------+ | +| +----<-----+ | | +| | v | +| +--> [consequent] --> [;] -{*}-> [else-statement] | +| | ++-------------------------------------------------------------+ +|01 - Else Statement | +| | +| [else] -+-> [alternative] ---> [;] | +| | | +| +--> [{] ---> [expression*] ---> [}] | +| | | +| +--> [if-statement] | +| | ++-------------------------------------------------------------+ +|02 - Ternary Statement | +| | +| [condition] ---> [?] ---> [consequent] ---> [:] --+ | +| | | +| +------------------------<------------------------+ | +| | | +| +--> [alternative] --> [;] | +| | ++-------------------------------------------------------------+ +|03 - While Loop | +| | +| [while] ---> [(] ---> [condition] ---> [)] ---+ | +| | | +| +----------------------<----------------------+ | +| | | +| +--> [{] ---> [expression*] ---> [}] | +| | ++-------------------------------------------------------------+ +|04 - Repeat Until Loop | +| | +| [repeat] ---> [expression*] ---+ | +| | | +| +--------------<---------------+ | +| | | +| +--> [until] ---> [(] ---> [condition] --->[)] | +| | ++-------------------------------------------------------------+ +|05 - For Loop | +| | +| [for] ---> [(] -+-> [initialise expression] --+--+ | +| | | | | +| +------------->---------------+ v | +| | | +| +-----------------------<------------------------+ | +| | | +| +--> [,] -+-> [condition] -+-> [,] ---+ | +| | | | | +| +------->--------+ v | +| | | +| +------------------<---------+--------+ | +| | | | +| +--> [increment expression] -+-> [)] --+ | +| | | +| +------------------<-------------------+ | +| | | +| +--> [{] ---> [expression*] ---> [}] | +| | ++-------------------------------------------------------------+ +|06 - Switch Statement | +| | +| [switch] ---> [{] ---+ | +| | | +| +---------<----------+-----------<-----------+ | +| | | | +| +--> [case] ---> [condition] ---> [:] ---+ | | +| | | | +| +-------------------<--------------------+ | | +| | | | +| +--> [consequent] ---> [;] --------->--------+ | +| | | | +| | | | +| +--> [default] ---> [consequent] ---> [;] ---+ | +| | | | +| +---------------------<----------------------+ | +| | | +| +--> [}] | +| | ++-------------------------------------------------------------+ +|07 - Multi Subexpression Statement | +| | +| +--------------<---------------+ | +| | | | +| [~] ---> [{\(] -+-> [expression] -+-> [;\,] ---+ | +| | | +| +----------------<----------------+ | +| | | +| +--> [}\)] | +| | ++-------------------------------------------------------------+ +|08 - Multi Case-Consequent Statement | +| | +| [[*]] ---> [{] ---+ | +| | | +| +--------<--------+--------------<----------+ | +| | | | +| +--> [case] ---> [condition] ---> [:] ---+ | | +| | | | +| +-------------------<--------------------+ | | +| | | | +| +--> [consequent] ---> [;] ---+------>------+ | +| | | +| +--> [}] | +| | ++-------------------------------------------------------------+ +|09 - Variable Definition Statement | +| | +| [var] ---> [symbol] -+-> [:=] ---> [expression] -+-> [;] | +| | | | +| +------------->-------------+ | +| | ++-------------------------------------------------------------+ +|10 - Vector Definition Statement | +| | +| [var] ---> [symbol] ---> [[] ---> [constant] ---> []] --+ | +| | | +| +---------------------------<---------------------------+ | +| | | +| | +--------->---------+ | +| | | | | +| +--> [:=] ---> [{] -+-+-> [expression] -+-> [}] -+-> [;] | +| | | | +| +--<--- [,] <-----+ | +| | ++-------------------------------------------------------------+