def test_generating_object(self): """ Test the finding of CFGObject """ var_a = Variable("A") var_b = Variable("B") ter_a = Terminal("a") ter_b = Terminal("b") start = Variable("S") prod0 = Production(start, [var_a, var_b]) prod1 = Production(start, [ter_a]) prod2 = Production(var_a, [ter_b]) cfg = CFG({var_a, var_b, start}, {ter_a, ter_b}, start, {prod0, prod1, prod2}) self.assertEqual(len(cfg.variables), 3) self.assertEqual(len(cfg.terminals), 2) self.assertEqual(len(cfg.productions), 3) self.assertEqual(cfg.get_generating_symbols(), {var_a, ter_a, ter_b, start}) prod3 = Production(var_b, [Epsilon()]) cfg = CFG({var_a, var_b, start}, {ter_a, ter_b}, start, {prod0, prod1, prod2, prod3}) self.assertEqual(len(cfg.variables), 3) self.assertEqual(len(cfg.terminals), 2) self.assertEqual(len(cfg.productions), 4) self.assertEqual(cfg.get_generating_symbols(), {var_a, var_b, ter_a, ter_b, start})
def part2(): rules, words = open("in.txt").read().split("\n\n") rules = rules.replace("8: 42", "8: 42 | 42 8") rules = rules.replace("11: 42 31", "11: 42 31 | 42 11 31") variables = set() productions = set() terminals = set() for line in rules.split("\n"): left, right = line.split(":") left = Variable(left) variables.add(left) for expression in right.split("|"): if '"' in expression: # Terminal expression expression = expression.strip('" ') right = [Terminal(expression)] terminals.add(Terminal(expression)) productions.add(Production(left, right)) else: right = [ Variable(token) for token in expression.strip().split() ] productions.add(Production(left, right)) cfg = CFG(variables, terminals, Variable("0"), productions) count = sum(map(lambda x: 1 if cfg.contains(x) else 0, words.split("\n"))) print(count)
def test_get_first_set2(self): # Example from: # https://www.geeksforgeeks.org/first-set-in-syntax-analysis/ text = """ S -> A C B | C b b | B a A -> d a | B C B -> g | Є C -> h | Є """ cfg = CFG.from_text(text) llone_parser = LLOneParser(cfg) first_set = llone_parser.get_first_set() self.assertEqual(first_set[Variable("S")], {Terminal(x) for x in {"d", "g", "h", "b", "a"} }.union({Epsilon()})) self.assertEqual(first_set[Variable("A")], {Terminal(x) for x in {"d", "g", "h"}}.union({Epsilon()})) self.assertEqual(first_set[Variable("B")], {Terminal(x) for x in {"g"}}.union({Epsilon()})) self.assertEqual(first_set[Variable("C")], {Terminal(x) for x in {"h"}}.union({Epsilon()}))
def test_generation_words(self): """ Tests the generation of word """ ter_a = Terminal("a") ter_b = Terminal("b") var_s = Variable("S") productions = { Production(var_s, [ter_a, var_s, ter_b]), Production(var_s, []) } cfg = CFG(productions=productions, start_symbol=var_s) words0 = list(cfg.get_words(max_length=0)) self.assertIn([], words0) self.assertEqual(len(words0), 1) words1 = list(cfg.get_words(max_length=1)) self.assertIn([], words1) self.assertEqual(len(words1), 1) words2 = list(cfg.get_words(max_length=2)) self.assertIn([], words2) self.assertIn([ter_a, ter_b], words2) self.assertEqual(len(words2), 2) words3 = list(cfg.get_words(max_length=3)) self.assertIn([], words3) self.assertIn([ter_a, ter_b], words3) self.assertEqual(len(words3), 2) words4 = list(cfg.get_words(max_length=4)) self.assertIn([], words4) self.assertIn([ter_a, ter_a, ter_b, ter_b], words4) self.assertEqual(len(words4), 3)
def hellings(g: LabelGraph, gr: WeakCNF): result = LabelGraph(g.size) for variable in gr.variables: result.dict[variable] = Matrix.sparse(BOOL, g.size, g.size) for label in g.labels: result[Terminal(label)] = g[label].dup() for i, j, _ in zip(*result[Terminal(label)].select(lib.GxB_NONZERO).to_lists()): for production in gr.productions: if len(production.body) == 1 and production.body[0] == Terminal(label): head = production.head result.dict[head][i, j] = True if gr.generate_epsilon(): for i in range(g.size): result.dict[gr.start_symbol][i, i] = True changing = True while changing: changing = False for p in gr.productions: if len(p.body) == 2: for i, k in zip(*result.dict[p.body[0]].select(lib.GxB_NONZERO).to_lists()[:2]): for l, j in zip(*result.dict[p.body[1]].select(lib.GxB_NONZERO).to_lists()[:2]): if k == l: if (i, j) not in zip(*result.dict[p.head].select(lib.GxB_NONZERO).to_lists()[:2]): changing = True result.dict[p.head][i, j] = True return set(zip(*result.dict[gr.start_symbol].to_lists()[:2]))
def test_intersection_dfa2(self): state0 = State(0) symb_a = Symbol("a") symb_b = Symbol("b") dfa = DeterministicFiniteAutomaton({state0}, {symb_a, symb_b}, start_state=state0, final_states={state0}) dfa.add_transition(state0, symb_a, state0) dfa.add_transition(state0, symb_b, state0) self.assertTrue(dfa.accepts([symb_a, symb_a, symb_b, symb_b])) ter_a = Terminal("a") ter_b = Terminal("b") var_s = Variable("S") var_s1 = Variable("S1") var_l = Variable("L") productions = { Production(var_s, [var_l, var_s1]), Production(var_l, [Epsilon()]), Production(var_s1, [ter_a, var_s1, ter_b]), Production(var_s1, [ter_b, var_s1, ter_a]), Production(var_s1, []) } cfg = CFG(productions=productions, start_symbol=var_s) self.assertTrue(cfg.contains([ter_a, ter_a, ter_b, ter_b])) self.assertFalse(cfg.contains([ter_a, ter_a, ter_b])) cfg_i = cfg.intersection(dfa) self.assertFalse(cfg_i.is_empty()) self.assertTrue(cfg_i.contains([ter_a, ter_a, ter_b, ter_b])) self.assertTrue(cfg_i.contains([]))
def _test_profiling_intersection(self): size = 50 states = [State(i) for i in range(size * 2 + 1)] symb_a = Symbol("a") symb_b = Symbol("b") dfa = DeterministicFiniteAutomaton(states, {symb_a, symb_b}, start_state=states[0], final_states={states[-1]}) for i in range(size): dfa.add_transition(states[i], symb_a, states[i + 1]) for i in range(size, size * 2): dfa.add_transition(states[i], symb_b, states[i + 1]) ter_a = Terminal("a") ter_b = Terminal("b") var_s = Variable("S") var_s1 = Variable("S1") var_l = Variable("L") productions = [ Production(var_s, [var_l, var_s1]), Production(var_l, [Epsilon()]), Production(var_s1, [ter_a, var_s1, ter_b]), Production(var_s1, [ter_b, var_s1, ter_a]), Production(var_s1, []) ] cfg = CFG(productions=productions, start_symbol=var_s) cfg_i = cfg.intersection(dfa) self.assertFalse(cfg_i.is_empty()) self.assertTrue(cfg_i.contains([ter_a] * size + [ter_b] * size)) self.assertFalse(cfg_i.contains([]))
def part2(file='input_test.txt'): rules, messages = get_input(file) # 8: 42 | 42 8 # 11: 42 31 | 42 11 31 rules['8'] = '42 | 42 8' rules['11'] = '42 31 | 42 11 31' rule_variables = set() rule_products = set() for rule in rules: subs = rules[rule].split(' | ') rule_variables.add(Variable(rule)) for sub in subs: if sub == '"a"' or sub == '"b"': rule_products.add( Production(Variable(rule), [Terminal(sub.replace('"', ''))])) else: rule_products.add( Production(Variable(rule), [Variable(x) for x in sub.split(' ')])) cfg = CFG(rule_variables, {Terminal('a'), Terminal('b')}, Variable('0'), rule_products) count = 0 for message in messages: if cfg.contains(message): count += 1 print('Part 2: Solution {}'.format(count))
def cyk(config: Config) -> bool: word = config['word'] query = config['pretty_cnf_query'] if word == '': return query.generate_epsilon for char in word: if Terminal(char) not in query.terminals: return False len_word = len(word) dp: MyMatrix = MyMatrix({ V: Matrix.sparse(types.BOOL, len_word, len_word) for V in query.variables }) for i, char in enumerate(word): term = Terminal(char) for V in query.simple_antiproductions[term]: dp[i, i, V] = True for m in range(1, len_word): for i in range(len_word - m): j = i + m for A in query.variables: flag = False for B, C in query.complex_productions.get(A, set()): for k in range(i, j): if dp[i, k, B] and dp[k + 1, j, C]: dp[i, j, A] = True flag = True break if flag: break return dp[0, len_word - 1, query.start_symbol]
def test_get_llone_table(self): # Example from: # https://www.geeksforgeeks.org/construction-of-ll1-parsing-table/ text = """ E -> T E’ E’ -> + T E’ | Є T -> F T’ T’ -> * F T’ | Є F -> ( E ) | id """ cfg = CFG.from_text(text, start_symbol="E") llone_parser = LLOneParser(cfg) parsing_table = llone_parser.get_llone_parsing_table() self.assertEqual( len( parsing_table.get(Variable("E"), dict()).get(Terminal("id"), [])), 1) self.assertEqual( len( parsing_table.get(Variable("E"), dict()).get(Terminal("+"), [])), 0) self.assertEqual( len( parsing_table.get(Variable("T’"), dict()).get(Terminal(")"), [])), 1) self.assertEqual( len( parsing_table.get(Variable("F"), dict()).get(Terminal("("), [])), 1) self.assertEqual( len( parsing_table.get(Variable("F"), dict()).get(Terminal("id"), [])), 1)
def test_intersection(self): """ Tests the intersection with a regex """ regex = Regex("a*b*") dfa = regex.to_epsilon_nfa() symb_a = Symbol("a") symb_b = Symbol("b") self.assertTrue(dfa.accepts([symb_a, symb_a, symb_b, symb_b])) self.assertFalse(dfa.accepts([symb_b, symb_b, symb_a])) ter_a = Terminal("a") ter_b = Terminal("b") var_s = Variable("S") productions = { Production(var_s, [ter_a, var_s, ter_b]), Production(var_s, [ter_b, var_s, ter_a]), Production(var_s, []) } cfg = CFG(productions=productions, start_symbol=var_s) self.assertTrue(cfg.contains([ter_a, ter_a, ter_b, ter_b])) self.assertFalse(cfg.contains([ter_a, ter_a, ter_b])) cfg_i = cfg.intersection(regex) self.assertTrue(cfg_i.contains([ter_a, ter_a, ter_b, ter_b])) self.assertFalse(cfg_i.contains([ter_a, ter_a, ter_b])) self.assertTrue(cfg_i.contains([])) cfg_i = cfg.intersection(dfa) self.assertTrue(cfg_i.contains([ter_a, ter_a, ter_b, ter_b])) self.assertFalse(cfg_i.contains([ter_a, ter_a, ter_b])) self.assertTrue(cfg_i.contains([]))
def test_pda_conversion(self): """ Tests conversions from a PDA """ state_p = State("p") state_q = State("q") state_a = Symbol("a") state_b = Symbol("b") state_c = Symbol("c") terminal_a = Terminal("a") terminal_b = Terminal("b") terminal_c = Terminal("c") stack_symbol_a = StackSymbol("a") stack_symbol_b = StackSymbol("b") stack_symbol_c = StackSymbol("c") stack_symbol_x0 = StackSymbol("X0") pda = PDA(states={state_p, state_q}, input_symbols={state_a, state_b, state_c}, stack_alphabet={ stack_symbol_a, stack_symbol_b, stack_symbol_c, stack_symbol_x0 }, start_state=state_p, start_stack_symbol=stack_symbol_x0, final_states={state_q}) pda.add_transition(state_p, Epsilon(), stack_symbol_x0, state_q, []) pda.add_transition( state_p, Epsilon(), stack_symbol_x0, state_p, [stack_symbol_a, stack_symbol_b, stack_symbol_c, stack_symbol_x0]) pda.add_transition(state_p, state_a, stack_symbol_a, state_p, []) pda.add_transition(state_p, state_b, stack_symbol_b, state_p, []) pda.add_transition(state_p, state_c, stack_symbol_c, state_p, []) cfg = pda.to_empty_stack().to_cfg() self.assertTrue(cfg.contains([])) self.assertTrue(cfg.contains([terminal_a, terminal_b, terminal_c])) self.assertFalse(cfg.contains([terminal_c, terminal_b, terminal_a]))
def test_derivation_does_not_exist(self): var_s = Variable("S") ter_a = Terminal("a") ter_b = Terminal("b") cfg = CFG(productions=[], start_symbol=var_s) with self.assertRaises(DerivationDoesNotExist): parse_tree = cfg.get_cnf_parse_tree([ter_a, ter_b]) parse_tree.get_rightmost_derivation()
def cyk(self, words, tokens=dict()): word_size = sum([ 1 if word in tokens.keys() else len(word) for word in words.split() ]) if word_size == 0: return self.eps cfg = self.cnf productions = cfg.productions cyk_table = [[set() for _ in range(word_size)] for _ in range(word_size)] shift = 0 for word in words.split(): if word in tokens.keys(): for production in productions: if len(production.body) == 1 \ and production.body[0] == Terminal(tokens[word]): cyk_table[shift][shift].add(production.head) shift += 1 else: for index, letter in enumerate(word): for production in productions: if len(production.body) == 1 \ and production.body[0] == Terminal(letter): cyk_table[shift + index][shift + index].add( production.head) shift += len(word) productions_len_2 = [ prod for prod in productions if len(prod.body) == 2 ] for level in range(1, word_size): for production_index in range(word_size - level): row = production_index column = level + production_index for col_new in range(row, column): row_new = col_new + 1 body_left = cyk_table[row][col_new] body_right = cyk_table[row_new][column] for production in productions_len_2: if production.body[0] in body_left \ and production.body[1] in body_right: cyk_table[row][column].add(production.head) start_symbol_table = cyk_table[0][word_size - 1] if len(start_symbol_table) != 0: return cfg.start_symbol in start_symbol_table return False
def cfg_obj_to_pretty(cfg_obj: Union[Variable, Terminal]): if isinstance(cfg_obj, Variable): return Variable(cfg_obj.value[2:]) elif isinstance(cfg_obj, Terminal): if cfg_obj.value == 't_newline': return Terminal('\n') if cfg_obj.value == 't_escape': return Terminal('\\') return Terminal(cls._from_pretty_term(cfg_obj.value))
def process_l(self, word, query, non_terminal): parse_tree = ParseTree(Variable(non_terminal)) parse_tree.sons.append(ParseTree(Terminal(non_terminal[1:]))) parse_tree.sons.append( self.construct_parse_tree( word[1:-1], query, "B" + utils.get_inverse_relation(non_terminal[1:]))) parse_tree.sons.append( ParseTree(Terminal(utils.get_inverse_relation(non_terminal[1:])))) return parse_tree
def get_lex(word): lexems = [] for lex in word.split(): if lex in KEYWORDS: lexems.append(Terminal(lex)) else: # Encountered string or int lexems.extend([Terminal(sym) for sym in lex]) return lexems
def test_emptiness(self): """ Tests the emptiness of a CFG """ # pylint: disable=too-many-locals var_s = Variable("S") ter_a = Terminal("a") ter_b = Terminal("b") prod0 = Production(var_s, [ter_a, var_s, ter_b]) prod1 = Production(var_s, []) cfg = CFG({var_s}, {ter_a, ter_b}, var_s, {prod0, prod1}) self.assertFalse(cfg.is_empty())
def test_get_follow_set(self): # Example from: # https://www.geeksforgeeks.org/follow-set-in-syntax-analysis/ text = """ E -> T E’ E’ -> + T E’ | Є T -> F T’ T’ -> * F T’ | Є F -> ( E ) | id """ cfg = CFG.from_text(text, start_symbol="E") llone_parser = LLOneParser(cfg) follow_set = llone_parser.get_follow_set() self.assertEqual(follow_set[Variable("E")], {"$", Terminal(")")}) self.assertEqual(follow_set[Variable("E’")], {"$", Terminal(")")}) self.assertEqual( follow_set[Variable("T")], {"$", Terminal("+"), Terminal(")")}) self.assertEqual( follow_set[Variable("T’")], {"$", Terminal("+"), Terminal(")")}) self.assertEqual( follow_set[Variable("F")], {"$", Terminal("+"), Terminal("*"), Terminal(")")})
def test_intersection_regex(self): """ Tests the intersection with a regex """ # pylint: disable=too-many-locals state_p = State("p") state_q = State("q") state_r = State("r") state_i = Symbol("i") state_e = Symbol("e") state_z = StackSymbol("Z") state_x0 = StackSymbol("X0") pda = PDA(states={state_p, state_q, state_r}, input_symbols={state_i, state_e}, stack_alphabet={state_z, state_x0}, start_state=state_p, start_stack_symbol=state_x0, final_states={state_r}) pda.add_transition(state_p, Epsilon(), state_x0, state_q, [state_z, state_x0]) pda.add_transition(state_q, state_i, state_z, state_q, [state_z, state_z]) pda.add_transition(state_q, state_e, state_z, state_q, []) pda.add_transition(state_q, Epsilon(), state_x0, state_r, []) state_s = finite_automaton.State("s") state_t = finite_automaton.State("t") i_dfa = finite_automaton.Symbol("i") e_dfa = finite_automaton.Symbol("e") dfa = finite_automaton.DeterministicFiniteAutomaton( states={state_s, state_t}, input_symbols={i_dfa, e_dfa}, start_state=state_s, final_states={state_s, state_t}) dfa.add_transition(state_s, i_dfa, state_s) dfa.add_transition(state_s, e_dfa, state_t) dfa.add_transition(state_t, e_dfa, state_t) new_pda = pda.intersection(dfa) pda_es = new_pda.to_empty_stack() cfg = pda_es.to_cfg() self.assertEqual(new_pda.get_number_transitions(), 6) self.assertEqual(len(new_pda.states), 5) self.assertEqual(len(new_pda.final_states), 2) self.assertEqual(len(new_pda.input_symbols), 2) self.assertEqual(len(new_pda.stack_symbols), 2) i_cfg = Terminal("i") e_cfg = Terminal("e") self.assertTrue(cfg.contains([i_cfg, i_cfg, e_cfg, e_cfg, e_cfg])) new_pda = pda.intersection( finite_automaton.DeterministicFiniteAutomaton()) self.assertEqual(new_pda.get_number_transitions(), 0)
def test_intersection_empty(self): regex = Regex("") ter_a = Terminal("a") ter_b = Terminal("b") var_s = Variable("S") productions = { Production(var_s, [ter_a, var_s, ter_b]), Production(var_s, [ter_b, var_s, ter_a]), Production(var_s, []) } cfg = CFG(productions=productions, start_symbol=var_s) cfg_i = cfg & regex self.assertFalse(cfg_i)
def test_reverse(self): """ Test the reversal of a CFG """ var_s = Variable("S") ter_a = Terminal("a") ter_b = Terminal("b") prod0 = Production(var_s, [ter_a, var_s, ter_b]) prod1 = Production(var_s, []) cfg = CFG({var_s}, {ter_a, ter_b}, var_s, {prod0, prod1}) new_cfg = cfg.reverse() self.assertEqual(len(new_cfg.variables), 1) self.assertEqual(len(new_cfg.terminals), 2) self.assertEqual(len(new_cfg.productions), 2) self.assertFalse(new_cfg.is_empty()) self.assertTrue(new_cfg.contains([ter_b, ter_b, ter_a, ter_a]))
def test_union(self): """ Tests the union of two cfg """ var_s = Variable("S") ter_a = Terminal("a") ter_b = Terminal("b") prod0 = Production(var_s, [ter_a, var_s, ter_b]) prod1 = Production(var_s, []) cfg = CFG({var_s}, {ter_a, ter_b}, var_s, {prod0, prod1}) new_cfg = cfg.union(cfg) self.assertEqual(len(new_cfg.variables), 3) self.assertEqual(len(new_cfg.terminals), 2) self.assertEqual(len(new_cfg.productions), 6) self.assertFalse(new_cfg.is_empty()) self.assertTrue(new_cfg.contains([ter_a, ter_a, ter_b, ter_b]))
def _test_profiling_conversions(): """ Tests multiple conversions """ ter_a = Terminal("a") ter_b = Terminal("b") ter_c = Terminal("c") var_s = Variable("S") productions = { Production(var_s, [ter_a, var_s, ter_b]), Production(var_s, [ter_c]) } cfg = CFG(productions=productions, start_symbol=var_s) cfg = cfg.to_pda().to_final_state().to_empty_stack().to_cfg() cfg = cfg.to_pda().to_final_state().to_empty_stack().to_cfg() cfg.to_pda().to_final_state().to_empty_stack().to_cfg()
def test_to_pda(self): """ Tests the conversion to PDA """ var_e = Variable("E") var_i = Variable("I") ter_a = Terminal("a") ter_b = Terminal("b") ter_0 = Terminal("0") ter_1 = Terminal("1") ter_par_open = Terminal("(") ter_par_close = Terminal(")") ter_mult = Terminal("*") ter_plus = Terminal("+") productions = { Production(var_e, [var_i]), Production(var_e, [var_e, ter_plus, var_e]), Production(var_e, [var_e, ter_mult, var_e]), Production(var_e, [ter_par_open, var_e, ter_par_close]), Production(var_i, [ter_a]), Production(var_i, [ter_b]), Production(var_i, [var_i, ter_a]), Production(var_i, [var_i, ter_b]), Production(var_i, [var_i, ter_0]), Production(var_i, [var_i, ter_1]), Production(var_i, [var_i, Epsilon()]) } cfg = CFG({var_e, var_i}, { ter_a, ter_b, ter_0, ter_1, ter_par_open, ter_par_close, ter_mult, ter_plus }, var_e, productions) pda = cfg.to_pda() self.assertEqual(len(pda.states), 1) self.assertEqual(len(pda.final_states), 0) self.assertEqual(len(pda.input_symbols), 8) self.assertEqual(len(pda.stack_symbols), 10) self.assertEqual(pda.get_number_transitions(), 19)
def test_substitution(self): """ Tests substitutions in a CFG """ var_s = Variable("S") ter_a = Terminal("a") ter_b = Terminal("b") prod0 = Production(var_s, [ter_a, var_s, ter_b]) prod1 = Production(var_s, []) cfg = CFG({var_s}, {ter_a, ter_b}, var_s, {prod0, prod1}) new_cfg = cfg.substitute({ter_a: cfg}) self.assertEqual(len(new_cfg.variables), 2) self.assertEqual(len(new_cfg.terminals), 2) self.assertEqual(len(new_cfg.productions), 4) self.assertFalse(new_cfg.is_empty()) self.assertTrue( new_cfg.contains([ter_a, ter_b, ter_a, ter_b, ter_b, ter_b]))
def test_nullable_object(self): """ Tests the finding of nullable objects """ var_a = Variable("A") var_b = Variable("B") ter_a = Terminal("a") ter_b = Terminal("b") start = Variable("S") prod0 = Production(start, [var_a, var_b]) prod1 = Production(var_a, [ter_a, var_a, var_a]) prod2 = Production(var_a, [Epsilon()]) prod3 = Production(var_b, [ter_b, var_b, var_b]) prod4 = Production(var_b, [Epsilon()]) cfg = CFG({var_a, var_b, start}, {ter_a, ter_b}, start, {prod0, prod1, prod2, prod3, prod4}) self.assertEqual(cfg.get_nullable_symbols(), {var_a, var_b, start})
def from_grammar_file(path, python_regex=False, nonterms_upper=True): with open(path, 'r') as g: productions = set() first_line = g.readline() rule = first_line.strip().split(' ', 1) start_symbol = Variable(rule[0]) if any(symb in rule[1] for symb in '?+*|') and len(rule[1]) > 1: body = rule[1].replace('?', f'| eps') productions |= GrammarAlgos.prod_from_regex( start_symbol, body, python_regex, nonterms_upper) else: body = [] for s in rule[1].split(' '): if s == 'eps': e = Epsilon() body.append(e) elif s.isupper(): v = Variable(s) body.append(v) else: t = Terminal(s) body.append(t) productions.add(Production(start_symbol, body)) for line in g.readlines(): rule = line.strip().split(' ', 1) var = Variable(rule[0]) if any(symb in rule[1] for symb in '?+*|') and len(rule[1]) > 1: body = rule[1].replace('?', f'| eps') productions |= GrammarAlgos.prod_from_regex( var, body, python_regex, nonterms_upper) else: body = [] for s in rule[1].split(' '): if s == 'eps': e = Epsilon() body.append(e) elif s.isupper(): v = Variable(s) body.append(v) else: t = Terminal(s) body.append(t) productions.add(Production(var, body)) return CFG(start_symbol=start_symbol, productions=productions)
def test_example62(self): """ Example from the book """ state0 = State("q0") state1 = State("q1") state2 = State("q2") s_zero = Symbol("0") s_one = Symbol("1") ss_zero = StackSymbol("0") ss_one = StackSymbol("1") ss_z0 = StackSymbol("Z0") pda = PDA(states={state0, state1, state2}, input_symbols={s_zero, s_one}, stack_alphabet={ss_zero, ss_one, ss_z0}, start_state=state0, start_stack_symbol=ss_z0, final_states={state2}) self.assertEqual(len(pda.states), 3) self.assertEqual(len(pda.input_symbols), 2) self.assertEqual(len(pda.stack_symbols), 3) self.assertEqual(pda.get_number_transitions(), 0) pda.add_transition(state0, s_zero, ss_z0, state0, [ss_zero, ss_z0]) pda.add_transition(state0, s_one, ss_z0, state0, [ss_one, ss_z0]) pda.add_transition(state0, s_zero, ss_zero, state0, [ss_zero, ss_zero]) pda.add_transition(state0, s_one, ss_one, state0, [ss_zero, ss_one]) pda.add_transition(state0, s_one, ss_zero, state0, [ss_one, ss_zero]) pda.add_transition(state0, s_one, ss_one, state0, [ss_one, ss_one]) pda.add_transition(state0, Epsilon(), ss_z0, state1, [ss_z0]) pda.add_transition(state0, Epsilon(), ss_zero, state1, [ss_zero]) pda.add_transition(state0, Epsilon(), ss_one, state1, [ss_one]) pda.add_transition(state1, s_zero, ss_zero, state1, []) pda.add_transition(state1, s_one, ss_one, state1, []) pda.add_transition(state1, Epsilon(), ss_z0, state2, [ss_z0]) self.assertEqual(pda.get_number_transitions(), 12) t_zero = Terminal("0") t_one = Terminal("1") cfg = pda.to_empty_stack().to_cfg() self.assertTrue(cfg.contains([])) self.assertTrue(cfg.contains([t_zero, t_zero])) self.assertTrue(cfg.contains([t_zero, t_one, t_one, t_zero])) self.assertFalse(cfg.contains([t_zero])) self.assertFalse(cfg.contains([t_zero, t_one, t_zero]))
def __init__(self, rules: Iterable[str], patch: bool = False): start_var: Variable vars: set[Variable] = set() terminals: Set[Terminal] = set() productions: Set[Production] = set() for rule in rules: i, r = rule.split(": ") var = Variable(i) if i == "0": start_var = var if r[0] == '"': ter = Terminal(r[1]) terminals.add(ter) productions.add(Production(var, [ter])) continue if patch: if i == "8": r = "42 | 42 8" if i == "11": r = "42 31 | 42 11 31" rr = r.split(" | ") for r in rr: productions.add( Production(var, [Variable(x) for x in r.split(" ")])) self.CFG = CFG(vars, terminals, start_var, productions)