Ejemplo n.º 1
0
 /**
  * Parse current rule.
  *
  * @param   \Hoa\Compiler\Llk\Rule  $zeRule    Current rule.
  * @param   int                     $next      Next rule index.
  * @return  bool
  */
 protected function _parse(Rule $zeRule, $next)
 {
     if ($zeRule instanceof Rule\Token) {
         $name = $this->getCurrentToken();
         if ($zeRule->getTokenName() !== $name) {
             return false;
         }
         $value = $this->getCurrentToken('value');
         if (0 <= ($unification = $zeRule->getUnificationIndex())) {
             for ($skip = 0, $i = count($this->_trace) - 1; $i >= 0; --$i) {
                 $trace = $this->_trace[$i];
                 if ($trace instanceof Rule\Entry) {
                     if (false === $trace->isTransitional()) {
                         if ($trace->getDepth() <= $this->_depth) {
                             break;
                         }
                         --$skip;
                     }
                 } elseif ($trace instanceof Rule\Ekzit && false === $trace->isTransitional()) {
                     $skip += $trace->getDepth() > $this->_depth;
                 }
                 if (0 < $skip) {
                     continue;
                 }
                 if ($trace instanceof Rule\Token && $unification === $trace->getUnificationIndex() && $value !== $trace->getValue()) {
                     return false;
                 }
             }
         }
         $namespace = $this->getCurrentToken('namespace');
         $zzeRule = clone $zeRule;
         $zzeRule->setValue($value);
         $zzeRule->setNamespace($namespace);
         if (isset($this->_tokens[$namespace][$name])) {
             $zzeRule->setRepresentation($this->_tokens[$namespace][$name]);
         } else {
             foreach ($this->_tokens[$namespace] as $_name => $regex) {
                 if (false === ($pos = strpos($_name, ':'))) {
                     continue;
                 }
                 $_name = substr($_name, 0, $pos);
                 if ($_name === $name) {
                     break;
                 }
             }
             $zzeRule->setRepresentation($regex);
         }
         array_pop($this->_todo);
         $this->_trace[] = $zzeRule;
         $this->_errorState = ++$this->_currentState;
         return true;
     } elseif ($zeRule instanceof Rule\Concatenation) {
         if (false === $zeRule->isTransitional()) {
             ++$this->_depth;
         }
         $this->_trace[] = new Rule\Entry($zeRule->getName(), 0, null, $this->_depth);
         $content = $zeRule->getContent();
         for ($i = count($content) - 1; $i >= 0; --$i) {
             $nextRule = $content[$i];
             $this->_todo[] = new Rule\Ekzit($nextRule, 0);
             $this->_todo[] = new Rule\Entry($nextRule, 0);
         }
         return true;
     } elseif ($zeRule instanceof Rule\Choice) {
         $content = $zeRule->getContent();
         if ($next >= count($content)) {
             return false;
         }
         if (false === $zeRule->isTransitional()) {
             ++$this->_depth;
         }
         $this->_trace[] = new Rule\Entry($zeRule->getName(), $next, $this->_todo, $this->_depth);
         $nextRule = $content[$next];
         $this->_todo[] = new Rule\Ekzit($nextRule, 0);
         $this->_todo[] = new Rule\Entry($nextRule, 0);
         return true;
     } elseif ($zeRule instanceof Rule\Repetition) {
         $nextRule = $zeRule->getContent();
         if (0 === $next) {
             $name = $zeRule->getName();
             $min = $zeRule->getMin();
             if (false === $zeRule->isTransitional()) {
                 ++$this->_depth;
             }
             $this->_trace[] = new Rule\Entry($name, $min, null, $this->_depth);
             array_pop($this->_todo);
             $this->_todo[] = new Rule\Ekzit($name, $min, $this->_todo);
             for ($i = 0; $i < $min; ++$i) {
                 $this->_todo[] = new Rule\Ekzit($nextRule, 0);
                 $this->_todo[] = new Rule\Entry($nextRule, 0);
             }
             return true;
         } else {
             $max = $zeRule->getMax();
             if (-1 != $max && $next > $max) {
                 return false;
             }
             $this->_todo[] = new Rule\Ekzit($zeRule->getName(), $next, $this->_todo);
             $this->_todo[] = new Rule\Ekzit($nextRule, 0);
             $this->_todo[] = new Rule\Entry($nextRule, 0);
             return true;
         }
     }
     return false;
 }