diff --git a/exprtk.hpp b/exprtk.hpp index 2c2e766..f3a53b4 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -4033,7 +4033,10 @@ namespace exprtk { if (0 != node) { - if (is_variable_node(node) && !force_delete) + if ( + (is_variable_node(node) || is_string_node(node)) || + force_delete + ) return; node_allocator.free(node); @@ -6407,9 +6410,11 @@ namespace exprtk range_t& range = str_range_ptr_->range_ref(); + const std::size_t base_str_size = str_base_ptr_->str().size(); + if ( - range (str_r0,str_r1,str_base_ptr_->str().size()) && - base_range_(r0,r1) + range (str_r0,str_r1,base_str_size) && + base_range_( r0, r1,base_str_size) ) { const std::size_t size = (r1 - r0) + 1; @@ -7293,7 +7298,19 @@ namespace exprtk variable_node* var_node_ptr_; }; - template + struct asn_assignment + { + static inline void execute(std::string& s, const char* data, const std::size_t size) + { s.assign(data,size); } + }; + + struct asn_addassignment + { + static inline void execute(std::string& s, const char* data, const std::size_t size) + { s.append(data,size); } + }; + + template class assignment_string_node : public binary_node , public string_base_node, public range_interface @@ -7359,7 +7376,9 @@ namespace exprtk if (range(r0,r1,str1_base_ptr_->str().size())) { - str0_node_ptr_->ref().assign(str1_base_ptr_->str().data() + r0, (r1 - r0) + 1); + AssignmentProcess::execute(str0_node_ptr_->ref(), + str1_base_ptr_->str().data() + r0, + (r1 - r0) + 1); binary_node::branch_[0].first->value(); } @@ -19627,6 +19646,7 @@ namespace exprtk (details::e_like == operation) || (details::e_ilike == operation) || (details::e_assign == operation) || + (details::e_addass == operation) || (details::e_swap == operation) ; } #else @@ -19836,15 +19856,22 @@ namespace exprtk inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { - return is_assignment_operation(operation) && - ( - ( - !details::is_variable_node (branch[0]) && - !details::is_vector_elem_node(branch[0]) && - !details::is_vector_node (branch[0]) - ) || - is_generally_string_node(branch[1]) - ); + if (is_assignment_operation(operation)) + { + const bool b1_is_genstring = details::is_generally_string_node(branch[1]); + + if (details::is_string_node(branch[0])) + return !b1_is_genstring; + else + return ( + !details::is_variable_node (branch[0]) && + !details::is_vector_elem_node(branch[0]) && + !details::is_vector_node (branch[0]) + ) + || b1_is_genstring; + } + else + return false; } inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) @@ -20170,8 +20197,8 @@ namespace exprtk #endif } - inline expression_node_ptr repeat_until_loop(expression_node_ptr condition, - expression_node_ptr branch, + inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, + expression_node_ptr& branch, const bool brkcont = false) const { if (!brkcont && details::is_constant_node(condition)) @@ -20204,10 +20231,10 @@ namespace exprtk #endif } - inline expression_node_ptr for_loop(expression_node_ptr initialiser, - expression_node_ptr condition, - expression_node_ptr incrementor, - expression_node_ptr loop_body, + inline expression_node_ptr for_loop(expression_node_ptr& initialiser, + expression_node_ptr& condition, + expression_node_ptr& incrementor, + expression_node_ptr& loop_body, bool brkcont = false) const { if (!brkcont && details::is_constant_node(condition)) @@ -20935,7 +20962,7 @@ namespace exprtk alloc_type* genfunc_node_ptr = static_cast(result); if ( - !arg_list.empty() && + !arg_list.empty() && !gf->has_side_effects && is_constant_foldable(arg_list) ) @@ -20971,7 +20998,7 @@ namespace exprtk alloc_type* genfunc_node_ptr = static_cast(result); if ( - !arg_list.empty() && + !arg_list.empty() && !gf->has_side_effects && is_constant_foldable(arg_list) ) @@ -21169,6 +21196,15 @@ namespace exprtk } } } + else if ( + (details::e_addass == operation) && + details::is_string_node(branch[0]) + ) + { + typedef details::assignment_string_node addass_t; + + return synthesize_expression(operation,branch); + } else { parser_->set_synthesis_error("Invalid assignment operation[2]"); @@ -28917,6 +28953,89 @@ namespace exprtk return true; } + namespace helper + { + namespace details + { + template + struct print_impl + { + typedef typename igeneric_function::generic_type generic_type; + typedef typename igeneric_function::parameter_list_t parameter_list_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + typedef typename generic_type::string_view string_t; + + static void process(const std::string& scalar_format, parameter_list_t parameters) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + generic_type& gt = parameters[i]; + + switch (gt.type) + { + case generic_type::e_scalar : printf(scalar_format.c_str(),scalar_t(gt)()); + break; + + case generic_type::e_vector : { + vector_t vector(gt); + + for (std::size_t x = 0; x < vector.size(); ++x) + { + printf(scalar_format.c_str(),vector[x]); + if ((x + 1) < vector.size()) + printf(" "); + } + } + break; + + case generic_type::e_string : printf("%s",to_str(string_t(gt)).c_str()); + break; + + default : continue; + } + } + } + }; + } + + template + struct print : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + print(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + {} + + inline T operator()(parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + return T(0); + } + + std::string scalar_format_; + }; + + template + struct println : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + println(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + {} + + inline T operator()(parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + printf("\n"); + return T(0); + } + + std::string scalar_format_; + }; + } } #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) diff --git a/exprtk_test.cpp b/exprtk_test.cpp index a82acc2..4bd4049 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -130,16 +130,16 @@ static const test_t test_list[] = test_t("-7.7",-7.7), test_t("-8.8",-8.8), test_t("-9.9",-9.9), - test_t("0.0e+0",+0.0e+0), - test_t("1.1e+1",+1.1e+1), - test_t("2.2e+2",+2.2e+2), - test_t("3.3e+3",+3.3e+3), - test_t("4.4e+4",+4.4e+4), - test_t("5.5e+5",+5.5e+5), - test_t("6.6e+6",+6.6e+6), - test_t("7.7e+7",+7.7e+7), - test_t("8.8e+8",+8.8e+8), - test_t("9.9e+9",+9.9e+9), + test_t("0.0e+0" ,+0.0e+0), + test_t("1.1e+1" ,+1.1e+1), + test_t("2.2e+2" ,+2.2e+2), + test_t("3.3e+3" ,+3.3e+3), + test_t("4.4e+4" ,+4.4e+4), + test_t("5.5e+5" ,+5.5e+5), + test_t("6.6e+6" ,+6.6e+6), + test_t("7.7e+7" ,+7.7e+7), + test_t("8.8e+8" ,+8.8e+8), + test_t("9.9e+9" ,+9.9e+9), test_t("-0.0e+0",-0.0e+0), test_t("-1.1e+1",-1.1e+1), test_t("-2.2e+2",-2.2e+2), @@ -150,16 +150,16 @@ static const test_t test_list[] = test_t("-7.7e+7",-7.7e+7), test_t("-8.8e+8",-8.8e+8), test_t("-9.9e+9",-9.9e+9), - test_t("0.0E+0",+0.0E+0), - test_t("1.1E+1",+1.1E+1), - test_t("2.2E+2",+2.2E+2), - test_t("3.3E+3",+3.3E+3), - test_t("4.4E+4",+4.4E+4), - test_t("5.5E+5",+5.5E+5), - test_t("6.6E+6",+6.6E+6), - test_t("7.7E+7",+7.7E+7), - test_t("8.8E+8",+8.8E+8), - test_t("9.9E+9",+9.9E+9), + test_t("0.0E+0" ,+0.0E+0), + test_t("1.1E+1" ,+1.1E+1), + test_t("2.2E+2" ,+2.2E+2), + test_t("3.3E+3" ,+3.3E+3), + test_t("4.4E+4" ,+4.4E+4), + test_t("5.5E+5" ,+5.5E+5), + test_t("6.6E+6" ,+6.6E+6), + test_t("7.7E+7" ,+7.7E+7), + test_t("8.8E+8" ,+8.8E+8), + test_t("9.9E+9" ,+9.9E+9), test_t("-0.0E+0",-0.0E+0), test_t("-1.1E+1",-1.1E+1), test_t("-2.2E+2",-2.2E+2), @@ -200,16 +200,16 @@ static const test_t test_list[] = test_t("(7.7)",7.7), test_t("(8.8)",8.8), test_t("(9.9)",9.9), - test_t("(+0)",0.0), - test_t("(+1)",1.0), - test_t("(+2)",2.0), - test_t("(+3)",3.0), - test_t("(+4)",4.0), - test_t("(+5)",5.0), - test_t("(+6)",6.0), - test_t("(+7)",7.0), - test_t("(+8)",8.0), - test_t("(+9)",9.0), + test_t("(+0)" ,0.0), + test_t("(+1)" ,1.0), + test_t("(+2)" ,2.0), + test_t("(+3)" ,3.0), + test_t("(+4)" ,4.0), + test_t("(+5)" ,5.0), + test_t("(+6)" ,6.0), + test_t("(+7)" ,7.0), + test_t("(+8)" ,8.0), + test_t("(+9)" ,9.0), test_t("(+0.0)",0.0), test_t("(+1.0)",1.0), test_t("(+2.0)",2.0), @@ -230,16 +230,16 @@ static const test_t test_list[] = test_t("(+7.7)",7.7), test_t("(+8.8)",8.8), test_t("(+9.9)",9.9), - test_t("(-0)",-0.0), - test_t("(-1)",-1.0), - test_t("(-2)",-2.0), - test_t("(-3)",-3.0), - test_t("(-4)",-4.0), - test_t("(-5)",-5.0), - test_t("(-6)",-6.0), - test_t("(-7)",-7.0), - test_t("(-8)",-8.0), - test_t("(-9)",-9.0), + test_t("(-0)" ,-0.0), + test_t("(-1)" ,-1.0), + test_t("(-2)" ,-2.0), + test_t("(-3)" ,-3.0), + test_t("(-4)" ,-4.0), + test_t("(-5)" ,-5.0), + test_t("(-6)" ,-6.0), + test_t("(-7)" ,-7.0), + test_t("(-8)" ,-8.0), + test_t("(-9)" ,-9.0), test_t("(-0.0)",-0.0), test_t("(-1.0)",-1.0), test_t("(-2.0)",-2.0), @@ -2086,7 +2086,33 @@ inline bool run_test02() test_ab("(a[r0:r0] + b[r3:r0+1]) == 'c3' ","abc","0123456789" ,T(1.0)), test_ab("(a[r0+1:] + b) == 'defghij0123' ","abcdefghij","0123",T(1.0)), test_ab("a[r0+1: ] + '123' == 'abc' + b[r0+1: ]","XYZabc", "XYZ123", T(1.0)), - test_ab("a[r0+1:a[] - 1] + '123' == 'abc' + b[r0+1:b[] - 1]","XYZabc", "XYZ123", T(1.0)) + test_ab("a[r0+1:a[] - 1] + '123' == 'abc' + b[r0+1:b[] - 1]","XYZabc", "XYZ123", T(1.0)), + test_ab("(a + b)[ :13] == 'abcdefghij0123' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a + b)[ 6: ] == 'ghij0123456789' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a + b)[ 2:3r1-1] == 'cdefghij01234567' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a[2:7] + b[2:7]) == 'cdefgh234567' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a[2:7] + b[2:7])[3:8] == 'fgh234' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a + b)[r0 - 2: r1 + r2] == 'abcdefghij0123' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a + b)[r0*r3:] == 'ghij0123456789' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a + b)[3r0: ] == 'ghij0123456789' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a + b)[2r3: ] == 'ghij0123456789' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a + b)[2:3r1 - 1] == 'cdefghij01234567' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a[r0:7] + b[r0:r2])== 'cdefgh234567' ", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a[r1 / r3:7] + b[r0:r2])[3:r2 + 1] == 'fgh234'", "abcdefghij", "0123456789" ,T(1.0)), + test_ab("(a += b) == 'abc123' ", "abc","123" ,T(1.0)), + test_ab("(a += '123') == 'abc123' ", "abc","123" ,T(1.0)), + test_ab("(a += b[3:5]) == 'abc123' ", "abc","XXX123XXX" ,T(1.0)), + test_ab("(a += 'XXX123XXX'[3:5]) == 'abc123' ", "abc","123" ,T(1.0)), + test_ab("(a += b)[:] == 'abc123' ", "abc","123" ,T(1.0)), + test_ab("(a += '123')[:] == 'abc123' ", "abc","123" ,T(1.0)), + test_ab("(a += b[3:5])[:] == 'abc123' ", "abc","XXX123XXX" ,T(1.0)), + test_ab("(a += 'XXX123XXX'[3:5])[:] == 'abc123' ", "abc","123" ,T(1.0)), + test_ab("(a += b[r1/2:r1-1]) == 'abc123' ", "abc","XXX123XXX" ,T(1.0)), + test_ab("(a += 'XXX123XXX'[r0+1:r1-1]) == 'abc123' ", "abc","123" ,T(1.0)), + test_ab("(a += b)[] == 6 ", "abc","123" ,T(1.0)), + test_ab("(a += '123')[] == 6 ", "abc","123" ,T(1.0)), + test_ab("(a += b[3:5])[] == 6 ", "abc","XXX123XXX" ,T(1.0)), + test_ab("(a += b[r0+1:r1-1])[] == 6 ", "abc","XXX123XXX" ,T(1.0)) }; static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_ab); diff --git a/readme.txt b/readme.txt index dec8207..15c3ffe 100644 --- a/readme.txt +++ b/readme.txt @@ -419,6 +419,13 @@ of C++ compilers: | | 6. 'abc' + '1234567' | | | 7. (x + 'a1B2c3D4' + y)[i:2j] | +----------+---------------------------------------------------------+ +| += | Append to x the value of y. Where x is a mutable string | +| | and y is either a string or a string range. eg: | +| | 1. x += y | +| | 2. x += 'abc' | +| | 3. x += y[:i + j] + 'abc' | +| | 4. x += '0123456789'[2:7] | ++----------+---------------------------------------------------------+ | [] | The string size operator returns the size of the string | | | being actioned. | | | eg: |