From e10cdcffcddd528011a2b53baf9a41a30ffca39b Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Thu, 18 Apr 2013 00:43:00 +1000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 226 ++++++++++++++++++++++++++++------- exprtk_simple_example_04.cpp | 28 ++--- exprtk_test.cpp | 28 ++--- readme.txt | 10 +- 4 files changed, 215 insertions(+), 77 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index d604573..95e67f5 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -1577,6 +1577,11 @@ namespace exprtk return eof_token_; } + inline bool finished() const + { + return (token_list_.end() == token_itr_); + } + private: inline bool is_end(const char* itr) @@ -5610,7 +5615,7 @@ namespace exprtk template class Sequence> static inline T process(const Sequence& arglist) { - if (arglist.size() > 5) + if (arglist.size() > 8) { if (arglist.empty()) return std::numeric_limits::quiet_NaN(); @@ -5632,6 +5637,9 @@ namespace exprtk 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); default : return std::numeric_limits::quiet_NaN(); } } @@ -5676,6 +5684,42 @@ namespace exprtk value(arglist[3]); return value(arglist[4]); } + + template + static inline T process_6(const Sequence& arglist) + { + value(arglist[0]); + value(arglist[1]); + value(arglist[2]); + value(arglist[3]); + value(arglist[4]); + return value(arglist[5]); + } + + template + static inline T process_7(const Sequence& arglist) + { + value(arglist[0]); + value(arglist[1]); + value(arglist[2]); + value(arglist[3]); + value(arglist[4]); + value(arglist[5]); + return value(arglist[6]); + } + + template + static inline T process_8(const Sequence& arglist) + { + 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]); + } }; template @@ -9472,7 +9516,7 @@ namespace exprtk lexer_.begin(); next_token(); - expression_node_ptr e = parse_expression(); + expression_node_ptr e = parse_corpus(); if ((0 != e) && (token_t::e_eof == current_token_.type)) { @@ -9739,6 +9783,43 @@ namespace exprtk current_token_ = lexer_.next_token(); } + inline expression_node_ptr parse_corpus() + { + std::deque arg_list; + expression_node_ptr result = error_node(); + + scoped_deq_delete sdd(*this,arg_list); + + do + { + expression_node_ptr arg = parse_expression(); + if (0 == arg) + 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.")); + return error_node(); + } + } + while (!lexer_.finished()); + + if (arg_list.empty()) + return error_node(); + else if (arg_list.size() == 1) + result = arg_list[0]; + else + result = expression_generator_.vararg_function(details::e_multi,arg_list); + + sdd.delete_ptr = (0 == result); + return result; + } + static const precedence_level default_precedence = e_level00; struct state_t @@ -10060,7 +10141,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR07 - Expecting argument list for function: '" + function_name + "'")); + "ERR08 - Expecting argument list for function: '" + function_name + "'")); return error_node(); } @@ -10072,7 +10153,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR08 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); + "ERR09 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); return error_node(); } else if (i < static_cast(NumberofParameters - 1)) @@ -10082,7 +10163,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR09 - Invalid number of arguments for function: '" + function_name + "'")); + "ERR10 - Invalid number of arguments for function: '" + function_name + "'")); return error_node(); } } @@ -10093,7 +10174,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR10 - Invalid number of arguments for function: '" + function_name + "'")); + "ERR11 - Invalid number of arguments for function: '" + function_name + "'")); return error_node(); } else @@ -10112,7 +10193,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR11 - Expecting '()' to proceed: '" + function_name + "'")); + "ERR12 - Expecting '()' to proceed: '" + function_name + "'")); return error_node(); } else @@ -10129,7 +10210,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR12 - No entries found for base operation: " + operation_name)); + "ERR13 - No entries found for base operation: " + operation_name)); return error_node(); } @@ -10152,7 +10233,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR13 - Impossible argument count for base function: " + operation_name)); + "ERR14 - Impossible argument count for base function: " + operation_name)); return error_node(); } @@ -10173,7 +10254,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR14 - Invalid parameter count for function: " + operation_name)); + "ERR15 - Invalid parameter count for function: " + operation_name)); return error_node(); } @@ -10193,7 +10274,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR15 - Failed to parse condition for if-statement")); + "ERR16 - Failed to parse condition for if-statement")); return error_node(); } else if (!token_is(token_t::e_comma)) @@ -10203,7 +10284,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR16 - Failed to parse consequent for if-statement")); + "ERR17 - Failed to parse consequent for if-statement")); return error_node(); } else if (!token_is(token_t::e_comma)) @@ -10213,7 +10294,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR17 - Failed to parse alternative for if-statement")); + "ERR18 - Failed to parse alternative for if-statement")); return error_node(); } else if (!token_is(token_t::e_rbracket)) @@ -10235,23 +10316,20 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR18 - Failed to parse condition for while-loop")); + "ERR19 - Failed to parse condition for while-loop")); return error_node(); } else if (!token_is(token_t::e_rbracket)) return error_node(); - else if (!token_is(token_t::e_lcrlbracket)) - return error_node(); - else if (0 == (branch = parse_expression())) + + if (0 == (branch = parse_multi_sequence("while-loop"))) { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR19 - Failed to parse branch for while-loop")); + "ERR20 - Failed to parse body of while-loop")); return error_node(); } - else if (!token_is(token_t::e_rcrlbracket)) - return error_node(); expression_node_ptr result; if (0 == (result = expression_generator_.while_loop(condition,branch))) @@ -10259,7 +10337,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR20 - Failed to parse branch for while-loop")); + "ERR21 - Failed to synthesize while-loop")); return error_node(); } else @@ -10281,7 +10359,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR21 - Expected '{' for call to switch statement.")); + "ERR22 - Expected '{' for call to switch statement.")); return error_node(); } @@ -10301,7 +10379,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR22 - Expected ':' for case of switch statement.")); + "ERR23 - Expected ':' for case of switch statement.")); return error_node(); } @@ -10314,7 +10392,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR23 - Expected ';' at end of case for switch statement.")); + "ERR24 - Expected ';' at end of case for switch statement.")); return error_node(); } @@ -10329,7 +10407,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR24 - Expected ':' for default of switch statement.")); + "ERR25 - Expected ':' for default of switch statement.")); return error_node(); } @@ -10340,7 +10418,7 @@ namespace exprtk { set_error(make_error(parser_error::e_syntax, current_token_, - "ERR25 - Expected ';' at end of default for switch statement.")); + "ERR26 - Expected ';' at end of default for switch statement.")); return error_node(); } @@ -10354,7 +10432,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR26 - Expected '}' at end of switch statement.")); + "ERR27 - Expected '}' at end of switch statement.")); return error_node(); } @@ -10372,20 +10450,24 @@ namespace exprtk details::operator_type opt_type = details::e_default; const std::string symbol = current_token_.value; - if (details::imatch(symbol,"sum" )) opt_type = details::e_sum; + if (details::imatch(symbol,"~")) + { + next_token(); + return parse_multi_sequence(); + } + 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,"mor" )) opt_type = details::e_mor; - else if (details::imatch(symbol,"~" )) opt_type = details::e_multi; else { set_error( make_error(parser_error::e_syntax, current_token_, - "ERR26 - Unsupported vararg function: " + symbol)); + "ERR28 - Unsupported vararg function: " + symbol)); return error_node(); } @@ -10397,7 +10479,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR28 - Expected '(' for call to vararg function: " + symbol)); + "ERR29 - Expected '(' for call to vararg function: " + symbol)); return error_node(); } @@ -10415,7 +10497,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR29 - Expected ',' for call to vararg function: " + symbol)); + "ERR30 - Expected ',' for call to vararg function: " + symbol)); return error_node(); } } @@ -10426,6 +10508,64 @@ namespace exprtk return result; } + inline expression_node_ptr parse_multi_sequence(const std::string& source = "") + { + token_t::token_type close_bracket = token_t::e_rcrlbracket; + token_t::token_type seperator = token_t::e_eof; + + if (!token_is(token_t::e_lcrlbracket)) + { + if (token_is(token_t::e_lbracket)) + { + close_bracket = token_t::e_rbracket; + seperator = token_t::e_comma; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR31 - Expected '"+ details::to_str(close_bracket) + "' for call to multi-sequence" + + ((!source.empty()) ? std::string(" section of " + source): ""))); + return error_node(); + } + } + + std::deque arg_list; + expression_node_ptr result = error_node(); + + scoped_deq_delete sdd(*this,arg_list); + + 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; + else if (!token_is(seperator)) + { + set_error( + make_error(parser_error::e_syntax, + current_token_, + "ERR32 - Expected '"+ details::to_str(seperator) +"' for call to multi-sequence section of " + source)); + return error_node(); + } + } + + if (arg_list.empty()) + return error_node(); + else if (arg_list.size() == 1) + result = arg_list[0]; + else + result = expression_generator_.vararg_function(details::e_multi,arg_list); + + sdd.delete_ptr = (0 == result); + return result; + } + inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) { std::vector arg_list; @@ -10441,7 +10581,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR30 - Expected '(' for call to vararg function: " + vararg_function_name)); + "ERR33 - Expected '(' for call to vararg function: " + vararg_function_name)); return error_node(); } @@ -10459,7 +10599,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR31 - Expected ',' for call to vararg function: " + vararg_function_name)); + "ERR34 - Expected ',' for call to vararg function: " + vararg_function_name)); return error_node(); } } @@ -10520,7 +10660,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token_, - "ERR32 - Invalid special function[1]: " + current_token_.value)); + "ERR35 - Invalid special function[1]: " + current_token_.value)); return error_node(); } @@ -10531,7 +10671,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token_, - "ERR33 - Invalid special function[2]: " + current_token_.value)); + "ERR36 - Invalid special function[2]: " + current_token_.value)); return error_node(); } @@ -10623,7 +10763,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR34 - Invalid number of parameters for function: " + symbol)); + "ERR37 - Invalid number of parameters for function: " + symbol)); return error_node(); } } @@ -10635,7 +10775,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR35 - Failed to generate node for function: '" + symbol + "'")); + "ERR38 - Failed to generate node for function: '" + symbol + "'")); return error_node(); } } @@ -10655,7 +10795,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR36 - Failed to generate node for vararg function: '" + symbol + "'")); + "ERR39 - Failed to generate node for vararg function: '" + symbol + "'")); return error_node(); } } @@ -10664,7 +10804,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR37 - Undefined variable or function: '" + symbol + "'")); + "ERR40 - Undefined variable or function: '" + symbol + "'")); return error_node(); } } @@ -10713,7 +10853,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token_, - "ERR38 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); + "ERR41 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); return error_node(); } } @@ -10788,7 +10928,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR39 - Premature end of expression.[1]")); + "ERR42 - Premature end of expression.[1]")); return error_node(); } else @@ -10796,7 +10936,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token_, - "ERR40 - Premature end of expression.[2]")); + "ERR43 - Premature end of expression.[2]")); return error_node(); } } diff --git a/exprtk_simple_example_04.cpp b/exprtk_simple_example_04.cpp index 983c2c8..011d868 100644 --- a/exprtk_simple_example_04.cpp +++ b/exprtk_simple_example_04.cpp @@ -33,21 +33,19 @@ void fibonacci() compositor .add("fibonacci_impl", - "switch " - "{ " - " case x == 0 : 0; " - " case x == 1 : 1; " - " default : " - " while (~(x := (x - 1)) > 0)" - " {~ " - " ( " - " w := z, " - " z := z + y, " - " y := w, " - " z " - " ) " - " }; " - "} ", + "switch " + "{ " + " case x == 0 : 0; " + " case x == 1 : 1; " + " default : " + " while ((x := (x - 1)) > 0)" + " { " + " w := z; " + " z := z + y; " + " y := w; " + " z " + " }; " + "} ", "x","y","z","w"); compositor diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 6c0b99b..b692920 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -3578,7 +3578,7 @@ inline bool run_test19() "{ " " switch " " { " - " case y == 1 : ~(y := 0,true); " + " case y == 1 : ~(y := 0, true);" " case (x % y) == 0 : ~(y := 0,false);" " default : y := y - 1; " " } " @@ -3718,20 +3718,18 @@ inline bool run_test19() compositor .add("fibonacci_impl3", - "switch " - "{ " - " case x == 0 : 0; " - " case x == 1 : 1; " - " default : while (~(x := (x - 1)) > 0)" - " {~ " - " ( " - " w := z, " - " z := z + y, " - " y := w, " - " z " - " ) " - " }; " - "} ", + "switch " + "{ " + " case x == 0 : 0; " + " case x == 1 : 1; " + " default : while ((x := (x - 1)) > 0)" + " { " + " w := z; " + " z := z + y; " + " y := w; " + " z " + " }; " + "} ", "x","y","z","w"); compositor diff --git a/readme.txt b/readme.txt index 713e2dd..80dbd68 100644 --- a/readme.txt +++ b/readme.txt @@ -277,9 +277,11 @@ include path (e.g: /usr/include/). | trunc | Integer portion of x | +-----------+--------------------------------------------------------+ | ~ | Evaluate each sub-expression, then return as the result| -| | the value of the last sub-expression. This is known as | -| | multiple sequence point evaluation. | -| | (eg: ~(x+1,y/z,abs(y^3),sin(w/u)) == (sin(w/u))) | +| | the value of the last sub-expression. This is sometimes| +| | known as multiple sequence point evaluation. | +| | eg: | +| | ~(i:=x+1, j:=y/z, k:=sin(w/u)) == (sin(w/u))) | +| | ~{i:=x+1; j:=y/z; k:=sin(w/u)} == (sin(w/u))) | +-----------+--------------------------------------------------------+ (4) Trigonometry Functions @@ -467,7 +469,7 @@ correctly optimize such expressions for a given architecture. compile time: exprtk_disable_string_capabilities (16) Composited functions can call themselves or any other functions - that have been previously defined. + that have been defined prior to their own definition. (17) Expressions may contain any of the following comment styles: 1. // .... \n