public function reduce(Context $ctx) { $this->stack = array(); $len = 0; // While there are input tokens left // Read the next token from input. while ($t = array_shift($this->queue)) { switch ($t->type) { case Token::T_NUMBER: case Token::T_IDENT: // wert einer konstanten ermitteln if ($t->type === Token::T_IDENT) { $t = new Token(Token::T_NUMBER, $ctx->cs($t->value)); } // If the token is a value or identifier // Push it onto the stack. $this->stack[] = $t; ++$len; break; case Token::T_PLUS: case Token::T_MINUS: case Token::T_UNARY_PLUS: case Token::T_UNARY_MINUS: case Token::T_TIMES: case Token::T_DIV: case Token::T_MOD: case Token::T_POW: case Token::T_NOT: // It is known a priori that the operator takes n arguments. $na = $this->argc($t); // If there are fewer than n values on the stack if ($len < $na) { throw new RuntimeError('laufzeit fehler: zu wenig paramter für operator "' . $t->value . '" (' . $na . ' -> ' . $len . ')'); } $rhs = array_pop($this->stack); $lhs = null; if ($na > 1) { $lhs = array_pop($this->stack); } // if ($lhs) print "{$lhs->value} {$t->value} {$rhs->value}\n"; // else print "{$t->value} {$rhs->value}\n"; $len -= $na - 1; // Push the returned results, if any, back onto the stack. $this->stack[] = new Token(Token::T_NUMBER, $this->op($t->type, $lhs, $rhs)); break; case Token::T_FUNCTION: // function $argc = $t->argc; $argv = array(); $len -= $argc - 1; for (; $argc > 0; --$argc) { array_unshift($argv, array_pop($this->stack)->value); } // Push the returned results, if any, back onto the stack. $this->stack[] = new Token(Token::T_NUMBER, $ctx->fn($t->value, $argv)); break; default: throw new RuntimeError('laufzeit fehler: unerwarteter token `' . $t->value . '`'); } } // If there is only one value in the stack // That value is the result of the calculation. if (count($this->stack) === 1) { return array_pop($this->stack)->value; } // If there are more values in the stack // (Error) The user input has too many values. throw new RuntimeError('laufzeit fehler: zu viele werte im stack'); }
/** * @expectedException \RR\Shunt\Exception\RuntimeError */ public function testCallNotsetConstantCausesException() { $context = new Context(); $context->cs('notdefinedfunction'); }
public function reduce(Context $ctx) { $this->reset(); $this->stack = array(); $len = 0; // While there are input tokens left // Read the next token from input. while ($t = array_shift($this->queue)) { switch ($t->type) { case Token::T_NUMBER: case Token::T_NULL: case Token::T_IDENT: // determine constant value if ($t->type === Token::T_IDENT) { $t = new Token(Token::T_NUMBER, $ctx->cs($t->value)); } // If the token is a value, null or identifier // Push it onto the stack. $this->stack[] = $t; ++$len; break; case Token::T_AND: case Token::T_OR: case Token::T_XOR: case Token::T_GREATER_EQUAL: case Token::T_LESS_EQUAL: case Token::T_GREATER: case Token::T_LESS: case Token::T_EQUAL: case Token::T_NOT_EQUAL: case Token::T_PLUS: case Token::T_MINUS: case Token::T_UNARY_PLUS: case Token::T_UNARY_MINUS: case Token::T_TIMES: case Token::T_DIV: case Token::T_MOD: case Token::T_POW: case Token::T_NOT: // It is known a priori that the operator takes n arguments. $na = $this->argc($t); // If there are fewer than n values on the stack if ($len < $na) { throw new RuntimeError('run-time error: too few parameters for operator "' . $t->value . '" (' . $na . ' -> ' . $len . ')'); } $rhs = array_pop($this->stack); $lhs = null; if ($na > 1) { $lhs = array_pop($this->stack); } // if ($lhs) print "{$lhs->value} {$t->value} {$rhs->value}\n"; // else print "{$t->value} {$rhs->value}\n"; $len -= $na - 1; // Push the returned results, if any, back onto the stack. $operationResult = $this->op($t->type, $lhs, $rhs, $ctx); $this->stack[] = new Token(is_null($operationResult) ? Token::T_NULL : Token::T_NUMBER, $operationResult); break; case Token::T_FUNCTION: // function $argc = $t->argc; $argv = array(); $len -= $argc - 1; for (; $argc > 0; --$argc) { array_unshift($argv, array_pop($this->stack)->value); } // Push the returned results, if any, back onto the stack. $this->stack[] = new Token(Token::T_NUMBER, $ctx->fn($t->value, $argv)); break; default: throw new RuntimeError('run-time error: unexpected token `' . $t->value . '`'); } } // If there is only one value in the stack // That value is the result of the calculation. if (count($this->stack) == 1) { return array_pop($this->stack)->value; } elseif (count($this->stack) == 0) { // Empty formula given return null; } // If there are more values in the stack // (Error) The user input has too many values. throw new RuntimeError('run-time error: too many values in the stack'); }