/** * @param $sentence * @param array|Symbol[][] $parseSets * @param array|Symbol[] $nonTerminals * @param array|Symbol[] $terminals * * @return ArraySet */ private function buildFirstSet($sentence, array $parseSets, array $nonTerminals, array $terminals) { $firstSets = $this->buildFirstSets($nonTerminals, $parseSets); $sentenceList = $this->buildSentenceList($sentence, $nonTerminals, $terminals); $set = new ArraySet(); $calculator = new FirstSetCalculator(); $calculator->processSymbolList($set, $sentenceList, $firstSets); return $set; }
/** * @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 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 \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; }