ExprTK unknown variable resolution depending on expression type

I am trying to create a parser for boolean expressions. The characters within the expression are read from an XML-like data structure.

It's easier to implement a parser for something like

a.b == 'some value'

      

with ExprTK with an "unknown character recognizer" which resolves ab as a string, returning a string value <a><b>some value</b></a>

.

But now let's look at XML <a><b>5</b></a>

Is there a way to write an unknown character recognition, which allows you to evaluate how a.b == 5

, and a.b == '5'

?

+3


source to share


1 answer


Initially in ExprTk, a variable (user-defined or local expression) can only be of one type (scalar, string, or scalar vector). So if your expression is:

"a.b == 5 and a.b == '5'"

      

Then this is not a valid expression, since the variable ab can only be of one type โ€” either a scalar or a string, but not both.

However, if you want to have two separate expressions that use the same variable name but in different contexts, for example:

  • a.b == 5

  • a.b == '5'

Then Yes, the ExprTk USR ( Unknown Symbol Resolver ) functionality provides one means of detecting an unknown symbol type during a USR callback , which allows the expression to be used to compile correctly.




As an example, suppose we would like to define a USR that will only allow unknown characters prefixed with "var _" and "str _" with types Scalar and String, respectively.

Examples of expressions might look like this:

var_x := 2; var_x + 7

str_y := 'abc';  str_y + '123' == 'abc123'

      

Below is an example of a USR using an extended callback mechanism that will resolve variables in the above format and additionally add them to the primary character table of the parsed expression:

typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::parser<double>             parser_t;

template <typename T>
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;

      //Is this unknown symbol in the format var_xyz ?
      if (0 == unknown_symbol.find("var_"))
      {
         const T default_scalar = T(0);
         result = symbol_table.create_variable(unknown_symbol, default_scalar);
         if (!result)
         {
            error_message =
             "Failed to create variable(" + unknown_symbol + ") in primary symbol table";
         }
      }
      //Is this unknown symbol in the format str_xyz ?
      else if (0 == unknown_symbol.find("str_"))
      {
         const std::string default_string = "N/A";
         result = symbol_table.create_stringvar(unknown_symbol,default_string)
         if (!result)
         {
            error_message =
             "Failed to create string variable(" + unknown_symbol + ") in primary symbol table";
         }
      }
      else
         error_message = "Indeterminable symbol type.";

      return result;
   }
};

      

The rest of the code is the same: one registers the USR instance with the parser, and then proceeds to compile its expression with the specified parser.

For more information see Section 18 - Unknown unknowns

+7


source







All Articles