/** * @param array|NormalizedProduction[] $productions * @param Symbol $startSymbol * @param ParseSets $followSets * @param ParseSets $firstSets * * @return \Helstern\Nomsky\GrammarAnalysis\ParseSets\SetsGenerator */ public function generateFollowSets(array $productions, Symbol $startSymbol, ParseSets $followSets, ParseSets $firstSets) { $followSets->addEpsilon($startSymbol); $occurrences = new \ArrayObject(); foreach ($productions as $production) { $symbol = $production->getLeftHandSide(); $rhs = $production->getRightHandSide(); $this->followSetCalculator->addNonTerminalOccurrences($occurrences, $symbol, $rhs); } do { $changes = false; /** @var SymbolOccurrence $occurrence */ foreach ($occurrences as $occurrence) { $set = new ArraySet(); if ($this->followSetCalculator->processOccurrence($set, $occurrence, $followSets, $firstSets)) { $symbol = $occurrence->getSymbol(); $changes |= $followSets->addAllTerminals($symbol, $set); } } } while ($changes); return $this; }