Implement arrays.

Added check to see that pointer types are compatible when passing function
arguments.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 313bf1c..0a16489 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -139,16 +139,17 @@
         TY_VOID,      // 3
         TY_FLOAT,     // 4
         TY_DOUBLE,    // 5
-        TY_POINTER, // 6
-        TY_ARRAY,   // 7
-        TY_STRUCT,  // 8
-        TY_FUNC,    // 9
-        TY_PARAM    // 10
+        TY_POINTER,   // 6
+        TY_ARRAY,     // 7
+        TY_STRUCT,    // 8
+        TY_FUNC,      // 9
+        TY_PARAM      // 10
     };
 
     struct Type {
         TypeTag tag;
-        tokenid_t id; // For function arguments (stores length for array)
+        tokenid_t id; // For function arguments, local vars
+        int length; // length of array
         Type* pHead;
         Type* pTail;
     };
@@ -405,7 +406,16 @@
         /**
          * Convert R0 to the given type.
          */
-        virtual void convertR0(Type* pType) = 0;
+
+        void convertR0(Type* pType) {
+            convertR0Imp(pType, false);
+        }
+
+        void castR0(Type* pType) {
+            convertR0Imp(pType, true);
+        }
+
+        virtual void convertR0Imp(Type* pType, bool isCast) = 0;
 
         /* Emit code to adjust the stack for a function call. Return the
          * label for the address of the instruction that adjusts the
@@ -622,14 +632,40 @@
             return collapseType(getR0Type()->tag);
         }
 
-        bool isFloatType(Type* pType) {
+        static bool isFloatType(Type* pType) {
             return isFloatTag(pType->tag);
         }
 
-        bool isFloatTag(TypeTag tag) {
+        static bool isFloatTag(TypeTag tag) {
             return tag == TY_FLOAT || tag == TY_DOUBLE;
         }
 
+        static bool isPointerType(Type* pType) {
+            return isPointerTag(pType->tag);
+        }
+
+        static bool isPointerTag(TypeTag tag) {
+            return tag == TY_POINTER || tag == TY_ARRAY;
+        }
+
+        Type* getPointerArithmeticResultType(Type* a, Type* b) {
+            TypeTag aTag = a->tag;
+            TypeTag bTag = b->tag;
+            if (aTag == TY_POINTER) {
+                return a;
+            }
+            if (bTag == TY_POINTER) {
+                return b;
+            }
+            if (aTag == TY_ARRAY) {
+                return a->pTail;
+            }
+            if (bTag == TY_ARRAY) {
+                return b->pTail;
+            }
+            return NULL;
+        }
+
         Type* mkpInt;
 
     private:
@@ -848,8 +884,8 @@
             bool isFloatTOS = isFloatTag(tagTOS);
             if (!isFloatR0 && !isFloatTOS) {
                 setupIntPtrArgs();
-                bool isPtrR0 = tagR0 == TY_POINTER;
-                bool isPtrTOS = tagTOS == TY_POINTER;
+                bool isPtrR0 = isPointerTag(tagR0);
+                bool isPtrTOS = isPointerTag(tagTOS);
                 if (isPtrR0 || isPtrTOS) {
                     if (isPtrR0 && isPtrTOS) {
                         if (op != OP_MINUS) {
@@ -871,7 +907,8 @@
                         if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
                             error("Unsupported pointer-scalar operation %d", op);
                         }
-                        Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
+                        Type* pPtrType = getPointerArithmeticResultType(
+                                pR0Type, pTOSType);
                         int size = sizeOf(pPtrType->pHead);
                         if (size != 1) {
                             // TODO: Optimize for power-of-two.
@@ -1131,7 +1168,8 @@
         virtual void loadR0FromR0() {
             Type* pPointerType = getR0Type();
             assert(pPointerType->tag == TY_POINTER);
-            switch (pPointerType->pHead->tag) {
+            TypeTag tag = pPointerType->pHead->tag;
+            switch (tag) {
                 case TY_POINTER:
                 case TY_INT:
                 case TY_FLOAT:
@@ -1147,7 +1185,7 @@
                     o4(0xE1C000D0); // ldrd   r0, [r0]
                     break;
                 default:
-                    error("loadR0FromR0: unimplemented type");
+                    error("loadR0FromR0: unimplemented type %d", tag);
                     break;
             }
             setR0Type(pPointerType->pHead);
@@ -1197,9 +1235,27 @@
             return result;
         }
 
-        virtual void convertR0(Type* pType){
+        virtual void convertR0Imp(Type* pType, bool isCast){
             Type* pR0Type = getR0Type();
-            if (bitsSame(pType, pR0Type)) {
+            if (isPointerType(pType) && isPointerType(pR0Type)) {
+                Type* pA = pR0Type;
+                Type* pB = pType;
+                // Array decays to pointer
+                if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
+                    pA = pA->pTail;
+                }
+                if (typeEqual(pA, pB)) {
+                    return; // OK
+                }
+                if (pB->pHead->tag == TY_VOID) {
+                    return; // convert to void* is OK.
+                }
+                if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
+                        && isCast) {
+                    return; // OK
+                }
+                error("Incompatible pointer or array types");
+            } else if (bitsSame(pType, pR0Type)) {
                 // do nothing special
             } else {
                 TypeTag r0Tag = collapseType(pR0Type->tag);
@@ -1423,14 +1479,17 @@
                     return 2;
                 case TY_CHAR:
                     return 1;
-                default:
-                    return 0;
                 case TY_FLOAT:
                     return 4;
                 case TY_DOUBLE:
                     return 8;
                 case TY_POINTER:
                     return 4;
+                case TY_ARRAY:
+                    return pType->length * sizeOf(pType->pHead);
+                default:
+                    error("Unsupported type %d", pType->tag);
+                    return 0;
             }
         }
 
@@ -1438,6 +1497,8 @@
             switch(pType->tag) {
                 case TY_DOUBLE:
                     return 8;
+                case TY_ARRAY:
+                    return stackAlignmentOf(pType->pHead);
                 default:
                     return 4;
             }
@@ -1447,6 +1508,11 @@
             switch(pType->tag) {
                 case TY_DOUBLE:
                     return 8;
+                case TY_ARRAY:
+                    return sizeOf(pType);
+                case TY_FUNC:
+                    error("stackSizeOf func not supported");
+                    return 4;
                 default:
                     return 4;
             }
@@ -1911,8 +1977,8 @@
             bool isFloatR0 = isFloatTag(tagR0);
             bool isFloatTOS = isFloatTag(tagTOS);
             if (!isFloatR0 && !isFloatTOS) {
-                bool isPtrR0 = tagR0 == TY_POINTER;
-                bool isPtrTOS = tagTOS == TY_POINTER;
+                bool isPtrR0 = isPointerTag(tagR0);
+                bool isPtrTOS = isPointerTag(tagTOS);
                 if (isPtrR0 || isPtrTOS) {
                     if (isPtrR0 && isPtrTOS) {
                         if (op != OP_MINUS) {
@@ -1936,7 +2002,8 @@
                         if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
                             error("Unsupported pointer-scalar operation %d", op);
                         }
-                        Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
+                        Type* pPtrType = getPointerArithmeticResultType(
+                                pR0Type, pTOSType);
                         o(0x59); /* pop %ecx */
                         int size = sizeOf(pPtrType->pHead);
                         if (size != 1) {
@@ -2146,7 +2213,8 @@
         virtual void loadR0FromR0() {
             Type* pPointerType = getR0Type();
             assert(pPointerType->tag == TY_POINTER);
-            switch (pPointerType->pHead->tag) {
+            TypeTag tag = pPointerType->pHead->tag;
+            switch (tag) {
                 case TY_POINTER:
                 case TY_INT:
                     o2(0x008b); /* mov (%eax), %eax */
@@ -2166,7 +2234,7 @@
                     o2(0x00dd); // fldl (%eax)
                     break;
                 default:
-                    error("loadR0FromR0: unsupported type");
+                    error("loadR0FromR0: unsupported type %d", tag);
                     break;
             }
             setR0Type(pPointerType->pHead);
@@ -2183,14 +2251,32 @@
             return getPC() - 4;
         }
 
-        virtual void convertR0(Type* pType){
+        virtual void convertR0Imp(Type* pType, bool isCast){
             Type* pR0Type = getR0Type();
             if (pR0Type == NULL) {
                 assert(false);
                 setR0Type(pType);
                 return;
             }
-            if (bitsSame(pType, pR0Type)) {
+            if (isPointerType(pType) && isPointerType(pR0Type)) {
+                Type* pA = pR0Type;
+                Type* pB = pType;
+                // Array decays to pointer
+                if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
+                    pA = pA->pTail;
+                }
+                if (typeEqual(pA, pB)) {
+                    return; // OK
+                }
+                if (pB->pHead->tag == TY_VOID) {
+                    return; // convert to void* is OK.
+                }
+                if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
+                        && isCast) {
+                    return; // OK
+                }
+                error("Incompatible pointer or array types");
+            } else if (bitsSame(pType, pR0Type)) {
                 // do nothing special
             } else if (isFloatType(pType) && isFloatType(pR0Type)) {
                 // do nothing special, both held in same register on x87.
@@ -2326,6 +2412,11 @@
                 return 1;
             case TY_SHORT:
                 return 2;
+            case TY_ARRAY:
+                return alignmentOf(pType->pHead);
+            case TY_FUNC:
+                error("alignment of func not supported");
+                return 1;
             default:
                 return 4;
             }
@@ -2342,14 +2433,17 @@
                     return 2;
                 case TY_CHAR:
                     return 1;
-                default:
-                    return 0;
                 case TY_FLOAT:
                     return 4;
                 case TY_DOUBLE:
                     return 8;
                 case TY_POINTER:
                     return 4;
+                case TY_ARRAY:
+                    return pType->length * sizeOf(pType->pHead);
+                default:
+                    error("Unsupported type %d", pType->tag);
+                    return 0;
             }
         }
 
@@ -2361,6 +2455,11 @@
             switch(pType->tag) {
                 case TY_DOUBLE:
                     return 8;
+                case TY_ARRAY:
+                    return sizeOf(pType);
+                case TY_FUNC:
+                    error("stackSizeOf func not supported");
+                    return 4;
                 default:
                     return 4;
             }
@@ -3911,7 +4010,7 @@
                     skip(')');
                     unary();
                     pGen->forceR0RVal();
-                    pGen->convertR0(pCast);
+                    pGen->castR0(pCast);
                 } else {
                     commaExpr();
                     skip(')');
@@ -3959,10 +4058,18 @@
                     }
                 }
                 // load a variable
-                Type* pVal = createPtrType(pVI->pType);
+                Type* pVal;
+                ExpressionType et;
+                if (pVI->pType->tag == TY_ARRAY) {
+                    pVal = pVI->pType;
+                    et = ET_RVALUE;
+                } else {
+                    pVal = createPtrType(pVI->pType);
+                    et = ET_LVALUE;
+                }
                 if (n) {
-                    ExpressionType et = ET_LVALUE;
-                    if (pVal->pHead->tag == TY_FUNC) {
+                    int tag = pVal->pHead->tag;
+                    if (tag == TY_FUNC) {
                         et = ET_RVALUE;
                     }
                     pGen->leaR0(n, pVal, et);
@@ -4251,6 +4358,8 @@
         }
         if (at == TY_POINTER) {
             return typeEqual(a->pHead, b->pHead);
+        } else if (at == TY_ARRAY) {
+            return a->length == b->length && typeEqual(a->pHead, b->pHead);
         } else if (at == TY_FUNC || at == TY_PARAM) {
             return typeEqual(a->pHead, b->pHead)
                 && typeEqual(a->pTail, b->pTail);
@@ -4345,6 +4454,9 @@
                 }
                 buffer.append('*');
                 break;
+            case TY_ARRAY:
+                decodeTypeImpPrefix(buffer, pType->pHead);
+                break;
             case TY_FUNC:
                 decodeTypeImp(buffer, pType->pHead);
                 break;
@@ -4369,6 +4481,13 @@
                 }
                 decodeTypeImpPostfix(buffer, pType->pHead);
                 break;
+            case TY_ARRAY:
+                {
+                    String temp;
+                    temp.printf("[%d]", pType->length);
+                    buffer.append(temp);
+                }
+                break;
             case TY_FUNC:
                 buffer.append('(');
                 for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
@@ -4418,9 +4537,13 @@
                                   nameRequired, reportFailure);
         if (declName) {
             // Clone the parent type so we can set a unique ID
+            Type* pOldType = pType;
             pType = createType(pType->tag, pType->pHead, pType->pTail);
 
             pType->id = declName;
+            pType->length = pOldType->length;
+        } else if (nameRequired) {
+            error("Expected a variable name");
         }
         // fprintf(stderr, "Parsed a declaration:       ");
         // printType(pType);
@@ -4490,11 +4613,27 @@
             error("Expected name. Got %s", temp.getUnwrapped());
             reportFailure = true;
         }
-        while (accept('(')) {
-            // Function declaration
-            Type* pTail = acceptArgs(nameAllowed);
-            pType = createType(TY_FUNC, pType, pTail);
-            skip(')');
+        for(;;) {
+            if (accept('(')) {
+                // Function declaration
+                Type* pTail = acceptArgs(nameAllowed);
+                pType = createType(TY_FUNC, pType, pTail);
+                skip(')');
+            } if (accept('[')) {
+                if (tok != ']') {
+                    if (tok != TOK_NUM || tokc <= 0) {
+                        error("Expected positive integer constant");
+                    } else {
+                        Type* pDecayType = createPtrType(pType);
+                        pType = createType(TY_ARRAY, pType, pDecayType);
+                        pType->length = tokc;
+                    }
+                    next();
+                }
+                skip(']');
+            } else {
+                break;
+            }
         }
 
         if (pNewHead) {
diff --git a/libacc/tests/data/array.c b/libacc/tests/data/array.c
new file mode 100644
index 0000000..3af5e31
--- /dev/null
+++ b/libacc/tests/data/array.c
@@ -0,0 +1,77 @@
+// Array allocation tests
+
+void testLocalInt()
+{
+    int a[3];
+    a[0] = 1;
+    a[1] = 2;
+    a[2] = a[0] + a[1];
+    printf("localInt: %d\n", a[2]);
+}
+
+char a[3];
+double d[3];
+
+void testGlobalChar()
+{
+    a[0] = 1;
+    a[1] = 2;
+    a[2] = a[0] + a[1];
+    printf("globalChar: %d\n", a[2]);
+}
+
+void testGlobalDouble()
+{
+    d[0] = 1;
+    d[1] = 2;
+    d[2] = d[0] + d[1];
+    printf("globalDouble: %g\n", d[2]);
+}
+
+void testLocalDouble()
+{
+    double d[3];
+    float  m[12];
+    m[0] = 1.0f;
+    m[1] = 2.0f;
+    d[0] = 1.0;
+    d[1] = 2.0;
+    d[2] = d[0] + d[1];
+    m[2] = m[0] + m[1];
+    printf("localDouble: %g %g\n", d[2], m[2]);
+}
+
+void vectorAdd(int* a, int* b, float* c, int len) {
+    int i;
+    for(i = 0; i < len; i++) {
+        c[i] = a[i] + b[i];
+    }
+}
+
+void testArgs() {
+    int a[3], b[3];
+    float c[3];
+    int i;
+    int len = 3;
+    for(i = 0; i < len; i++) {
+        a[i] = i;
+        b[i] = i;
+        c[i] = 0;
+    }
+    vectorAdd(a,b,c, len);
+    printf("testArgs:");
+    for(i = 0; i < len; i++) {
+        printf(" %g", c[i]);
+    }
+    printf("\n");
+}
+
+int main()
+{
+    testLocalInt();
+    testLocalDouble();
+    testGlobalChar();
+    testGlobalDouble();
+    testArgs();
+    return 0;
+}
diff --git a/libacc/tests/test.py b/libacc/tests/test.py
index a3114ad..4ad2e13 100644
--- a/libacc/tests/test.py
+++ b/libacc/tests/test.py
@@ -387,6 +387,16 @@
 result: -2
 ""","""""")
 
+    def testArray(self):
+        self.compileCheck(["-R", "data/array.c"], """Executing compiled code:
+localInt: 3
+localDouble: 3 3
+globalChar: 3
+globalDouble: 3
+testArgs: 0 2 4
+result: 0
+""","""""")
+
 if __name__ == '__main__':
     if not outputCanRun():
         print "Many tests are expected to fail, because acc is not a 32-bit x86 Linux executable."