// Consume operators with precedence >= than op then add op void rpnBuilder::handle_op(const std::string& op) { // "Convert" unary operators into binary, so they can // be treated as if they were the same: handle_unary(op); // Check if operator exists: if (!opp.exists(op)) { cleanRPN(&(rpn)); throw std::domain_error("Undefined operator: `" + op + "`!"); } // Let p(o) denote the precedence of an operator o. // // If the token is an operator, o1, then // While there is an operator token, o2, at the top // and p(o1) >= p(o2), then (`>` for Right to Left associativity) // pop o2 off the stack onto the output queue. // Push o1 on the stack. // If it associates from left to right: if (opp.assoc(op) == 0) { while (!opStack.empty() && opp.prec(op) >= opp.prec(opStack.top())) { rpn.push(new Token<std::string>(opStack.top(), OP)); opStack.pop(); } } else { while (!opStack.empty() && opp.prec(op) > opp.prec(opStack.top())) { rpn.push(new Token<std::string>(opStack.top(), OP)); opStack.pop(); } } opStack.push(op); lastTokenWasOp = op[0]; }
double calculator::calculate(const char* expr, std::map<std::string, double>* vars) { // Convert to RPN with Dijkstra's Shunting-yard algorithm. TokenQueue_t rpn = toRPN(expr, vars); double ret = calculate(rpn); cleanRPN(rpn); return ret; }
// Check for unary operators and "convert" them to binary: void rpnBuilder::handle_unary(const std::string& op) { if (this->lastTokenWasOp) { // Convert unary operators to binary in the RPN. if (!op.compare("-") || !op.compare("+")) { this->rpn.push(new Token<int64_t>(0, INT)); this->lastTokenWasUnary = true; } else { cleanRPN(&(this->rpn)); throw std::domain_error("Unrecognized unary operator: '" + op + "'."); } } else { this->lastTokenWasUnary = false; } }