private function evaluatePostfixNotation($tokens, $variables = array()) { if ($tokens == false) { return false; } $stack = new Stack(); foreach ($tokens as $token) { if (in_array($token, array('+', '-', '*', '/', '^', '%'))) { $lastOperatorTwo = $stack->pop(); $lastOperatorOne = $stack->pop(); if (is_null($lastOperatorOne)) { return $this->raiseError('Internal error'); } if (is_null($lastOperatorTwo)) { return $this->raiseError('Internal error'); } switch ($token) { case '+': $stack->push($this->executionEngine->add($lastOperatorOne, $lastOperatorTwo)); break; case '-': $stack->push($this->executionEngine->subtract($lastOperatorOne, $lastOperatorTwo)); break; case '*': $stack->push($this->executionEngine->multiply($lastOperatorOne, $lastOperatorTwo)); break; case '/': if ($lastOperatorTwo == 0) { return $this->raiseError('Divide by zero error.'); } $stack->push($this->executionEngine->divide($lastOperatorOne, $lastOperatorTwo)); break; case '^': $stack->push($this->executionEngine->pow($lastOperatorOne, $lastOperatorTwo)); break; case '%': $stack->push($this->executionEngine->mod($lastOperatorOne, $lastOperatorTwo)); break; } } elseif ($token == '_') { // If the token is a unary operator, pop one value off the stack and // then do the operation, then push it back on. $stack->push(-1 * $stack->pop()); } elseif (preg_match("/^([a-z]\\w*)\\(\$/", $token, $matches)) { // If the token is a function, pop arguments off the stack, hand them to // the function and push the result back on. $functionName = $matches[1]; if (in_array($functionName, $this->functions)) { // The function name is one of the default functions. $lastOperatorOne = $stack->pop(); if (is_null($lastOperatorOne)) { return $this->raiseError('Internal error.'); } // Handles the 'arc' trig synonyms. $functionName = preg_replace("/^arc/", "a", $functionName); // Converts 'ln' into the 'log' function name. if ($functionName == 'ln') { $functionName = 'log'; } // Here the original code had an eval statement. We are going to try and do // away with that and handle the function execution ourself. We will also do // this so that this driver can use the MathExecutionEngine implementation. // This piece of code will look-up a function on the MathExecutionEngine // implementation and call an instance method on the implementation. We do this // so that we do not have to define a use-case for each and every function // that the driver may encounter. if (in_array($functionName, $this->functions)) { $stack->push($this->executionEngine->{$functionName}($lastOperatorOne)); } } elseif (array_key_exists($functionName, $this->userFunctions)) { // This is a user defined function. $arguments = array(); for ($i = count($this->userFunctions[$functionName]['args']) - 1; $i >= 0; $i--) { if (is_null($arguments[$this->userFunctions[$functionName]['args'][$i]] = $stack->pop())) { return $this->raiseError('Internal error.'); } } $stack->push($this->evaluatePostfixNotation($this->userFunctions[$functionName]['func'], $arguments)); } } else { if (is_numeric($token)) { $stack->push($token); } elseif (array_key_exists($token, $this->constants)) { $stack->push($this->constants[$token]); } elseif (array_key_exists($token, $variables)) { $stack->push($variables[$token]); } else { return $this->raiseError('Undefined variable \'' . $token . '\''); } } } // After there are no more tokens, the stack should have the final result. if ($stack->getCount() != 1) { return $this->raiseError('Internal error'); } // Return the result. return $stack->pop(); }
/** * Calculates the factorial of a number. * * @param number $number * @return number */ public function factorial($number) { return $this->executionEngine->factorial($number); }