/** * @param \Helstern\Nomsky\Grammar\Symbol\SymbolSet $set * @param NormalizedProduction $production * @param \Helstern\Nomsky\GrammarAnalysis\ParseSets\ParseSets $followSets * @param \Helstern\Nomsky\GrammarAnalysis\ParseSets\ParseSets $firstSets * * @return bool */ public function processProduction(SymbolSet $set, NormalizedProduction $production, ParseSets $followSets, ParseSets $firstSets) { $rhs = $production->getRightHandSide(); $epsilonAdded = $this->firstSetCalculator->processSymbolList($set, $rhs, $firstSets); if ($epsilonAdded) { $lhs = $production->getLeftHandSide(); $otherSet = $followSets->getTerminalSet($lhs); $set->addAll($otherSet); } return $epsilonAdded; }
/** * @param \Helstern\Nomsky\Grammar\Symbol\SymbolSet $set * @param SymbolOccurrence $occurrence * @param \Helstern\Nomsky\GrammarAnalysis\ParseSets\ParseSets $followSets * @param \Helstern\Nomsky\GrammarAnalysis\ParseSets\ParseSets $firstSets * * @return bool */ public function processOccurrence(SymbolSet $set, SymbolOccurrence $occurrence, ParseSets $followSets, ParseSets $firstSets) { $symbol = $occurrence->getSymbol(); $isTerminal = SymbolTypeEquals::newInstanceMatchingTerminals(); if ($isTerminal->matchSymbol($symbol)) { return false; } $following = $occurrence->getFollowing(); $epsilonAdded = $this->firstSetCalculator->processSymbolList($set, $following, $firstSets); if ($epsilonAdded) { $set->remove(new EpsilonSymbol()); $lhs = $occurrence->getProductionNonTerminal(); $otherSet = $followSets->getTerminalSet($lhs); $set->addAll($otherSet); } return true; }
/** * Calculates the first set of the symbol $source and adds it's elements to $set * * @param \Helstern\Nomsky\Grammar\Symbol\SymbolSet $set * @param \Helstern\Nomsky\Grammar\Symbol\Symbol $source * @param \Helstern\Nomsky\GrammarAnalysis\ParseSets\ParseSets $firstSets * * @return boolean if the epsilon symbol was added to $set */ public function processSymbol(SymbolSet $set, Symbol $source, ParseSets $firstSets) { $symbolIsEpsilon = SymbolIsEpsilon::singletonInstance(); if ($symbolIsEpsilon->matchSymbol($source)) { $set->add(new EpsilonSymbol()); return true; } $symbolsIsNonTerminal = SymbolTypeEquals::newInstanceMatchingNonTerminals(); if ($symbolsIsNonTerminal->matchSymbol($source)) { $epsilonCounter = new MatchCountingInterceptor($symbolIsEpsilon); $acceptPredicate = Inverter::newInstance($epsilonCounter); $otherSet = $firstSets->filterTerminalSet($source, $acceptPredicate); $set->addAll($otherSet); if ($epsilonCounter->getMatchCount() > 0) { $set->add(new EpsilonSymbol()); return true; } return false; } $set->add($source); return false; }
/** * @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 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; }
/** * @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; }