changeset 249:e41e4109addd

Added current position arrow
author Windel Bouwman
date Fri, 26 Jul 2013 20:26:05 +0200
parents b10d46e5c8dd
children f5fba5b554d7
files python/c3/analyse.py python/c3/astnodes.py python/c3/codegenerator.py python/codeedit.py python/codegenarm.py python/icons/arrow.png python/ide.py python/ir/builder.py python/outstream.py python/ppci/common.py python/target.py python/testc3.py python/zcc.py
diffstat 13 files changed, 200 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/analyse.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/c3/analyse.py	Fri Jul 26 20:26:05 2013 +0200
@@ -89,7 +89,8 @@
             return t
         elif type(t) is Designator:
             t = self.resolveDesignator(t, scope)
-            return self.resolveType(t, scope)
+            if t:
+                return self.resolveType(t, scope)
         elif isinstance(t, Type):
             # Already resolved??
             return t
--- a/python/c3/astnodes.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/c3/astnodes.py	Fri Jul 26 20:26:05 2013 +0200
@@ -242,6 +242,7 @@
 
 class CompoundStatement(Statement):
     def __init__(self, statements):
+        super().__init__(None)
         self.statements = statements
         for s in self.statements:
             assert isinstance(s, Statement)
--- a/python/c3/codegenerator.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/c3/codegenerator.py	Fri Jul 26 20:26:05 2013 +0200
@@ -55,6 +55,7 @@
 
     def genCode(self, code):
         assert isinstance(code, astnodes.Statement)
+        self.builder.setLoc(code.loc)
         if type(code) is astnodes.CompoundStatement:
             for s in code.statements:
                 self.genCode(s)
--- a/python/codeedit.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/codeedit.py	Fri Jul 26 20:26:05 2013 +0200
@@ -13,8 +13,8 @@
    return v
 
 class InnerCode(QWidget):
-   textChanged = pyqtSignal()
-   def __init__(self, scrollArea):
+    textChanged = pyqtSignal()
+    def __init__(self, scrollArea):
       super().__init__(scrollArea)
       self.scrollArea = scrollArea
       self.setFont(QFont('Courier', 12))
@@ -23,8 +23,10 @@
       self.setCursor(Qt.IBeamCursor)
       h = QFontMetrics(self.font()).height()
       self.errorPixmap = QPixmap('icons/error.png').scaled(h, h)
+      self.arrowPixmap = QPixmap('icons/arrow.png').scaled(h, h)
       self.blinkcursor = False
       self.errorlist = []
+      self.arrow = None
       # Initial values:
       self.setSource('')
       self.CursorPosition = 0
@@ -32,74 +34,86 @@
       t.timeout.connect(self.updateCursor)
       t.setInterval(500)
       t.start()
-   def updateCursor(self):
+    def updateCursor(self):
       self.blinkcursor = not self.blinkcursor
       self.update()
       #self.update(self.cursorX, self.cursorY, self.charWidth, self.charHeight)
-   def setSource(self, src):
+
+    def setSource(self, src):
       self.src = src
       self.adjust()
-   def getSource(self):
+
+    def getSource(self):
       return self.src
-   def setErrors(self, el):
+
+    def setErrors(self, el):
       self.errorlist = el
       self.update()
-   def setCursorPosition(self, c):
+
+    def setCursorPosition(self, c):
       self.cursorPosition = clipVal(c, 0, len(self.src))
       self.update()
-   CursorPosition = property(lambda self: self.cursorPosition, setCursorPosition)
-   @property
-   def Rows(self):
-      # Make this nicer:
-      return self.src.split('\n')
-   @property
-   def CursorRow(self):
-      # TODO: make this nice.
-      txt = self.src[0:self.cursorPosition]
-      return len(txt.split('\n'))
-   @property
-   def CursorCol(self):
-      txt = self.src[0:self.cursorPosition]
-      curLine = txt.split('\n')[-1]
-      return len(curLine) + 1
-   @property
-   def CurrentLine(self):
-      return self.getRow(self.CursorRow)
-   def setRowCol(self, r, c):
+
+    CursorPosition = property(lambda self: self.cursorPosition, setCursorPosition)
+
+    @property
+    def Rows(self):
+        # Make this nicer:
+        return self.src.split('\n')
+
+    @property
+    def CursorRow(self):
+        # TODO: make this nice.
+        txt = self.src[0:self.cursorPosition]
+        return len(txt.split('\n'))
+
+    @property
+    def CursorCol(self):
+        txt = self.src[0:self.cursorPosition]
+        curLine = txt.split('\n')[-1]
+        return len(curLine) + 1
+
+    @property
+    def CurrentLine(self):
+        return self.getRow(self.CursorRow)
+
+    def setRowCol(self, r, c):
       prevRows = self.Rows[:r-1]
       txt = '\n'.join(prevRows)
       c = clipVal(c, 1, len(self.getRow(r)))
       self.CursorPosition = len(txt) + c + 1
       self.showRow(self.CursorRow)
-   def getRow(self, r):
+
+    def getRow(self, r):
       rows = self.Rows
       r = r - 1
       if r < 0 or r > len(rows) - 1:
          return ''
       else:
          return rows[r]
-   def showRow(self, r):
+
+    def showRow(self, r):
       self.scrollArea.ensureVisible(self.xposTXT, r * self.charHeight, 4, self.charHeight)
-   # Annotations:
-   def addAnnotation(self, row, col, ln, msg):
+    # Annotations:
+    def addAnnotation(self, row, col, ln, msg):
       pass
-   # Text modification:
-   def getChar(self, pos):
+    # Text modification:
+    def getChar(self, pos):
       pass
-   def insertText(self, txt):
+    def insertText(self, txt):
       self.setSource(self.src[0:self.CursorPosition] + txt + self.src[self.CursorPosition:])
       self.CursorPosition += len(txt)
       self.textChanged.emit()
-   def deleteChar(self):
+    def deleteChar(self):
       self.setSource(self.src[0:self.CursorPosition] + self.src[self.CursorPosition+1:])
       self.textChanged.emit()
-   def GotoNextChar(self):
+    def GotoNextChar(self):
       if self.src[self.CursorPosition] != '\n':
          self.CursorPosition += 1
-   def GotoPrevChar(self):
+    def GotoPrevChar(self):
       if self.src[self.CursorPosition - 1] != '\n':
          self.CursorPosition -= 1
-   def GotoNextLine(self):
+    def GotoNextLine(self):
       curLine = self.CurrentLine
       c = self.CursorCol - 1 # go to zero based
       self.CursorPosition += len(curLine) - c + 1 # line break char!
@@ -109,14 +123,14 @@
       else:
          self.CursorPosition += c
       self.showRow(self.CursorRow)
-   def GotoPrevLine(self):
+    def GotoPrevLine(self):
       c = self.CursorCol - 1 # go to zero based
       self.CursorPosition -= c + 1 # line break char!
       curLine = self.CurrentLine
       if len(curLine) > c:
          self.CursorPosition -= len(curLine) - c
       self.showRow(self.CursorRow)
-   def paintEvent(self, event):
+    def paintEvent(self, event):
       # Helper variables:
       er = event.rect()
       chw, chh = self.charWidth, self.charHeight
@@ -144,6 +158,8 @@
          painter.drawText(self.xposLNA, ypos, '{0}'.format(row))
          xpos = self.xposTXT
          painter.drawText(xpos, ypos, self.getRow(row))
+         if self.arrow and self.arrow.row == row:
+                painter.drawPixmap(self.xposERR, ypos + ydt, self.arrowPixmap)
          curErrors = [e for e in self.errorlist if e.loc.row == row]
          for e in curErrors:
                painter.drawPixmap(self.xposERR, ypos + ydt, self.errorPixmap)
@@ -157,9 +173,9 @@
                #painter.drawText(x, ypos + chh, e.msg)
          #if len(curErrors) > 0:
          #   ypos += chh
+         ypos += chh
 
-         ypos += chh
-   def keyPressEvent(self, event):
+    def keyPressEvent(self, event):
       if event.matches(QKeySequence.MoveToNextChar):
          self.GotoNextChar()
       elif event.matches(QKeySequence.MoveToPreviousChar):
@@ -190,13 +206,15 @@
          if char:
             self.insertText(char)
       self.update()
-   def mousePressEvent(self, event):
+
+    def mousePressEvent(self, event):
       pos = event.pos()
       if pos.x() > self.xposTXT and pos.x():
          c = round((pos.x() - self.xposTXT) / self.charWidth)
          r = int(pos.y() / self.charHeight) + 1
          self.setRowCol(r, c)
-   def adjust(self):
+
+    def adjust(self):
       metrics = self.fontMetrics()
       self.charHeight = metrics.height()
       self.charWidth = metrics.width('x')
@@ -223,6 +241,7 @@
         self.setRowCol = self.ic.setRowCol
         self.FileName = None
     Source = property(lambda s: s.ic.getSource(), lambda s, v: s.ic.setSource(v))
+
     def setErrors(self, el):
         self.ic.setErrors(el)
 
@@ -234,18 +253,18 @@
         if not fn:
             fn = 'Untitled'
         self.setWindowTitle(fn)
+
     def getFileName(self):
         return self.filename
     FileName = property(getFileName, setFileName)
 
 
 if __name__ == '__main__':
-   app = QApplication(sys.argv)
-   ce = CodeEdit()
-   ce.show()
-   src = ''.join(inspect.getsourcelines(InnerCode)[0])
-   ce.Source = src
-   print(ce.Source)
-   ce.resize(600, 800)
-   app.exec()
+    app = QApplication(sys.argv)
+    ce = CodeEdit()
+    ce.show()
+    src = ''.join(inspect.getsourcelines(InnerCode)[0])
+    ce.Source = src
+    ce.resize(600, 800)
+    app.exec()
 
--- a/python/codegenarm.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/codegenarm.py	Fri Jul 26 20:26:05 2013 +0200
@@ -1,5 +1,5 @@
 import ir
-from target import Label, Comment, Alignment, LabelRef, Imm32
+from target import Label, Comment, Alignment, LabelRef, Imm32, DebugInfo
 import cortexm3 as arm
 from ppci import CompilerError
 
@@ -62,23 +62,34 @@
 
     def align(self):
         self.outs.emit(Alignment(4))
+
     # Helper functions:
     def getStack(self, v):
         off = self.stack_frame.index(v)
         return off * 4
+
     def addStack(self, v):
         self.stack_frame.append(v)
         return self.getStack(v)
+
     def getGlobal(self, r, g):
         _global_address = g.name + '__global'
         self.emit(arm.ldr_pcrel(r, LabelRef(_global_address)))
+
     def loadStack(self, reg, val):
         self.emit(arm.ldr_sprel(reg, arm.MemSpRel(self.getStack(val))))
+
     def comment(self, txt):
         self.emit(Comment(txt))
 
+    def debugInfo(self, loc):
+        if loc:
+            self.emit(DebugInfo(loc))
+
     def generateInstruction(self, ins):
         self.comment(str(ins))
+        if hasattr(ins, 'debugLoc'):
+            self.debugInfo(ins.debugLoc)
         if type(ins) is ir.Branch:
             tgt = LabelRef(ins.target.name)
             self.emit(arm.b_ins(tgt))
Binary file python/icons/arrow.png has changed
--- a/python/ide.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/ide.py	Fri Jul 26 20:26:05 2013 +0200
@@ -12,6 +12,8 @@
 from codeedit import CodeEdit
 stutil = __import__('st-util')
 import c3
+import zcc
+import outstream
 
 
 class BuildOutput(QTextEdit):
@@ -91,6 +93,7 @@
         # Create mdi area:
         self.mdiArea = QMdiArea()
         self.mdiArea.setViewMode(QMdiArea.TabbedView)
+        self.mdiArea.setTabsClosable(True)
         self.setCentralWidget(self.mdiArea)
 
         # Create components:
@@ -178,9 +181,10 @@
     # MDI:
     def newCodeEdit(self):
         ce = CodeEdit()
-        ce.textChanged.connect(self.buildFile)
+        ce.textChanged.connect(self.parseFile)
         w = self.mdiArea.addSubWindow(ce)
-        ce.show()
+        self.mdiArea.setActiveSubWindow(w)
+        ce.showMaximized()
         return ce
 
     def activeMdiChild(self):
@@ -233,16 +237,26 @@
             ce.clearErrors()
 
     def pointCode(self, p):
-        print('PC', p)
+        # Lookup pc in debug infos:
+        loc = None
+        if hasattr(self, 'debugInfo'):
+            for di in self.debugInfo:
+                if di.address > p:
+                    loc = di.info
+                    break
+        if loc:
+            ce = self.activeMdiChild()
+            if ce:
+                ce.ic.arrow = loc
+            self.showLoc(loc)
 
     # Build recepy:
-    def buildFile(self):
+    def parseFile(self):
         ce = self.activeMdiChild()
         if not ce:
             return
-        self.buildOutput.clear()
         self.diag.clear()
-        self.buildOutput.append('Starting build')
+        self.buildOutput.append('Starting parse')
         ir = self.c3front.build(ce.Source)
 
         # Set errors:
@@ -254,6 +268,27 @@
         self.astViewer.setAst(ast)
         self.buildOutput.append("Done!")
 
+    def buildFile(self):
+        ce = self.activeMdiChild()
+        if not ce:
+            return
+        self.diag.clear()
+        self.buildOutput.append('Starting build')
+        outs = outstream.TextOutputStream()
+        if not zcc.zcc(ce.Source, outs, self.diag):
+            # Set errors:
+            for err in self.diag.diags:
+                self.buildOutput.append(str(err))
+            self.builderrors.setErrorList(self.diag.diags)
+            ce.setErrors(self.diag.diags)
+            return
+
+        self.buildOutput.append("Flashing stm32f4 discovery")
+        code_s = outs.getSection('code')
+        self.debugInfo = code_s.debugInfos()
+
+        self.buildOutput.append("Done!")
+
 if __name__ == '__main__':
     app = QApplication(sys.argv)
     ide = Ide()
--- a/python/ir/builder.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/ir/builder.py	Fri Jul 26 20:26:05 2013 +0200
@@ -29,40 +29,45 @@
       return v
 
 class Builder:
-   def __init__(self):
+    def __init__(self):
       self.newTmp = ValueGenerator().gen
       self.newBBint = BBGenerator().gen
       self.bb = None
       self.m = None
       self.fn = None
+      self.loc = None
 
-   # Helpers:
-   def newBB(self):
+    # Helpers:
+    def newBB(self):
       bb = self.newBBint()
       self.fn.addBB(bb)
       return bb
 
-   def setModule(self, m):
+    def setModule(self, m):
       self.m = m
 
-   def newFunction(self, name):
+    def newFunction(self, name):
       f = Function(name)
       self.m.addFunc(f)
       return f
 
-   def newVariable(self, name):
+    def newVariable(self, name):
         v = Variable(name)
         self.m.addVariable(v)
         return v
 
-   def setFunction(self, f):
+    def setFunction(self, f):
       self.fn = f
 
-   def setBB(self, bb):
+    def setBB(self, bb):
       self.bb = bb
 
-   def addIns(self, i):
-      if not self.bb:
+    def setLoc(self, l):
+        self.loc = l
+
+    def addIns(self, i):
+        i.debugLoc = self.loc
+        if not self.bb:
             raise Exception('No basic block')
-      self.bb.addInstruction(i)
+        self.bb.addInstruction(i)
 
--- a/python/outstream.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/outstream.py	Fri Jul 26 20:26:05 2013 +0200
@@ -1,5 +1,5 @@
 import binascii
-from target import Instruction, Label
+from target import Instruction, Label, DebugInfo
 
 """
  The output stream is a stream of instructions that can be output
@@ -24,6 +24,10 @@
             d.extend(insword)
         return bytes(d)
 
+    def debugInfos(self):
+        di = [i for i in self.instructions if isinstance(i, DebugInfo)]
+        return di
+
 class OutputStream:
     def __init__(self):
         self.sections = {}
@@ -35,8 +39,7 @@
 
     def selectSection(self, s):
         self.currentSection = s
-        if not s in self.sections:
-            self.sections[s] = Section()
+        self.getSection(s)
 
     def getLabelAddress(self, lname):
         assert isinstance(lname, str)
@@ -47,6 +50,11 @@
                         return i.address
         return 0
 
+    def getSection(self, name):
+        if not name in self.sections:
+            self.sections[name] = Section()
+        return self.sections[name]
+
     def backpatch(self):
         """ Fixup references to other parts in the assembler """
         for s in self.sections:
--- a/python/ppci/common.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/ppci/common.py	Fri Jul 26 20:26:05 2013 +0200
@@ -13,10 +13,14 @@
         return 'Token({0}, {1})'.format(self.typ, self.val)
 
 class SourceLocation:
-   def __init__(self, row, col, ln):
-      self.row = row
-      self.col = col
-      self.length = ln
+    def __init__(self, row, col, ln):
+        self.row = row
+        self.col = col
+        self.length = ln
+        self.filename = ''
+
+    def __repr__(self):
+        return '{}, {}'.format(self.row, self.col)
 
 SourceRange = namedtuple('SourceRange', ['p1', 'p2'])
 
--- a/python/target.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/target.py	Fri Jul 26 20:26:05 2013 +0200
@@ -86,8 +86,10 @@
 class Comment(PseudoInstruction):
     def __init__(self, txt):
         self.txt = txt
+
     def encode(self):
         return bytes()
+
     def __repr__(self):
         return '; {}'.format(self.txt)
 
@@ -107,6 +109,15 @@
             pad.append(0)
         return bytes(pad)
 
+class DebugInfo(PseudoInstruction):
+    def __init__(self, i):
+        self.info = i
+
+    def __repr__(self):
+        return 'DebugInfo: {}'.format(self.info)
+
+    def encode(self):
+        return bytes()
 
 class Register(Operand):
     def __init__(self, name):
--- a/python/testc3.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/testc3.py	Fri Jul 26 20:26:05 2013 +0200
@@ -284,6 +284,15 @@
          ret  """
         self.expectIR(snippet, block_code)
 
+    def testUnknownType(self):
+        snippet = """package testlocalvar;
+         function void t()
+         {
+            var int2 a;
+         }
+        """
+        self.expectErrors(snippet, [4])
+
     def testStruct1(self):
         snippet = """
          package teststruct1;
--- a/python/zcc.py	Fri Jul 26 16:46:02 2013 +0200
+++ b/python/zcc.py	Fri Jul 26 20:26:05 2013 +0200
@@ -15,17 +15,12 @@
 parser.add_argument('-o', '--output', help='Output file', metavar='filename')
 parser.add_argument('--hexfile', help='Output hexfile', type=argparse.FileType('w'))
 
-def main(args):
+def zcc(src, outs, diag, dumpir=False):
     # Front end:
-    src = args.source.read()
-    args.source.close()
-    diag = ppci.DiagnosticsManager()
     c3b = c3.Builder(diag)
-
     ircode = c3b.build(src)
     if not ircode:
-        diag.printErrors(src)
-        sys.exit(1)
+        return
 
     # Optimization passes:
     ircode.check()
@@ -36,14 +31,25 @@
     sidp.run(ircode)
     ircode.check()
 
-    if args.dumpir:
+    if dumpir:
         ircode.dump()
+
     # Code generation:
-
-    #cg = codegen.CodeGenerator(arm_cm3.armtarget)
-    outs = outstream.TextOutputStream()
     cg = codegenarm.ArmCodeGenerator(outs)
     obj = cg.generate(ircode)
+    return True
+
+def main(args):
+    src = args.source.read()
+    args.source.close()
+    diag = ppci.DiagnosticsManager()
+    outs = outstream.TextOutputStream()
+
+    # Invoke compiler:
+    res = zcc(src, outs, diag, dumpir=args.dumpir)
+    if not res:
+        diag.printErrors(src)
+        sys.exit(1)
 
     if args.dumpir:
         outs.dump()
@@ -54,6 +60,7 @@
         output_filename = args.output
     else:
         output_filename = 'b.output'
+
     with open(output_filename, 'wb') as f:
         f.write(code_bytes)