private function shuntingYard(array $tokens)
    {
        // Clear the oepratorStack
        $this->operatorStack = new Stack();

        // Clear the operandStack.
        $this->operandStack = new Stack();

        // Remember the last token handled, this is done to recognize unary operators.
        $lastNode = null;

        // Loop over the tokens
        for ($index = 0; $index < count($tokens); $index++)
        {
            $token = $tokens[$index];

            // echo "current token $token\n";
            // echo("operands:" . $this->operandStack . "\n");
            // echo("operators: " . $this->operatorStack . "\n\n");

            if ($this->rationalFactory) {
                $node = Node::rationalFactory($token);
            } else {
                $node = Node::factory($token);
            }

            // Handle closing parentheses
            if ($token->getType() == TokenType::CloseParenthesis) {
                $this->handleSubExpression();
            }
            // Push terminal tokens on the operandStack
            elseif ($node->isTerminal()) {
                $this->operandStack->push($node);

                // Push function applications or open parentheses `(` onto the operatorStack
            } elseif ($node instanceof FunctionNode) {
                $this->operatorStack->push($node);

            } elseif ($node instanceof SubExpressionNode) {
                $this->operatorStack->push($node);

                // Handle the remaining operators.
            } elseif ($node instanceof PostfixOperatorNode) {
                $op = $this->operandStack->pop();
                if ($op == NULL) throw new SyntaxErrorException();
                $this->operandStack->push(new FunctionNode($node->getOperator(), $op));

            } elseif ($node instanceof ExpressionNode) {

                // Check for unary minus and unary plus.
                $unary = $this->isUnary($node, $lastNode);

                if ($unary) {
                    switch($token->getType()) {
                        // Unary +, just ignore it
                        case TokenType::AdditionOperator:
                        $node = null;
                        break;
                        // Unary -, replace the token.
                        case TokenType::SubtractionOperator:
                        $node->setOperator('~');
                        break;
                    }
                } else {
                    // Pop operators with higher priority

                    while ($node->lowerPrecedenceThan($this->operatorStack->peek())) {

                        $popped = $this->operatorStack->pop();
                        $popped = $this->handleExpression($popped);
                        $this->operandStack->push($popped);
                    }
                }

                if ($node) $this->operatorStack->push($node);
            }

            // Remember the current token (if it hasn't been nulled, for example being a unary +)
            if ($node) $lastNode = $node;
        }


        // Pop remaining operators

        while (!$this->operatorStack->isEmpty()) {
            $node = $this->operatorStack->pop();
            $node = $this->handleExpression($node);
            $this->operandStack->push($node);
        }

        // Stack should be empty here
        if ($this->operandStack->count() > 1) {
            throw new SyntaxErrorException();
        }

        return $this->operandStack->pop();
    }
private function shuntingYard(array $tokens)
    {
        // Clear the oepratorStack
        $this->operatorStack = new Stack();

        // Clear the operandStack.
        $this->operandStack = new Stack();

        // Remember the last token handled, this is done to recognize unary operators.
        $lastNode = null;

        // Loop over the tokens
        for ($index = 0; $index < count($tokens); $index++)
        {
            $token = $tokens[$index];

            // echo "current token $token\n";
            // echo("operands:" . $this->operandStack . "\n");
            // echo("operators: " . $this->operatorStack . "\n\n");

            if ($this->rationalFactory) {
                $node = Node::rationalFactory($token);
            } else {
                $node = Node::factory($token);
            }

            // Handle closing parentheses
            if ($token->getType() == TokenType::CloseParenthesis) {
                $this->handleSubExpression();
            }
            // Push terminal tokens on the operandStack
            elseif ($node->isTerminal()) {
                $this->operandStack->push($node);

                // Push function applications or open parentheses `(` onto the operatorStack
            } elseif ($node instanceof FunctionNode) {
                $this->operatorStack->push($node);

            } elseif ($node instanceof SubExpressionNode) {
                $this->operatorStack->push($node);

                // Handle the remaining operators.
            } elseif ($node instanceof PostfixOperatorNode) {
                $op = $this->operandStack->pop();
                if ($op == NULL) throw new SyntaxErrorException();
                $this->operandStack->push(new FunctionNode($node->getOperator(), $op));

            } elseif ($node instanceof ExpressionNode) {

                // Check for unary minus and unary plus.
                $unary = $this->isUnary($node, $lastNode);

                if ($unary) {
                    switch($token->getType()) {
                        // Unary +, just ignore it
                        case TokenType::AdditionOperator:
                        $node = null;
                        break;
                        // Unary -, replace the token.
                        case TokenType::SubtractionOperator:
                        $node->setOperator('~');
                        break;
                    }
                } else {
                    // Pop operators with higher priority

                    while ($node->lowerPrecedenceThan($this->operatorStack->peek())) {

                        $popped = $this->operatorStack->pop();
                        $popped = $this->handleExpression($popped);
                        $this->operandStack->push($popped);
                    }
                }

                if ($node) $this->operatorStack->push($node);
            }

            // Remember the current token (if it hasn't been nulled, for example being a unary +)
            if ($node) $lastNode = $node;
        }


        // Pop remaining operators

        while (!$this->operatorStack->isEmpty()) {
            $node = $this->operatorStack->pop();
            $node = $this->handleExpression($node);
            $this->operandStack->push($node);
        }

        // Stack should be empty here
        if ($this->operandStack->count() > 1) {
            throw new SyntaxErrorException();
        }

        return $this->operandStack->pop();
    }
private function shuntingYard ( array $ tokens ) { // Clear the oepratorStack $ this -> operatorStack = new Stack ( ) ; // Clear the operandStack. $ this -> operandStack = new Stack ( ) ; // Remember the last token handled, this is done to recognize unary operators. $ lastNode = null ; // Loop over the tokens for ( $ index = 0 ; $ index < count ( $ tokens ) ; $ index ++ ) { $ token = $ tokens [ $ index ] ; // echo "current token $token\n"; // echo("operands:" . $this->operandStack . "\n"); // echo("operators: " . $this->operatorStack . "\n\n"); if ( $ this -> rationalFactory ) { $ node = Node :: rationalFactory ( $ token ) ; } else { $ node = Node :: factory ( $ token ) ; } // Handle closing parentheses if ( $ token -> getType ( ) == TokenType :: CloseParenthesis ) { $ this -> handleSubExpression ( ) ; } // Push terminal tokens on the operandStack elseif ( $ node -> isTerminal ( ) ) { $ this -> operandStack -> push ( $ node ) ; // Push function applications or open parentheses `(` onto the operatorStack } elseif ( $ node instanceof FunctionNode ) { $ this -> operatorStack -> push ( $ node ) ; } elseif ( $ node instanceof SubExpressionNode ) { $ this -> operatorStack -> push ( $ node ) ; // Handle the remaining operators. } elseif ( $ node instanceof PostfixOperatorNode ) { $ op = $ this -> operandStack -> pop ( ) ; if ( $ op == NULL ) throw new SyntaxErrorException ( ) ; $ this -> operandStack -> push ( new FunctionNode ( $ node -> getOperator ( ) , $ op ) ) ; } elseif ( $ node instanceof ExpressionNode ) { // Check for unary minus and unary plus. $ unary = $ this -> isUnary ( $ node , $ lastNode ) ; if ( $ unary ) { switch ( $ token -> getType ( ) ) { // Unary +, just ignore it case TokenType :: AdditionOperator : $ node = null ; break ; // Unary -, replace the token. case TokenType :: SubtractionOperator : $ node -> setOperator ( '~' ) ; break ; } } else { // Pop operators with higher priority while ( $ node -> lowerPrecedenceThan ( $ this -> operatorStack -> peek ( ) ) ) { $ popped = $ this -> operatorStack -> pop ( ) ; $ popped = $ this -> handleExpression ( $ popped ) ; $ this -> operandStack -> push ( $ popped ) ; } } if ( $ node ) $ this -> operatorStack -> push ( $ node ) ; } // Remember the current token (if it hasn't been nulled, for example being a unary +) if ( $ node ) $ lastNode = $ node ; } // Pop remaining operators while ( ! $ this -> operatorStack -> isEmpty ( ) ) { $ node = $ this -> operatorStack -> pop ( ) ; $ node = $ this -> handleExpression ( $ node ) ; $ this -> operandStack -> push ( $ node ) ; } // Stack should be empty here if ( $ this -> operandStack -> count ( ) > 1 ) { throw new SyntaxErrorException ( ) ; } return $ this -> operandStack -> pop ( ) ; }
Implementation of the shunting yard parsing algorithm

@param array $tokens Token[] array of tokens to process
@retval Node AST of the parsed expression
@throws SyntaxErrorException
@throws ParenthesisMismatchException
Implementation of the shunting yard parsing algorithm