| @@ -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<lol::real> 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); | |||
| } | |||
| }; | |||