def test_book_example(self): """ S -> i E t S | i E t S e S | a E -> b """ solved = f.parse_bnf(test_data.solved_left_factoring) unsolved = f.parse_bnf(test_data.unsolved_left_factoring) g = f.remove_left_factoring(unsolved) self.assertEqual(solved, g)
def test_cases(self): try: for case in test_data.examples: g = f.parse_bnf(case) h = f.remove_left_recursion(g) i = f.remove_left_factoring(h) for x in i.nonterminals: i.first(x) except Exception as e: self.fail(str(e))
def do_the_whole_thing(grammar_text, epsilon='ε', eof='$', output=None, verbose=True): file = None if output: file = open(output, 'w') sys.stdout = file vprint = print if verbose else lambda *a, **key: None # Only print if verbose is True vprint("Original:") g = parse_bnf(grammar_text, epsilon=epsilon, eof=eof) vprint(g) vprint("\nAfter removing left-recursion:") g = remove_left_recursion(g) vprint(g) vprint("\nAfter removing left-factoring:") g = remove_left_factoring(g) vprint(g) vprint() for nt in g.nonterminals: vprint('FIRST({}) = {}'.format(nt, g.first(nt))) vprint() follow = [(nt, g.follow(nt)) for nt in g.nonterminals] for nt, f in follow: vprint('FOLLOW({}) = {}'.format(nt, f)) vprint() table, ambiguous = g.parsing_table() vprint("Parsing Table: ") if ambiguous: vprint( "El lenguaje de entrada no es LL(1) debido a que se encontraron ambigüedades." ) vprint() pprint_table(g, table) if file: file.close()
def parsing_table(self, is_clean=True): """ Compute LL(1) predictive parsing table :param is_clean: If False, will remove left factoring and left recursions. :return: parsing table """ from parser.functions import remove_left_recursion, remove_left_factoring # To avoid cyclic import equiv = self if is_clean else remove_left_recursion(remove_left_factoring(copy(self))) table = {} ambigous = False for r in equiv.iter_productions(): terminals = equiv.first(r.body) for t in terminals: if not equiv.is_terminal(t): continue if t == equiv.epsilon: f = equiv.follow(r.head) for ef in f: if (table.get((r.head, ef))): ls = [] ls.append(table[(r.head, ef)]) ls.append(r) table[(r.head, ef)] = ls ambigous = True else: table[(r.head, ef)] = r else: if (table.get((r.head, t))): ls = [] ls.append(table[(r.head, t)]) ls.append(r) table[(r.head, t)] = ls ambigous = True else: table[(r.head, t)] = r return (table, ambigous)
def just_do_it(req): errors = [] g = None grammar_not_recursive = None grammar_not_factor = None parsing_table = None try: g = parse_bnf(req.form['bnf'], epsilon=req.form['epsilon'], eof=req.form['eof']) grammar_not_recursive = remove_left_recursion(g) grammar_not_factor = remove_left_factoring(grammar_not_recursive) table, ambiguous = grammar_not_factor.parsing_table() if ambiguous: errors.append( 'El lenguaje de entrada no es LL(1) debido a que se encontraron ambigüedades.' ) parsing_table = { 'table': table, 'terminals': sorted(set(g.terminals) - {g.epsilon}) + [g.eof], 'nonterminals': [nt for nt in grammar_not_factor.nonterminals] } except InvalidGrammar: errors.append( 'Gramática inválida. Revise las especificaciones de BNF.') except InvalidProduction as e: errors.append('Produccion invalida: {}.'.format(e.production)) return render_template('results.html', grammar=g, no_recursion=grammar_not_recursive, no_factor=grammar_not_factor, parsing_table=parsing_table, errors=errors)
def test_cases(self): for case in test_data.examples: g = f.parse_bnf(case) g = f.remove_left_factoring(g) self.assertFalse(f.check_left_factors(g), msg='{} has left factors'.format(g))