def __remove_epsilon_productions(grammar): S, d = grammar_to_graph(grammar) nonterminals = [t.name for t in grammar.nonterminals] nullable = {} nullable = __find_nullable_nonterminals(d, nullable, S, nonterminals) for key, value in d.items(): new_value = [v for v in value] for sentence in value: if sentence == []: new_value.remove(sentence) for i in range(0, len(sentence)): if sentence[i] in nonterminals and nullable[sentence[i]]: new_sentence = sentence[0:i] + sentence[i + 1:len(sentence)] if not new_sentence in new_value: new_value.append(new_sentence) d[key] = new_value if nullable[S]: d[S].append([]) return graph_to_grammar(S, d)
def remove_left_recursion(grammar): new_grammar = __remove_epsilon_productions(grammar) new_grammar = remove_unit_prods(new_grammar) nonterminals = [t.name for t in new_grammar.nonterminals] S, d = grammar_to_graph(new_grammar) for i in range(0, len(nonterminals)): for j in range(0, i): for sentence in d[nonterminals[i]]: if sentence[0] == nonterminals[j]: d[nonterminals[i]].remove(sentence) remove_first = sentence[1:len(sentence)] for sentence in d[nonterminals[j]]: new_sentence = [] for item in sentence: new_sentence.append(item) for item in remove_first: new_sentence.append(item) d[nonterminals[i]].append(new_sentence) d = __remove_inmediate_left_recursion(d) return graph_to_grammar(S, d)
def remove_unit_prods(G: Grammar): S, d = grammar_to_graph(G) nonterminals = [t.name for t in G.nonterminals] new_d = {} u = __find_unitary_pairs(d, nonterminals) for pair in u: for sentence in d[pair[1]]: if not (len(sentence) == 1 and sentence[0] in nonterminals): try: if not sentence in new_d[pair[0]]: new_d[pair[0]].append(sentence) except KeyError: new_d[pair[0]] = [sentence] return graph_to_grammar(S, new_d)
def remove_unreachable_prods(G: Grammar): S, d = grammar_to_graph(G) nonterminals = [t.name for t in G.nonterminals] mark = {} for p in d.keys(): mark[p[0]] = False __overlook(d, mark, nonterminals, S) for t in nonterminals: if not mark[t]: _ = d.pop(t) return graph_to_grammar(S, d)
def remove_common_prefixes(grammar: Grammar): S, d = grammar_to_graph(grammar) nonterminals = [nt.name for nt in grammar.nonterminals] for A in nonterminals: try: _ = d[A] except KeyError: continue count = 1 trie = Trie((A, d[A])) prefix_nodes = [n for n in trie.prefix_nodes] prefix_nodes.sort(key=lambda x: x.depth, reverse=True) for (n) in ( prefix_nodes ): # get the longest common prefix among the productions be the prefix α productions = trie.get_node_productions( n) # get all the productions with that prefix n.children.clear() # A -> α ω1 | α ω2 | ... | α ωΝ # replace those productions with # A -> αA' # A' -> ω1 | ω2 | ... | ωΝ A_new = A + ("'" * count) count += 1 d[A] = [productions[0][0:n.depth + 1] + [A_new]] n.productions = [d[A][-1]] for p in productions: if len(p) > n.depth + 1: try: d[A_new].append(p[n.depth + 1:]) except KeyError: d[A_new] = [p[n.depth + 1:]] else: try: d[A_new].append([]) except KeyError: d[A_new] = [[]] print(d) return graph_to_grammar(S, d)