changeset 221:848c4b15fd0b

pointers
author Windel Bouwman
date Mon, 08 Jul 2013 22:21:44 +0200
parents 3f6c30a5d234
children c3f1ce8b638f
files python/c3/astnodes.py python/c3/codegenerator.py python/c3/examples/cast.c3 python/c3/lexer.py python/c3/parser.py python/c3/typecheck.py python/ir/instruction.py python/stm32f4/blink.c3 python/testc3.py
diffstat 9 files changed, 102 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/python/c3/astnodes.py	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/c3/astnodes.py	Mon Jul 08 22:21:44 2013 +0200
@@ -74,6 +74,9 @@
    def __repr__(self):
       return 'Named type {0} of type {1}'.format(self.name, self.typ)
 
+#class TypeCast(Node):
+#    def __init__(self, 
+
 # Variables, parameters, local variables, constants:
 class Symbol(Node):
     def __init__(self, name):
--- a/python/c3/codegenerator.py	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/c3/codegenerator.py	Mon Jul 08 22:21:44 2013 +0200
@@ -51,12 +51,13 @@
 
     def genCode(self, code):
       if type(code) is astnodes.CompoundStatement:
-         for s in code.statements:
-            self.genCode(s)
+            for s in code.statements:
+                self.genCode(s)
       elif type(code) is astnodes.Assignment:
          re = self.genExprCode(code.rval)
          # TODO: Handle pointers
-         loc = self.varMap[code.lval.target]
+         loc = self.genExprCode(code.lval)
+         # determine location of variable
          self.builder.addIns(ir.Store(loc, re))
       elif type(code) is astnodes.IfStatement:
          bbtrue = self.builder.newBB()
@@ -70,9 +71,6 @@
          self.genCode(code.falsestatement)
          self.builder.addIns(ir.Branch(te))
          self.builder.setBB(te)
-      elif type(code) is astnodes.FunctionCall:
-         print('TODO')
-         pass
       elif type(code) is astnodes.EmptyStatement:
          pass
       elif type(code) is astnodes.ReturnStatement:
@@ -126,9 +124,9 @@
       if type(expr) is astnodes.Binop:
          ra = self.genExprCode(expr.a)
          rb = self.genExprCode(expr.b)
-         ops = ['+', '-', '*', '/']
+         ops = ['+', '-', '*', '/', '|', '&']
          if expr.op in ops:
-            tmpnames = {'+':'addtmp', '-':'subtmp', '*': 'multmp', '/':'divtmp'}
+            tmpnames = {'+':'add', '-':'sub', '*': 'mul', '/':'div', '|':'or', '&':'and'}
             tmp = self.builder.newTmp(tmpnames[expr.op])
             op = expr.op
             ins = ir.BinaryOperator(tmp, op, ra, rb)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/c3/examples/cast.c3	Mon Jul 08 22:21:44 2013 +0200
@@ -0,0 +1,18 @@
+
+/*
+ Demo of how to type cast
+*/
+
+package castdemo;
+
+function int testcast()
+{
+    var int a;
+    var int* b;
+    a = 3;
+    
+    b = cast<int*>(a);
+
+    return 0;
+}
+
--- a/python/c3/lexer.py	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/c3/lexer.py	Mon Jul 08 22:21:44 2013 +0200
@@ -9,7 +9,7 @@
 keywords = ['and', 'or', 'not', 'true', 'false', \
    'else', 'if', 'while', 'return', \
    'function', 'var', 'type', 'const', \
-   'struct', \
+   'struct', 'cast', \
    'import', 'package' ]
 
 def tokenize(s):
--- a/python/c3/parser.py	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/c3/parser.py	Mon Jul 08 22:21:44 2013 +0200
@@ -276,30 +276,45 @@
         return e
 
     def Term(self):
-        t = self.Factor()
+        t = self.BitwiseOr()
         while self.Peak in ['*', '/']:
             op = self.Consume(self.Peak)
-            t2 = self.Factor()
+            t2 = self.BitwiseOr()
             t = astnodes.Binop(t, op.typ, t2, op.loc)
         return t
-        
-    def Factor(self):
-        # TODO: eliminate this step?
-        return self.CastExpression()
+
+    def BitwiseOr(self):
+        a = self.BitwiseAnd()
+        while self.Peak in ['|']:
+            op = self.Consume(self.Peak)
+            b = self.BitwiseAnd()
+            a = astnodes.Binop(a, op.typ, b, op.loc)
+        return a
+
+    def BitwiseAnd(self):
+        a = self.CastExpression()
+        while self.Peak in ['&']:
+            op = self.Consume(self.Peak)
+            b = self.CastExpression()
+            a = astnodes.Binop(a, op.typ, b, op.loc)
+        return a
 
     # Domain of unary expressions:
 
     def CastExpression(self):
-        # TODO: cast conflicts with '(' expr ')'
-        if self.Peak == '(ii':
-            self.Consume('(')
+        # TODO: cast conflicts with '(' expr ')', so introduce extra keyword 'cast'
+        if self.Peak == 'cast':
+            self.Consume('cast')
+            self.Consume('<')
             print('TODO: implement type cast')
-            #rrrrr
-            self.parseTypeSpec()
+            t = self.parseTypeSpec()
 
             # Type
+            self.Consume('>')
+            self.Consume('(')
+            ce = self.CastExpression()
             self.Consume(')')
-            ce = self.CastExpression()
+            # TODO: use type spec here
             return ce 
         else:
             return self.UnaryExpression()
--- a/python/c3/typecheck.py	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/c3/typecheck.py	Mon Jul 08 22:21:44 2013 +0200
@@ -31,11 +31,12 @@
          if not equalTypes(sym.condition.typ, boolType):
             self.error('Condition must be of type {0}'.format(boolType), sym.condition.loc)
       elif type(sym) is Assignment:
-         if type(sym.lval.typ) is PointerType and sym.rval.typ == intType:
-            print('special case, int to pointer is ok for now')
-            # TODO: add cast instruction?
-         elif not equalTypes(sym.lval.typ, sym.rval.typ):
-            self.error('Cannot assign {0} to {1}'.format(sym.rval.typ, sym.lval.typ), sym.loc)
+            if not equalTypes(sym.lval.typ, sym.rval.typ):
+                self.error('Cannot assign {0} to {1}'.format(sym.rval.typ, sym.lval.typ), sym.loc)
+            if not sym.lval.lvalue:
+                self.error('No valid lvalue {}'.format(sym.lval), sym.lval.loc)
+            #if sym.rval.lvalue:
+            #    self.error('Right hand side must be an rvalue', sym.rval.loc)
       elif type(sym) is ReturnStatement:
          pass
       elif type(sym) is FunctionCall:
@@ -55,31 +56,37 @@
          else:
             sym.typ = intType
       elif type(sym) is VariableUse:
-         if sym.target:
-            sym.typ = sym.target.typ
-         else:
-            sym.typ = intType
+            sym.lvalue = True
+            if sym.target:
+                sym.typ = sym.target.typ
+            else:
+                sym.typ = intType
       elif type(sym) is Literal:
-         if type(sym.val) is int:
-            sym.typ = intType
-         elif type(sym.val) is float:
-            sym.typ = doubleType
-         elif type(sym.val) is bool:
-            sym.typ = boolType
-         else:
-            self.error('Unknown literal type', sym.loc)
+            sym.lvalue = False
+            if type(sym.val) is int:
+                sym.typ = intType
+            elif type(sym.val) is float:
+                sym.typ = doubleType
+            elif type(sym.val) is bool:
+                sym.typ = boolType
+            else:
+                self.error('Unknown literal type', sym.loc)
       elif type(sym) is Unop:
             if sym.op == '&':
                 sym.typ = PointerType(sym.a.typ)
+                sym.lvalue = False
             elif sym.op == '*':
                 # pointer deref
+                sym.lvalue = True
                 if type(sym.a.typ) is PointerType:
                     sym.typ = sym.a.typ.ptype
                 else:
+                    sym.typ = intType
                     self.error('Cannot dereference non-pointer type {}'.format(sym.a.typ), sym.loc)
             else:
                 print('unknown unop', sym.op)
       elif type(sym) is Binop:
+         sym.lvalue = False
          if sym.op in ['+', '-', '*', '/']:
             if equalTypes(sym.a.typ, sym.b.typ):
                if equalTypes(sym.a.typ, intType):
@@ -101,6 +108,9 @@
                self.error('Must be {0}'.format(boolType), sym.a.loc)
             if not equalTypes(sym.b.typ, boolType):
                self.error('Must be {0}'.format(boolType), sym.b.loc)
+         elif sym.op in ['|', '&']:
+                sym.typ = intType
+                # TODO: elaborate?
          else:
             sym.typ = voidType
             print('unknown binop', sym.op)
--- a/python/ir/instruction.py	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/ir/instruction.py	Mon Jul 08 22:21:44 2013 +0200
@@ -140,7 +140,7 @@
       self.location = location
       self.addUse(self.location)
    def __repr__(self):
-      return '{1} = [{0}]'.format(self.location, self.value)
+      return '{} <= [{}]'.format(self.value, self.location)
 
 class Store(Instruction):
    def __init__(self, location, value):
@@ -152,7 +152,7 @@
       self.addUse(value)
       self.addUse(location)
    def __repr__(self):
-      return '[{0}] = {1}'.format(self.location, self.value)
+      return '[{}] <= {}'.format(self.location, self.value)
 
 # Branching:
 class Branch(Terminator):
@@ -174,6 +174,7 @@
       self.a = a
       assert type(a) is Value
       self.cond = cond
+      assert cond in ['==', '<', '>']
       self.b = b
       self.addUse(a)
       self.addUse(b)
--- a/python/stm32f4/blink.c3	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/stm32f4/blink.c3	Mon Jul 08 22:21:44 2013 +0200
@@ -30,7 +30,7 @@
     divider = 0;
 
     var int* RCC_AHB1ENR;
-    RCC_AHB1ENR = 0x40003022;
+    RCC_AHB1ENR = cast<int*>(0x40003022);
     *RCC_AHB1ENR = *RCC_AHB1ENR | 8943;
     /*
 	RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
--- a/python/testc3.py	Sat Jul 06 21:32:20 2013 +0200
+++ b/python/testc3.py	Mon Jul 08 22:21:44 2013 +0200
@@ -212,13 +212,28 @@
          var int* pa;
          function void t(int a, double b)
          {
-            pa = 2;
             pa = &a;
             *pa = 22;
          }
         """
         self.expectOK(snippet)
 
+    def testPointerTypeInCorrect(self):
+        snippet = """
+         package testpointerincorrect;
+         var int* pa;
+         function void t(int a, double b)
+         {
+            pa = 2; // type conflict
+            pa = &a;
+            pa = &2;
+            &a = 3; // no valid lvalue and incorrect types.
+            &a = pa; // No valid lvalue
+            **pa = 22; // Cannot deref int
+         }
+        """
+        self.expectErrors(snippet, [6, 9, 9, 10, 11])
+
     @unittest.skip 
     def testComplexType(self):
         snippet = """