** 🇨🇳 中文文档 **
A powerful, header-only C++ library for parsing and evaluating mathematical expressions
![]()
• Header-only – Zero compilation overhead, easy integration
• Type Flexible – Works with any numeric type (double, float, int, etc.)
• Character Support – Full support for narrow (char) and wide (wchar_t) strings
• Variable Management – Register variables with const/mutable semantics
• Operator Control – Define custom operators with precedence and associativity
• Function Library – Extensive built-in mathematical functions
• Expression Parsing – Three parsing modes: Immediate, Persistent, Normal
• Constant Folding – Automatically optimizes constant subexpressions
• Custom Functions – Define new functions using expression strings
• Smart Memory – RAII-compliant with shared_ptr/weak_ptr support
• C++11 or later
• Standard Template Library (STL)
• No external dependencies
- Download
eval.hppandtable.hpp - Place them in your project's include directory
- Include
eval.hppin your source files - Compile with C++11 support enabled
#include "eval.hpp" #include "eval.hpp"
#include <iostream>
int main()
{
using Evaluator = cxx_eval::basic_eval<char, double>::Evaluator;
using Simple = cxx_eval::basic_eval<char, double>::simple;
Evaluator eval;
Simple::setup_allmath(eval);
Simple::register_vars(eval, "x", 10.0);
auto expr = eval.parse<false>("2 * x + 3.14");
double result = expr.evaluate();
std::cout << "Result: " << result << std::endl; // 23.14
return 0;
} Simple::register_vars(eval, "a", 5.0, "b", 3.0, "c", 2.0);
auto expr = eval.parse<false>("a * b + c");
std::cout << expr.evaluate() << std::endl; // 17.0
auto var_node = eval.get_variables()->find_seq("a");
var_node->get_data()->data = 10.0;
std::cout << expr.evaluate() << std::endl; // 32.0 See below for full documentation, API reference, and advanced examples.
The library uses a postfix (RPN) representation internally:
• c – Constant value
• v – Variable reference
• f – Function/operator application
• Immediate – All values become constants (optimization)
• Persistent – All values remain variables (uses weak_ptr)
• Normal – Respects const/mutable declarations
Higher precedence numbers bind tighter. Default precedences:
• Assignment (=) – 0
• Addition/Subtraction (+, -) – 1
• Multiplication/Division (*, /, %) – 2
• Exponentiation (^) – 3
• Unary operators – 2
• Functions – size_max (highest)
cxx_eval::basic_eval<char, double>::Evaluator eval;
eval.set_skip([](char c) { return c == ' '; });
eval.enable_whitespace_skip(true);
eval.set_left_delimiter('(');
eval.set_right_delimiter(')');
eval.set_cut_delimiter(',');
evaluator.enable_brackets(true);
evaluator.enable_cut(true);Simple::register_vars(eval, "var1", 1.0, "var2", 2.0);
Simple::register_consts(eval, "PI", 3.14159);
auto vars = eval.get_variables();
auto node = vars->find_seq("var1");
if (node && node->has_data())
{
double value = node->get_data()->data;
} Simple::register_infix(eval, "**", [](std::shared_ptr<RootVar>* args)
{
ConstVar result;
result.data = std::pow(args[0]->data, args[1]->data);
return std::make_shared<ConstVar>(result);
}, 3);
Simple::register_prefix(eval, "
", [](std::shared_ptr<RootVar>* args)
{
ConstVar result;
result.data = -args[0]->data;
return std::make_shared<ConstVar>(result);
}, 2);
Simple::register_function(eval, "max", [](std::shared_ptr<RootVar>* args)
{
ConstVar result;
result.data = std::max(args[0]->data, args[1]->data);
return std::make_shared<ConstVar>(result);
}, 2); Simple::register_function<false>(eval, "f", std::vector<std::string>{"x", "y"}, "x^2 + y^2");
auto expr = eval.parse<false>("f(3,4)");
std::cout << expr.evaluate() << std::endl; // 25.0 auto expr = eval.parse<false>("2 + 2");
double result = expr.evaluate();
auto persistent = eval.parse<true>("x + y"); Simple::register_consts(eval, "e", 2.718281828459045);
Simple::register_consts(eval, "phi", 1.618033988749895); Simple::register_function<false>(eval, "quadratic", std::vector<std::string>{"a", "b", "c"}, "(-b + sqrt(b^2 - 4*a*c)) / (2*a)");
auto expr = eval.parse<false>("quadratic(1, -5, 6)");
std::cout << expr.evaluate() << std::endl; // 3.0 Simple::setup_assignment(eval);
auto expr = eval.parse<false>("x = 42");
expr.evaluate();
auto check = eval.parse<false>("x");
std::cout << check.evaluate() << std::endl; // 42 using WEvaluator = cxx_eval::basic_eval<wchar_t, double>::Evaluator;
using WSimple = cxx_eval::basic_eval<wchar_t, double>::simple;
WEvaluator weval;
WSimple::setup_allmath(weval);
WSimple::register_vars(weval, L"变量", 3.14);
auto wexpr = weval.parse<false>(L"变量 * 2");
std::wcout << wexpr.evaluate() << std::endl; eval.set_skip([](char c)
{
return !std::isalnum(c) && c != '+' && c != '-' && c != '*' && c != '/' && c != '^' && c != '(' && c != ')';
});
eval.enable_whitespace_skip(true); struct Complex
{
double real, imag;
Complex operator+(const Complex& other) const
{
return {real + other.real, imag + other.imag};
}
};
using ComplexEval = cxx_eval::basic_eval<char, Complex>::Evaluator;
using ComplexSimple = cxx_eval::basic_eval<char, Complex>::simple; eval.set_constant_parser([](const std::string& str, std::size_t& pos, std::string& structure, std::vector<cxx_eval::basic_eval<char, double>::ConstVar>& constants) -> bool
{
if (str.substr(pos, 2) == "0x")
{
// Parse hexadecimal logic
return true;
}
return false;
}); The library throws std::runtime_error for:
• Syntax errors
• Undefined variables
• Mismatched parentheses
• Stack underflow/overflow
• Expired weak_ptr access
try
{
auto result = expr.evaluate();
}
catch (const std::runtime_error& e)
{
std::cerr << "Evaluation error: " << e.what() << std::endl;
} Contributions welcome! Submit pull requests or open issues for bugs and feature requests.