def cfg_to_text(cfg: CFG) -> str: """Turns a context-free grammar [1]_ into its text representation. Parameters ---------- cfg : CFG Context-free grammar. Examples -------- >>> import cfpq_data >>> cfg = cfpq_data.cfg_from_text("S -> a S b S") >>> cfpq_data.cfg_to_text(cfg) 'S -> a S b S\\n' Returns ------- text : str Context-free grammar text representation. References ---------- .. [1] https://en.wikipedia.org/wiki/Context-free_grammar#Formal_definitions """ return cfg.to_text()
def change_terminals_in_cfg(cfg: CFG, spec: Dict[str, str]) -> CFG: """Change terminals of a context-free grammar [1]_. Parameters ---------- cfg : CFG Context-free grammar. spec: Dict Terminals mapping. Examples -------- >>> import cfpq_data >>> cfg = cfpq_data.cfg_from_text("S -> a S b S") >>> new_cfg = cfpq_data.change_terminals_in_cfg(cfg, {"a": "b", "b": "c"}) >>> new_cfg.to_text() 'S -> b S c S\\n' Returns ------- cfg : CFG Context-free grammar with changed terminals. References ---------- .. [1] https://en.wikipedia.org/wiki/Context-free_grammar#Formal_definitions """ regex = re.compile("|".join(map(re.escape, spec.keys()))) text = regex.sub(lambda match: spec[match.group(0)], cfg.to_text()) return cfg_from_text(text)
def from_cfg(cls, cfg: CFG): """ Build RSA from a given cfpq_data context-free grammar @param cfg: CFG on which RSA is built @return: initialized class """ grammar = cfg.to_text() productions = dict() for line in grammar.split("\n")[:-1]: part_line = line.split(" -> ") right = part_line[1] if right == "": right = "epsilon" if part_line[0] in productions: productions[part_line[0]] += " | " + right else: productions[part_line[0]] = right grammar_new = "" for nonterminal in productions: grammar_new += nonterminal + " -> " + productions[nonterminal] + "\n" grammar_new = grammar_new[:-1] return RecursiveAutomaton.from_rsm(rsm_from_text(grammar_new))
def cfg_from_cnf(cnf: CFG) -> CFG: """Create a context-free grammar [2]_ from given context-free grammar in Chomsky normal form [1]_. Parameters ---------- cnf : CFG Context free grammar in Chomsky normal form. Examples -------- >>> import cfpq_data >>> cnf = cfpq_data.cnf_from_text("S -> a S b S | epsilon") >>> cfg = cfpq_data.cfg_from_cnf(cnf) >>> [cfg.contains(word) for word in ["", "ab", "aabb"]] [True, True, True] Returns ------- cfg : CFG Context-free grammar. References ---------- .. [1] https://en.wikipedia.org/wiki/Chomsky_normal_form .. [2] https://en.wikipedia.org/wiki/Context-free_grammar#Formal_definitions """ return CFG.from_text(cnf.to_text(), cnf.start_symbol)
def rsm_from_cnf(cnf: CFG) -> RSM: """Create a Recursive State Machine [2]_ from context-free grammar in Chomsky normal form [1]_. Parameters ---------- cnf : CFG Context-free grammar in Chomsky normal form. Examples -------- >>> import cfpq_data >>> cnf = cfpq_data.cnf_from_text("S -> a S b S | epsilon") >>> rsm = cfpq_data.rsm_from_cnf(cnf) >>> [rsm.contains(word) for word in ["", "ab", "aabb"]] [True, True, True] Returns ------- rsm : RSM Recursive State Machine. References ---------- .. [1] https://en.wikipedia.org/wiki/Chomsky_normal_form .. [2] Alur R., Etessami K., Yannakakis M. (2001) Analysis of Recursive State Machines. In: Berry G., Comon H., Finkel A. (eds) Computer Aided Verification. CAV 2001. Lecture Notes in Computer Science, vol 2102. Springer, Berlin, Heidelberg. https://doi.org/10.1007/3-540-44585-4_18 """ return rsm_from_text(cnf.to_text(), cnf.start_symbol)
def cnf_to_text(cnf: CFG) -> str: """Turns a context-free grammar in Chomsky normal form [1]_ into its text representation. Parameters ---------- cnf : CFG Context-free grammar in Chomsky normal form. Examples -------- >>> import cfpq_data >>> cnf = cfpq_data.cnf_from_text("S -> a") >>> cfpq_data.cnf_to_text(cnf) 'S -> a\\n' Returns ------- text : str Context-free grammar in Chomsky normal form text representation. References ---------- .. [1] https://en.wikipedia.org/wiki/Chomsky_normal_form """ return cnf.to_text()
def from_cfg(cls, cfg: CFG): """ Create a recursive automaton from context-free grammar Parameters ----------- cfg : :class:`~pyformlang.cfg.CFG` The context-free grammar Returns ----------- rsa : :class:`~pyformlang.rsa.RecursiveAutomaton` The new recursive automaton built from context-free grammar """ initial_label = to_symbol(cfg.start_symbol) grammar_in_true_format = remove_repetition_of_nonterminals_from_productions( cfg.to_text()) boxes = set() labels = set() notation_for_epsilon = Epsilon().to_text() for production in grammar_in_true_format.splitlines(): head, body = production.split(" -> ") labels.add(to_symbol(head)) if body == "": body = notation_for_epsilon boxes.add( Box(Regex(body).to_epsilon_nfa().minimize(), to_symbol(head))) return RecursiveAutomaton(labels, initial_label, boxes)
def change_terminals_in_cnf(cnf: CFG, spec: Dict[str, str]) -> CFG: """Change terminals of a context-free grammar [1]_ in Chomsky normal form. Parameters ---------- cnf : CFG Context-free grammar in Chomsky normal form. spec: Dict Terminals mapping. Examples -------- >>> import cfpq_data >>> cnf = cfpq_data.cnf_from_text("S -> a S b S | epsilon") >>> new_cnf = cfpq_data.change_terminals_in_cnf(cnf, {"a": "b", "b": "c"}) >>> [new_cnf.contains(word) for word in ["", "bc", "bbcc"]] [True, True, True] Returns ------- cnf : CFG Context-free grammar in Chomsky normal form with changed terminals. References ---------- .. [1] https://en.wikipedia.org/wiki/Chomsky_normal_form """ regex = re.compile("|".join(map(re.escape, spec.keys()))) text = regex.sub(lambda match: spec[match.group(0)], cnf.to_text()) return cnf_from_text(text)