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)