C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html

This commit is contained in:
Arash Partow 2014-04-07 07:01:02 +10:00
parent 904f924005
commit e5f917033f
3 changed files with 323 additions and 138 deletions

View File

@ -18,7 +18,7 @@
* (03) 1 - sin(2 * x) + cos(pi / y) *
* (04) a * exp(2 * t) + c *
* (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) *
* (06) if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x *
* (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x *
* (07) z := x + sin(2 * pi / y) *
* (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) *
* (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) *
@ -1514,7 +1514,8 @@ namespace exprtk
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_mod = '%', e_pow = '^', e_colon = ':',
e_ternary = '?'
};
token()
@ -1635,6 +1636,7 @@ namespace exprtk
case e_mod : return "%";
case e_pow : return "^";
case e_colon : return ":";
case e_ternary : return "?";
default : return "UNKNOWN";
}
}
@ -2765,30 +2767,33 @@ namespace exprtk
sequence_validator()
: lexer::token_scanner(2)
{
add_invalid(lexer::token::e_number,lexer::token::e_number);
add_invalid(lexer::token::e_string,lexer::token::e_string);
add_invalid(lexer::token::e_number,lexer::token::e_string);
add_invalid(lexer::token::e_string,lexer::token::e_number);
add_invalid(lexer::token::e_string,lexer::token::e_colon );
add_invalid(lexer::token::e_colon ,lexer::token::e_string);
add_invalid(lexer::token::e_assign,lexer::token::e_string);
add_invalid_set1(lexer::token::e_assign);
add_invalid_set1(lexer::token::e_shr );
add_invalid_set1(lexer::token::e_shl );
add_invalid_set1(lexer::token::e_lte );
add_invalid_set1(lexer::token::e_ne );
add_invalid_set1(lexer::token::e_gte );
add_invalid_set1(lexer::token::e_lt );
add_invalid_set1(lexer::token::e_gt );
add_invalid_set1(lexer::token::e_eq );
add_invalid_set1(lexer::token::e_comma );
add_invalid_set1(lexer::token::e_add );
add_invalid_set1(lexer::token::e_sub );
add_invalid_set1(lexer::token::e_div );
add_invalid_set1(lexer::token::e_mul );
add_invalid_set1(lexer::token::e_mod );
add_invalid_set1(lexer::token::e_pow );
add_invalid_set1(lexer::token::e_colon );
add_invalid(lexer::token::e_number ,lexer::token::e_number );
add_invalid(lexer::token::e_string ,lexer::token::e_string );
add_invalid(lexer::token::e_number ,lexer::token::e_string );
add_invalid(lexer::token::e_string ,lexer::token::e_number );
add_invalid(lexer::token::e_string ,lexer::token::e_colon );
add_invalid(lexer::token::e_string ,lexer::token::e_ternary);
add_invalid(lexer::token::e_colon ,lexer::token::e_string );
add_invalid(lexer::token::e_ternary,lexer::token::e_string );
add_invalid(lexer::token::e_assign ,lexer::token::e_string );
add_invalid_set1(lexer::token::e_assign );
add_invalid_set1(lexer::token::e_shr );
add_invalid_set1(lexer::token::e_shl );
add_invalid_set1(lexer::token::e_lte );
add_invalid_set1(lexer::token::e_ne );
add_invalid_set1(lexer::token::e_gte );
add_invalid_set1(lexer::token::e_lt );
add_invalid_set1(lexer::token::e_gt );
add_invalid_set1(lexer::token::e_eq );
add_invalid_set1(lexer::token::e_comma );
add_invalid_set1(lexer::token::e_add );
add_invalid_set1(lexer::token::e_sub );
add_invalid_set1(lexer::token::e_div );
add_invalid_set1(lexer::token::e_mul );
add_invalid_set1(lexer::token::e_mod );
add_invalid_set1(lexer::token::e_pow );
add_invalid_set1(lexer::token::e_colon );
add_invalid_set1(lexer::token::e_ternary);
}
bool result()
@ -2878,13 +2883,14 @@ namespace exprtk
{
switch (t)
{
case lexer::token::e_number : return false;
case lexer::token::e_symbol : return false;
case lexer::token::e_string : return false;
case lexer::token::e_add : return false;
case lexer::token::e_sub : return false;
case lexer::token::e_colon : return false;
default : return true;
case lexer::token::e_number : return false;
case lexer::token::e_symbol : return false;
case lexer::token::e_string : return false;
case lexer::token::e_add : return false;
case lexer::token::e_sub : return false;
case lexer::token::e_colon : return false;
case lexer::token::e_ternary : return false;
default : return true;
}
}
}
@ -2892,12 +2898,13 @@ namespace exprtk
{
switch (base)
{
case lexer::token::e_number : return false;
case lexer::token::e_symbol : return false;
case lexer::token::e_string : return false;
case lexer::token::e_eof : return false;
case lexer::token::e_colon : return false;
default : return true;
case lexer::token::e_number : return false;
case lexer::token::e_symbol : return false;
case lexer::token::e_string : return false;
case lexer::token::e_eof : return false;
case lexer::token::e_colon : return false;
case lexer::token::e_ternary : return false;
default : return true;
}
}
else if (details::is_left_bracket(static_cast<char>(t)))
@ -10776,7 +10783,13 @@ namespace exprtk
return error_node();
}
else
{
expression = new_expression;
if (token_is(token_t::e_ternary,false) && (precedence == e_level00))
{
expression = parse_ternary_conditional_statement(expression);
}
}
}
return expression;
@ -11071,6 +11084,8 @@ namespace exprtk
expression_node_ptr consequent = error_node();
expression_node_ptr alternative = error_node();
bool result = true;
next_token();
if (!token_is(token_t::e_lbracket))
@ -11095,7 +11110,7 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR19 - Expected ',' between if-statement condition and consequent"));
return error_node();
result = false;
}
else if (0 == (consequent = parse_expression()))
{
@ -11103,7 +11118,7 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR20 - Failed to parse consequent for if-statement"));
return error_node();
result = false;
}
else if (!token_is(token_t::e_comma))
{
@ -11111,8 +11126,7 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR21 - Expected ',' between if-statement consequent and alternative"));
return error_node();
result = false;
}
else if (0 == (alternative = parse_expression()))
{
@ -11120,7 +11134,7 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR22 - Failed to parse alternative for if-statement"));
return error_node();
result = false;
}
else if (!token_is(token_t::e_rbracket))
{
@ -11128,6 +11142,74 @@ namespace exprtk
make_error(parser_error::e_syntax,
current_token_,
"ERR23 - Expected ')' at end of if-statement"));
result = false;
}
if (!result)
{
free_node(node_allocator_,condition );
free_node(node_allocator_,consequent );
free_node(node_allocator_,alternative);
return error_node();
}
else
return expression_generator_.conditional(condition,consequent,alternative);
}
inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition)
{
// Parse: [condition][?][consequent][:][alternative]
expression_node_ptr consequent = error_node();
expression_node_ptr alternative = error_node();
bool result = true;
if (0 == condition)
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR24 - Encountered invalid condition branch for ternary if-statement"));
return error_node();
}
else if (!token_is(token_t::e_ternary))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR25 - Expected '?' after condition of ternary if-statement"));
result = false;
}
else if (0 == (consequent = parse_expression()))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR26 - Failed to parse consequent for if-statement"));
result = false;
}
else if (!token_is(token_t::e_colon))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR27 - Expected ':' between ternary if-statement consequent and alternative"));
result = false;
}
else if (0 == (alternative = parse_expression()))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR28 - Failed to parse alternative for if-statement"));
result = false;
}
if (!result)
{
free_node(node_allocator_,condition );
free_node(node_allocator_,consequent );
free_node(node_allocator_,alternative);
return error_node();
}
else
@ -11139,13 +11221,15 @@ namespace exprtk
// Parse: [while][(][test expr][)][{][expression][}]
expression_node_ptr condition = error_node();
expression_node_ptr branch = error_node();
next_token();
if (!token_is(token_t::e_lbracket))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR24 - Expected '(' at start of while-statement condition"));
"ERR29 - Expected '(' at start of while-statement condition"));
return error_node();
}
else if (0 == (condition = parse_expression()))
@ -11153,7 +11237,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR25 - Failed to parse condition for while-loop"));
"ERR30 - Failed to parse condition for while-loop"));
return error_node();
}
else if (!token_is(token_t::e_rbracket))
@ -11161,7 +11245,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR26 - Expected ')' at end of while-statement condition"));
"ERR31 - Expected ')' at end of while-statement condition"));
return error_node();
}
if (0 == (branch = parse_multi_sequence("while-loop")))
@ -11169,7 +11253,8 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR27 - Failed to parse body of while-loop"));
"ERR32 - Failed to parse body of while-loop"));
free_node(node_allocator_,condition);
return error_node();
}
@ -11179,7 +11264,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR28 - Failed to synthesize while-loop"));
"ERR33 - Failed to synthesize while-loop"));
return error_node();
}
else
@ -11217,7 +11302,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR29 - Expected '" + token_t::to_str(seperator) +"' for body of repeat until loop"));
"ERR34 - Expected '" + token_t::to_str(seperator) +"' for body of repeat until loop"));
return error_node();
}
@ -11237,7 +11322,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR30 - Failed to parse body of repeat until loop"));
"ERR35 - Failed to parse body of repeat until loop"));
return error_node();
}
}
@ -11247,7 +11332,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR31 - Expected '(' before condition of repeat until loop"));
"ERR36 - Expected '(' before condition of repeat until loop"));
return error_node();
}
else if (0 == (condition = parse_expression()))
@ -11255,7 +11340,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR32 - Failed to parse condition for repeat until loop"));
"ERR37 - Failed to parse condition for repeat until loop"));
return error_node();
}
else if (!token_is(token_t::e_rbracket))
@ -11263,7 +11348,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR33 - Expected ')' after condition of repeat until loop"));
"ERR38 - Expected ')' after condition of repeat until loop"));
return error_node();
}
@ -11273,7 +11358,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR34 - Failed to synthesize repeat until loop"));
"ERR39 - Failed to synthesize repeat until loop"));
return error_node();
}
else
@ -11292,7 +11377,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR35 - Expected keyword 'switch'"));
"ERR40 - Expected keyword 'switch'"));
return error_node();
}
@ -11305,7 +11390,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR36 - Expected '{' for call to switch statement"));
"ERR41 - Expected '{' for call to switch statement"));
return error_node();
}
@ -11316,7 +11401,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR37 - Expected either a 'case' or 'default' statement"));
"ERR42 - Expected either a 'case' or 'default' statement"));
return error_node();
}
@ -11331,7 +11416,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR38 - Expected ':' for case of switch statement"));
"ERR43 - Expected ':' for case of switch statement"));
return error_node();
}
@ -11344,7 +11429,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR39 - Expected ';' at end of case for switch statement"));
"ERR44 - Expected ';' at end of case for switch statement"));
return error_node();
}
@ -11370,7 +11455,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR40 - Expected ':' for default of switch statement"));
"ERR45 - Expected ':' for default of switch statement"));
return error_node();
}
@ -11382,7 +11467,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR41 - Expected ';' at end of default for switch statement"));
"ERR46 - Expected ';' at end of default for switch statement"));
return error_node();
}
@ -11396,7 +11481,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR42 - Expected '}' at end of switch statement"));
"ERR47 - Expected '}' at end of switch statement"));
return error_node();
}
@ -11418,7 +11503,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR43 - Expected token '[*]'"));
"ERR48 - Expected token '[*]'"));
return error_node();
}
@ -11431,7 +11516,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR44 - Expected '{' for call to [*] statement"));
"ERR49 - Expected '{' for call to [*] statement"));
return error_node();
}
@ -11442,7 +11527,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR45 - Expected a 'case' statement for multi-switch."));
"ERR50 - Expected a 'case' statement for multi-switch."));
return error_node();
}
@ -11457,7 +11542,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR46 - Expected ':' for case of [*] statement"));
"ERR51 - Expected ':' for case of [*] statement"));
return error_node();
}
@ -11470,7 +11555,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR47 - Expected ';' at end of case for [*] statement"));
"ERR52 - Expected ';' at end of case for [*] statement"));
return error_node();
}
@ -11499,7 +11584,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR48 - Expected '}' at end of [*] statement"));
"ERR53 - Expected '}' at end of [*] statement"));
return error_node();
}
@ -11538,7 +11623,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR49 - Unsupported vararg function: " + symbol));
"ERR54 - Unsupported vararg function: " + symbol));
return error_node();
}
@ -11550,7 +11635,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR50 - Expected '(' for call to vararg function: " + symbol));
"ERR55 - Expected '(' for call to vararg function: " + symbol));
return error_node();
}
@ -11569,7 +11654,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR51 - Expected ',' for call to vararg function: " + symbol));
"ERR56 - Expected ',' for call to vararg function: " + symbol));
return error_node();
}
}
@ -11626,7 +11711,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR52 - Expected '"+ details::to_str(close_bracket) + "' for call to multi-sequence" +
"ERR57 - Expected '"+ details::to_str(close_bracket) + "' for call to multi-sequence" +
((!source.empty()) ? std::string(" section of " + source): "")));
return error_node();
}
@ -11654,7 +11739,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR53 - Expected '"+ details::to_str(seperator) +"' for call to multi-sequence section of " + source));
"ERR58 - Expected '"+ details::to_str(seperator) +"' for call to multi-sequence section of " + source));
return error_node();
}
@ -11780,7 +11865,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR54 - Expected '[' for start of range"));
"ERR59 - Expected '[' for start of range"));
return false;
}
@ -11798,7 +11883,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR55 - Failed parse begin section of range"));
"ERR60 - Failed parse begin section of range"));
return false;
}
@ -11816,7 +11901,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR56 - Range lower bound less than zero! Constraint: r0 >= 0"));
"ERR61 - Range lower bound less than zero! Constraint: r0 >= 0"));
return false;
}
}
@ -11831,7 +11916,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR57 - Expected ':' for break in range"));
"ERR62 - Expected ':' for break in range"));
rp.free();
return false;
}
@ -11851,7 +11936,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR58 - Failed parse end section of range"));
"ERR63 - Failed parse end section of range"));
rp.free();
return false;
@ -11870,7 +11955,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR59 - Range upper bound less than zero! Constraint: r1 >= 0"));
"ERR64 - Range upper bound less than zero! Constraint: r1 >= 0"));
return false;
}
}
@ -11885,7 +11970,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR60 - Expected ']' for start of range"));
"ERR65 - Expected ']' for start of range"));
rp.free();
return false;
}
@ -11901,7 +11986,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR61 - Invalid range, Constraint: r0 <= r1"));
"ERR66 - Invalid range, Constraint: r0 <= r1"));
return false;
}
}
@ -11926,7 +12011,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR62 - Unknown string symbol"));
"ERR67 - Unknown string symbol"));
return error_node();
}
@ -11987,7 +12072,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR63 - Overflow in range for string: '" + const_str + "'[" +
"ERR68 - 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();
@ -12016,7 +12101,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR64 - Expected '(' for call to vararg function: " + vararg_function_name));
"ERR69 - Expected '(' for call to vararg function: " + vararg_function_name));
return error_node();
}
@ -12037,7 +12122,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR65 - Expected ',' for call to vararg function: " + vararg_function_name));
"ERR70 - Expected ',' for call to vararg function: " + vararg_function_name));
return error_node();
}
}
@ -12066,7 +12151,7 @@ namespace exprtk
p.set_error(
make_error(parser_error::e_syntax,
p.current_token(),
"ERR66 - Expected '(' for special function"));
"ERR71 - Expected '(' for special function"));
return error_node();
}
@ -12084,7 +12169,7 @@ namespace exprtk
p.set_error(
make_error(parser_error::e_syntax,
p.current_token(),
"ERR67 - Expected ',' before next parameter of special function"));
"ERR72 - Expected ',' before next parameter of special function"));
return p.error_node();
}
}
@ -12110,7 +12195,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_token,
current_token_,
"ERR68 - Invalid special function[1]: " + current_token_.value));
"ERR73 - Invalid special function[1]: " + current_token_.value));
return error_node();
}
@ -12121,7 +12206,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_token,
current_token_,
"ERR69 - Invalid special function[2]: " + current_token_.value));
"ERR74 - Invalid special function[2]: " + current_token_.value));
return error_node();
}
@ -12200,7 +12285,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR70 - Invalid number of parameters for function: " + symbol));
"ERR75 - Invalid number of parameters for function: " + symbol));
return error_node();
}
}
@ -12212,7 +12297,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR71 - Failed to generate node for function: '" + symbol + "'"));
"ERR76 - Failed to generate node for function: '" + symbol + "'"));
return error_node();
}
}
@ -12232,7 +12317,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR72 - Failed to generate node for vararg function: '" + symbol + "'"));
"ERR77 - Failed to generate node for vararg function: '" + symbol + "'"));
return error_node();
}
}
@ -12276,7 +12361,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR73 - Failed to create variable: '" + symbol + "'"));
"ERR78 - Failed to create variable: '" + symbol + "'"));
return error_node();
}
@ -12285,7 +12370,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR74 - Undefined variable or function: '" + symbol + "'"));
"ERR79 - Undefined variable or function: '" + symbol + "'"));
return error_node();
}
@ -12338,13 +12423,15 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR75 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
"ERR80 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
return error_node();
}
}
inline expression_node_ptr parse_branch(precedence_level precedence = e_level00)
{
expression_node_ptr branch = error_node();
if (token_t::e_number == current_token_.type)
{
T numeric_value = T(0);
@ -12353,100 +12440,89 @@ namespace exprtk
{
expression_node_ptr literal_exp = expression_generator_(numeric_value);
next_token();
return literal_exp;
branch = literal_exp;
}
else
{
set_error(
make_error(parser_error::e_numeric,
current_token_,
"ERR76 - Failed to convert '" + current_token_.value + "' to a number."));
"ERR81 - Failed to convert '" + current_token_.value + "' to a number."));
return error_node();
}
}
else if (token_t::e_symbol == current_token_.type)
{
return parse_symbol();
branch = parse_symbol();
}
#ifndef exprtk_disable_string_capabilities
else if (token_t::e_string == current_token_.type)
{
return parse_const_string();
branch = parse_const_string();
}
#endif
else if (token_t::e_lbracket == current_token_.type)
{
next_token();
expression_node_ptr branch = parse_expression();
if (0 == branch)
if (0 == (branch = parse_expression()))
return error_node();
else if (token_is(token_t::e_rbracket))
return branch;
else
else if (!token_is(token_t::e_rbracket))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR77 - Expected ')' instead of: '" + current_token_.value + "'"));
"ERR82 - Expected ')' instead of: '" + current_token_.value + "'"));
return error_node();
}
}
else if (token_t::e_lsqrbracket == current_token_.type)
{
next_token();
expression_node_ptr branch = parse_expression();
if (0 == branch)
if (0 == (branch = parse_expression()))
return error_node();
else if (token_is(token_t::e_rsqrbracket))
return branch;
else
else if (!token_is(token_t::e_rsqrbracket))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR78 - Expected ']' instead of: '" + current_token_.value + "'"));
"ERR83 - Expected ']' instead of: '" + current_token_.value + "'"));
return error_node();
}
}
else if (token_t::e_lcrlbracket == current_token_.type)
{
next_token();
expression_node_ptr branch = parse_expression();
if (0 == branch)
if (0 == (branch = parse_expression()))
return error_node();
else if (token_is(token_t::e_rcrlbracket))
return branch;
else
else if (!token_is(token_t::e_rcrlbracket))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR79 - Expected '}' instead of: '" + current_token_.value + "'"));
"ERR84 - Expected '}' instead of: '" + current_token_.value + "'"));
return error_node();
}
}
else if (token_t::e_sub == current_token_.type)
{
next_token();
return expression_generator_(details::e_neg,
// Was the previous operation exponentiation?
(e_level12 == precedence) ?
parse_branch (e_level09) :
parse_expression(e_level09));
branch = expression_generator_(details::e_neg,
// Was the previous operation exponentiation?
(e_level12 == precedence) ?
parse_branch (e_level09) :
parse_expression(e_level09));
}
else if (token_t::e_add == current_token_.type)
{
next_token();
return parse_expression(e_level13);
branch = parse_expression(e_level13);
}
else if (token_t::e_eof == current_token_.type)
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR80 - Premature end of expression[1]"));
"ERR85 - Premature end of expression[1]"));
return error_node();
}
else
@ -12454,9 +12530,20 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR81 - Premature end of expression[2]"));
"ERR86 - Premature end of expression[2]"));
return error_node();
}
if (
branch &&
(e_level00 == precedence) &&
token_is(token_t::e_ternary,false)
)
{
branch = parse_ternary_conditional_statement(branch);
}
return branch;
}
inline bool token_is(const typename token_t::token_type& ttype, const bool advance_token = true)

View File

@ -1006,7 +1006,29 @@ static const test_t test_list[] =
test_t("repeat 1.1234; 1 < 2; (1.1 + 2.2) until (1 < 2)",3.3),
test_t("repeat 1.1234; 1 < 2; 1.1 + 2.2; until (1 < 2)",3.3),
test_t("repeat 1.1234; 1 < 2; (1.1 + 2.2); until (1 < 2)",3.3),
test_t("[*] { case 1 < 2 : 1 / 2; case (1 < 3) : 2 / 2; case 1 < 4 : 3 / 2; case (1 < 5) : 4 / 2; }",2.0)
test_t("[*] { case 1 < 2 : 1 / 2; case (1 < 3) : 2 / 2; case 1 < 4 : 3 / 2; case (1 < 5) : 4 / 2; }",2.0),
test_t(" 0 ? 1 : 2",2.0),
test_t(" 1 ? 3 : 4",3.0),
test_t("(0 ? 1 : 2) == 2",1.0),
test_t("(1 ? 3 : 4) == 3",1.0),
test_t("[(0)] ? [(1)] : [(2)]",2.0),
test_t("([(0)] ? [(1)] : [(2)]) == 2",1.0),
test_t("([(1)] ? [(3)] : [(4)]) == 3",1.0),
test_t("(1 < 2 ? 3 : 4) == 3",1.0),
test_t("(1 > 2 ? 3 : 4) == 4",1.0),
test_t("(1 < 2 ? 3 + 5 : 4) == 8",1.0),
test_t("(1 > 2 ? 3 : 4 + 5) == 9",1.0),
test_t("(2 < 3 + 3 ? 7 : 9) == 7",1.0),
test_t("(1 + 1 < 3 ? 7 : 9) == 7",1.0),
test_t("(1 + 1 < 3 + 3 ? 7 : 9) == 7",1.0),
test_t("(2 > 3 + 3 ? 7 : 9) == 9",1.0),
test_t("(1 + 1 > 3 ? 7 : 9) == 9",1.0),
test_t("(1 + 1 > 3 + 3 ? 7 : 9) == 9",1.0),
test_t("(2 < (3 + 3) ? 7 : 9) == 7",1.0),
test_t("((1 + 1) < 3 ? 7 : 9) == 7",1.0),
test_t("((1 + 1) < (3 + 3) ? 7 : 9) == 7",1.0),
test_t("(min(1,2) ? 1 + 3 : 1 + 4) == 4",1.0),
test_t("(min(0,1) ? 1 + 3 : 1 + 4) == 5",1.0)
};
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_t);
@ -1109,13 +1131,17 @@ inline bool run_test00()
const std::size_t rounds = 10;
for (std::size_t r = 0; r < rounds; ++r)
{
bool result = true;
for (std::size_t i = 0; i < test_list_size; ++i)
{
if (!test_expression<T>(test_list[i].first,T(test_list[i].second)))
{
return false;
result = false;
}
}
if (!result)
return false;
}
return true;
@ -1442,7 +1468,23 @@ inline bool run_test01()
test_xy<T>("switch { case {(x <= y)} : switch { case ({x <= y}) : x; default: 1.12345; }; default: 1.12345; }",T(1.0),T(2.0),T(1.0)),
test_xy<T>("[*]{ case x < y : x + y; case y < x : y - x; }",T(2.0),T(3.0),T(5.0)),
test_xy<T>("[*]{ case x > y : x + y; case y > x : y - x; }",T(2.0),T(3.0),T(1.0)),
test_xy<T>("[*]{ case x > y : x - y; case y < x : y + x; }",T(2.0),T(3.0),T(0.0))
test_xy<T>("[*]{ case x > y : x - y; case y < x : y + x; }",T(2.0),T(3.0),T(0.0)),
test_xy<T>("0 ? x : y" ,T(1.0),T(2.0),T( 2.0)),
test_xy<T>("1 ? x : y" ,T(1.0),T(2.0),T( 1.0)),
test_xy<T>("x ? x : y" ,T(1.0),T(2.0),T( 1.0)),
test_xy<T>("x ? x : y" ,T(0.0),T(2.0),T( 2.0)),
test_xy<T>("(x + y < 4) ? 1 : 2" ,T(1.0),T(2.0),T( 1.0)),
test_xy<T>("(x + y > 4) ? 1 : 2" ,T(1.0),T(2.0),T( 2.0)),
test_xy<T>("x < y ? x + y : x - y" ,T(1.0),T(2.0),T( 3.0)),
test_xy<T>("x > y ? x + y : x - y" ,T(1.0),T(2.0),T(-1.0)),
test_xy<T>("(x + x < y ? 7 : 9) == 7" ,T(1.0),T(3.0),T( 1.0)),
test_xy<T>("(x + x < y + y ? 7 : 9) == 7" ,T(1.0),T(3.0),T( 1.0)),
test_xy<T>("(x > y + y ? 7 : 9) == 9" ,T(1.0),T(3.0),T( 1.0)),
test_xy<T>("(x + x > y ? 7 : 9) == 9" ,T(1.0),T(3.0),T( 1.0)),
test_xy<T>("(x + x > y + 3 ? 7 : 9) == 9" ,T(1.0),T(3.0),T( 1.0)),
test_xy<T>("(x < (y + y) ? 7 : 9) == 7" ,T(1.0),T(3.0),T( 1.0)),
test_xy<T>("((x + x) < y ? 7 : 9) == 7" ,T(1.0),T(3.0),T( 1.0)),
test_xy<T>("((x + x) < (y + y) ? 7 : 9) == 7",T(1.0),T(3.0),T( 1.0)),
};
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy<T>);
@ -2391,6 +2433,13 @@ inline bool run_test08()
"equal($f96(x,y,z,w),if(x > y,z,w))",
"equal($f97(x,y,z,w),if(x >= y,z,w))",
"equal($f98(x,y,z,w),if(equal(x,y),z,w))",
"equal($f92(x,y,z,w),x and y ? z : w)",
"equal($f93(x,y,z,w),x or y ? z : w)",
"equal($f94(x,y,z,w),x < y ? z : w)",
"equal($f95(x,y,z,w),x <= y ? z : w)",
"equal($f96(x,y,z,w),x > y ? z : w)",
"equal($f97(x,y,z,w),x >= y ? z : w)",
"equal($f98(x,y,z,w),equal(x,y) ? z : w)",
"equal($f99(x,y,z,w),x*sin(y)+z*cos(w))"
};
static const std::size_t expr_str_size = sizeof(expr_str) / sizeof(std::string);

View File

@ -32,7 +32,8 @@ arithmetic operations, functions and processes:
(5) Conditional,
Switch &
Loop statements: if-then-else, switch-case, while, repeat-until
Loop statements: if-then-else, ternary conditional, switch-case,
while, repeat-until
(6) Assignment: :=
@ -64,7 +65,7 @@ expressions that can be parsed and evaluated using the ExprTk library.
(13) (x + y)z + 1.1 / 2.7 == (x + y) * z + 1.1 / 2.7
(14) (sin(x / pi) cos(2y) + 1) == (sin(x / pi) * cos(2 * y) + 1)
(15) 75x^17 + 25.1x^5 - 35x^4 - 15.2x^3 + 40x^2 - 15.3x + 1
(16) if (avg(x,y) <= x + y, x - y, x * y) + 2.345 * pi / x
(16) (avg(x,y) <= x + y ? x - y : x * y) + 2.345 * pi / x
(17) fib_i := fib_i + (x := y + 0 * (fib_i := x + (y := fib_i)))
(18) while (x <= 100) { x := x + 1 }
(19) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z)
@ -406,6 +407,13 @@ include path (e.g: /usr/include/).
| | w := z + y; |
| | until ((x := (x - 1)) <= 0) |
+----------+---------------------------------------------------------+
| ?: | Ternary conditional statement, similar to that of the |
| | above denoted if-statement. |
| | eg: |
| | 0. x ? y : z |
| | 1. x + 1 > 2y ? z + 1 : (w / v) |
| | 2. min(x,y) > z ? (x < y + 1) ? x : y : (w * v) |
+----------+---------------------------------------------------------+
| ~ | Evaluate each sub-expression, then return as the result |
| | the value of the last sub-expression. This is sometimes |
| | known as multiple sequence point evaluation. |
@ -459,6 +467,46 @@ types a symbol table can handle:
(e) Functions
(f) Vararg functions
During the compilation process if an expression is found to require
any of the elements noted above, the expression's associated
symbol_table will be queried for the element and if present a
reference to the element will be embedded within the expression's AST.
This allows for the original element to be modified independently of
the expression instance and to also allow the expression to be
evaluated using the current value of the element.
The example below demonstrates the relationship between variables,
symbol_table and expression. Note the variables are modified as they
normally would in a program, and when the expression is evaluated the
current values assigned to the variables will be used.
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
symbol_table_t symbol_table;
expression_t expression;
parser_t parser;
double x = 0;
double y = 0;
std::string expression_string = "x * y + 3";
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);
expression.register_symbol_table(symbol_table);
parser.compile(expression_string,expression);
x = 1.0;
y = 2.0;
parser.value(); // 1 * 2 + 3
x = 3.7;
parser.value(); // 3.7 * 2 + 3
y = -9.0;
parser.value(); // 3.7 * -9 + 3
(2) Expression
A structure that holds an AST for a specified expression and is used
@ -474,21 +522,21 @@ Expression: z := (x + y^-2.345) * sin(pi / min(w - 7.3,v))
[Assignment]
________/ \_____
/ \
Variable(z) [Multiply]
Variable(z) [Multiplication]
____________/ \___________
/ \
/ [Unary-Func(sin)]
[Addition] |
____/ \____ [Division]
/ \ ___/ \___
Variable(x) [Power] / \
Variable(x) [Exponentiation] / \
______/ \______ Constant(pi) [Binary-Func(min)]
/ \ ____/ \____
Variable(y) [Negate] / \
Variable(y) [Negation] / \
| / Variable(v)
Constant(2.345) /
/
[Subtract]
[Subtraction]
____/ \____
/ \
Variable(w) Constant(7.3)
@ -809,7 +857,8 @@ int main()
typedef exprtk::parser<double> parser_t;
typedef exprtk::parser_error::type error_t;
std::string expression_str = "z := 2 myfunc([4+sin(x/pi)^3],y^2)";
std::string expression_str =
"z := 2 myfunc([4 + sin(x / pi)^3],y ^ 2)";
double x = 1.1;
double y = 2.2;