/** * @return Symbol[] */ public function getTerminals() { $visitor = new SymbolCollectorVisitor(SymbolTypeEquals::newInstanceMatchingTerminals()); $walks = Walks::singletonInstance(); $productions = $this->getProductions(); foreach ($productions as $production) { $expression = $production->getExpression(); $walks->depthFirstWalk($expression, $visitor); } $terminals = $visitor->getCollected(); return $terminals; }
/** * @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 $list and adds it's elements to $set * * @param \Helstern\Nomsky\Grammar\Symbol\SymbolSet $newFirstSet * @param array|NormalizedProduction[] $list * @param \Helstern\Nomsky\GrammarAnalysis\ParseSets\ParseSets $firstSets * * @return bool if the epsilon symbol was added to $set */ public function processSymbolList(SymbolSet $newFirstSet, array $list, ParseSets $firstSets) { if (0 == count($list)) { $newFirstSet->add(new EpsilonSymbol()); return true; } if (1 == count($list)) { /** @var Symbol $symbol */ $symbol = $list[0]; return $this->processSymbol($newFirstSet, $symbol, $firstSets); } $symbolIsEpsilon = SymbolIsEpsilon::singletonInstance(); $symbolsIsNonTerminal = SymbolTypeEquals::newInstanceMatchingNonTerminals(); /** @var SymbolSet $lastSet */ $lastSet = null; $epsilonCounter = new MatchCountingInterceptor($symbolIsEpsilon); $acceptor = Inverter::newInstance($epsilonCounter); //we assume there is no epsilon symbol in the $list list $previousSymbol = reset($list); //add the first non-terminal and continue past this one later on if ($symbolsIsNonTerminal->matchSymbol($previousSymbol)) { $lastSet = $firstSets->filterTerminalSet($previousSymbol, $acceptor); $newFirstSet->addAll($lastSet); } else { $newFirstSet->add($previousSymbol); } //as long as the previous symbol was a non-terminal, process the next symbol for (next($list); !is_null(key($list)) && $symbolsIsNonTerminal->matchSymbol($previousSymbol) && $epsilonCounter->getMatchCount() > 0; next($list)) { $previousSymbol = current($list); $epsilonCounter = new MatchCountingInterceptor($symbolIsEpsilon); $acceptor = Inverter::newInstance($epsilonCounter); if ($symbolsIsNonTerminal->matchSymbol($previousSymbol)) { $lastSet = $firstSets->filterTerminalSet($previousSymbol, $acceptor); $newFirstSet->addAll($lastSet); } else { $newFirstSet->add($previousSymbol); } } if (is_null(key($list)) && $symbolsIsNonTerminal->matchSymbol($previousSymbol) && $epsilonCounter->getMatchCount() > 0) { $newFirstSet->add(new EpsilonSymbol()); return true; } return false; }
public function findAllNonTerminals() { $predicate = SymbolTypeEquals::newInstance(Symbol::TYPE_NON_TERMINAL); return $this->findMax($predicate, PHP_INT_MAX); }