def test_is_factored(): g = ContextFreeGrammar.from_string(''' S -> a S | a B | d S B -> b B | b ''') assert not g.is_factored() g = ContextFreeGrammar.from_string(''' S -> a S1 | d S S1 -> S | B B -> b B1 B1 -> B | & ''') assert g.is_factored() g = ContextFreeGrammar.from_string(''' S -> A B | B C A -> a A | & B -> b B | d C -> c C | c ''') assert not g.is_factored() g = ContextFreeGrammar.from_string(''' S -> a A B | B C1 A -> a A | & B -> b B | d C -> c C1 C1 -> C | & ''') assert g.is_factored()
def test_valid(): ContextFreeGrammar.from_string('E -> E + T | E - T | T\n' 'T -> T * F | T / F | F\n' 'F -> ( E ) | id') ContextFreeGrammar.from_string('E -> T E1\n' 'E1 -> + T E1 | &\n' 'T -> F T1\n' 'T1 -> * F T1 | &\n' 'F -> ( E ) | id')
def test_invalid_spacing(): with raises(ParseError): ContextFreeGrammar.from_string('E -> E+T | E-T | T\n' 'T -> T*F | T/F | F\n' 'F -> (E) | id') with raises(ParseError): ContextFreeGrammar.from_string('E -> T E1' 'E1 -> T E1 | &' 'T -> F T1' 'T1 -> * FT1 | &' 'F -> ( E ) | id')
def test_valid_with_whitespace(): ContextFreeGrammar.from_string(''' E -> E + T | E - T | T T -> T * F | T / F | F F -> ( E ) | id ''') ContextFreeGrammar.from_string(''' E -> T E1 E1 -> + T E1 | & T -> F T1 T1 -> * F T1 | & F -> ( E ) | id ''')
def test_first_of_string(): string = '''S -> A B C A -> a A | & B -> b B | A C d C -> c C | &''' g = ContextFreeGrammar.from_string(string) g.calculate_first() expected = set({Terminal('c'), Terminal('d')}) got = g.first_of_string([NonTerminal('C'), Terminal('d')]) assert got == expected
def test_remove_simple_productions(): g = ContextFreeGrammar.from_string(''' S -> F G H F -> G | a G -> d G | H | b H -> c ''') expected = ContextFreeGrammar.from_string(''' S -> F G H F -> a | d G | b | c G -> d G | b | c H -> c ''') new_grammar = g.without_simple_productions() new_productions = sorted( (lhs, sorted(rhs)) for lhs, rhs in new_grammar.production_rules.items()) expected_productions = sorted( (lhs, sorted(rhs)) for lhs, rhs in expected.production_rules.items()) assert new_productions == expected_productions
def test_n_sets(): g = ContextFreeGrammar.from_string(''' S -> F G H F -> G | a G -> d G | H | b H -> c ''') S, F, G, H = (NonTerminal(x) for x in 'SFGH') expected = { S: {S}, F: {F, G, H}, G: {G, H}, H: {H}, } assert g.simple_production_sets() == expected
def test_first_nt_02(): S = NonTerminal('S') A = NonTerminal('A') B = NonTerminal('B') epsilon = Epsilon('&') string = '''S -> A b | A B c B -> b B | A d | & A -> a A | &''' g = ContextFreeGrammar.from_string(string) g.calculate_first_nt() expected_first_nt = { S: set([A, B]), B: set([epsilon, A]), A: set([epsilon]), } assert g.first_nt == expected_first_nt
def test_invalid_syntax(): with raises(ParseError): ContextFreeGrammar.from_string('E + T | E - T | T\n' 'T -> T * F | T / F | F\n' 'F -> ( E ) | id') with raises(ParseError): ContextFreeGrammar.from_string('E -> T E1\n' 'E1 ->' 'T -> F T1\n' 'T1 -> * F T1 | &\n' 'F -> ( E ) | id') with raises(ParseError): ContextFreeGrammar.from_string('E -> E + T | E - T | T\n' 'T -> T * F | T / F |\n' 'F -> ( E ) | id') with raises(ParseError): ContextFreeGrammar.from_string('E -> T E1\n' 'E1 -> + T E1 | &\n' 'T -> F T1\n' 'T1 -> | &\n' 'F -> ( E ) | id')
def test_follow_02(): a = Terminal('a') b = Terminal('b') c = Terminal('c') e = Terminal('e') eos = EoS('$') string = '''S -> A C | C e B | B a A -> a A | B C C -> c C | & B -> b B | A B | &''' g = ContextFreeGrammar.from_string(string) g.calculate_follow() expected_follow = { NonTerminal('S'): set([eos]), NonTerminal('A'): set([a, b, c, eos]), NonTerminal('C'): set([a, b, c, e, eos]), NonTerminal('B'): set([a, b, c, eos]), } assert g.follow == expected_follow
def test_follow_01(): a = Terminal('a') b = Terminal('b') c = Terminal('c') d = Terminal('d') eos = EoS('$') string = '''S -> A B C A -> a A | & B -> b B | A C d C -> c C | &''' g = ContextFreeGrammar.from_string(string) g.calculate_follow() expected_follow = { NonTerminal('S'): set([eos]), NonTerminal('A'): set([a, b, c, d]), NonTerminal('B'): set([c, eos]), NonTerminal('C'): set([d, eos]) } assert g.follow == expected_follow
def test_first_01(): a = Terminal('a') b = Terminal('b') c = Terminal('c') d = Terminal('d') epsilon = Epsilon('&') string = '''S -> A B C A -> a A | & B -> b B | A C d C -> c C | &''' g = ContextFreeGrammar.from_string(string) g.calculate_first() expected_first = { NonTerminal('S'): set([a, b, c, d]), NonTerminal('A'): set([a, epsilon]), NonTerminal('B'): set([a, b, c, d]), NonTerminal('C'): set([c, epsilon]) } assert g.first == expected_first
def test_first_02(): a = Terminal('a') b = Terminal('b') c = Terminal('c') e = Terminal('e') epsilon = Epsilon('&') string = '''S -> A C | C e B | B a A -> a A | B C C -> c C | & B -> b B | A B | &''' g = ContextFreeGrammar.from_string(string) g.calculate_first() expected_first = { NonTerminal('S'): set([a, b, c, e, epsilon]), NonTerminal('A'): set([a, b, c, epsilon]), NonTerminal('C'): set([c, epsilon]), NonTerminal('B'): set([a, b, c, epsilon]), } assert g.first == expected_first
def test_first_nt_01(): S = NonTerminal('S') A = NonTerminal('A') B = NonTerminal('B') C = NonTerminal('C') epsilon = Epsilon('&') string = '''S -> A B C A -> a A | & B -> b B | A C d C -> c C | &''' g = ContextFreeGrammar.from_string(string) g.calculate_first_nt() expected_first_nt = { S: set([A, B, C]), A: set([epsilon]), B: set([A, C]), C: set([epsilon]), } assert g.first_nt == expected_first_nt
from pprint import pprint from chomchom import ContextFreeGrammar g1 = ContextFreeGrammar.from_string(''' S -> a S1 | d S S1 -> S | B B -> b B1 B1 -> B | & ''') g2 = ContextFreeGrammar.from_string(''' S -> A B | B C A -> a A | & B -> b B | d C -> c C | c ''') g3 = ContextFreeGrammar.from_string(''' S -> a S | B C | B D A -> c C | A B B -> b B | & C -> a A | B C D -> d D d | c ''') # Empty grammar g4 = ContextFreeGrammar.from_string(''' S -> a S ''') g5 = ContextFreeGrammar.from_string('''