void Expr::Reduce(void) { Expr *a, *b; Expr *op = PopOperator(); Expr *n; int o; switch(op->c) { case '+': o = PLUS; goto c; case '-': o = MINUS; goto c; case '*': o = TIMES; goto c; case '/': o = DIV; goto c; c: b = PopOperand(); a = PopOperand(); n = a->AnyOp(o, b); break; case 'n': n = PopOperand()->Negate(); break; case 'q': n = PopOperand()->Sqrt(); break; case 's': n = (PopOperand()->Times(Expr::From(PI/180)))->Sin(); break; case 'c': n = (PopOperand()->Times(Expr::From(PI/180)))->Cos(); break; default: oops(); } PushOperand(n); }
void Expr::Parse(void) { Expr *e = AllocExpr(); e->op = ALL_RESOLVED; PushOperator(e); for(;;) { Expr *n = Next(); if(!n) throw "end of expression unexpected"; if(n->op == CONSTANT) { PushOperand(n); Consume(); } else if(n->op == PAREN && n->c == '(') { Consume(); Parse(); n = Next(); if(n->op != PAREN || n->c != ')') throw "expected: )"; Consume(); } else if(n->op == UNARY_OP) { PushOperator(n); Consume(); continue; } else if(n->op == BINARY_OP && n->c == '-') { // The minus sign is special, because it might be binary or // unary, depending on context. n->op = UNARY_OP; n->c = 'n'; PushOperator(n); Consume(); continue; } else { throw "expected expression"; } n = Next(); if(n && n->op == BINARY_OP) { ReduceAndPush(n); Consume(); } else { break; } } while(TopOperator()->op != ALL_RESOLVED) { Reduce(); } PopOperator(); // discard the ALL_RESOLVED marker }
//------------------------------------------------------------------------------ void Evaluator::ApplyUntilLeftParen(bool discardParen) { while (!operatorStack.empty()) { Token token = PopOperator(); if (token.type == Token::Type::LeftParen) { if (!discardParen) operatorStack.push_back(token); break; } else { ApplyBinOp(token.binOp); } } }
//------------------------------------------------------------------------------ float Evaluator::Evaluate(const vector<Token>& expression, const Environment* env) { // Now perform the actual shunting :) for (size_t i = 0; i < expression.size(); ++i) { const Token& t = expression[i]; if (t.type == Token::Type::Constant) { operandStack.push_back(t); } else if (t.type == Token::Type::BinOp) { // Apply any higher priority operators int prio = BINOP_PRIO[t.binOp]; while (!operatorStack.empty()) { const Token& op = operatorStack.back(); if (op.type == Token::Type::BinOp && BINOP_PRIO[op.binOp] >= prio) { ApplyBinOp(op.binOp); operatorStack.pop_back(); } else break; } operatorStack.push_back(t); } else if (t.type == Token::Type::FuncCall) { operatorStack.push_back(t); } else if (t.type == Token::Type::LeftParen) { operatorStack.push_back(t); } else if (t.type == Token::Type::Comma) { // apply all the operators until the left paren ApplyUntilLeftParen(false); } else if (t.type == Token::Type::RightParen) { ApplyUntilLeftParen(true); if (!operatorStack.empty()) { // if the token at the top of the operator stack is a function call, // then invoke it Token t = operatorStack.back(); if (t.type == Token::Type::FuncCall) { InvokeFunction(t, env); operatorStack.pop_back(); } } } else if (t.type == Token::Type::Var) { LookupVar(t, env); } } // apply all the remaining operators while (!operatorStack.empty()) { ApplyBinOp(PopOperator().binOp); } return PopValue(); }