1 evalmath.inc EvalMath::pfx($tokens, $vars = array())

File

core/includes/evalmath.inc, line 294

Class

EvalMath

Code

function pfx($tokens, $vars = array()) {

  if ($tokens == false) {
    return false;
  }

  $stack = new EvalMathStack;

  foreach ($tokens as $token) { // nice and easy
    // if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
    if (in_array($token, array('+', '-', '*', '/', '^'))) {
      if (is_null($op2 = $stack->pop())) {
        return $this->trigger("internal error");
      }
      if (is_null($op1 = $stack->pop())) {
        return $this->trigger("internal error");
      }
      switch ($token) {
        case '+':
          $stack->push($op1 + $op2);
          break;
        case '-':
          $stack->push($op1 -$op2);
          break;
        case '*':
          $stack->push($op1 * $op2);
          break;
        case '/':
          if ($op2 == 0) {
            return $this->trigger("division by zero");
          }
          $stack->push($op1 / $op2);
          break;
        case '^':
          $stack->push(pow($op1, $op2));
          break;
      }
      // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
    }
    elseif ($token == "_") {
      $stack->push(-1 * $stack->pop());
      // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
    }
    elseif (preg_match("/^([a-z]\w*)\($/", $token, $matches)) { // it's a function!
      $fnn = $matches[1];
      if (in_array($fnn, $this->fb)) { // built-in function:
        if (is_null($op1 = $stack->pop())) {
          return $this->trigger("internal error");
        }
        $fnn = preg_replace("/^arc/", "a", $fnn); // for the 'arc' trig synonyms
        if ($fnn == 'ln') {
          $fnn = 'log';
        }
        eval('$stack->push(' . $fnn . '($op1));'); // perfectly safe eval()
      }
      elseif (array_key_exists($fnn, $this->f)) { // user function
        // get args
        $args = array();
        for ($i = count($this->f[$fnn]['args']) -1; $i >= 0; $i--) {
          if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) {
            return $this->trigger("internal error");
          }
        }
        $stack->push($this->pfx($this->f[$fnn]['func'], $args)); // yay... recursion!!!!
      }
      // if the token is a number or variable, push it on the stack
    }
    else {
      if (is_numeric($token)) {
        $stack->push($token);
      }
      elseif (array_key_exists($token, $this->v)) {
        $stack->push($this->v[$token]);
      }
      elseif (array_key_exists($token, $vars)) {
        $stack->push($vars[$token]);
      }
      else {
        return $this->trigger("undefined variable '$token'");
      }
    }
  }
  // when we're out of tokens, the stack should have a single element, the final result
  if ($stack->count != 1) {
    return $this->trigger("internal error");
  }
  return $stack->pop();
}