def get_grammar(): # Expression grammar with float numbers E, T, F = [NonTerminal(name) for name in ['E', 'T', 'F']] PLUS, MULT, OPEN, CLOSE = [ Terminal(value) for value in ['+', '*', '(', ')'] ] NUMBER = Terminal('number', RegExRecognizer(r'\d+(\.\d+)?')) productions = [(E, (E, PLUS, T)), (E, (T, )), (T, (T, MULT, F)), (T, (F, )), (F, (OPEN, E, CLOSE)), (F, (NUMBER, ))] return Grammar.from_struct(productions, E)
def test_terminal_nonterminal(): # Production A is a terminal ("a") and non-terminal at the same time. # Thus, it must be recognized as non-terminal. grammar = """ S: A B; A: "a" | B; B: "b"; """ g = Grammar.from_string(grammar) assert NonTerminal("A") in g.nonterminals assert Terminal("A") not in g.terminals assert Terminal("B") in g.terminals assert NonTerminal("B") not in g.nonterminals # Here A should be non-terminal while B should be terminal. grammar = """ S: A B; A: B; B: "b"; """ g = Grammar.from_string(grammar) assert NonTerminal("A") in g.nonterminals assert Terminal("A") not in g.terminals assert Terminal("B") in g.terminals assert NonTerminal("B") not in g.nonterminals grammar = """ S: A; A: S; A: 'x'; """ g = Grammar.from_string(grammar) assert NonTerminal("S") in g.nonterminals assert NonTerminal("A") in g.nonterminals assert Terminal("A") not in g.terminals assert Terminal("x") in g.terminals grammar = """ S: S S; S: 'x'; S: EMPTY; """ g = Grammar.from_string(grammar) assert NonTerminal("S") in g.nonterminals assert Terminal("x") in g.terminals assert NonTerminal("x") not in g.nonterminals assert Terminal("S") not in g.terminals
def test_multiple_terminal_definition(): # A is defined multiple times as terminal thus it must be recognized # as non-terminal with alternative expansions. grammar = """ S: A A; A: "a"; A: "b"; """ g = Grammar.from_string(grammar) assert NonTerminal("A") in g.nonterminals assert Terminal("A") not in g.terminals
def test_first_empty_in_rhs(): """ Test FIRST calculation when there are empty derivations in RHS of a production. """ grammar = """ S: A C; A: B | EMPTY; B: "b"; C: "c"; """ g = Grammar.from_string(grammar) first_set = first(g) assert EMPTY in first_set[NonTerminal('A')] assert Terminal('B') in first_set[NonTerminal('A')] assert Terminal('B') in first_set[NonTerminal('S')] # 'A' can derive empty, thus 'C' must be in firsts of 'S'. assert Terminal('C') in first_set[NonTerminal('S')]
from parglare import Grammar, NonTerminal, Terminal, RegExRecognizer # Expression grammar with float numbers E, T, F = [NonTerminal(name) for name in ['E', 'T', 'F']] PLUS, MULT, OPEN, CLOSE = [Terminal(value) for value in ['+', '*', '(', ')']] NUMBER = Terminal('number', RegExRecognizer(r'\d+(\.\d+)?')) productions = [(E, (E, PLUS, T)), (E, (T, )), (T, (T, MULT, F)), (T, (F, )), (F, (OPEN, E, CLOSE)), (F, (NUMBER, ))] def get_grammar(): return Grammar.from_struct(productions, E)