/**
  * 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;
 }
Exemple #2
0
 /**
  * Recursive method applied to our problematic.
  *
  * @param   \Hoa\Compiler\Llk\Rule  $rule    Rule to start.
  * @param   int                     $n       Size.
  * @return  int
  */
 public function count(Compiler\Llk\Rule $rule = null, $n = -1)
 {
     if (null === $rule || -1 === $n) {
         return 0;
     }
     $ruleName = $rule->getName();
     if (isset($this->_data[$ruleName][$n])) {
         return $this->_data[$ruleName][$n]['n'];
     }
     $this->_data[$ruleName][$n] = ['n' => 0];
     $out =& $this->_data[$ruleName][$n]['n'];
     $rule = $this->_rules[$ruleName];
     if ($rule instanceof Compiler\Llk\Rule\Choice) {
         foreach ($rule->getContent() as $child) {
             $out += $this->count($this->_rules[$child], $n);
         }
     } elseif ($rule instanceof Compiler\Llk\Rule\Concatenation) {
         $children = $rule->getContent();
         $Γ = new Math\Combinatorics\Combination\Gamma(count($children), $n);
         $this->_data[$ruleName][$n]['Γ'] = [];
         $handle =& $this->_data[$ruleName][$n]['Γ'];
         foreach ($Γ as $γ) {
             $oout = 1;
             foreach ($γ as $α => $_γ) {
                 $oout *= $this->count($this->_rules[$children[$α]], $_γ);
             }
             if (0 !== $oout) {
                 $handle[] = $γ;
             }
             $out += $oout;
         }
     } elseif ($rule instanceof Compiler\Llk\Rule\Repetition) {
         $this->_data[$ruleName][$n]['xy'] = [];
         $handle =& $this->_data[$ruleName][$n]['xy'];
         $child = $this->_rules[$rule->getContent()];
         $x = $rule->getMin();
         $y = $rule->getMax();
         if (-1 === $y) {
             $y = $n;
         } else {
             $y = min($n, $y);
         }
         if (0 === $x && $x === $y) {
             $out = 1;
         } else {
             for ($α = $x; $α <= $y; ++$α) {
                 $ut = 0;
                 $handle[$α] = ['n' => 0, 'Γ' => []];
                 $Γ = new Math\Combinatorics\Combination\Gamma($α, $n);
                 foreach ($Γ as $γ) {
                     $oout = 1;
                     foreach ($γ as $β => $_γ) {
                         $oout *= $this->count($child, $_γ);
                     }
                     if (0 !== $oout) {
                         $handle[$α]['Γ'][] = $γ;
                     }
                     $ut += $oout;
                 }
                 $handle[$α]['n'] = $ut;
                 $out += $ut;
             }
         }
     } elseif ($rule instanceof Compiler\Llk\Rule\Token) {
         $out = Math\Util::δ($n, 1);
     }
     return $out;
 }
Exemple #3
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;
 }