/** * 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; }
/** * 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; }