Mercurial > lcfOS
diff 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 |
line wrap: on
line diff
--- a/python/ppci/assembler.py Fri Feb 21 13:35:07 2014 +0100 +++ b/python/ppci/assembler.py Sun Feb 23 16:24:01 2014 +0100 @@ -5,6 +5,7 @@ from target import Target, Label from .asmnodes import ALabel, AInstruction, ABinop, AUnop, ASymbol, ANumber + def tokenize(s): """ Tokenizer, generates an iterator that @@ -70,11 +71,12 @@ class Parser: - def __init__(self): + def __init__(self, tokens, instruction_rules): # Construct a parser given a grammar: ident = lambda x: x # Identity helper function g = pyyacc.Grammar(['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*', pyyacc.EPS, 'COMMENT', '{', '}', pyyacc.EOF]) + # Global structure of assembly line: g.add_production('asmline', ['asmline2']) g.add_production('asmline', ['asmline2', 'COMMENT']) g.add_production('asmline2', ['label', 'instruction']) @@ -83,17 +85,19 @@ g.add_production('asmline2', []) g.add_production('label', ['ID', ':'], self.p_label) #g.add_production('label', []) - g.add_production('instruction', ['opcode', 'operands'], self.p_ins_1) - g.add_production('instruction', ['opcode'], self.p_ins_2) + + # Add instruction rules for the target in question: + for prod, rhs, f in instruction_rules: + if prod is 'instruction': + def f_wrap(*rhs): + i = f(rhs) + self.emit(i) + else: + def f_wrap(*rhs): + return f(rhs) + g.add_production(prod, rhs, f_wrap) + #g.add_production('instruction', []) - g.add_production('opcode', ['ID'], lambda x: x.val) - g.add_production('operands', ['operand'], self.p_operands_1) - g.add_production('operands', ['operands', ',', 'operand'], self.p_operands_2) - g.add_production('operand', ['expression'], ident) - g.add_production('operand', ['[', 'expression', ']'], self.p_mem_op) - g.add_production('operand', ['{', 'listitems', '}'], self.p_list_op) - g.add_production('listitems', ['expression'], self.p_listitems_1) - g.add_production('listitems', ['listitems', ',', 'expression'], self.p_listitems_2) g.add_production('expression', ['term'], ident) g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop) g.add_production('addop', ['-'], lambda x: x.val) @@ -147,56 +151,31 @@ self.emit = emitter self.p.parse(lexer) -# Pre construct parser to save time: -asmParser = Parser() class Assembler: def __init__(self, target, stream): self.target = target - assert isinstance(target,Target) + assert isinstance(target, Target) self.stream = stream - self.restart() - self.p = asmParser + self.parser = Parser(None, target.assembler_rules, self.stream.emit) # Top level interface: - def restart(self): - self.stack = [] - - def emit(self, a): - """ Emit a parsed instruction """ - self.stack.append(a) - def parse_line(self, line): - """ Parse line into asm AST """ + """ Parse line into assembly instructions """ tokens = Lexer(line) - self.p.parse(tokens, self.emit) + self.parser.parse(tokens) def assemble(self, asmsrc): """ Assemble this source snippet """ - if type(asmsrc) is not str: + if hasattr(asmsrc, 'read'): asmsrc2 = asmsrc.read() asmsrc.close() asmsrc = asmsrc2 + # TODO: use generic newline?? + # TODO: the bothersome newline ... for line in asmsrc.split('\n'): - self.assemble_line(line) + self.parse_line(line) def assemble_line(self, line): - """ - Assemble a single source line. - Do not take newlines into account - """ + """ Assemble a single assembly line. """ self.parse_line(line) - self.assemble_aast() - - def assemble_aast(self): - """ Assemble a parsed asm line """ - while self.stack: - vi = self.stack.pop(0) - if type(vi) is AInstruction: - mi = self.target.mapInstruction(vi) - elif type(vi) is ALabel: - mi = Label(vi.name) - else: - raise NotImplementedError('{}'.format(vi)) - if self.stream: - self.stream.emit(mi)