def test_ex433(self): p = {"S" : [("i", "E", "t", "S", "S'"), ("a", )], "S'" : [("e", "S"), ("epsilon",)], "E" : [("b",)]} g = Grammar("S", p, ["S", "S'", "E"], ["a", "b", "e", "i", "t"]) g.compute_first() g.compute_follow() g.compute_pred_parsing_tab() self.assertEqual(g.first_tab, {'S': {'a', 'i'}, "S'": {'e', 'epsilon'}, 'E': {'b'}, 'a': {'a'}, 'b': {'b'}, 'e': {'e'}, 'i': {'i'}, 't': {'t'}}) self.assertEqual(g.follow_tab, {'S': {'e', '$'}, "S'": {'e', '$'}, 'E': {'t'}}) self.assertEqual(g.pred_parsing_tab, {'S': {'a': ['S -> a'], 'b': [], 'e': [], 'i': ["S -> iEtSS'"], 't': [], '$': []}, "S'": {'a': [], 'b': [], 'e': ["S' -> eS", "S' -> epsilon"], 'i': [], 't': [], '$': ["S' -> epsilon"]}, 'E': {'a': [], 'b': ['E -> b'], 'e': [], 'i': [], 't': [], '$': []}})
def test_ex430(self): p = {"E" : [("T", "E'")], "E'" : [("+", "T", "E'"), ("epsilon",)], "T" : [("F", "T'")], "T'" : [("*", "F", "T'"), ("epsilon",)], "F" : [("(", "E", ")"), ("id",)]} g = Grammar("E", p, ["E", "E'", "T", "T'", "F"], ["+", "*", "(", ")", "id"]) g.compute_first() g.compute_follow() g.compute_pred_parsing_tab() self.assertEqual(g.first_tab, {'E': {'id', '('}, "E'": {'+', 'epsilon'}, 'T': {'id', '('}, "T'": {'*', 'epsilon'}, 'F': {'id', '('}, '+': {'+'}, '*': {'*'}, '(': {'('}, ')': {')'}, 'id': {'id'}}) self.assertEqual(g.follow_tab, {'E': {')', '$'}, "E'": {')', '$'}, 'T': {'+', ')', '$'}, "T'": {'+', '$', ')'}, 'F': {'+', '$', ')', '*'}}) self.assertEqual(g.pred_parsing_tab, {'E': {'+': [], '*': [], '(': ["E -> TE'"], ')': [], 'id': ["E -> TE'"], '$': []}, "E'": {'+': ["E' -> +TE'"], '*': [], '(': [], ')': ["E' -> epsilon"], 'id': [], '$': ["E' -> epsilon"]}, 'T': {'+': [], '*': [], '(': ["T -> FT'"], ')': [], 'id': ["T -> FT'"], '$': []}, "T'": {'+': ["T' -> epsilon"], '*': ["T' -> *FT'"], '(': [], ')': ["T' -> epsilon"], 'id': [], '$': ["T' -> epsilon"]}, 'F': {'+': [], '*': [], '(': ['F -> (E)'], ')': [], 'id': ['F -> id'], '$': []}})
class TestSlrParsing(unittest.TestCase): def setUp(self): p = {"E" : [("E", "+", "T"), tuple("T")], "T" : [("T", "*", "F"), tuple("F")], "F" : [("(", "E", ")"), ("id",)]} self.g = Grammar("E", p, ["E", "T", "F"], ["+", "*", "(", ")", "id"]) def test_closure(self): self.assertEqual(closure({("E'", "E", 0)}, self.g), {("E'", 'E', 0), ('T', ('F',), 0), ('F', ('(', 'E', ')'), 0), ('F', ('id',), 0), ('E', ('E', '+', 'T'), 0), ('T', ('T', '*', 'F'), 0), ('E', ('T',), 0)}) def test_goto(self): self.assertEqual( goto({("E'", "E", 1), ("E", ("E","+","T"), 1)}, "+", self.g), {('T', ('F',), 0), ('E', ('E', '+', 'T'), 2), ('F', ('id',), 0), ('F', ('(', 'E', ')'), 0), ('T', ('T', '*', 'F'), 0)}) def test_canonical_items(self): augment(self.g) self.assertEqual(canonical_items(self.g), [{('E', ('E', '+', 'T'), 0), ('E', ('T',), 0), ("E'", 'E', 0), ('F', ('(', 'E', ')'), 0), ('F', ('id',), 0), ('T', ('F',), 0), ('T', ('T', '*', 'F'), 0)}, {("E'", 'E', 1), ('E', ('E', '+', 'T'), 1)}, {('E', ('T',), 1), ('T', ('T', '*', 'F'), 1)}, {('T', ('F',), 1)}, {('E', ('E', '+', 'T'), 0), ('E', ('T',), 0), ('F', ('(', 'E', ')'), 0), ('F', ('(', 'E', ')'), 1), ('F', ('id',), 0), ('T', ('F',), 0), ('T', ('T', '*', 'F'), 0)}, {('F', ('id',), 1)}, {('E', ('E', '+', 'T'), 2), ('F', ('(', 'E', ')'), 0), ('F', ('id',), 0), ('T', ('F',), 0), ('T', ('T', '*', 'F'), 0)}, {('T', ('T', '*', 'F'), 2), ('F', ('id',), 0), ('F', ('(', 'E', ')'), 0)}, {('E', ('E', '+', 'T'), 1), ('F', ('(', 'E', ')'), 2)}, {('E', ('E', '+', 'T'), 3), ('T', ('T', '*', 'F'), 1)}, {('T', ('T', '*', 'F'), 3)}, {('F', ('(', 'E', ')'), 3)}]) def test_slr_parsing_table(self): augment(self.g) self.g.compute_first() self.g.compute_follow() act_tb, goto_tb = slr_parsing_table(self.g) self.assertEqual(act_tb, {0: {'$': [], '(': [('shift', 4)], ')': [], '*': [], '+': [], 'id': [('shift', 5)]}, 1: {'$': [('accept',)], '(': [], ')': [], '*': [], '+': [('shift', 6)], 'id': []}, 2: {'$': [('reduce', ('E', ('T',)))], '(': [], ')': [('reduce', ('E', ('T',)))], '*': [('shift', 7)], '+': [('reduce', ('E', ('T',)))], 'id': []}, 3: {'$': [('reduce', ('T', ('F',)))], '(': [], ')': [('reduce', ('T', ('F',)))], '*': [('reduce', ('T', ('F',)))], '+': [('reduce', ('T', ('F',)))], 'id': []}, 4: {'$': [], '(': [('shift', 4)], ')': [], '*': [], '+': [], 'id': [('shift', 5)]}, 5: {'$': [('reduce', ('F', ('id',)))], '(': [], ')': [('reduce', ('F', ('id',)))], '*': [('reduce', ('F', ('id',)))], '+': [('reduce', ('F', ('id',)))], 'id': []}, 6: {'$': [], '(': [('shift', 4)], ')': [], '*': [], '+': [], 'id': [('shift', 5)]}, 7: {'$': [], '(': [('shift', 4)], ')': [], '*': [], '+': [], 'id': [('shift', 5)]}, 8: {'$': [], '(': [], ')': [('shift', 11)], '*': [], '+': [('shift', 6)], 'id': []}, 9: {'$': [('reduce', ('E', ('E', '+', 'T')))], '(': [], ')': [('reduce', ('E', ('E', '+', 'T')))], '*': [('shift', 7)], '+': [('reduce', ('E', ('E', '+', 'T')))], 'id': []}, 10: {'$': [('reduce', ('T', ('T', '*', 'F')))], '(': [], ')': [('reduce', ('T', ('T', '*', 'F')))], '*': [('reduce', ('T', ('T', '*', 'F')))], '+': [('reduce', ('T', ('T', '*', 'F')))], 'id': []}, 11: {'$': [('reduce', ('F', ('(', 'E', ')')))], '(': [], ')': [('reduce', ('F', ('(', 'E', ')')))], '*': [('reduce', ('F', ('(', 'E', ')')))], '+': [('reduce', ('F', ('(', 'E', ')')))], 'id': []}}) self.assertEqual(goto_tb, {0: {'E': [1], "E'": [], 'F': [3], 'T': [2]}, 1: {'E': [], "E'": [], 'F': [], 'T': []}, 2: {'E': [], "E'": [], 'F': [], 'T': []}, 3: {'E': [], "E'": [], 'F': [], 'T': []}, 4: {'E': [8], "E'": [], 'F': [3], 'T': [2]}, 5: {'E': [], "E'": [], 'F': [], 'T': []}, 6: {'E': [], "E'": [], 'F': [3], 'T': [9]}, 7: {'E': [], "E'": [], 'F': [10], 'T': []}, 8: {'E': [], "E'": [], 'F': [], 'T': []}, 9: {'E': [], "E'": [], 'F': [], 'T': []}, 10: {'E': [], "E'": [], 'F': [], 'T': []}, 11: {'E': [], "E'": [], 'F': [], 'T': []}})
"T": [("T", "*", "F"), tuple("F")], "F": [("(", "E", ")"), ("id", )] } g = Grammar("E", p, ["E", "T", "F"], ["+", "*", "(", ")", "id"]) print("Example 4.40, 244") pp = pprint.PrettyPrinter() pp.pprint(closure({("E'", "E", 0)}, g)) print("Example 4.4.1, pg 246") pp.pprint(goto({("E'", "E", 1), ("E", ("E", "+", "T"), 1)}, "+", g)) augment(g) pp.pprint(canonical_items(g)) print("\n# Production rules for Example 4.45, pg 251, Exp. Grammar 4.1.") g.print_productions() g.compute_first() g.compute_follow() act_tb, goto_tb = slr_parsing_table(g) print_slr_table(act_tb, goto_tb) print("\n# Production rules for grammar 4.28") p = { "E": [("T", "E2")], "E2": [("+", "T", "E2"), ("epsilon", )], "T": [("F", "T'")], "T'": [("*", "F", "T'"), ("epsilon", )], "F": [("(", "E", ")"), ("id", )] } # Grammar 4.28 g = Grammar("E", p, ["E", "E2", "T", "T'", "F"], ["+", "*", "(", ")", "id"])
def goto(s, x, g): ''' Calculates GOTO(s, x) as defined to be the closure of the set of all items [A -> alpha X * beta] such that [A -> alpha * X beta] is in s. ''' goto_sx = set() for lhs, rhs, dot_idx in s: # Do your magic here! return goto_sx def augment(g): new_start_symbol = g.start_symbol + "'" assert(not new_start_symbol in g.non_terminals) g.production_rules[new_start_symbol] = [tuple(g.start_symbol)] g.start_symbol = new_start_symbol g.non_terminals.append(new_start_symbol) g.first_tab[new_start_symbol] = set() g.follow_tab[new_start_symbol] = set() def canonical_items(g): ''' Calculates the canonical collection of sets of LR(0) items. ''' # Dragon book, 2nd ed, pg 246 # void items(G') { # C = {closure({[S'-> * S]})} # repeat # for each set of items I in C # for each grammar symbol X # if GOTO(I, X) is not empty and not in C # add GOTO(I, X) to C # until no new set of items are added to C on a round # } # Grammar g is assumed augmented s = g.start_symbol # S' orig_s = s[:len(s) - 1] # S start_item = (s, orig_s, 0) # S' -> * S # I chose to represent C as a list of set of items # instead of a set so we can assign a natural number to # each set of items I beig its position in the # list representing C. can = [closure({start_item}, g)] while True: can_size = len(can) # Do your magic here! new_can_size = len(can) if new_can_size == can_size: break return can def slr_parsing_table(g): ''' Computes SLR parsing table according to Dragon 2nd ed. pgs 253, 254. ''' # Grammar g is assumed to augmented. assert(g.follow_computed) # 1. Construct C = {I0, I1, ... In}, the collection of sets of LR(0) # items for G. can = canonical_items(g) # Initializes ACTION and GOTO tables. action_tab = {} goto_tab = {} for st in range(len(can)): d = {} for t in g.terminals: d[t] = [] d["$"] = [] action_tab[st] = d d = {} for v in g.non_terminals: d[v] = [] goto_tab[st] = d # 2. State i is constructed from Ii. # (They are encoded as the indices of 'can'.) # The parsing actions for state i are deter mined as follows: for state_l, l in enumerate(can): for i, item in enumerate(l): lhs = item[0] rhs = item[1] dot_idx = item[2] if dot_idx < len(rhs): a = rhs[dot_idx] # (a) If [A -> alpha * a beta]is in Ii # and GOTO(Ii, a) = Ij then # set ACTION[i,a] =shift j. # Here a must be a terminal. # Do your magic here! else: # (b) If [A -> alpha *] is in Ii, then set # ACTION[i, a] = "reduce A -> alpha" to # all a in FOLLOW(A); here A may not be S'. # (c) If [S' -> S *] is in Ii, then set # ACTION[i, $] = "accept". # Do your magic here! # 3. The goto transitions for state i are constructed for all # nonterminals A using the rule If GOTO(Ii, A) = Ij # then GOTO[i,A] = j. # Do your magic here! return (action_tab, goto_tab) def print_slr_table(act_tb, goto_tb): print("ACTION table") df = pd.DataFrame(act_tb).T df.fillna(0, inplace=True) print(tabulate(df, headers='keys', tablefmt='psql')) print("GOTO table") df = pd.DataFrame(goto_tb).T df.fillna(0, inplace=True) print(tabulate(df, headers='keys', tablefmt='psql')) if __name__ == '__main__': # Production rules for Expression Grammar 4.1 p = {"E" : [("E", "+", "T"), tuple("T")], "T" : [("T", "*", "F"), tuple("F")], "F" : [("(", "E", ")"), ("id",)]} g = Grammar("E", p, ["E", "T", "F"], ["+", "*", "(", ")", "id"]) print("Example 4.40, 244") pp = pprint.PrettyPrinter() pp.pprint(closure({("E'", "E", 0)}, g)) print("Example 4.4.1, pg 246") pp.pprint(goto({("E'", "E", 1), ("E", ("E","+","T"), 1)}, "+", g)) augment(g) pp.pprint(canonical_items(g)) print("\n# Production rules for Example 4.45, pg 251, Exp. Grammar 4.1.") g.print_productions() g.compute_first() g.compute_follow() act_tb, goto_tb = slr_parsing_table(g) print_slr_table(act_tb, goto_tb) print("\n# Production rules for grammar 4.28") p = {"E" : [("T", "E2")], "E2" : [("+", "T", "E2"), ("epsilon",)], "T" : [("F", "T'")], "T'" : [("*", "F", "T'"), ("epsilon",)], "F" : [("(", "E", ")"), ("id",)]} # Grammar 4.28 g = Grammar("E", p, ["E", "E2", "T", "T'", "F"], ["+", "*", "(", ")", "id"]) augment(g) print("\n# Production rules for Example 4.32, pg. 225, Grammar 4.28.") g.print_productions() g.compute_first() g.compute_follow() act_tb, goto_tb = slr_parsing_table(g) print_slr_table(act_tb, goto_tb)