function ctools_math_expr::pfx
Evaluate a prefix-operator stack expression.
Parameters
array $tokens: The array of token values to evaluate. A token is a string value representing either an operation to perform, a variable, or a value. Literal values are checked using is_numeric(), or a value that starts with a double-quote; functions and variables by existence in the appropriate tables. If FALSE is passed in the function terminates immediately, returning FALSE.
array $vars: Additional variable values to use when evaluating the expression. These variables do not override internal variables with the same name.
Return value
bool|mixed The expression's value, otherwise FALSE is returned if there is an error detected unless php error handling intervenes: see suppress_error.
1 call to ctools_math_expr::pfx()
- ctools_math_expr::evaluate in includes/
math-expr.inc - Evaluate the expression.
File
-
includes/
math-expr.inc, line 652
Class
- ctools_math_expr
- ctools_math_expr Class.
Code
public function pfx(array $tokens, array $vars = array()) {
if ($tokens == FALSE) {
return FALSE;
}
$stack = new ctools_math_expr_stack();
foreach ($tokens as $token) {
// If the token is a binary operator, pop two values off the stack, do
// the operation, and push the result back on again.
if (in_array($token, $this->binaryops)) {
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;
case '==':
$stack->push((int) ($op1 == $op2));
break;
case '!=':
$stack->push((int) ($op1 != $op2));
break;
case '<=':
$stack->push((int) ($op1 <= $op2));
break;
case '<':
$stack->push((int) ($op1 < $op2));
break;
case '>=':
$stack->push((int) ($op1 >= $op2));
break;
case '>':
$stack->push((int) ($op1 > $op2));
break;
}
}
elseif ($token === "_") {
$stack->push(-1 * $stack->pop());
}
elseif (preg_match("/^([a-z]\\w*)\\(\$/", (string) $token, $matches)) {
$fnn = $matches[1];
// Check for a built-in function.
if (isset($this->funcs[$fnn])) {
$args = array();
// Collect all required args from the stack.
for ($i = 0; $i < $this->funcs[$fnn]['arguments']; $i++) {
if (is_null($op1 = $stack->pop())) {
return $this->trigger("function {$fnn} missing argument {$i}");
}
$args[] = $op1;
}
// If func allows additional args, collect them too, stopping on a
// NULL arg.
if (!empty($this->funcs[$fnn]['max arguments'])) {
for (; $i < $this->funcs[$fnn]['max arguments']; $i++) {
$arg = $stack->pop();
if (!isset($arg)) {
break;
}
$args[] = $arg;
}
}
$stack->push(call_user_func_array($this->funcs[$fnn]['function'], array_reverse($args)));
}
elseif (isset($fnn, $this->userfuncs)) {
$args = array();
for ($i = count($this->userfuncs[$fnn]['args']) - 1; $i >= 0; $i--) {
$value = $stack->pop();
$args[$this->userfuncs[$fnn]['args'][$i]] = $value;
if (is_null($value)) {
return $this->trigger('internal error');
}
}
// yay... recursion!!!!
$stack->push($this->pfx($this->userfuncs[$fnn]['func'], $args));
}
}
else {
if (is_numeric($token) || $token[0] == '"') {
$stack->push($token);
}
elseif (array_key_exists($token, $this->vars)) {
$stack->push($this->vars[$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();
}