/**
  * @param NormalizedProduction $production
  * @param SymbolSet $alreadyAdded
  *
  * @return bool
  */
 private function indirectlyGeneratesEpsilon(NormalizedProduction $production, SymbolSet $alreadyAdded)
 {
     $rhsItems = $production->getRightHandSide();
     /** @var Symbol $item */
     $item = reset($rhsItems);
     $answer = $alreadyAdded->contains($item);
     for (next($rhsItems); $answer && !is_null(key($rhsItems)); next($rhsItems)) {
         $item = current($rhsItems);
         $answer = $answer && $alreadyAdded->contains($item);
     }
     $answer = is_null(key($rhsItems)) && $answer;
     return $answer;
 }
Beispiel #2
0
 /**
  * @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;
 }
Beispiel #3
0
 /**
  * @param Symbol $nonTerminal
  * @param Symbol $terminal
  * @throws \Exception
  * @return null
  */
 private function assertKnownSymbols(Symbol $nonTerminal, Symbol $terminal)
 {
     $knownNonTerminal = $this->nonTerminals->contains($nonTerminal);
     $knownTerminal = $this->terminals->contains($terminal);
     if ($knownNonTerminal && $knownTerminal) {
         return true;
     }
     if (!$knownNonTerminal && !$knownTerminal) {
         $assertionMessage = 'Uknown symbols: non-terminal %s and terminal %s';
         $assertionMessage = sprintf($assertionMessage, $nonTerminal->toString(), $terminal->toString());
     } else {
         if ($knownTerminal) {
             $assertionMessage = 'Uknown non-terminal: %s';
             $assertionMessage = sprintf($assertionMessage, $nonTerminal->toString());
         } else {
             $assertionMessage = 'Uknown terminal: %s';
             $assertionMessage = sprintf($assertionMessage, $terminal->toString());
         }
     }
     throw new \RuntimeException($assertionMessage);
 }