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