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