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');
 }
Example #3
0
 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');
 }