def fix_non_derive_terminal(gramm:Grammar,return_derivations = False,left_derivation = True): """ Remove from gramm the non terminals A that dont satisfy:\n A->*w where w in {G.T}* return grammar return grammar,derivation """ gramm = gramm.copy() derivation = { x:[Production(x,Sentence(x)),] for x in gramm.terminals } derivation[gramm.Epsilon] = [Production(gramm.Epsilon,Sentence(gramm.Epsilon)),] derive_something = set(gramm.terminals) productions = set(gramm.Productions) change = -1 while change != len(derive_something): change = len(derive_something) to_remove = [] for x in productions: if not any([y for y in x.Right if not y in derive_something]): # if y ->* w with w in T* derive_something.add(x.Left) update_derivation(x,derivation,left_derivation) to_remove.append(x) for x in to_remove: productions.remove(x) remove_unnecessary_symbols(gramm,[x for x in gramm.nonTerminals if x not in derive_something]) if return_derivations: return gramm,derivation return gramm
def fix_left_recursion(grammar:Grammar, errors): ''' Fix immediate left recursion of grammar\n return a fixed copy of grammar ''' new_grammar = grammar.copy() new_grammar.Productions = [] for n_ter in grammar.nonTerminals: for prod in n_ter.productions: if not prod.Right.IsEpsilon and prod.Right[0] == prod.Left: fix_non_terminal_left_recursion(n_ter,new_grammar, errors) break else: new_grammar.Productions.extend(n_ter.productions) return new_grammar
def fix_unreachable_symbols(gramm:Grammar): gramm = gramm.copy() pending = [gramm.startSymbol] reachable = set(pending) while pending: symb = pending.pop() for prod in symb.productions: for r in prod.Right: if not r in reachable: reachable.add(r) if isinstance(r,NonTerminal): pending.append(r) remove_unnecessary_symbols(gramm,[x for x in gramm.nonTerminals + gramm.terminals if x not in reachable]) return gramm
def fix_common_prefix(grammar:Grammar): """ returns a copy of grammar without common prefixes """ G = grammar.copy() G.Productions = [] for non_terminal in grammar.nonTerminals: trie = Trie() epsilon = False for x in non_terminal.productions: if not x.Right.IsEpsilon: trie.add(x.Right) else: epsilon = True non_terminal.productions = [] if epsilon: G.Add_Production(Production(x.Left,G.Epsilon)) for node in trie.top.sons: execute_node(trie.top.sons[node],non_terminal,[],G,0) return G
def fix_unit_productions(gramm:Grammar): """ returns an equivalent grammar without productions of the form:\n A -> B """ gramm = gramm.copy() unit_productions = {x for x in gramm.Productions if len(x.Right) == 1 and x.Right[0].IsNonTerminal} new_productions = set() for x in gramm.Productions: if not x in unit_productions: new_productions.add(x) pending = get_unit_tuples(unit_productions) while pending: l,r = pending.pop() for prod in r.productions: if not prod in unit_productions: new_productions.add(Production(l,prod.Right)) return change_grammar_from_productions(gramm,new_productions)