diff --git a/exprtk.hpp b/exprtk.hpp index 43dc96f..bcb4ebc 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -18792,20 +18792,42 @@ namespace exprtk e_usr_constant_type = 1 }; + enum usr_mode + { + e_usrmode_default = 0, + e_usrmode_extended = 1 + }; + + usr_mode mode; + + unknown_symbol_resolver(const usr_mode m = e_usrmode_default) + : mode(m) + {} + virtual ~unknown_symbol_resolver() {} virtual bool process(const std::string& /*unknown_symbol*/, - usr_symbol_type& st, - T& default_value, - std::string& error_message) + usr_symbol_type& st, + T& default_value, + std::string& error_message) { + if (e_usrmode_default != mode) + return false; + st = e_usr_variable_type; default_value = T(0); error_message.clear(); return true; } + + virtual bool process(const std::string& /* unknown_symbol */, + symbol_table_t& /* symbol_table */, + std::string& /* error_message */) + { + return false; + } }; enum collect_type @@ -19948,6 +19970,11 @@ namespace exprtk unknown_symbol_resolver_ = &default_usr_; } + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) + { + enable_unknown_symbol_resolver(&usr); + } + inline void disable_unknown_symbol_resolver() { resolve_unknown_symbol_ = false; @@ -24539,63 +24566,93 @@ namespace exprtk { if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) { - T default_value = T(0); + symbol_table_t& symtab = symtab_store_.get_symbol_table(); std::string error_message; - typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type; - if (unknown_symbol_resolver_->process(symbol,usr_symbol_type,default_value,error_message)) + if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) { - bool create_result = false; + T default_value = T(0); + typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type; - symbol_table_t& symtab = symtab_store_.get_symbol_table(); - - switch (usr_symbol_type) + if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) { - case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol,default_value); - break; + bool create_result = false; - case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol,default_value); - break; - - default : create_result = false; - } - - if (create_result) - { - expression_node_ptr var = symtab_store_.get_variable(symbol); - - if (var) + switch (usr_symbol_type) { - if (symtab_store_.is_constant_node(symbol)) + case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); + break; + + case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); + break; + + default : create_result = false; + } + + if (create_result) + { + expression_node_ptr var = symtab_store_.get_variable(symbol); + + if (var) { - var = expression_generator_(var->value()); + if (symtab_store_.is_constant_node(symbol)) + { + var = expression_generator_(var->value()); + } + + lodge_symbol(symbol,e_st_variable); + + if (!post_variable_process(symbol)) + return error_node(); + + next_token(); + + return var; } - - lodge_symbol(symbol,e_st_variable); - - if (!post_variable_process(symbol)) - return error_node(); - - next_token(); - - return var; } } set_error( make_error(parser_error::e_symtab, current_token(), - "ERR183 - Failed to create variable: '" + symbol + "'")); + "ERR183 - Failed to create variable: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message))); - return error_node(); } + else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) + { + if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) + { + static bool usr_extmode_active = false; + + if (!usr_extmode_active) + { + usr_extmode_active = true; + expression_node_ptr result = parse_symtab_symbol(); + usr_extmode_active = false; + + if (result) + { + return result; + } + } + } + + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR184 - Failed to resolve symbol: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message))); + } + + return error_node(); } } set_error( make_error(parser_error::e_syntax, current_token(), - "ERR184 - Undefined symbol: '" + symbol + "'")); + "ERR185 - Undefined symbol: '" + symbol + "'")); return error_node(); } @@ -24701,7 +24758,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR185 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value)); + "ERR186 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value)); return error_node(); } @@ -24726,7 +24783,7 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token(), - "ERR186 - Failed to convert '" + current_token().value + "' to a number")); + "ERR187 - Failed to convert '" + current_token().value + "' to a number")); return error_node(); } @@ -24752,7 +24809,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR187 - Expected ')' instead of: '" + current_token().value + "'")); + "ERR188 - Expected ')' instead of: '" + current_token().value + "'")); free_node(node_allocator_,branch); @@ -24776,7 +24833,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR188 - Expected ']' instead of: '" + current_token().value + "'")); + "ERR189 - Expected ']' instead of: '" + current_token().value + "'")); free_node(node_allocator_,branch); @@ -24800,7 +24857,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR189 - Expected '}' instead of: '" + current_token().value + "'")); + "ERR190 - Expected '}' instead of: '" + current_token().value + "'")); free_node(node_allocator_,branch); @@ -24839,7 +24896,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR190 - Premature end of expression[1]")); + "ERR191 - Premature end of expression[1]")); return error_node(); } @@ -24848,7 +24905,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR191 - Premature end of expression[2]")); + "ERR192 - Premature end of expression[2]")); return error_node(); } diff --git a/readme.txt b/readme.txt index 210418f..4a89a52 100644 --- a/readme.txt +++ b/readme.txt @@ -2841,7 +2841,7 @@ simple user defined USR: T& default_value, std::string& error_message) { - if (0 != unknown_symbol.find('var_')) + if (0 != unknown_symbol.find("var_")) { error_message = "Invalid symbol: " + unknown_symbol; return false; @@ -2884,6 +2884,77 @@ USR's process method will be invoked. The USR in the example will only variables, all other unknown symbols will result in a compilation error being raised. +In the example above the callback of the USR that is invoked during +the unknown symbol resolution process only allows for scalar variables +to be defined and resolved - as that is the simplest and most common +form. + +There is also an extended version of the callback that can be +overridden that will allow for more control and choice over the type +of symbol being resolved. The following is an example definition of +said extended callback: + + template + struct my_usr : public parser_t::unknown_symbol_resolver + { + typedef typename parser_t::unknown_symbol_resolver usr_t; + + my_usr() + : usr_t(usr_t::e_usrmode_extended) + {} + + virtual bool process(const std::string& unknown_symbol, + symbol_table_t& symbol_table, + std::string& error_message) + { + bool result = false; + + if (0 == unknown_symbol.find("var_")) + { + // Default value of zero + result = symbol_table.create_variable(unknown_symbol,0); + + if (!result) + { + error_message = "Failed to create variable..."; + } + } + else if (0 == unknown_symbol.find("str_")) + { + // Default value of empty string + result = symbol_table.create_stringvar(unknown_symbol,""); + + if (!result) + { + error_message = "Failed to create string variable..."; + } + } + else + error_message = "Indeterminable symbol type."; + + return result; + } + }; + + +In the example above, the USR callback when invoked will pass the +primary symbol table associated with the expression being parsed. The +symbol resolution business logic can then determine under what +conditions a symbol will be resolved including its type (scalar, +string, vector etc) and default value. When the callback successfully +returns the symbol parsing and resolution process will again be +executed by the parser. The idea here is that given the primary symbol +table will now have the previously detected unknown symbol registered, +it will be correctly resolved and the general parsing processing can +then resume as per normal. + +Note: In order to have the USR's extended mode callback be invoked It +is necessary to pass the e_usrmode_extended enum value during the +constructor of the user defined USR. + +Note: The primary symbol table for an expression is the first symbol +table to be registered with that instance of the expression. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 19 - ENABLING & DISABLING FEATURES] @@ -4658,4 +4729,4 @@ ExprTk and their structural representations. | | | | | +--<--- [,] <-----+ | | | -+-------------------------------------------------------------+ \ No newline at end of file ++-------------------------------------------------------------+