From 4e76c6e7087b9682e5f07d4dba3d91d6f7e0a966 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Fri, 16 Jan 2015 15:41:07 +0000 Subject: [PATCH] lolremez: shorter code in the expression parser. --- tools/lolremez/expression.h | 157 +++++++++++++----------------------- 1 file changed, 58 insertions(+), 99 deletions(-) diff --git a/tools/lolremez/expression.h b/tools/lolremez/expression.h index f8834914..ba9ad48f 100644 --- a/tools/lolremez/expression.h +++ b/tools/lolremez/expression.h @@ -13,7 +13,12 @@ #pragma once // -// Parser tools for a simple calculator grammar with + - * / +// Powerful arithmetic expression parser/evaluator +// +// Usage: +// expression e; +// e.parse(" 2*x^3 + 3 * sin(x - atan(x))"); +// auto y = e.eval("1.5"); // #include "pegtl.hh" @@ -85,114 +90,68 @@ struct expression */ lol::real eval(lol::real const &x) const { + /* Use a stack */ lol::array stack; - lol::real tmp; for (int i = 0; i < m_ops.Count(); ++i) { - switch (m_ops[i].m1) + /* Rules that do not consume stack elements */ + if (m_ops[i].m1 == op::x) { - case op::plus: - break; - case op::minus: - stack.Push(-stack.Pop()); - break; - case op::abs: - stack.Push(fabs(stack.Pop())); - break; - case op::sqrt: - stack.Push(sqrt(stack.Pop())); - break; - case op::cbrt: - stack.Push(cbrt(stack.Pop())); - break; - case op::exp: - stack.Push(exp(stack.Pop())); - break; - case op::exp2: - stack.Push(exp2(stack.Pop())); - break; - case op::log: - stack.Push(log(stack.Pop())); - break; - case op::log2: - stack.Push(log2(stack.Pop())); - break; - case op::log10: - stack.Push(log10(stack.Pop())); - break; - case op::sin: - stack.Push(sin(stack.Pop())); - break; - case op::cos: - stack.Push(cos(stack.Pop())); - break; - case op::tan: - stack.Push(tan(stack.Pop())); - break; - case op::asin: - stack.Push(asin(stack.Pop())); - break; - case op::acos: - stack.Push(acos(stack.Pop())); - break; - case op::atan: - stack.Push(atan(stack.Pop())); - break; - case op::sinh: - stack.Push(sinh(stack.Pop())); - break; - case op::cosh: - stack.Push(cosh(stack.Pop())); - break; - case op::tanh: - stack.Push(tanh(stack.Pop())); - break; + stack.push(x); + continue; + } + else if (m_ops[i].m1 == op::constant) + { + stack.push(m_constants[m_ops[i].m2]); + continue; + } - case op::add: - tmp = stack.Pop(); - stack.Push(stack.Pop() + tmp); - break; - case op::sub: - tmp = stack.Pop(); - stack.Push(stack.Pop() - tmp); - break; - case op::mul: - tmp = stack.Pop(); - stack.Push(stack.Pop() * tmp); - break; - case op::div: - tmp = stack.Pop(); - stack.Push(stack.Pop() / tmp); - break; - case op::atan2: - tmp = stack.Pop(); - stack.Push(atan2(stack.Pop(), tmp)); - break; - case op::pow: - tmp = stack.Pop(); - stack.Push(pow(stack.Pop(), tmp)); - break; - case op::min: - tmp = stack.Pop(); - stack.Push(min(stack.Pop(), tmp)); - break; - case op::max: - tmp = stack.Pop(); - stack.Push(max(stack.Pop(), tmp)); - break; + /* All other rules consume at least the head of the stack */ + lol::real head = stack.pop(); - case op::x: - stack.Push(x); - break; + switch (m_ops[i].m1) + { + case op::plus: stack.push(head); break; + case op::minus: stack.push(-head); break; + + case op::abs: stack.push(fabs(head)); break; + case op::sqrt: stack.push(sqrt(head)); break; + case op::cbrt: stack.push(cbrt(head)); break; + case op::exp: stack.push(exp(head)); break; + case op::exp2: stack.push(exp2(head)); break; + case op::log: stack.push(log(head)); break; + case op::log2: stack.push(log2(head)); break; + case op::log10: stack.push(log10(head)); break; + case op::sin: stack.push(sin(head)); break; + case op::cos: stack.push(cos(head)); break; + case op::tan: stack.push(tan(head)); break; + case op::asin: stack.push(asin(head)); break; + case op::acos: stack.push(acos(head)); break; + case op::atan: stack.push(atan(head)); break; + case op::sinh: stack.push(sinh(head)); break; + case op::cosh: stack.push(cosh(head)); break; + case op::tanh: stack.push(tanh(head)); break; + + case op::add: stack.push(stack.pop() + head); break; + case op::sub: stack.push(stack.pop() - head); break; + case op::mul: stack.push(stack.pop() * head); break; + case op::div: stack.push(stack.pop() / head); break; + + case op::atan2: stack.push(atan2(stack.pop(), head)); break; + case op::pow: stack.push(pow(stack.pop(), head)); break; + case op::min: stack.push(min(stack.pop(), head)); break; + case op::max: stack.push(max(stack.pop(), head)); break; + case op::x: case op::constant: - stack.Push(m_constants[m_ops[i].m2]); + /* Already handled above */ break; } } - return stack.Pop(); + ASSERT(stack.count() == 1); + return stack.pop(); } private: @@ -205,8 +164,8 @@ private: static void apply(std::string const &ctx, expression *that) { /* FIXME: check if the constant is already in the list */ - that->m_ops.Push(op::constant, that->m_constants.Count()); - that->m_constants.Push(lol::real(ctx.c_str())); + that->m_ops.push(op::constant, that->m_constants.Count()); + that->m_constants.push(lol::real(ctx.c_str())); } }; @@ -216,7 +175,7 @@ private: static void apply(std::string const &ctx, expression *that) { UNUSED(ctx); - that->m_ops.Push(OP, -1); + that->m_ops.push(OP, -1); } };