Loading grammars_cfg.py +39 −28 Original line number Diff line number Diff line Loading @@ -529,7 +529,7 @@ class CFG: return word if full_cmp_cnt is None: full_cmp_cnt = pow(2, 12) full_cmp_cnt = pow(2, 16) if max_cmp_len is None: max_cmp_len = min(max(pow(2, len(left.nonterminals) + 1), Loading Loading @@ -764,8 +764,10 @@ class WordGenerator: def __init__(self, cfg: CFG): self.cfg = cfg.cnf() self.seen: Set[CFG.Symbols] = set() self.queue: Deque[CFG.Symbols] = deque([(self.cfg.init,)]) self._seen: Set[CFG.Symbols] = set() self._stack: List[CFG.Symbols] = [(self.cfg.init,)] self._cur_lenght = 1 self._next_length: Optional[int] = 2 self.last: Optional[CFG.Word] = None \ if Eps() not in self.cfg.rules.get(self.cfg.init, []) \ else () Loading @@ -781,20 +783,21 @@ class WordGenerator: return self.last def _next(self) -> Optional[CFG.Word]: # Walk in BFS order so the the sentences are explored from shorter # to longer for CNF. # As we yield a word immediatelly on finding it between the sentences # (i.e., when we find a sentence with no nonterminals), we also yield # words from shorter to longer for CNF grammars (because a word of # length N needs exactly N + (N - 1) derivations in CNF and therefore # shorter words preceed longer once in BFS order. while self.queue: sentence = self.queue.popleft() if sentence in self.seen: # Iterative-Deepening DFS (as a generator) while self._stack or self._next_length is not None: while self._stack: sentence = self._stack.pop() if len(sentence) > self._cur_lenght: # cutoff self._next_length = len(sentence) \ if self._next_length is None \ else min(self._next_length, len(sentence)) continue self.seen.add(sentence) if sentence in self._seen: continue self._seen.add(sentence) if CFG.all_terminal(sentence): if len(sentence) == self._cur_lenght: self.last = typing.cast(CFG.Word, sentence) return self.last else: Loading @@ -805,6 +808,14 @@ class WordGenerator: if isinstance(p, Eps): continue new_sentence = sentence[:i] + p + sentence[i + 1:] self.queue.append(new_sentence) self._stack.append(new_sentence) break # it suffices to perform left derivations if self._next_length is not None \ and self._next_length > self._cur_lenght: self._cur_lenght = self._next_length self._next_length = None self._stack = [(self.cfg.init,)] self._seen = set() return None Loading
grammars_cfg.py +39 −28 Original line number Diff line number Diff line Loading @@ -529,7 +529,7 @@ class CFG: return word if full_cmp_cnt is None: full_cmp_cnt = pow(2, 12) full_cmp_cnt = pow(2, 16) if max_cmp_len is None: max_cmp_len = min(max(pow(2, len(left.nonterminals) + 1), Loading Loading @@ -764,8 +764,10 @@ class WordGenerator: def __init__(self, cfg: CFG): self.cfg = cfg.cnf() self.seen: Set[CFG.Symbols] = set() self.queue: Deque[CFG.Symbols] = deque([(self.cfg.init,)]) self._seen: Set[CFG.Symbols] = set() self._stack: List[CFG.Symbols] = [(self.cfg.init,)] self._cur_lenght = 1 self._next_length: Optional[int] = 2 self.last: Optional[CFG.Word] = None \ if Eps() not in self.cfg.rules.get(self.cfg.init, []) \ else () Loading @@ -781,20 +783,21 @@ class WordGenerator: return self.last def _next(self) -> Optional[CFG.Word]: # Walk in BFS order so the the sentences are explored from shorter # to longer for CNF. # As we yield a word immediatelly on finding it between the sentences # (i.e., when we find a sentence with no nonterminals), we also yield # words from shorter to longer for CNF grammars (because a word of # length N needs exactly N + (N - 1) derivations in CNF and therefore # shorter words preceed longer once in BFS order. while self.queue: sentence = self.queue.popleft() if sentence in self.seen: # Iterative-Deepening DFS (as a generator) while self._stack or self._next_length is not None: while self._stack: sentence = self._stack.pop() if len(sentence) > self._cur_lenght: # cutoff self._next_length = len(sentence) \ if self._next_length is None \ else min(self._next_length, len(sentence)) continue self.seen.add(sentence) if sentence in self._seen: continue self._seen.add(sentence) if CFG.all_terminal(sentence): if len(sentence) == self._cur_lenght: self.last = typing.cast(CFG.Word, sentence) return self.last else: Loading @@ -805,6 +808,14 @@ class WordGenerator: if isinstance(p, Eps): continue new_sentence = sentence[:i] + p + sentence[i + 1:] self.queue.append(new_sentence) self._stack.append(new_sentence) break # it suffices to perform left derivations if self._next_length is not None \ and self._next_length > self._cur_lenght: self._cur_lenght = self._next_length self._next_length = None self._stack = [(self.cfg.init,)] self._seen = set() return None