7  Usage

Data Types

The following data types and constants are used throughout TinyExpr++:

te_parser: The main class for defining an evaluation engine and solving expressions.

te_type: The data type for variables, function parameters, and results. By default this is double, but can be float (when TE_FLOAT is defined) or long double (when TE_LONG_DOUBLE is defined).

If long double is in use, then various bitwise functions (BITNOT(), BITRROTATE()) may be able to support 64-bit integers. This will depend on the compiler used to build the library and can be verified by calling te_parser::supports_64bit() in your code or SUPPORTS64BIT() in an expression at runtime.

te_variable: A user-defined variable or function that can be embedded into a te_parser. (Refer to custom variables.)

te_expr: The base class for a compiled expression. Classes that derive from this can be bound to custom functions. In turn, this allows for connecting more complex, class-based objects to the parser. (Refer to custom classes.)

te_parser::te_nan: An invalid numeric value. This should be returned from user-defined functions to signal a failed calculation.

te_parser::npos: An invalid position. This is returned from te_parser::get_last_error_position() when no error occurred.

te_usr_noop: A no-op function. When passed to te_parser::set_unknown_symbol_resolver(), will disable unknown symbol resolution. (Refer to ch. 9.)

Functions

The primary interface to TinyExpr++ is the class te_parser. A te_parser is a self-contained parser, which stores its own user-defined variables & functions, separators, and state information.

te_parser provides these functions:

1te_type evaluate(const std::string_view expression);
2te_type get_result();
bool success();
int64_t get_last_error_position();
std::string get_last_error_message();
3set_variables_and_functions(const std::set<te_variable>& vars);
std::set<te_variable>& get_variables_and_functions();
add_variable_or_function(const te_variable& var);
4set_unknown_symbol_resolver(te_usr_variant_type usr);
5get_decimal_separator();
set_decimal_separator();
get_list_separator();
set_list_separator();
1
evaluate() takes an expression and immediately returns the result. If there is a parse error, then it returns NaN (which can be verified by using std::isnan()). (success() will also return false.)
2
get_result() can be called anytime afterwards to retrieve the result from evaluate().
3
set_variables_and_functions(), get_variables_and_functions(), and add_variable_or_function() are used to add custom variables and functions to the parser.
4
set_unknown_symbol_resolver() is used to provide a custom function to resolve unknown symbols in an expression. (Refer to ch. 9 for further details.)
5
get_decimal_separator()/set_decimal_separator() and get_list_separator()/set_list_separator() can be used to parse non-US formatted formulas.

Example:

te_parser tep;

// Returns 10, error position is set to te_parser::npos (i.e., no error).
auto result = tep.evaluate("(5+5)");
// Returns NaN, error position is set to 3.
auto result2 = tep.evaluate("(5+5");

You can also provide set_variables_and_functions() a list of constants, bound variables, and function pointers/lambdas. evaluate() will then evaluate expressions using these variables and functions.

Error Handling

TinyExpr++ will throw exceptions when:

  • An illegal character is specified in a custom function or variable name.
  • An illegal character is provided as a list or decimal separator.
  • The same character is provided as both the list and decimal separator.

It is recommended to wrap the following functions in try/catch blocks to handle these exceptions:

  • compile()
  • evaluate()
  • set_variables_and_functions()
  • add_variable_or_function()
  • set_decimal_separator()
  • set_list_separator()

Syntax and calculation errors are trapped within calls to compile() and evaluate(). Error information can be retrieved afterwards by calling the following:

  • success(): returns whether the last parse was successful or not.
  • get_last_error_position(): returns the 0-based index of where in the expression the parse failed (useful for syntax errors). If there was no parse error, then this will return te_parser::npos.
  • get_last_error_message(): returns a more detailed message for some calculation errors (e.g., division by zero).

Example:

#include "tinyexpr.h"
#include <iostream>

te_type x{ 0 }, y{ 0 };
// Store variable names and pointers.
te_parser tep;
tep.set_variables_and_functions({{"x", &x}, {"y", &y}});

// Compile the expression with variables.
auto result = tep.evaluate("sqrt(x^2+y^2)");

if (tep.success())
    {
    x = 3; y = 4;
    // Will use the previously used expression, returns 5.
    const auto h1 = tep.evaluate();

    x = 5; y = 12;
    // Returns 13.
    const auto h2 = tep.evaluate();
    }
else
    {
    std::cout << "Parse error at " <<
        std::to_string(tep.get_last_error_position()) << "\n";
    }

Along with positional and message information, the return value of a parse can also indicate failure. When an evaluation fails, the parser will return NaN (i.e., std::numeric_limits<te_type>::quiet_NaN()) as the result. NaN values can be verified using the standard function std::isnan().

Example

The following is a short example demonstrating how to use TinyExpr++.

#include "tinyexpr.h"
#include <iostream>

int main(int argc, char *argv[])
    {
    te_parser tep;
    const char* expression = "sqrt(5^2+7^2+11^2+(8-2)^2)";
    const auto res = tep.evaluate(expression);
    std::cout << "The expression:\n\t" <<
        expression << "\nevaluates to:\n\t" << res << "\n";
    return EXIT_SUCCESS;
    }