comparison test/testpyy.py @ 318:e84047f29c78

Add burg and yacc initial attempts
author Windel Bouwman
date Tue, 31 Dec 2013 12:38:15 +0100
parents 05184b95fa16
children 8d07a4254f04
comparison
equal deleted inserted replaced
317:e30a77ae359b 318:e84047f29c78
1 import unittest, pprint 1 import unittest
2 from pyyacc import Grammar, Item, ParserGenerationException, ParserException, EPS, EOF 2 from pyyacc import Grammar, Item, ParserGenerationException, ParserException
3 from pyyacc import EPS, EOF
3 from ppci import Token 4 from ppci import Token
4 5
5 def genTokens(lst): 6
6 for t in lst: 7 class genTokens:
7 yield Token(t, t) 8 def __init__(self, lst):
9 def tokGen():
10 for t in lst:
11 yield Token(t, t)
12 while True:
13 yield Token(EOF, EOF)
14 self.tokens = tokGen()
15 self.token = self.tokens.__next__()
16
17 def next_token(self):
18 t = self.token
19 if t.typ != EOF:
20 self.token = self.tokens.__next__()
21 return t
22
8 23
9 class testLR(unittest.TestCase): 24 class testLR(unittest.TestCase):
10 """ Test basic LR(1) parser generator constructs """ 25 """ Test basic LR(1) parser generator constructs """
11 def testSimpleGrammar(self): 26 def testSimpleGrammar(self):
12 # 1. define a simple grammar: 27 # 1. define a simple grammar:
23 tokens = genTokens(['identifier', '+', 'identifier', '+', 'identifier']) 38 tokens = genTokens(['identifier', '+', 'identifier', '+', 'identifier'])
24 # 3. build parser: 39 # 3. build parser:
25 p = g.genParser() 40 p = g.genParser()
26 # 4. feed input: 41 # 4. feed input:
27 p.parse(tokens) 42 p.parse(tokens)
43
28 def testReduceReduceConflict(self): 44 def testReduceReduceConflict(self):
29 """ Check if a reduce-reduce conflict is detected """ 45 """ Check if a reduce-reduce conflict is detected """
30 # Define a grammar with an obvious reduce-reduce conflict: 46 # Define a grammar with an obvious reduce-reduce conflict:
31 g = Grammar(['id']) 47 g = Grammar(['id'])
32 g.add_production('goal', ['a']) 48 g.add_production('goal', ['a'])
35 g.add_production('b', ['id']) 51 g.add_production('b', ['id'])
36 g.add_production('c', ['id']) 52 g.add_production('c', ['id'])
37 g.start_symbol = 'goal' 53 g.start_symbol = 'goal'
38 with self.assertRaises(ParserGenerationException): 54 with self.assertRaises(ParserGenerationException):
39 p = g.genParser() 55 p = g.genParser()
56
40 def testShiftReduceConflict(self): 57 def testShiftReduceConflict(self):
41 """ Must be handled automatically by doing shift """ 58 """ Must be handled automatically by doing shift """
42 g = Grammar([EOF, 'if', 'then', 'else', 'ass']) 59 g = Grammar([EOF, 'if', 'then', 'else', 'ass'])
43 # Ambiguous grammar: 60 # Ambiguous grammar:
44 g.add_production('if_stmt', ['if', 'then', 'stmt']) 61 g.add_production('if_stmt', ['if', 'then', 'stmt'])
58 g.add_production('a', ['b']) 75 g.add_production('a', ['b'])
59 g.add_production('a', ['c']) 76 g.add_production('a', ['c'])
60 g.start_symbol = 'goal' 77 g.start_symbol = 'goal'
61 with self.assertRaises(ParserGenerationException): 78 with self.assertRaises(ParserGenerationException):
62 g.genParser() 79 g.genParser()
80
63 def testRedefineTerminal(self): 81 def testRedefineTerminal(self):
64 """ Test correct behavior when a terminal is redefined """ 82 """ Test correct behavior when a terminal is redefined """
65 g = Grammar([EOF, 'b', 'c']) 83 g = Grammar([EOF, 'b', 'c'])
66 g.add_production('goal', ['a']) 84 g.add_production('goal', ['a'])
67 with self.assertRaises(ParserGenerationException): 85 with self.assertRaises(ParserGenerationException):
68 g.add_production('b', ['c']) # Not allowed 86 g.add_production('b', ['c']) # Not allowed
69 g.add_production('a', ['c']) 87 g.add_production('a', ['c'])
70 g.start_symbol = 'goal' 88 g.start_symbol = 'goal'
71 g.genParser() 89 g.genParser()
90
72 def testEmpty(self): 91 def testEmpty(self):
73 """ Test empty token stream """ 92 """ Test empty token stream """
74 g = Grammar([',']) 93 g = Grammar([','])
75 g.add_production('input', [',']) 94 g.add_production('input', [','])
76 g.start_symbol = 'input' 95 g.start_symbol = 'input'
77 p = g.genParser() 96 p = g.genParser()
78 tokens = genTokens([]) 97 tokens = genTokens([])
79 with self.assertRaises(ParserException): 98 with self.assertRaises(ParserException):
80 p.parse(tokens) 99 p.parse(tokens)
81 100
82 def testEps(self): 101 def testEps(self):
83 """ Test epsilon terminal """ 102 """ Test epsilon terminal """
84 g = Grammar(['a', 'b']) 103 g = Grammar(['a', 'b'])
85 g.add_production('input', ['optional_a', 'b']) 104 g.add_production('input', ['optional_a', 'b'])
86 g.add_production('optional_a', ['a']) 105 g.add_production('optional_a', ['a'])
107 def test_cb(self): 126 def test_cb(self):
108 """ Test callback of one rule and order or parameters """ 127 """ Test callback of one rule and order or parameters """
109 self.cb_called = False 128 self.cb_called = False
110 def cb(a, c, b): 129 def cb(a, c, b):
111 self.cb_called = True 130 self.cb_called = True
112 self.assertEqual(a, 'a') 131 self.assertEqual(a.val, 'a')
113 self.assertEqual(b, 'b') 132 self.assertEqual(b.val, 'b')
114 self.assertEqual(c, 'c') 133 self.assertEqual(c.val, 'c')
115 g = Grammar(['a', 'b', 'c']) 134 g = Grammar(['a', 'b', 'c'])
116 g.add_production('goal', ['a', 'c', 'b'], cb) 135 g.add_production('goal', ['a', 'c', 'b'], cb)
117 g.start_symbol = 'goal' 136 g.start_symbol = 'goal'
118 p = g.genParser() 137 p = g.genParser()
119 tokens = genTokens(['a', 'c', 'b']) 138 tokens = genTokens(['a', 'c', 'b'])
145 s0 = self.g.initialItemSet() 164 s0 = self.g.initialItemSet()
146 s, gt = self.g.genCanonicalSet(s0) 165 s, gt = self.g.genCanonicalSet(s0)
147 # Must result in 12 sets: 166 # Must result in 12 sets:
148 self.assertEqual(len(s), 24) 167 self.assertEqual(len(s), 24)
149 168
150 class testPG(unittest.TestCase): 169
170 class testParserGenerator(unittest.TestCase):
151 """ Tests several parts of the parser generator """ 171 """ Tests several parts of the parser generator """
152 def setUp(self): 172 def setUp(self):
153 g = Grammar(['(', ')']) 173 g = Grammar(['(', ')'])
154 g.add_production('goal', ['list']) 174 g.add_production('goal', ['list'])
155 g.add_production('list', ['list', 'pair']) 175 g.add_production('list', ['list', 'pair'])
214 # 4. feed input: 234 # 4. feed input:
215 p.parse(genTokens(tokens)) 235 p.parse(genTokens(tokens))
216 236
217 if __name__ == '__main__': 237 if __name__ == '__main__':
218 unittest.main() 238 unittest.main()
219
220