annotate python/ppci/assembler.py @ 340:c7cc54c0dfdf devel

Test featurebranch
author Windel Bouwman
date Sun, 23 Feb 2014 16:24:01 +0100
parents b00219172a42
children 4d204f6f7d4e
rev   line source
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
1
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
2 import re
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
3 import pyyacc
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
4 from . import Token, CompilerError, SourceLocation
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
5 from target import Target, Label
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
6 from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
7
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
8
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
9 def tokenize(s):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
10 """
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
11 Tokenizer, generates an iterator that
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
12 returns tokens!
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
13
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
14 This GREAT example was taken from python re doc page!
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
15 """
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
16 tok_spec = [
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
17 ('REAL', r'\d+\.\d+'),
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
18 ('HEXNUMBER', r'0x[\da-fA-F]+'),
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
19 ('NUMBER', r'\d+'),
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
20 ('ID', r'[A-Za-z][A-Za-z\d_]*'),
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
21 ('SKIP', r'[ \t]'),
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
22 ('LEESTEKEN', r':=|[\.,=:\-+*\[\]/\(\)]|>=|<=|<>|>|<|}|{'),
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
23 ('STRING', r"'.*?'"),
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
24 ('COMMENT', r";.*")
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
25 ]
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
26 tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
27 gettok = re.compile(tok_re).match
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
28 line = 1
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
29 pos = line_start = 0
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
30 mo = gettok(s)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
31 while mo is not None:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
32 typ = mo.lastgroup
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
33 val = mo.group(typ)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
34 if typ == 'NEWLINE':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
35 line_start = pos
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
36 line += 1
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
37 elif typ != 'SKIP':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
38 if typ == 'LEESTEKEN':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
39 typ = val
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
40 elif typ == 'NUMBER':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
41 val = int(val)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
42 elif typ == 'HEXNUMBER':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
43 val = int(val[2:], 16)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
44 typ = 'NUMBER'
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
45 elif typ == 'REAL':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
46 val = float(val)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
47 elif typ == 'STRING':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
48 val = val[1:-1]
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
49 col = mo.start() - line_start
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
50 loc = SourceLocation('', line, col, 0) # TODO retrieve length?
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
51 yield Token(typ, val, loc)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
52 pos = mo.end()
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
53 mo = gettok(s, pos)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
54 if pos != len(s):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
55 col = pos - line_start
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
56 loc = SourceLocation('', line, col, 0)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
57 raise CompilerError('Unexpected character {0}'.format(s[pos]), loc)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
58 yield Token('EOF', pyyacc.EOF)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
59
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
60
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
61 class Lexer:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
62 def __init__(self, src):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
63 self.tokens = tokenize(src)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
64 self.curTok = self.tokens.__next__()
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
65
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
66 def next_token(self):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
67 t = self.curTok
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
68 if t.typ != 'EOF':
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
69 self.curTok = self.tokens.__next__()
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
70 return t
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
71
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
72
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
73 class Parser:
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
74 def __init__(self, tokens, instruction_rules):
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
75 # Construct a parser given a grammar:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
76 ident = lambda x: x # Identity helper function
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
77 g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}',
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
78 pyyacc.EOF])
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
79 # Global structure of assembly line:
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
80 g.add_production('asmline', ['asmline2'])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
81 g.add_production('asmline', ['asmline2', 'COMMENT'])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
82 g.add_production('asmline2', ['label', 'instruction'])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
83 g.add_production('asmline2', ['instruction'])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
84 g.add_production('asmline2', ['label'])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
85 g.add_production('asmline2', [])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
86 g.add_production('label', ['ID', ':'], self.p_label)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
87 #g.add_production('label', [])
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
88
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
89 # Add instruction rules for the target in question:
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
90 for prod, rhs, f in instruction_rules:
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
91 if prod is 'instruction':
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
92 def f_wrap(*rhs):
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
93 i = f(rhs)
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
94 self.emit(i)
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
95 else:
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
96 def f_wrap(*rhs):
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
97 return f(rhs)
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
98 g.add_production(prod, rhs, f_wrap)
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
99
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
100 #g.add_production('instruction', [])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
101 g.add_production('expression', ['term'], ident)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
102 g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
103 g.add_production('addop', ['-'], lambda x: x.val)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
104 g.add_production('addop', ['+'], lambda x: x.val)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
105 g.add_production('mulop', ['*'], lambda x: x.val)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
106 g.add_production('term', ['factor'], ident)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
107 g.add_production('term', ['term', 'mulop', 'factor'], self.p_binop)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
108 g.add_production('factor', ['ID'], lambda name: ASymbol(name.val))
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
109 g.add_production('factor', ['NUMBER'], lambda num: ANumber(int(num.val)))
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
110 g.start_symbol = 'asmline'
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
111 self.p = g.genParser()
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
112
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
113 # Parser handlers:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
114 def p_ins_1(self, opc, ops):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
115 ins = AInstruction(opc, ops)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
116 self.emit(ins)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
117
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
118 def p_ins_2(self, opc):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
119 self.p_ins_1(opc, [])
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
120
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
121 def p_operands_1(self, op1):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
122 return [op1]
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
123
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
124 def p_operands_2(self, ops, comma, op2):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
125 assert type(ops) is list
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
126 ops.append(op2)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
127 return ops
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
128
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
129 def p_listitems_1(self, li1):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
130 return [li1]
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
131
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
132 def p_listitems_2(self, lis, comma, li2):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
133 assert type(lis) is list
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
134 lis.append(li2)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
135 return lis
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
136
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
137 def p_list_op(self, brace_open, lst, brace_close):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
138 return AUnop('{}', lst)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
139
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
140 def p_mem_op(self, brace_open, exp, brace_close):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
141 return AUnop('[]', exp)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
142
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
143 def p_label(self, lname, cn):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
144 lab = ALabel(lname.val)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
145 self.emit(lab)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
146
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
147 def p_binop(self, exp1, op, exp2):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
148 return ABinop(op, exp1, exp2)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
149
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
150 def parse(self, lexer, emitter):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
151 self.emit = emitter
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
152 self.p.parse(lexer)
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
153
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
154
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
155 class Assembler:
336
d1ecc493384e Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents: 334
diff changeset
156 def __init__(self, target, stream):
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
157 self.target = target
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
158 assert isinstance(target, Target)
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
159 self.stream = stream
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
160 self.parser = Parser(None, target.assembler_rules, self.stream.emit)
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
161
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
162 # Top level interface:
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
163 def parse_line(self, line):
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
164 """ Parse line into assembly instructions """
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
165 tokens = Lexer(line)
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
166 self.parser.parse(tokens)
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
167
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
168 def assemble(self, asmsrc):
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
169 """ Assemble this source snippet """
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
170 if hasattr(asmsrc, 'read'):
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
171 asmsrc2 = asmsrc.read()
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
172 asmsrc.close()
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
173 asmsrc = asmsrc2
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
174 # TODO: use generic newline??
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
175 # TODO: the bothersome newline ...
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
176 for line in asmsrc.split('\n'):
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
177 self.parse_line(line)
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
178
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
179 def assemble_line(self, line):
340
c7cc54c0dfdf Test featurebranch
Windel Bouwman
parents: 337
diff changeset
180 """ Assemble a single assembly line. """
334
6f4753202b9a Added more recipes
Windel Bouwman
parents:
diff changeset
181 self.parse_line(line)