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': []}})
Пример #4
0
        "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"])
Пример #5
0
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)