comparison 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
comparison
equal deleted inserted replaced
339:6ee17c4dd6b8 340:c7cc54c0dfdf
2 import re 2 import re
3 import pyyacc 3 import pyyacc
4 from . import Token, CompilerError, SourceLocation 4 from . import Token, CompilerError, SourceLocation
5 from target import Target, Label 5 from target import Target, Label
6 from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber 6 from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber
7
7 8
8 def tokenize(s): 9 def tokenize(s):
9 """ 10 """
10 Tokenizer, generates an iterator that 11 Tokenizer, generates an iterator that
11 returns tokens! 12 returns tokens!
68 self.curTok = self.tokens.__next__() 69 self.curTok = self.tokens.__next__()
69 return t 70 return t
70 71
71 72
72 class Parser: 73 class Parser:
73 def __init__(self): 74 def __init__(self, tokens, instruction_rules):
74 # Construct a parser given a grammar: 75 # Construct a parser given a grammar:
75 ident = lambda x: x # Identity helper function 76 ident = lambda x: x # Identity helper function
76 g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}', 77 g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}',
77 pyyacc.EOF]) 78 pyyacc.EOF])
79 # Global structure of assembly line:
78 g.add_production('asmline', ['asmline2']) 80 g.add_production('asmline', ['asmline2'])
79 g.add_production('asmline', ['asmline2', 'COMMENT']) 81 g.add_production('asmline', ['asmline2', 'COMMENT'])
80 g.add_production('asmline2', ['label', 'instruction']) 82 g.add_production('asmline2', ['label', 'instruction'])
81 g.add_production('asmline2', ['instruction']) 83 g.add_production('asmline2', ['instruction'])
82 g.add_production('asmline2', ['label']) 84 g.add_production('asmline2', ['label'])
83 g.add_production('asmline2', []) 85 g.add_production('asmline2', [])
84 g.add_production('label', ['ID', ':'], self.p_label) 86 g.add_production('label', ['ID', ':'], self.p_label)
85 #g.add_production('label', []) 87 #g.add_production('label', [])
86 g.add_production('instruction', ['opcode', 'operands'], self.p_ins_1) 88
87 g.add_production('instruction', ['opcode'], self.p_ins_2) 89 # Add instruction rules for the target in question:
90 for prod, rhs, f in instruction_rules:
91 if prod is 'instruction':
92 def f_wrap(*rhs):
93 i = f(rhs)
94 self.emit(i)
95 else:
96 def f_wrap(*rhs):
97 return f(rhs)
98 g.add_production(prod, rhs, f_wrap)
99
88 #g.add_production('instruction', []) 100 #g.add_production('instruction', [])
89 g.add_production('opcode', ['ID'], lambda x: x.val)
90 g.add_production('operands', ['operand'], self.p_operands_1)
91 g.add_production('operands', ['operands', ',', 'operand'], self.p_operands_2)
92 g.add_production('operand', ['expression'], ident)
93 g.add_production('operand', ['[', 'expression', ']'], self.p_mem_op)
94 g.add_production('operand', ['{', 'listitems', '}'], self.p_list_op)
95 g.add_production('listitems', ['expression'], self.p_listitems_1)
96 g.add_production('listitems', ['listitems', ',', 'expression'], self.p_listitems_2)
97 g.add_production('expression', ['term'], ident) 101 g.add_production('expression', ['term'], ident)
98 g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop) 102 g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop)
99 g.add_production('addop', ['-'], lambda x: x.val) 103 g.add_production('addop', ['-'], lambda x: x.val)
100 g.add_production('addop', ['+'], lambda x: x.val) 104 g.add_production('addop', ['+'], lambda x: x.val)
101 g.add_production('mulop', ['*'], lambda x: x.val) 105 g.add_production('mulop', ['*'], lambda x: x.val)
145 149
146 def parse(self, lexer, emitter): 150 def parse(self, lexer, emitter):
147 self.emit = emitter 151 self.emit = emitter
148 self.p.parse(lexer) 152 self.p.parse(lexer)
149 153
150 # Pre construct parser to save time:
151 asmParser = Parser()
152 154
153 class Assembler: 155 class Assembler:
154 def __init__(self, target, stream): 156 def __init__(self, target, stream):
155 self.target = target 157 self.target = target
156 assert isinstance(target,Target) 158 assert isinstance(target, Target)
157 self.stream = stream 159 self.stream = stream
158 self.restart() 160 self.parser = Parser(None, target.assembler_rules, self.stream.emit)
159 self.p = asmParser
160 161
161 # Top level interface: 162 # Top level interface:
162 def restart(self):
163 self.stack = []
164
165 def emit(self, a):
166 """ Emit a parsed instruction """
167 self.stack.append(a)
168
169 def parse_line(self, line): 163 def parse_line(self, line):
170 """ Parse line into asm AST """ 164 """ Parse line into assembly instructions """
171 tokens = Lexer(line) 165 tokens = Lexer(line)
172 self.p.parse(tokens, self.emit) 166 self.parser.parse(tokens)
173 167
174 def assemble(self, asmsrc): 168 def assemble(self, asmsrc):
175 """ Assemble this source snippet """ 169 """ Assemble this source snippet """
176 if type(asmsrc) is not str: 170 if hasattr(asmsrc, 'read'):
177 asmsrc2 = asmsrc.read() 171 asmsrc2 = asmsrc.read()
178 asmsrc.close() 172 asmsrc.close()
179 asmsrc = asmsrc2 173 asmsrc = asmsrc2
174 # TODO: use generic newline??
175 # TODO: the bothersome newline ...
180 for line in asmsrc.split('\n'): 176 for line in asmsrc.split('\n'):
181 self.assemble_line(line) 177 self.parse_line(line)
182 178
183 def assemble_line(self, line): 179 def assemble_line(self, line):
184 """ 180 """ Assemble a single assembly line. """
185 Assemble a single source line.
186 Do not take newlines into account
187 """
188 self.parse_line(line) 181 self.parse_line(line)
189 self.assemble_aast()
190
191 def assemble_aast(self):
192 """ Assemble a parsed asm line """
193 while self.stack:
194 vi = self.stack.pop(0)
195 if type(vi) is AInstruction:
196 mi = self.target.mapInstruction(vi)
197 elif type(vi) is ALabel:
198 mi = Label(vi.name)
199 else:
200 raise NotImplementedError('{}'.format(vi))
201 if self.stream:
202 self.stream.emit(mi)