Math Evaluator — C++ source
Evaluate math expressions - arithmetic, functions (sqrt, sin, log), comparisons, and constants (pi, e) - safely, in real time. Input is constrained to math-safe characters, fully client-side.
This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.
// math-evaluator — C++ port: safe arithmetic expression evaluator (no eval).
// Guards with the TS lib's patterns verbatim (std::regex, ECMAScript grammar),
// then runs the Go twin's recursive-descent grammar: comparison < > → + - →
// * / % → ^ (right-assoc) → unary - → postfix ! → primary (number, parens,
// pi/e, 1-arg calls). Unsafe or invalid input yields nullptr, never throws.
#include <cctype>
#include <cmath>
#include <cstdio>
#include <map>
#include <regex>
#include <string>
using std::string;
// COPIED VERBATIM from src/lib/math-evaluator.ts — the code-injection guard.
const std::regex SAFE{R"(^[0-9+\-*/().,\s a-zA-Z%^!<>]+$)"}, FORBIDDEN{
R"(\b(import|require|eval|function|while|for|process|global|this|window|document|constructor)\b)"};
const size_t MAX_LEN = 200;
const std::map<string, double (*)(double)> FN{
{"sqrt", sqrt}, {"sin", sin}, {"cos", cos}, {"tan", tan},
{"log", log}, {"abs", fabs}, {"exp", exp}};
struct Parser {
string s;
size_t i = 0;
bool err = false, is_bool = false;
int peek() { while (s[i] == ' ' || s[i] == '\t') i++; return s[i]; }
bool eat(char c) { if (peek() == c && c) { i++; return true; } return false; }
double factorial(double n) {
if (n < 0 || n != floor(n)) { err = true; return 0; }
double r = 1;
for (int k = 2; k <= n; k++) r *= k;
return r;
}
double primary() {
int c = peek();
if (c == '(') { i++; double v = cmp(); err |= !eat(')'); return v; }
if (isdigit(c) || c == '.') {
size_t n = 0;
double v = 0;
try { v = std::stod(s.substr(i), &n); } catch (...) { err = true; return 0; }
i += n;
return v;
}
if (isalpha(c)) {
string name;
while (isalpha((unsigned char)s[i])) name += tolower(s[i++]);
auto fn = FN.find(name);
if (fn != FN.end()) { // one-arg call, e.g. sqrt(2)
if (!eat('(')) { err = true; return 0; }
double v = cmp();
err |= !eat(')');
return fn->second(v);
}
if (name == "pi") return M_PI;
if (name == "e") return M_E;
}
err = true; // bare function reference or unknown symbol → rejected
return 0;
}
double post() { double v = primary(); while (eat('!')) v = factorial(v); return v; }
double unary() { if (eat('-')) return -unary(); if (eat('+')) return unary(); return post(); }
double powr() { double l = unary(); if (eat('^')) return std::pow(l, powr()); return l; }
double mul() {
double v = powr();
while (eat('*') || eat('/') || eat('%')) {
char op = s[i - 1];
double r = powr();
v = op == '*' ? v * r : op == '/' ? v / r : std::fmod(v, r);
}
return v;
}
double add() {
double v = mul();
while (eat('+') || eat('-')) v = s[i - 1] == '+' ? v + mul() : v - mul();
return v;
}
double cmp() { // lowest precedence; parens recurse back here
double v = add();
while (eat('<') || eat('>')) {
bool lt = s[i - 1] == '<';
double r = add();
v = lt ? v < r : v > r;
is_bool = true;
}
return v;
}
};
// Mirrors evaluateExpression in src/lib/math-evaluator.ts: formatted result,
// or nullptr for empty/over-long/unsafe input or any parse failure.
const char *evaluate(const char *expr) {
static char out[32];
string t = expr;
size_t b = t.find_first_not_of(" \t\r\n");
if (b == string::npos) return nullptr;
t = t.substr(b, t.find_last_not_of(" \t\r\n") - b + 1);
if (t.empty() || t.size() > MAX_LEN || !std::regex_match(t, SAFE) ||
std::regex_search(t, FORBIDDEN))
return nullptr;
Parser p{t};
double v = p.cmp();
p.peek();
if (p.err || p.i < t.size()) return nullptr; // parse error or leftover tokens
if (p.is_bool) return v ? "true" : "false";
snprintf(out, sizeof out, "%g", v);
return out;
}
int main() {
for (const char *c : {"1 + 2 * 3", "2^10", "5! + sqrt(16)", "sin(pi)", "3 > 2", "sqrt"}) {
const char *r = evaluate(c);
printf("%-14s = %s\n", c, r ? r : "(rejected)");
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →