From 6b86ec0deb86afb162ec58fff2ab11c963b306ae Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Thu, 29 May 2014 06:35:33 +1000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 130 ++++++++++++++++++++--------------- exprtk_simple_example_12.cpp | 4 +- exprtk_test.cpp | 68 ++++++++++++------ 3 files changed, 122 insertions(+), 80 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index ab4b646..d426fb5 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -11436,13 +11436,14 @@ namespace exprtk { for (std::size_t i = 0; i < element_.size(); ++i) { - if (element_[i].depth > parser_.scope_depth_) + scope_element& se = element_[i]; + if (se.depth > parser_.scope_depth_) return null_element_; else if ( - (element_[i].name == var_name) && - (element_[i].index == index) + (se.name == var_name) && + (se.index == index) ) - return element_[i]; + return se; } return null_element_; @@ -11455,7 +11456,8 @@ namespace exprtk if ( (element_[j].name == se.name ) && (element_[j].depth <= se.depth) && - (element_[j].index == se.index) + (element_[j].index == se.index) && + (element_[j].size == se.size ) ) return false; } @@ -11465,7 +11467,7 @@ namespace exprtk return true; } - inline void deactivate(const std::size_t scope_depth) + inline void deactivate(const std::size_t& scope_depth) { for (std::size_t j = 0; j < element_.size(); ++j) { @@ -11476,34 +11478,31 @@ namespace exprtk } } - void cleanup(const bool purge = false) + void cleanup() { - std::vector tmp_element_(element_.size()); - for (std::size_t i = 0; i < element_.size(); ++i) - { - if (purge) - element_[i].ref_count = 0; + for (std::size_t i = 0; i < element_.size(); ++i) + { + if (element_[i].var_node) + { + delete element_[i].var_node; + } - 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; + if (element_[i].vec_node) + { + delete element_[i].vec_node; + } - case scope_element::e_vector : delete [] data; - break; + T* data = (T*)(element_[i].data); - default : break; - } - } - } + 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_; + element_.clear(); } private: @@ -11531,8 +11530,8 @@ namespace exprtk ~scope_handler() { - parser_.sem_.deactivate(parser_.scope_depth_); parser_.scope_depth_--; + parser_.sem_.deactivate(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_)); @@ -11685,7 +11684,7 @@ namespace exprtk error_list_ .clear(); brkcnt_list_ .clear(); synthesis_error_.clear(); - sem_ .cleanup(true); + sem_ .cleanup(); expression_generator_.set_allocator(node_allocator_); scope_depth_ = 0; @@ -11741,7 +11740,7 @@ namespace exprtk } symbol_name_cache_.clear(); - sem_.cleanup(true); + sem_.cleanup(); if (0 != e) { @@ -14113,8 +14112,8 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR92 - Symbol '" + symbol+ " not a vector")); + current_token_, + "ERR92 - Symbol '" + symbol+ " not a vector")); return error_node(); } @@ -14562,16 +14561,28 @@ namespace exprtk std::size_t vec_size = static_cast(vector_size); - scope_element& se = sem_.get_element(vec_name,vec_size); + scope_element& se = sem_.get_element(vec_name); - if ((se.name == vec_name) && se.active) + if (se.name == vec_name) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR118 - Illegal redefinition of local vector: '" + vec_name + "'")); + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR118 - Illegal redefinition of local vector: '" + vec_name + "'")); - return error_node(); + return error_node(); + } + else if ( + (se.size == vec_size) && + (scope_element::e_vector == se.type) + ) + { + vec_holder = se.vec_node; + se.active = true; + se.ref_count++; + } } if (0 == vec_holder) @@ -14588,8 +14599,8 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR119 - Failed to add new local variable to SEM")); + current_token_, + "ERR119 - Failed to add new local vector '" + vec_name + "' to SEM")); return error_node(); } @@ -14597,7 +14608,9 @@ namespace exprtk 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()); + printf("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", + nse.name.c_str(), + static_cast(nse.size)); #endif } @@ -14617,7 +14630,7 @@ namespace exprtk inline bool local_variable_is_shadowed(const std::string& symbol) { const scope_element& se = sem_.get_element(symbol); - return (se.name == symbol); + return (se.name == symbol) && se.active; } inline expression_node_ptr parse_define_var_statement() @@ -14732,18 +14745,23 @@ namespace exprtk return error_node(); } else if (scope_element::e_variable == se.type) - var_node = se.var_node; + { + var_node = se.var_node; + se.active = true; + se.ref_count++; + } } 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)); + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + 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)) { @@ -14783,8 +14801,8 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR129 - Expected '(' at start of swap statement")); + current_token_, + "ERR129 - Expected '(' at start of swap statement")); return error_node(); } @@ -14914,8 +14932,8 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR137 - Expected ')' at end of swap statement")); + current_token_, + "ERR137 - Expected ')' at end of swap statement")); return error_node(); } diff --git a/exprtk_simple_example_12.cpp b/exprtk_simple_example_12.cpp index 81ada05..8aedf10 100644 --- a/exprtk_simple_example_12.cpp +++ b/exprtk_simple_example_12.cpp @@ -29,7 +29,8 @@ void bubble_sort() typedef exprtk::parser parser_t; std::string bubblesort_program = - " upper_bound := v[]; " + " var upper_bound := v[]; " + " var swapped := false; " " repeat " " swapped := false; " " for(i := 0; i < upper_bound; i += 1) " @@ -55,7 +56,6 @@ void bubble_sort() expression.register_symbol_table(symbol_table); parser_t parser; - parser.enable_unknown_symbol_resolver(); parser.compile(bubblesort_program,expression); diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 3f680c1..fa742c8 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -3286,7 +3286,28 @@ inline bool run_test10() "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)" + "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)", + "~{ var x := 1 } + ~{ var x := 2 } == 3", + "(~{ var x := 1 } + ~{ var x := 2 }) == (~{ var x := 2 } + ~{ var x := 1 })", + "(~{ var x := 1 } + ~{ var x := 2 } + ~{~{ var x := 1 } + ~{ var x := 2 }}) == 6", + "(~{ var x[3] := [1] } + ~{ var x[6] := {6,5,4,3,2,1}}) == 7", + "(~{ var x[6] := {6,5,4,3,2,1} } + ~{ var x := 1 }) == 7", + "(~{ var x := 1 } + ~{ var x[6] := {6,5,4,3,2,1} }) == 7", + + "var x := 2; (~{ for (i := 0; i < 10; i += 1) { for (j := 0; j <= i;" + "j += 1) { var y := 3; if ((i + j + y + x) < 6) { y += x; continue; " + "} else break[i + j]; } } } + ~{ for (i := 0; i < 10; i += 1) { for " + "(j := 0; j <= i; j += 1) { var y := 3; if ((i + j + y + x) < 6) { " + "y += x; continue; } else break[i + j]; } } }) == 18 ", + + "var x := 2; var v0[3] := {1,2,3}; ( ~{ for (i := 0; i < 10; i += 1) { " + "for (j := 0; j <= i; j += 1) { var y := 3; var v2[3] := {1,2,3}; if ( " + "(i + j + y + x + abs(v0[i % v0[]] - v2[j % v2[]])) < 6) { var v3[3] :=" + "{1,2,3}; y += x / v3[j % v3[]]; continue; } else break[i + j]; } } } " + "+ ~{ for (i := 0; i < 10; i += 1) { for (j := 0; j <= i; j += 1) { var" + " y := 3; var v2[3] := {1,2,3}; if ((i + j + y + x + abs(v0[i % v0[]] -" + "v2[j % v2[]])) < 6) { var v3[3] := {1,2,3}; y += x / v3[j % v3[]]; " + "continue; } else break[i + j]; } } } ) == 18 " }; const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); @@ -3301,35 +3322,38 @@ inline bool run_test10() bool failed = false; - for (std::size_t i = 0; i < expression_list_size; ++i) + for (std::size_t r = 0; r < 100; ++r) { - expression_t expression; - expression.register_symbol_table(symbol_table); - + for (std::size_t i = 0; i < expression_list_size; ++i) { - exprtk::parser parser; - if (!parser.compile(expression_list[i],expression)) + expression_t expression; + expression.register_symbol_table(symbol_table); + { - printf("run_test10() - swaps Error: %s Expression: %s\n", - parser.error().c_str(), + 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()); - return false; + + failed = true; } } - 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; } - - if (failed) - return false; } return true;