public function reduce(): void
    {
        $rule = $this->stateRow->reduceRule;
        if (!$rule) {
            throw new NoReduceException();
        }
        $reduce_count = count($rule->getDefinition());
        $total_count = count($this->items);
        if ($total_count < $reduce_count) {
            throw new InternalException('Not enough items in stack');
        }
        $nodes = [];
        $offset = null;
        $reduce_items = array_slice($this->items, -$reduce_count);
        foreach ($rule->getDefinition() as $i => $symbol) {
            $item = $reduce_items[$i];
            if ($item->node->getNodeName() !== $symbol->getName()) {
                throw new InternalException('Unexpected stack content');
            }

            if (!$symbol->isHidden()) {
                $nodes[] = $item->node;
            }

            if (null === $offset) {
                $offset = $item->node->getOffset();
            }
        }

        $base_state_index = ($total_count > $reduce_count)
            ? $this->items[$total_count - 1 - $reduce_count]->state
            : 0;
        $base_state_row = $this->table->getRow($base_state_index);

        $new_symbol_name = $rule->getSubject()->getName();

        $new_node = new NonTerminal($new_symbol_name, $nodes, $rule->getTag(), $offset);

        $goto = $base_state_row->gotoSwitches;
        if (!isset($goto[$new_symbol_name])) {
            throw new InternalException('No required state in GOTO table');
        }
        $next_state = $goto[$new_symbol_name];

        array_splice($this->items, -$reduce_count);
        $this->shift($new_node, $next_state);
    }
public function reduce(): void
    {
        $rule = $this->stateRow->reduceRule;
        if (!$rule) {
            throw new NoReduceException();
        }
        $reduce_count = count($rule->getDefinition());
        $total_count = count($this->items);
        if ($total_count < $reduce_count) {
            throw new InternalException('Not enough items in stack');
        }
        $nodes = [];
        $offset = null;
        $reduce_items = array_slice($this->items, -$reduce_count);
        foreach ($rule->getDefinition() as $i => $symbol) {
            $item = $reduce_items[$i];
            if ($item->node->getNodeName() !== $symbol->getName()) {
                throw new InternalException('Unexpected stack content');
            }

            if (!$symbol->isHidden()) {
                $nodes[] = $item->node;
            }

            if (null === $offset) {
                $offset = $item->node->getOffset();
            }
        }

        $base_state_index = ($total_count > $reduce_count)
            ? $this->items[$total_count - 1 - $reduce_count]->state
            : 0;
        $base_state_row = $this->table->getRow($base_state_index);

        $new_symbol_name = $rule->getSubject()->getName();

        $new_node = new NonTerminal($new_symbol_name, $nodes, $rule->getTag(), $offset);

        $goto = $base_state_row->gotoSwitches;
        if (!isset($goto[$new_symbol_name])) {
            throw new InternalException('No required state in GOTO table');
        }
        $next_state = $goto[$new_symbol_name];

        array_splice($this->items, -$reduce_count);
        $this->shift($new_node, $next_state);
    }
public function reduce ( ) : void { $ rule = $ this -> stateRow -> reduceRule ; if ( ! $ rule ) { throw new NoReduceException ( ) ; } $ reduce_count = count ( $ rule -> getDefinition ( ) ) ; $ total_count = count ( $ this -> items ) ; if ( $ total_count < $ reduce_count ) { throw new InternalException ( 'Not enough items in stack' ) ; } $ nodes = [ ] ; $ offset = null ; $ reduce_items = array_slice ( $ this -> items , - $ reduce_count ) ; foreach ( $ rule -> getDefinition ( ) as $ i => $ symbol ) { $ item = $ reduce_items [ $ i ] ; if ( $ item -> node -> getNodeName ( ) !== $ symbol -> getName ( ) ) { throw new InternalException ( 'Unexpected stack content' ) ; } if ( ! $ symbol -> isHidden ( ) ) { $ nodes [ ] = $ item -> node ; } if ( null === $ offset ) { $ offset = $ item -> node -> getOffset ( ) ; } } $ base_state_index = ( $ total_count > $ reduce_count ) ? $ this -> items [ $ total_count - 1 - $ reduce_count ] -> state : 0 ; $ base_state_row = $ this -> table -> getRow ( $ base_state_index ) ; $ new_symbol_name = $ rule -> getSubject ( ) -> getName ( ) ; $ new_node = new NonTerminal ( $ new_symbol_name , $ nodes , $ rule -> getTag ( ) , $ offset ) ; $ goto = $ base_state_row -> gotoSwitches ; if ( ! isset ( $ goto [ $ new_symbol_name ] ) ) { throw new InternalException ( 'No required state in GOTO table' ) ; } $ next_state = $ goto [ $ new_symbol_name ] ; array_splice ( $ this -> items , - $ reduce_count ) ; $ this -> shift ( $ new_node , $ next_state ) ; }
Perform the Reduce
@throws NoReduceException No rule to reduce by in the current state
@throws InternalException Internal package error
@throws AbortParsingException
Perform the Reduce