comparison python/pyburg.py @ 321:8c569fbe60e4

Load yacc and burg dynamic
author Windel Bouwman
date Sun, 19 Jan 2014 18:48:45 +0100
parents 84d67cce67b7
children 44f336460c2a
comparison
equal deleted inserted replaced
320:84d67cce67b7 321:8c569fbe60e4
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 """ 3 """
4 Bottom up rewrite generator. 4 Bottom up rewrite generator.
5 5
6 This script takes as input a description of patterns and outputs a 6 This script takes as input a description of patterns and outputs a
7 matcher class that can match trees given the patterns. 7 matcher class that can match trees given the patterns.
8 8
9 Patterns are specified as follows: 9 Patterns are specified as follows:
10 reg -> ADDI32(reg, reg) 2 (. add $1 $2 .) 10 reg -> ADDI32(reg, reg) 2 (. add NT0 NT1 .)
11 reg -> MULI32(reg, reg) 3 (. .) 11 reg -> MULI32(reg, reg) 3 (. .)
12 or a multiply add: 12 or a multiply add:
13 reg -> ADDI32(MULI32(reg, reg), reg) 4 (. muladd $1, $2, $3 .) 13 reg -> ADDI32(MULI32(reg, reg), reg) 4 (. muladd $1, $2, $3 .)
14 The general specification pattern is: 14 The general specification pattern is:
15 [result] -> [tree] [cost] [template code] 15 [result] -> [tree] [cost] [template code]
16 16
17 A tree is described using parenthesis notation. For example a node X with 17 Trees
18 three 18 -----
19 child nodes is described as: 19
20 A tree is described using parenthesis notation. For example a node X with
21 three child nodes is described as:
20 X(a, b, b) 22 X(a, b, b)
21 Trees can be nested: 23 Trees can be nested:
22 X(Y(a, a), a) 24 X(Y(a, a), a)
23 The 'a' in the example above indicates an open connection to a next tree 25 The 'a' in the example above indicates an open connection to a next tree
24 pattern. 26 pattern.
25 27
26 In the example above 'reg' is a non-terminal. ADDI32 is a terminal. non-terminals 28
27 cannot have child nodes. A special case occurs in this case: 29 In the example above 'reg' is a non-terminal. ADDI32 is a terminal. non-terminals
28 reg -> rc 30 cannot have child nodes. A special case occurs in this case:
29 where 'rc' is a non-terminal. This is an example of a chain rule. Chain rules 31 reg -> rc
30 can be used to allow several variants of non-terminals. 32 where 'rc' is a non-terminal. This is an example of a chain rule. Chain rules
31 33 can be used to allow several variants of non-terminals.
32 The generated matcher uses dynamic programming to find the best match of the 34
33 tree. This strategy consists of two steps: 35 The generated matcher uses dynamic programming to find the best match of the
34 - label: During this phase the given tree is traversed in a bottom up way. 36 tree. This strategy consists of two steps:
35 each node is labelled with a possible matching rule and the corresponding cost. 37 - label: During this phase the given tree is traversed in a bottom up way.
36 - select: In this step, the tree is traversed again, selecting at each point 38 each node is labelled with a possible matching rule and the corresponding cost.
37 the cheapest way to get to the goal. 39 - select: In this step, the tree is traversed again, selecting at each point
40 the cheapest way to get to the goal.
38 41
39 """ 42 """
40 43
41 import sys 44 import sys
45 import os
42 import argparse 46 import argparse
43 from ppci import Token 47 from ppci import Token
44 import burg_parser # Automatically generated
45 from pyyacc import ParserException, EOF 48 from pyyacc import ParserException, EOF
49 import yacc
46 import baselex 50 import baselex
47 from tree import Tree 51 from tree import Tree
52
53 # Generate parser on the fly:
54 spec_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'burg.x')
55 burg_parser = yacc.load_as_module(spec_file)
48 56
49 57
50 class BurgLexer: 58 class BurgLexer:
51 def feed(self, txt): 59 def feed(self, txt):
52 tok_spec = [ 60 tok_spec = [
127 template = template[2:-2].strip() 135 template = template[2:-2].strip()
128 if not template: 136 if not template:
129 template = 'pass' 137 template = 'pass'
130 rule = Rule(non_term, tree, cost, template) 138 rule = Rule(non_term, tree, cost, template)
131 if len(tree.children) == 0 and tree.name not in self.terminals: 139 if len(tree.children) == 0 and tree.name not in self.terminals:
132 print('chain:', rule)
133 self.non_term(tree.name).chain_rules.append(rule) 140 self.non_term(tree.name).chain_rules.append(rule)
134 self.non_term(rule.non_term) 141 self.non_term(rule.non_term)
135 self.rules.append(rule) 142 self.rules.append(rule)
136 rule.nr = len(self.rules) 143 rule.nr = len(self.rules)
137 144
260 child_tests = ' and ' + child_tests if child_tests else '' 267 child_tests = ' and ' + child_tests if child_tests else ''
261 tst = '{}.name == "{}"'.format(prefix, tree.name) 268 tst = '{}.name == "{}"'.format(prefix, tree.name)
262 return tst + child_tests 269 return tst + child_tests
263 270
264 271
265 def main(): 272 def make_argument_parser():
266 # Parse arguments: 273 """ Constructs an argument parser """
267 parser = argparse.ArgumentParser(description='pyburg bottom up rewrite system generator compiler compiler') 274 parser = argparse.ArgumentParser(description='pyburg bottom up rewrite system generator compiler compiler')
268 parser.add_argument('source', type=argparse.FileType('r'), \ 275 parser.add_argument('source', type=argparse.FileType('r'), \
269 help='the parser specification') 276 help='the parser specification')
270 parser.add_argument('-o', '--output', type=argparse.FileType('w'), \ 277 parser.add_argument('-o', '--output', type=argparse.FileType('w'), \
271 default=sys.stdout) 278 default=sys.stdout)
272 args = parser.parse_args() 279 return parser
280
281
282 def main(args):
273 src = args.source.read() 283 src = args.source.read()
274 args.source.close() 284 args.source.close()
275 285
276 # Parse specification into burgsystem: 286 # Parse specification into burgsystem:
277 l = BurgLexer() 287 l = BurgLexer()
281 291
282 # Generate matcher: 292 # Generate matcher:
283 generator = BurgGenerator() 293 generator = BurgGenerator()
284 generator.generate(burg_system, args.output) 294 generator.generate(burg_system, args.output)
285 295
296
286 if __name__ == '__main__': 297 if __name__ == '__main__':
287 main() 298 # Parse arguments:
299 args = make_argument_parser().parse_args()
300 main(args)