/** * @return ParseSets */ public static function followSets() { $sets = new ParseSets([StandardSymbol::nonTerminal('S'), StandardSymbol::nonTerminal('B'), StandardSymbol::nonTerminal('C')]); $sets->addTerminal(StandardSymbol::nonTerminal('S'), StandardSymbol::terminal('e')); $sets->addTerminal(StandardSymbol::nonTerminal('S'), new EpsilonSymbol()); $sets->addTerminal(StandardSymbol::nonTerminal('B'), StandardSymbol::terminal('e')); $sets->addTerminal(StandardSymbol::nonTerminal('B'), new EpsilonSymbol()); $sets->addTerminal(StandardSymbol::nonTerminal('C'), StandardSymbol::terminal('e')); $sets->addTerminal(StandardSymbol::nonTerminal('C'), new EpsilonSymbol()); return $sets; }
/** * @param array|NormalizedProduction[] $productions * @param ParseSets $firstSets * @param SymbolSet $emptySet * * @return SetsGenerator */ public function generateFirstSets(array $productions, ParseSets $firstSets, SymbolSet $emptySet) { //add epsilon to the first sets of the non terminals which generate epsilon foreach ($productions as $production) { $lhs = $production->getLeftHandSide(); if ($emptySet->contains($lhs)) { $firstSets->addEpsilon($lhs); } } //initialize the obvious first sets of productions which start with a terminal foreach ($productions as $production) { $symbol = $production->getFirstSymbol(); if ($symbol->getType() == Symbol::TYPE_TERMINAL) { $firstSets->addTerminal($production->getLeftHandSide(), $symbol); } } //initialize first sets for productions which contain several non-terminals do { $changes = false; foreach ($productions as $production) { $updateSet = new ArraySet(); $rhs = $production->getRightHandSide(); $this->firstSetCalculator->processSymbolList($updateSet, $rhs, $firstSets); $nonTerminal = $production->getLeftHandSide(); $changes |= $firstSets->addAllTerminals($nonTerminal, $updateSet); } } while ($changes); return $this; }
/** * @param array|Symbol[] $nonTerminals * @param array|Symbol[][] $parseSets * * @return \Helstern\Nomsky\GrammarAnalysis\ParseSets\ParseSets */ private function buildFirstSets(array $nonTerminals, array $parseSets) { $firstSets = new ParseSets(array_values($nonTerminals)); foreach ($parseSets as $nonTerminal => $listOfTerminals) { foreach ($listOfTerminals as $terminal) { $firstSets->addTerminal($nonTerminals[$nonTerminal], $terminal); } } return $firstSets; }