changeset 104:ed230e947dc6

Added hexviewer
author windel
date Sun, 30 Dec 2012 22:31:55 +0100
parents 28a35161ef23
children 6a303f835c6d
files python/hexfile.py python/hexviewer.py python/ppci/compilers/kscompiler.py python/ppci/core/__init__.py python/ppci/core/bitreader.py python/ppci/core/context.py python/ppci/core/function.py python/ppci/core/instruction.py python/ppci/core/llvmtype.py python/ppci/core/module.py python/ppci/core/value.py python/ppci/frontends/ks/irgenerator.py python/ppci/frontends/ks/nodes.py python/zcc.py
diffstat 14 files changed, 315 insertions(+), 183 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/hexfile.py	Sun Dec 30 22:31:55 2012 +0100
@@ -0,0 +1,97 @@
+import os
+
+class HexFileException(Exception):
+   pass
+
+def parseHexLine(line):
+   """ Parses a hexfile line into three parts """
+   line = line[1:] # Remove ':'
+   nums = bytes.fromhex(line)
+   bytecount = nums[0]
+   if len(nums) != bytecount + 5:
+      raise HexFileException('byte count field incorrect')
+   crc = sum(nums)
+   if (crc & 0xFF) != 0:
+      raise HexFileException('crc incorrect')
+   address = nums[1] * 256 + nums[2]
+   typ = nums[3]
+   data = nums[4:-1]
+   return (address, typ, data)
+
+class HexFile:
+   """ Represents an intel hexfile """
+   def __init__(self, filename=None):
+      self.regions = []
+      self.startAddress = 0
+      self.filename = None
+      if filename:
+         self.load(filename)
+
+   def load(self, filename):
+      with open(filename, 'r') as f:
+         endOfFile = False
+         offset = 0
+         startAddress = 0
+         curAddress = 0
+         curData = bytearray()
+         for line in f:
+            line = line.strip() # Strip spaces and newlines
+            if not line: continue # Skip empty lines
+            if line[0] != ':': continue # Skip lines that do not start with a ':'
+            if endOfFile: raise HexFileException('hexfile line after end of file record')
+            address, typ, data = parseHexLine(line)
+            if typ == 0x0: # Data record
+               address += offset # Fix address with offset
+               # Append data
+               if address == curAddress:
+                  curData += data
+                  curAddress += len(data)
+               else:
+                  if curData:
+                     self.regions.append(HexFileRegion(startAddress, bytes(curData)))
+                  startAddress = address
+                  curAddress = address + len(data)
+                  curData = bytearray(data)
+            elif typ == 0x4: # Extended linear address record
+               offset = ((data[0] << 8) + data[1]) << 16
+            elif typ == 0x1: # End of file record
+               if len(data) != 0:
+                  raise HexFileException('end of file record must contain no data')
+               endOfFile = True
+            elif typ == 0x5: # Start address record (where IP goes after loading)
+               self.startAddress = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3]
+            else:
+               raise HexFileException('record type {0} not implemented'.format(typ))
+               print(hex(address), typ, data)
+         # After all lines:
+         if curData:
+            self.regions.append(HexFileRegion(startAddress, bytes(curData)))
+         # Store the filename:
+         self.filename = filename
+   def __repr__(self):
+      i = []
+      i.append(super().__repr__())
+      i.append('Start address {0}'.format(hex(self.startAddress)))
+      i.append('Filename: {0}'.format(self.filename))
+      for r in self.regions:
+         i.append(str(r))
+      return os.linesep.join(i)
+   def save(self, filename):
+      with open(filename, 'w') as f:
+         for line in f:
+            pass
+     
+class HexFileRegion:
+   def __init__(self, address, data = bytes()):
+      self.address = address
+      self.data = data
+   def __repr__(self):
+      return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data))
+
+if __name__ == '__main__':
+   h = HexFile()
+   print(h)
+   """ Test hexfile implementation with some hexfile """
+   h1 = HexFile('audio.hex')
+   print(h1)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/hexviewer.py	Sun Dec 30 22:31:55 2012 +0100
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+import sys
+import hexfile
+
+class BinViewer(QWidget):
+   """
+      The binviewer consists of a hex view, a ascii view
+      and perhaps others..
+   """
+   def __init__(self):
+      super().__init__()
+      self.setFont(QFont('Courier'))
+      self.fontHeight = self.fontMetrics().height()
+      self.fontWidth = self.fontMetrics().width('x')
+      self.hexfile = hexfile.HexFile()
+   def paintEvent(self, event):
+      painter = QPainter(self)
+      br = QBrush(Qt.lightGray)
+      painter.setBrush(br)
+      h = self.height()
+      addressWidth = self.fontWidth * 8
+      painter.drawRect(2, 2, addressWidth, h)
+      br2 = QBrush(Qt.yellow)
+      painter.setBrush(br2)
+      w = self.width()
+      byteWidth = self.fontWidth * 16 * 3
+      painter.drawRect(addressWidth + 4, 2, byteWidth, h)
+      asciiWidth = self.fontWidth * 16
+      br2 = QBrush(Qt.gray)
+      painter.setBrush(br2)
+      painter.drawRect(addressWidth + byteWidth + 4, 2, asciiWidth, h)
+      for r in range(1, 10):
+         addr = '{0:08X}'.format(r << 16)
+         painter.drawText(2, 2 + self.fontHeight * r, addr)
+         bts = bytes(range(16))
+         x = addressWidth + 4
+         for b in bts:
+            b = '{0:02X}'.format(b)
+            painter.drawText(x, 2 + self.fontHeight * r, b)
+            x += 3 * self.fontWidth
+         x = addressWidth + byteWidth + 4
+         for b in bts:
+            b = '{0}'.format(chr(b))
+            painter.drawText(x, 2 + self.fontHeight * r, b)
+            x += 1 * self.fontWidth
+   def setHexFile(self, hf):
+      self.hexFile = hf
+      self.update()
+
+class BinViewMain(QMainWindow):
+   def __init__(self):
+      super().__init__()
+      self.bv = BinViewer()
+      self.setCentralWidget(self.bv)
+      self.bv.setHexFile(hexfile.HexFile('audio.hex'))
+      mb = self.menuBar()
+      fileMenu = mb.addMenu("File")
+      
+      def addMenuEntry(name, menu, callback, shortcut=None):
+         a = QAction(name, self)
+         menu.addAction(a)
+         a.triggered.connect(callback)
+         if shortcut: a.setShortcut(shortcut)
+      addMenuEntry("Open", fileMenu, self.openFile, QKeySequence(QKeySequence.Open))
+   def openFile(self):
+      filename = QFileDialog.getOpenFileName(self, "Open hex file...", "*.hex", "Intel hexfiles (*.hex)")
+      if filename:
+         h = hexfile.HexFile(filename)
+
+if __name__ == '__main__':
+   app = QApplication(sys.argv)
+   bv = BinViewMain()
+   bv.show()
+   app.exec_()
+
--- a/python/ppci/compilers/kscompiler.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/compilers/kscompiler.py	Sun Dec 30 22:31:55 2012 +0100
@@ -5,17 +5,16 @@
 #from .codegenerator import CodeGenerator
 #from .nodes import ExportedSymbol
 from ..core.errors import CompilerException
-from ..core import version
+from ..core.bitreader import BitcodeWriter
+from ..core import version, Context
 #from .. import version
 
 class KsCompiler:
    def __repr__(self):
       return 'LCFOS compiler {0}'.format(version)
 
-   def generateSignature(self, src):
-      return hashlib.md5(bytes(src,encoding='ascii')).hexdigest()
-
    def compilesource(self, src):
+      context = Context()
       """ Front end that handles the stages: """
       self.errorlist = []
       # Pass 1: parsing and type checking
@@ -28,22 +27,10 @@
       if len(p.errorlist) > 0:
          self.errorlist = p.errorlist
          return
+      ir = KsIrGenerator().generateIr(context, ast)
       # pass 2: Optimization
       # TODO: implement optimization
 
       # Pass 3: code generation
-      ir = KsIrGenerator().generateIr(ast)
-      # Attach a signature:
-      ast.signature = self.generateSignature(src)
-      # Generate exported symbols:
       return ast
 
-   def compileProject(self, project):
-      mods = []
-      for fname in project.files:
-         print('Compiling {0}...'.format(fname))
-         source = project.loadProjectFile(fname)
-         mod = self.compilesource(source)
-         mods.append(mod)
-      return mods
-
--- a/python/ppci/core/__init__.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/__init__.py	Sun Dec 30 22:31:55 2012 +0100
@@ -1,10 +1,11 @@
 from .instruction import *
-from .function import *
-from .value import *
-from .bitreader import BitReader
+from .function import Function
+from .value import Value
+from .bitreader import BitReader, BitcodeWriter
 from .errors import CompilerException
 from .module import Module
-
+from .llvmtype import FunctionType
+from .context import Context
 
 version='0.0.1'
 
--- a/python/ppci/core/bitreader.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/bitreader.py	Sun Dec 30 22:31:55 2012 +0100
@@ -26,3 +26,49 @@
          return int(b[0])
       return 2
 
+class BitstreamWriter:
+   def __init__(self, f):
+      self.f = f
+      self.u32 = 0
+      self.curpos = 0
+   def Emit1(self, val):
+      self.Emit(val, 1)
+   def Emit(self, val, numbits):
+      """ Emits value using numbits bits """
+      if numbits == 1:
+         if val != 0:
+            self.u32 |= (0x1 << self.curpos)
+         self.curpos += 1
+         if self.curpos == 32:
+            self.writeWord()
+      elif numbits > 1:
+         for i in range(numbits):
+            if val & (1 << i) != 0:
+               self.Emit1(1)
+            else:
+               self.Emit1(0)
+   def writeWord(self):
+      bts = struct.pack('<I', self.u32)
+      self.f.write(bts)
+      self.u32 = 0
+      self.curpos = 0
+   def flush(self):
+      if self.curpos != 0:
+         self.writeWord()
+
+class BitcodeWriter:
+   def __init__(self):
+      pass
+   def WriteModule(self, module):
+      pass
+   def WriteModuleToFile(self, module, f):
+      s = BitstreamWriter(f)
+      s.Emit(ord('B'), 8)
+      s.Emit(ord('C'), 8)
+      s.Emit(0x0, 4)
+      s.Emit(0xC, 4)
+      s.Emit(0xE, 4)
+      s.Emit(0xD, 4)
+      self.WriteModule(module)
+      s.flush()
+
--- a/python/ppci/core/context.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/context.py	Sun Dec 30 22:31:55 2012 +0100
@@ -1,4 +1,12 @@
+from .llvmtype import IntegerType, llvmType, typeID, FunctionType
 
 class Context:
-   pass
+   """ Global context """
+   def __init__(self):
+      self.Int8Type = IntegerType(self, 8)
+      self.Int16Type = IntegerType(self, 16)
+      self.Int32Type = IntegerType(self, 32)
+      self.Int64Type = IntegerType(self, 64)
+      self.VoidType = llvmType(self, typeID.Void)
+      self.DoubleType = llvmType(self, typeID.Double)
 
--- a/python/ppci/core/function.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/function.py	Sun Dec 30 22:31:55 2012 +0100
@@ -1,6 +1,7 @@
 
 class Function:
-   def __init__(self):
-      pass
+   def __init__(self, functiontype, name, module):
+      self.functiontype = functiontype
+      self.name = name
+      self.module = module
 
-
--- a/python/ppci/core/instruction.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/instruction.py	Sun Dec 30 22:31:55 2012 +0100
@@ -2,16 +2,18 @@
 from .value import Value
 
 class Instruction(Value):
-   """
-      Base class for all instructions.
-   """
+   """ Base class for all instructions. """
    pass
 
 class CallInstruction(Instruction):
    pass
 
 class BinaryOperator(Instruction):
-   pass
+   def __init__(self, operation, value1, value2):
+      # Check types of the two operands:
+      self.value1 = value1
+      self.value2 = value2
+      self.operation = operation
 
 class LoadInstruction(Instruction):
    def __init__(self, ptr, name, insertBefore):
--- a/python/ppci/core/llvmtype.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/llvmtype.py	Sun Dec 30 22:31:55 2012 +0100
@@ -2,12 +2,20 @@
 def Enum(**enums):
    return type('Enum', (), enums)
 
+typeID = Enum(Void=0, Double=3, Integer=10, Function=11, Struct=12, Array=13, Pointer=14, Vector=15)
+
 class llvmType:
-   typeID = Enum(Void=0, Double=3, Integer=10, \
-                 Function=11, Struct=12, \
-                 Array=13, Pointer=14\
-                 Vector=15)
    def __init__(self, context, tid):
       self.context = context
       
+class IntegerType(llvmType):
+   def __init__(self, context, bits):
+      super().__init__(context, typeID.Integer)
+      self.bits = bits
 
+class FunctionType(llvmType):
+   def __init__(self, resultType, parameterTypes):
+      super().__init__(resultType.context, typeID.Function)
+      self.resultType = resultType
+      self.parameterTypes = parameterTypes
+
--- a/python/ppci/core/module.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/module.py	Sun Dec 30 22:31:55 2012 +0100
@@ -1,5 +1,7 @@
 
-class Module:
+from .value import Value
+
+class Module(Value):
    def __init__(self):
       print('new module!')
    
--- a/python/ppci/core/value.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/core/value.py	Sun Dec 30 22:31:55 2012 +0100
@@ -5,6 +5,8 @@
       self.name = None
    def getContext(self):
       return self.valueType.context
+   def dump(self):
+      print(self)
 
    def setName(self, name):
       if not self.name and not name:
--- a/python/ppci/frontends/ks/irgenerator.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/frontends/ks/irgenerator.py	Sun Dec 30 22:31:55 2012 +0100
@@ -6,7 +6,6 @@
 from ...core.errors import Error
 from ... import core
 from .builtin import real, integer, boolean, char
-#from .assembler import *
 
 class KsIrGenerator:
    def __init__(self):
@@ -26,19 +25,17 @@
 
          if node.op == 'mod':
             assert(node.typ.isType(integer))
-            self.addCode(mov('rax', node.a.reg))
          elif node.op == 'div':
             assert(node.typ.isType(integer))
-            self.addCode(mov('rax', node.a.reg))
          elif node.op == '*':
             if node.typ.isType(integer):
-               self.addCode(imulreg64(node.a.reg, node.b.reg))
+               pass
          elif node.op == '+':
             if node.typ.isType(integer):
-               self.addCode(addreg64(node.a.reg, node.b.reg))
+               pass
          elif node.op == '-':
             if node.typ.isType(integer):
-               self.addCode(subreg64(node.a.reg, node.b.reg))
+               pass
          else:
             Error('Unknown Binop {0}'.format(node.op))
 
@@ -78,14 +75,8 @@
                   self.genexprcode(node.obj)
                   node.reg = node.obj.reg
                else:
-                  self.getreg(node)
+                  pass
                   # Get a register to store the integer value
-                  if node.obj.isLocal:
-                     # relative to rbp:
-                     self.addCode( mov(node.reg, ['rbp', node.obj.offset]) )
-                  else:
-                     self.addCode(mov(node.reg, ['RIP', 0x0]))
-                     self.fixCode(self.rip-4, imm32(node.obj.offset - self.rip))
             else:
                Error('Cannot load variable type {0}'.format(node.typ))
 
@@ -101,32 +92,10 @@
             Error('Relop not implemented for {0}'.format(node.a.typ))
 
       elif type(node) is Constant:
-         if node.typ.isType(integer):
-            self.getreg(node)
+         print('TODO: constant')
 
       elif type(node) is ProcedureCall:
-         if type(node.proc.obj) is BuiltinProcedure:
-            # Handle builtin procedures different, these not always call
-            # a function, but generate code.
-            bi = node.proc.obj
-            if bi.name == 'chr':
-               arg = node.args[0]
-               self.genexprcode(arg)
-               # Store character in full width register:
-               # TODO: store in char only register
-               node.reg = arg.reg
-            else:
-               Error('Unknown builtin function {0}'.format(bi.name))
-         else:
-            # Use generic procedure call first
-            self.gencode(node)
-            # Retrieve result:
-            if node.typ.isType(integer):
-               # Store result!
-               self.getreg(node)
-               self.addCode( mov(node.reg, 'rax') )
-            else:
-               Error('Return type not supported {0}'.format(node.typ))
+         Error('TODO: proc call')
       else:
          Error('Cannot generate expression code for: {0}'.format(node))
 
@@ -134,44 +103,19 @@
       """ Code generation function for AST nodes """
       if isinstance(node, Module):
          # TODO: recurse!
-         return core.Module()
+         
+         self.mod = core.Module()
+         # Create a function called init for this module:
+         ftype = core.FunctionType(self.context.VoidType, [])
+         func = core.Function(ftype, "init", self.mod)
+         bb = self.gencode(node.initcode)
+         self.mod.dump()
+         return self.mod
 
       elif type(node) is Procedure:
         # calculate offsets for local variables and parameters
         # Variable location relative to 'rbp' register
         variables = node.symtable.getAllLocal(Variable)
-        offset = 0
-        paramoffset = 16
-        for var in variables:
-           var.isLocal = True
-           if not var.isParameter:
-              offset += var.typ.size
-              # Offset is negative of rbp in stack frame
-              var.offset = -offset
-        node.framesize = offset
-        # Calculate offsets of parameters relative to rbp register
-        for par in reversed(node.typ.parameters):
-           pvar = node.symtable.getLocal(Variable, par.name)
-           pvar.offset = paramoffset
-           paramoffset += pvar.typ.size
-
-        # code generation
-        node.entrypoint = self.rip
-        self.addCode(push('rbp'))
-        self.addCode(mov('rbp', 'rsp')) # Setup the base pointer
-        self.addCode(subreg64('rsp', node.framesize)) # reserve space for locals
-        self.gencode(node.block)
-        if node.retexpr:
-           if node.retexpr.typ.isType(integer):
-              self.genexprcode(node.retexpr)
-              self.addCode( mov('rax', node.retexpr.reg) )
-              self.freereg(node.retexpr)
-           else:
-              Error('Cannot return this kind yet {0}'.format(node.retexpr.typ))
-        self.addCode( addreg64('rsp', node.framesize) )
-        self.addCode( pop('rbp') )
-        self.addCode( ret() )
-        assert(len(self.usedregs) == 0)
 
       elif isinstance(node, StatementSequence):
          for s in node.statements:
@@ -179,7 +123,6 @@
 
       elif type(node) is ProcedureCall:
          # Prepare parameters on the stack:
-         stacksize = 0
          assert(len(node.args) == len(node.proc.typ.parameters))
          for arg, param in zip(node.args, node.proc.typ.parameters):
 
@@ -191,98 +134,33 @@
             else:
                Error('Parameter kind other than value')
 
-         # Calculate address using designator
-         if type(node.proc.obj) is Procedure:
-            self.addCode( call(0x0) )
-            self.fixCode( self.rip - 4, imm32(node.proc.obj.entrypoint - self.rip))
-         elif type(node.proc.obj) is ImportedSymbol:
-            # Load the entry point of the import table
-            self.getreg(node.proc.obj)
-            # Load the address of the procedure:
-            self.addCode( mov(node.proc.obj.reg, ['RIP', 0x0]) )
-            self.fixCode( self.rip - 4, imm32(node.proc.obj.offset - self.rip) )
-            # Call to the address in register:
-            self.addCode( call(node.proc.obj.reg) )
-            # Free register that holds the address of the object
-            self.freereg( node.proc.obj )
-         elif type(node.proc.obj) is BuiltinProcedure:
-            if node.proc.obj.name == 'chr':
-               print('int to char')
-            else:
-               Error('Unknown builtin function {0}'.format(node.proc.obj.name))
-         else:
-            Error('Cannot call designator of type {0}'.format(node.proc.obj))
-
-         # Restore stack (pop all arguments of):
-         self.addCode(addreg64('rsp', stacksize))
-
       elif type(node) is Assignment:
          if node.lval.typ.isType(integer):
            # TODO if node.rval is Constant of some datatype, move it to mem directly
            self.genexprcode(node.rval) # Calculate the value that has to be stored.
-           self.storeRegInDesignator(node.rval.reg, node.lval)
-           self.freereg(node.rval)
+           print("TODO")
          else:
             Error('Assignments of other types not implemented')
             # TODO if left and right are designators, do some sort of memcpy.
 
       elif type(node) is IfStatement:
         self.genexprcode(node.condition)
-        self.addCode( cmpreg64(node.condition.reg, 1) )
-        self.freereg(node.condition)
+        print("TODO IF")
         if node.falsestatement:
            # If with else clause
-           self.addCode( nearjump(0x0, condition='NE') ) # if Not Equal jump to false
-           rip1 = self.rip
-           fixloc1 = self.rip - 4
-           self.gencode(node.truestatement)
-           self.addCode( nearjump( 0x0 ) ) # jump over false code
-           fixloc2 = self.rip - 4
-           self.fixCode(fixloc1, imm32(self.rip - rip1))
-           rip2 = self.rip
-           self.gencode(node.falsestatement)
-           self.fixCode(fixloc2, imm32(self.rip - rip2))
+           pass
         else:
            # If without else clause
-           self.addCode( nearjump(0x0, condition='NE') ) # if Not Equal jump to false
-           rip1 = self.rip
-           fixloc1 = self.rip - 4
-           self.gencode(node.truestatement)
-           self.fixCode(fixloc1, imm32(self.rip - rip1)) # Fixup near jump over true code.
+           pass
 
       elif isinstance(node, WhileStatement):
-        rip1 = self.rip # Store the start of the while loop
         self.genexprcode(node.condition)
-        self.addCode( cmpreg64(node.condition.reg, 1) ) # Test condition for true-ness
-        self.freereg(node.condition)
-        self.addCode( nearjump(0x0, condition='NE') ) # If Not Equal jump over while code AND jump back (fix later)
-        fixloc1 = self.rip - 4
-        rip2 = self.rip
         self.gencode(node.dostatements)
-        self.addCode( nearjump(0x0) ) # JMP to condition, fix exact jump position below
-        fixloc2 = self.rip - 4
-        rip3 = self.rip # end of while loop
-        self.fixCode(fixloc2, imm32(rip1 - rip3)) # Fixup jump to start of while loop
-        self.fixCode(fixloc1, imm32(rip3 - rip2)) # Fixup jump out of while loop
-
       elif type(node) is ForStatement:
          # Initial load of iterator variable:
          self.genexprcode(node.begin)
          self.genexprcode(node.end)
-         # TODO: link reg with variable so that a register is used instead of a variable
-         iterreg = node.begin.reg # Get the register used for the loop
-         #self.addCode(cmpreg64(iterreg, node.endvalue))
-         rip1 = self.rip
          self.gencode(node.statements)
-         #self.loadDesignatorInReg(node.
-         #self.addCode( addreg64(node.variable, node.increment) )
-         self.addCode(nearjump(0x0))
-         fixloc1 = self.rip - 4
-         rip2 = self.rip
-         self.fixCode(fixloc1, imm32(rip1 - rip2))
-
-         self.freereg(node.begin) # Release register used in loop
-         self.freereg(node.end)
          Error('No implementation of FOR statement')
 
       elif type(node) is AsmCode:
@@ -325,11 +203,6 @@
                if type(selector) is Index:
                   # Deref an array index
                   self.genexprcode(selector.index)
-                  self.getreg(selector)
-                  self.addCode( mov(selector.reg, selector.typ.elementType.size) )
-                  self.addCode( imulreg64(selector.reg, selector.index.reg ) )
-                  self.freereg(selector.index)
-                  self.addCode(addreg64(node.reg, selector.reg))
                   self.freereg(selector)
                elif type(selector) is Field:
                   print('Field')
@@ -338,11 +211,12 @@
                   Error('Unknown selector')
          else:
             Error('Can only gencode for designator with selectors')
-
       else:
          print('not generating code for {0}'.format(node))
 
-   def generateIr(self, ast):
+   def generateIr(self, context, ast):
      """ ir generation front end """
+     # Create a new context for this code.
+     self.context = context
      return self.gencode(ast)
 
--- a/python/ppci/frontends/ks/nodes.py	Wed Dec 26 10:53:33 2012 +0100
+++ b/python/ppci/frontends/ks/nodes.py	Sun Dec 30 22:31:55 2012 +0100
@@ -31,14 +31,14 @@
    def __init__(self, fieldname):
       self.fieldname = fieldname
    def __repr__(self):
-      return 'FLD {0}'.format(self.fieldname)
+      return 'FIELD {0}'.format(self.fieldname)
 
 class Index(Node):
    def __init__(self, index, typ):
       self.index = index
       self.typ = typ
    def __repr__(self):
-      return 'IDX {0}'.format(self.index)
+      return 'INDEX {0}'.format(self.index)
 
 class Deref(Node):
    pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/zcc.py	Sun Dec 30 22:31:55 2012 +0100
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+
+import sys, os, argparse
+from ppci.compilers import KsCompiler
+from ppci.core import BitcodeWriter
+
+if __name__ == '__main__':
+   parser = argparse.ArgumentParser(description='K# to bitcode compiler')
+   parser.add_argument('source', type=str, help='the source file to build')
+   args = parser.parse_args()
+
+   print(args)
+   try:
+      with open(args.source, 'r') as f:
+         src = f.read()
+   except IOError:
+      print('Failed to load {0}'.format(args.project))
+      sys.exit(3)
+   c = KsCompiler()
+   module = c.compilesource(src)
+
+   with open('sjaak.bc', 'wb') as f:
+      BitcodeWriter().WriteModuleToFile(module, f)
+
+      
+