annotate python/pyburg.py @ 376:1e951e71d3f1

Change to readme
author Windel Bouwman
date Tue, 25 Mar 2014 19:36:51 +0100
parents d2ddfe134c48
children 0c44e494ef58
rev   line source
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
1 #!/usr/bin/python
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
2
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
3 """
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
4 Bottom up rewrite generator
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
5 ---------------------------
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
6
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
7 This script takes as input a description of patterns and outputs a
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
8 matcher class that can match trees given the patterns.
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
9
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
10 Patterns are specified as follows::
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
11
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
12 reg -> ADDI32(reg, reg) 2 (. add NT0 NT1 .)
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
13 reg -> MULI32(reg, reg) 3 (. .)
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
14
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
15 or a multiply add::
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
16
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
17 reg -> ADDI32(MULI32(reg, reg), reg) 4 (. muladd $1, $2, $3 .)
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
18
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
19 The general specification pattern is::
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
20
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
21 [result] -> [tree] [cost] [template code]
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
22
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
23 Trees
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
24 -----
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
25
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
26 A tree is described using parenthesis notation. For example a node X with
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
27 three child nodes is described as:
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
28
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
29 X(a, b, b)
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
30
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
31 Trees can be nested:
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
32
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
33 X(Y(a, a), a)
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
34
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
35 The 'a' in the example above indicates an open connection to a next tree
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
36 pattern.
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
37
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
38
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
39 In the example above 'reg' is a non-terminal. ADDI32 is a terminal. non-terminals
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
40 cannot have child nodes. A special case occurs in this case:
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
41
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
42 reg -> rc
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
43
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
44 where 'rc' is a non-terminal. This is an example of a chain rule. Chain rules
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
45 can be used to allow several variants of non-terminals.
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
46
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
47 The generated matcher uses dynamic programming to find the best match of the
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
48 tree. This strategy consists of two steps:
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
49
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
50 - label: During this phase the given tree is traversed in a bottom up way.
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
51 each node is labelled with a possible matching rule and the corresponding cost.
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
52 - select: In this step, the tree is traversed again, selecting at each point
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
53 the cheapest way to get to the goal.
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
54
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
55 """
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
56
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
57 import sys
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
58 import os
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
59 import io
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
60 import types
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
61 import argparse
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
62 from ppci import Token
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
63 from pyyacc import ParserException, EOF
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
64 import yacc
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
65 import baselex
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
66 from tree import Tree
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
67
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
68 # Generate parser on the fly:
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
69 spec_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'burg.x')
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
70 burg_parser = yacc.load_as_module(spec_file)
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
71
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
72
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
73 class BurgLexer:
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
74 def feed(self, txt):
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
75 tok_spec = [
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
76 ('id', r'[A-Za-z][A-Za-z\d_]*', lambda typ, val: (typ, val)),
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
77 ('kw', r'%[A-Za-z][A-Za-z\d_]*', lambda typ, val: (val, val)),
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
78 ('number', r'\d+', lambda typ, val: (typ, int(val))),
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
79 ('STRING', r"'[^']*'", lambda typ, val: ('string', val[1:-1])),
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
80 ('OTHER', r'[:;\|\(\),]', lambda typ, val: (val, val)),
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
81 ('SKIP', r'[ ]', None)
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
82 ]
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
83
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
84 lines = txt.split('\n')
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
85 header_lines = []
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
86
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
87 def tokenize():
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
88 section = 0
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
89 for line in lines:
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
90 line = line.strip()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
91 if not line:
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
92 continue # Skip empty lines
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
93 elif line == '%%':
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
94 section += 1
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
95 if section == 1:
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
96 yield Token('header', header_lines)
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
97 yield Token('%%', '%%')
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
98 else:
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
99 if section == 0:
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
100 header_lines.append(line)
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
101 else:
368
d2ddfe134c48 Remove yield from for python < 3.3
Windel Bouwman
parents: 357
diff changeset
102 for tk in baselex.tokenize(tok_spec, line):
d2ddfe134c48 Remove yield from for python < 3.3
Windel Bouwman
parents: 357
diff changeset
103 yield tk
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
104 yield Token(EOF, EOF)
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
105 self.tokens = tokenize()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
106 self.token = self.tokens.__next__()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
107
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
108 def next_token(self):
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
109 t = self.token
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
110 if t.typ != EOF:
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
111 self.token = self.tokens.__next__()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
112 return t
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
113
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
114
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
115 class Rule:
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
116 """ A rewrite rule. Specifies a tree that can be rewritten into a result
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
117 at a specific cost """
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
118 def __init__(self, non_term, tree, cost, acceptance, template):
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
119 self.non_term = non_term
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
120 self.tree = tree
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
121 self.cost = cost
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
122 self.acceptance = acceptance
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
123 self.template = template
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
124 self.nr = 0
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
125
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
126 def __repr__(self):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
127 return '{} -> {} ${}'.format(self.non_term, self.tree, self.cost)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
128
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
129
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
130 class Symbol:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
131 def __init__(self, name):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
132 self.name = name
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
133
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
134
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
135 class Term(Symbol):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
136 pass
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
137
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
138
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
139 class Nonterm(Symbol):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
140 def __init__(self, name):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
141 super().__init__(name)
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
142 self.chain_rules = []
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
143
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
144
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
145 class BurgSystem:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
146 def __init__(self):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
147 self.rules = []
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
148 self.symbols = {}
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
149 self.goal = None
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
150
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
151 def symType(self, t):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
152 return (s.name for s in self.symbols.values() if type(s) is t)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
153
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
154 terminals = property(lambda s: s.symType(Term))
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
155
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
156 non_terminals = property(lambda s: s.symType(Nonterm))
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
157
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
158 def add_rule(self, non_term, tree, cost, acceptance, template):
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
159 template = template.strip()
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
160 if not template:
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
161 template = 'pass'
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
162 rule = Rule(non_term, tree, cost, acceptance, template)
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
163 if len(tree.children) == 0 and tree.name not in self.terminals:
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
164 self.non_term(tree.name).chain_rules.append(rule)
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
165 self.non_term(rule.non_term)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
166 self.rules.append(rule)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
167 rule.nr = len(self.rules)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
168
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
169 def non_term(self, name):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
170 if name in self.terminals:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
171 raise BurgError('Cannot redefine terminal')
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
172 if not self.goal:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
173 self.goal = name
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
174 return self.install(name, Nonterm)
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
175
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
176 def tree(self, name, *args):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
177 return Tree(name, *args)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
178
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
179 def install(self, name, t):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
180 assert type(name) is str
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
181 if name in self.symbols:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
182 assert type(self.symbols[name]) is t
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
183 else:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
184 self.symbols[name] = t(name)
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
185 return self.symbols[name]
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
186
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
187 def add_terminal(self, terminal):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
188 self.install(terminal, Term)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
189
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
190
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
191 class BurgError(Exception):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
192 pass
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
193
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
194
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
195 class BurgParser(burg_parser.Parser):
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
196 """ Derived from automatically generated parser """
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
197 def parse(self, l):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
198 self.system = BurgSystem()
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
199 super().parse(l)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
200 return self.system
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
201
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
202
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
203 class BurgGenerator:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
204 def print(self, *args):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
205 """ Print helper function that prints to output file """
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
206 print(*args, file=self.output_file)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
207
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
208 def generate(self, system, output_file):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
209 """ Generate script that implements the burg spec """
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
210 self.output_file = output_file
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
211 self.system = system
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
212
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
213 self.print('#!/usr/bin/python')
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
214 self.print('from tree import Tree, BaseMatcher, State')
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
215 for header in self.system.header_lines:
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
216 self.print(header)
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
217 self.print()
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
218 self.print('class Matcher(BaseMatcher):')
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
219 self.print(' def __init__(self):')
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
220 self.print(' self.kid_functions = {}')
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
221 self.print(' self.nts_map = {}')
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
222 self.print(' self.pat_f = {}')
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
223 for rule in self.system.rules:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
224 kids, dummy = self.compute_kids(rule.tree, 't')
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
225 rule.num_nts = len(dummy)
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
226 lf = 'lambda t: [{}]'.format(', '.join(kids), rule)
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
227 pf = 'self.P{}'.format(rule.nr)
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
228 self.print(' # {}: {}'.format(rule.nr, rule))
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
229 self.print(' self.kid_functions[{}] = {}'.format(rule.nr, lf))
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
230 self.print(' self.nts_map[{}] = {}'.format(rule.nr, dummy))
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
231 self.print(' self.pat_f[{}] = {}'.format(rule.nr, pf))
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
232 self.print()
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
233 for rule in self.system.rules:
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
234 if rule.num_nts > 0:
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
235 args = ', '.join('c{}'.format(x) for x in range(rule.num_nts))
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
236 args = ', ' + args
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
237 else:
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
238 args = ''
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
239 # Create template function:
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
240 self.print(' def P{}(self, tree{}):'.format(rule.nr, args))
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
241 template = rule.template
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
242 for t in template.split(';'):
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
243 self.print(' {}'.format(t.strip()))
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
244 # Create acceptance function:
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
245 if rule.acceptance:
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
246 self.print(' def A{}(self, tree):'.format(rule.nr))
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
247 for t in rule.acceptance.split(';'):
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
248 self.print(' {}'.format(t.strip()))
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
249 self.emit_state()
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
250 self.print(' def gen(self, tree):')
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
251 self.print(' self.burm_label(tree)')
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
252 self.print(' if not tree.state.has_goal("{}"):'.format(self.system.goal))
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
253 self.print(' raise Exception("Tree {} not covered".format(tree))')
323
e9fe6988497c Used burg for generating expressions
Windel Bouwman
parents: 322
diff changeset
254 self.print(' return self.apply_rules(tree, "{}")'.format(self.system.goal))
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
255
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
256 def emit_record(self, rule, state_var):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
257 # TODO: check for rules fullfilled (by not using 999999)
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
258 acc = ''
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
259 if rule.acceptance:
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
260 acc = ' and self.A{}(tree)'.format(rule.nr)
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
261 self.print(' nts = self.nts({})'.format(rule.nr))
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
262 self.print(' kids = self.kids(tree, {})'.format(rule.nr))
357
818be710e13d Added acceptance function to burg
Windel Bouwman
parents: 354
diff changeset
263 self.print(' if all(x.state.has_goal(y) for x, y in zip(kids, nts)){}:'.format(acc))
354
5477e499b039 Added some sort of string functionality
Windel Bouwman
parents: 323
diff changeset
264 self.print(' c = sum(x.state.get_cost(y) for x, y in zip(kids, nts)) + {}'.format(rule.cost))
5477e499b039 Added some sort of string functionality
Windel Bouwman
parents: 323
diff changeset
265 self.print(' tree.state.set_cost("{}", c, {})'.format(rule.non_term, rule.nr))
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
266 for cr in self.system.symbols[rule.non_term].chain_rules:
354
5477e499b039 Added some sort of string functionality
Windel Bouwman
parents: 323
diff changeset
267 self.print(' # Chain rule: {}'.format(cr))
5477e499b039 Added some sort of string functionality
Windel Bouwman
parents: 323
diff changeset
268 self.print(' tree.state.set_cost("{}", c + {}, {})'.format(cr.non_term, cr.cost, cr.nr))
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
269
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
270 def emit_state(self):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
271 """ Emit a function that assigns a new state to a node """
320
84d67cce67b7 Working burg
Windel Bouwman
parents: 319
diff changeset
272 self.print(' def burm_state(self, tree):')
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
273 self.print(' tree.state = State()')
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
274 for term in self.system.terminals:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
275 self.emitcase(term)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
276 self.print()
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
277
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
278 def emitcase(self, term):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
279 rules = [rule for rule in self.system.rules if rule.tree.name == term]
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
280 for rule in rules:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
281 condition = self.emittest(rule.tree, 'tree')
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
282 self.print(' if {}:'.format(condition))
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
283 self.emit_record(rule, 'state')
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
284
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
285 def compute_kids(self, t, root_name):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
286 """ Compute of a pattern the blanks that must be provided from below in the tree """
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
287 if t.name in self.system.non_terminals:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
288 return [root_name], [t.name]
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
289 else:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
290 k = []
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
291 nts = []
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
292 for i, c in enumerate(t.children):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
293 pfx = root_name + '.children[{}]'.format(i)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
294 kf, dummy = self.compute_kids(c, pfx)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
295 nts.extend(dummy)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
296 k.extend(kf)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
297 return k, nts
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
298
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
299
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
300 def emittest(self, tree, prefix):
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
301 """ Generate condition for a tree pattern """
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
302 ct = (c for c in tree.children if c.name not in self.system.non_terminals)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
303 child_tests = (self.emittest(c, prefix + '.children[{}]'.format(i)) for i, c in enumerate(ct))
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
304 child_tests = ('({})'.format(ct) for ct in child_tests)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
305 child_tests = ' and '.join(child_tests)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
306 child_tests = ' and ' + child_tests if child_tests else ''
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
307 tst = '{}.name == "{}"'.format(prefix, tree.name)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
308 return tst + child_tests
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
309
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
310
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
311 def make_argument_parser():
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
312 """ Constructs an argument parser """
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
313 parser = argparse.ArgumentParser(description='pyburg bottom up rewrite system generator compiler compiler')
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
314 parser.add_argument('source', type=argparse.FileType('r'), \
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
315 help='the parser specification')
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
316 parser.add_argument('-o', '--output', type=argparse.FileType('w'), \
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
317 default=sys.stdout)
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
318 return parser
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
319
322
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
320 def load_as_module(filename):
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
321 """ Load a parser spec file, generate LR tables and create module """
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
322 ob = io.StringIO()
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
323 args = argparse.Namespace(source=open(filename), output=ob)
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
324 main(args)
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
325
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
326 matcher_mod = types.ModuleType('generated_matcher')
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
327 exec(ob.getvalue(), matcher_mod.__dict__)
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
328 return matcher_mod
44f336460c2a Half of use of burg spec for arm
Windel Bouwman
parents: 321
diff changeset
329
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
330
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
331 def main(args):
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
332 src = args.source.read()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
333 args.source.close()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
334
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
335 # Parse specification into burgsystem:
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
336 l = BurgLexer()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
337 p = BurgParser()
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
338 l.feed(src)
319
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
339 burg_system = p.parse(l)
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
340
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
341 # Generate matcher:
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
342 generator = BurgGenerator()
8d07a4254f04 Work on burg
Windel Bouwman
parents: 318
diff changeset
343 generator.generate(burg_system, args.output)
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
344
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
345
318
e84047f29c78 Add burg and yacc initial attempts
Windel Bouwman
parents:
diff changeset
346 if __name__ == '__main__':
321
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
347 # Parse arguments:
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
348 args = make_argument_parser().parse_args()
8c569fbe60e4 Load yacc and burg dynamic
Windel Bouwman
parents: 320
diff changeset
349 main(args)