Mercurial > lcfOS
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 |