/**
  * The bounded-exhaustive algorithm.
  *
  * @param   \Hoa\Compiler\Llk\Rule  $rule    Rule to cover.
  * @param   int                     $next    Next rule.
  * @return  bool
  */
 protected function boundedExhaustive(Compiler\Llk\Rule $rule, $next)
 {
     $content = $rule->getContent();
     if ($rule instanceof Compiler\Llk\Rule\Repetition) {
         if (0 === $next) {
             $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), $rule->getMin());
             array_pop($this->_todo);
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), $rule->getMin(), $this->_todo);
             for ($i = 0, $min = $rule->getMin(); $i < $min; ++$i) {
                 $this->_todo[] = new Compiler\Llk\Rule\Ekzit($content, 0);
                 $this->_todo[] = new Compiler\Llk\Rule\Entry($content, 0);
             }
         } else {
             $nbToken = 0;
             foreach ($this->_trace as $trace) {
                 if ($trace instanceof Compiler\Llk\Rule\Token) {
                     ++$nbToken;
                 }
             }
             $max = $rule->getMax();
             if (-1 != $max && $next > $max) {
                 return false;
             }
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), $next, $this->_todo);
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($content, 0);
             $this->_todo[] = new Compiler\Llk\Rule\Entry($content, 0);
         }
         return true;
     } elseif ($rule instanceof Compiler\Llk\Rule\Choice) {
         if (count($content) <= $next) {
             return false;
         }
         $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), $next, $this->_todo);
         $nextRule = $content[$next];
         $this->_todo[] = new Compiler\Llk\Rule\Ekzit($nextRule, 0);
         $this->_todo[] = new Compiler\Llk\Rule\Entry($nextRule, 0);
         return true;
     } elseif ($rule instanceof Compiler\Llk\Rule\Concatenation) {
         $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), $next);
         for ($i = count($content) - 1; $i >= 0; --$i) {
             $nextRule = $content[$i];
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($nextRule, 0);
             $this->_todo[] = new Compiler\Llk\Rule\Entry($nextRule, 0);
         }
         return true;
     } elseif ($rule instanceof Compiler\Llk\Rule\Token) {
         $nbToken = 0;
         foreach ($this->_trace as $trace) {
             if ($trace instanceof Compiler\Llk\Rule\Token) {
                 ++$nbToken;
             }
         }
         if ($nbToken >= $this->getLength()) {
             return false;
         }
         $this->_trace[] = $rule;
         array_pop($this->_todo);
         return true;
     }
     return false;
 }
Example #2
0
 /**
  * The coverage algorithm.
  *
  * @param   \Hoa\Compiler\Llk\Rule  $rule    Rule to cover.
  * @return  bool
  */
 protected function coverage(Compiler\Llk\Rule $rule)
 {
     $content = $rule->getContent();
     if ($rule instanceof Compiler\Llk\Rule\Repetition) {
         $uncovered = [];
         $inprogress = [];
         $already = [];
         foreach ($this->_coveredRules[$rule->getName()] as $child => $value) {
             if (0 == $value || 0.5 == $value) {
                 $uncovered[] = $child;
             } elseif (-1 == $value) {
                 $inprogress[] = $child;
             } else {
                 $already[] = $child;
             }
         }
         if (empty($uncovered)) {
             if (empty($already)) {
                 $rand = $inprogress[rand(0, count($inprogress) - 1)];
             } else {
                 $rand = $already[rand(0, count($already) - 1)];
             }
             $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), $this->_coveredRules, $this->_todo);
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), $rand);
             if ($this->_rules[$content] instanceof Compiler\Llk\Rule\Token) {
                 for ($i = 0; $i < $rand; ++$i) {
                     $this->_todo[] = new Compiler\Llk\Rule\Entry($content, $this->_coveredRules, $this->_todo);
                 }
             } else {
                 $sequence = $this->extract([$content]);
                 if (null === $sequence) {
                     return null;
                 }
                 for ($i = 0; $i < $rand; ++$i) {
                     foreach ($sequence as $seq) {
                         $this->_trace[] = $seq;
                         if ($seq instanceof Compiler\Llk\Rule\Ekzit) {
                             $this->updateCoverage($seq);
                         }
                     }
                 }
             }
         } else {
             $rand = $uncovered[rand(0, count($uncovered) - 1)];
             $this->_coveredRules[$rule->getName()][$rand] = -1;
             $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), $this->_coveredRules, $this->_todo);
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), $rand);
             for ($i = 0; $i < $rand; ++$i) {
                 $this->_todo[] = new Compiler\Llk\Rule\Entry($content, $this->_coveredRules, $this->_todo);
             }
         }
         return true;
     } elseif ($rule instanceof Compiler\Llk\Rule\Choice) {
         $uncovered = [];
         $inprogress = [];
         $already = [];
         foreach ($this->_coveredRules[$rule->getName()] as $child => $value) {
             if (0 == $value || 0.5 == $value) {
                 $uncovered[] = $child;
             } elseif (-1 == $value) {
                 $inprogress[] = $child;
             } else {
                 $already[] = $child;
             }
         }
         if (empty($uncovered)) {
             $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), $this->_coveredRules, $this->_todo);
             $sequence = $this->extract($content);
             if (null === $sequence) {
                 return null;
             }
             foreach ($sequence as $seq) {
                 $this->_trace[] = $seq;
                 if ($seq instanceof Compiler\Llk\Rule\Ekzit) {
                     $this->updateCoverage($seq);
                 }
             }
             if (empty($already)) {
                 $rand = $inprogress[rand(0, count($inprogress) - 1)];
             } else {
                 $rand = $already[rand(0, count($already) - 1)];
             }
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), $rand);
         } else {
             $rand = $uncovered[rand(0, count($uncovered) - 1)];
             $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), $this->_coveredRules, $this->_todo);
             $this->_coveredRules[$rule->getName()][$rand] = -1;
             $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), $rand);
             $this->_todo[] = new Compiler\Llk\Rule\Entry($content[$rand], $this->_coveredRules, $this->_todo);
         }
         return true;
     } elseif ($rule instanceof Compiler\Llk\Rule\Concatenation) {
         $this->_coveredRules[$rule->getName()][0] = -1;
         $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), false);
         $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), false);
         for ($i = count($content) - 1; $i >= 0; --$i) {
             $this->_todo[] = new Compiler\Llk\Rule\Entry($content[$i], false, $this->_todo);
         }
         return true;
     } elseif ($rule instanceof Compiler\Llk\Rule\Token) {
         $this->_trace[] = new Compiler\Llk\Rule\Entry($rule->getName(), false);
         $this->_trace[] = $rule;
         $this->_todo[] = new Compiler\Llk\Rule\Ekzit($rule->getName(), false);
         return true;
     }
     return false;
 }