def test_associativity_conflicts_resolving(): """ Test that using associativity will resolve conflicts. """ grammar = r""" E: E '+' E | number; terminals number: /d+/; """ g = Grammar.from_string(grammar) table = create_table(g) assert len(table.sr_conflicts) == 1 grammar = r""" E: E '+' E {left} | number; terminals number: /d+/; """ g = Grammar.from_string(grammar) table = create_table(g) assert len(table.sr_conflicts) == 0
def test_prefer_shifts_no_sr_conflicts(): """ Test that grammar with S/R conflict will be resolved to SHIFT actions if prefer_shift option is used. """ # This grammar has S/R conflict as B+ may consume multiple single "a" A # because "b" is optional. Thus, parser can't decide if it should shift "a" # or reduce by 'B: "b"? A+' and later by 'S: B+'; Most of the time we want # gready behavior so in case of doubt parser will choose shift if # prefer_shift is set to `True`. This means that the parser will first # consume all "a" using A+ and that reduce B at the end. grammar = r""" S: B+; B: "b"? A+; terminals A: "a"; """ g = Grammar.from_string(grammar) # There is a shift reduce conflict so we can't use LR parser. table = create_table(g) assert len(table.sr_conflicts) == 1 # But we can eliminate conflict by prefer_shifts strategy. table = create_table(g, prefer_shifts=True) assert len(table.sr_conflicts) == 0 # With prefer_shifts we get a greedy behavior input_str = 'b a a a b a a' output = [['b', ['a', 'a', 'a']], ['b', ['a', 'a']]] parser = Parser(g, prefer_shifts=True) result = parser.parse(input_str) assert result == output # GLR parser can parse without prefer_shifts strategy. This grammar is # ambiguous and yields 11 solutions for the given input. parser = GLRParser(g) results = parser.parse(input_str) expected = [ [['b', ['a']], [None, ['a']], [None, ['a']], ['b', ['a', 'a']]], [['b', ['a', 'a']], [None, ['a']], ['b', ['a', 'a']]], [['b', ['a', 'a', 'a']], ['b', ['a', 'a']]], [['b', ['a']], [None, ['a', 'a']], ['b', ['a', 'a']]], [['b', ['a']], [None, ['a', 'a']], ['b', ['a']], [None, ['a']]], [['b', ['a', 'a', 'a']], ['b', ['a']], [None, ['a']]], [['b', ['a', 'a']], [None, ['a']], ['b', ['a']], [None, ['a']]], [['b', ['a']], [None, ['a', 'a']], ['b', ['a']], [None, ['a']]], [['b', ['a', 'a', 'a']], ['b', ['a']], [None, ['a']]], [['b', ['a', 'a']], [None, ['a']], ['b', ['a']], [None, ['a']]], [['b', ['a']], [None, ['a']], [None, ['a']], ['b', ['a']], [None, ['a']]] # noqa ] assert results == expected # But if `prefer_shift` is used we get only one solution parser = GLRParser(g, prefer_shifts=True) result = parser.parse(input_str) assert len(result) == 1 assert result[0] == output
def check_get_grammar_table(grammar_file, debug, colors): try: g = Grammar.from_file(grammar_file, _no_check_recognizers=True, debug_colors=colors) if debug: g.print_debug() table = create_table(g) if debug: table.print_debug() h_print("Grammar OK.") if table.sr_conflicts: a_print("There are {} Shift/Reduce conflicts.".format( len(table.sr_conflicts))) prints("Either use 'prefer_shifts' parser mode, try to resolve " "manually or use GLR parsing.".format( len(table.sr_conflicts))) if table.rr_conflicts: a_print("There are {} Reduce/Reduce conflicts.".format( len(table.rr_conflicts))) prints("Try to resolve manually or use GLR parsing.") if (table.sr_conflicts or table.rr_conflicts) and not debug: prints("Run in debug mode to print all the states.") except (GrammarError, ParseError) as e: print("Error in the grammar file.") print(e) sys.exit(1) return g, table
def test_precomputed_table(): """If parser is initialized with a `table` parameter then this table should be used, and no call to create_table should be made.""" grammar = get_grammar() table = create_table(grammar) if HAS_MOCK: with patch('parglare.tables.create_table') as mocked_create_table: parser = GLRParser(grammar, table=table) assert not mocked_create_table.called else: parser = GLRParser(grammar, table=table) parser.parse('id+id')
def test_dot_export(): grammar = 'S: S S | S S S | "b";' g = Grammar.from_string(grammar) table = create_table(g) f, file_name = mkstemp() grammar_pda_export(table, file_name) assert os.path.exists(file_name) with open(file_name) as f: assert 'label' in f.read() os.remove(file_name)
def test_dot_export(): grammar = 'S: S S | S S S | "b";' g = Grammar.from_string(grammar) table = create_table(g) tmp_dir = tempfile.mkdtemp() file_name = os.path.join(tmp_dir, 'testexport.dot') grammar_pda_export(table, file_name) with open(file_name) as f: assert 'label' in f.read() os.remove(file_name) os.rmdir(tmp_dir)
def bnf2parglare(productions, terminals, original_start): grammar, start = to_parglare_grammar(productions, terminals, original_start) with timeit('computing parse table'): table = create_table( grammar, start_production=grammar.get_production_id(start), itemset_type=LALR, prefer_shifts=False, prefer_shifts_over_empty=False, lexical_disambiguation=False, ) serializable_table = table_to_serializable(table) return productions, terminals, original_start, start, serializable_table
def test_table_construction(): """ Tests LR table construction. """ # From the Knuth's 1965 paper: On the Translation of Languages from Left to # Right grammar = r""" S: 'a' A 'd' | 'b' A 'd'; A: 'c' A | 'c'; """ g = Grammar.from_string(grammar) table = create_table(g) c = g.get_terminal('c') d = g.get_terminal('d') assert len(table.states) == 11 assert table.states[0].symbol.name == "S'" state = table.states[2] assert state.symbol.name == 'a' assert len(state.kernel_items) == 1 assert len(state.items) == 3 assert len(state.actions) == 1 assert len(state.actions[c]) == 1 action = list(state.actions.values())[0][0] assert action.action == SHIFT assert action.state.state_id == 6 state = table.states[6] assert state.symbol.name == 'c' assert len(state.kernel_items) == 2 assert len(state.items) == 4 assert len(state.actions) == 2 assert len(state.actions[c]) == 1 assert len(state.actions[d]) == 1 action = list(state.actions.values())[0][0] assert action.action == REDUCE assert action.prod.prod_id == 4 action = list(state.actions.values())[1][0] assert action.action == SHIFT assert action.state.state_id == 6
from parglare.tables import create_table, LALR from parglare.tables.persist import table_to_serializable from grammar import grammar, start_symbol table = create_table( grammar, start_production=grammar.get_production_id(start_symbol), itemset_type=LALR, prefer_shifts=False, prefer_shifts_over_empty=False, ) serializable_table = table_to_serializable(table) with open('_table.py', 'w') as f: f.write('table = ') f.write(repr(serializable_table))