Start teaching the code generator about types.

Remove the concept of "R1" from the code generator API, R1 is used
internally as needed.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 0209031..7547fde 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -68,6 +68,8 @@
 };
 
 class Compiler : public ErrorSink {
+    struct Type;
+
     class CodeBuf {
         char* ind; // Output code pointer
         char* pProgramBase;
@@ -157,8 +159,7 @@
      * architecture.
      *
      * The code generator implements the following abstract machine:
-     * R0 - the main accumulator.
-     * R1 - the secondary accumulator.
+     * R0 - the accumulator.
      * FP - a frame pointer for accessing function arguments and local
      *      variables.
      * SP - a stack pointer for storing intermediate results while evaluating
@@ -168,7 +169,7 @@
      * stack such that the first argument has the lowest address.
      * After the call, the result is in R0. The caller is responsible for
      * removing the arguments from the stack.
-     * The R0 and R1 registers are not saved across function calls. The
+     * The R0 register is not saved across function calls. The
      * FP and SP registers are saved.
      */
 
@@ -232,41 +233,42 @@
          */
         virtual int gtst(bool l, int t) = 0;
 
-        /* Compare R1 against R0, and store the boolean result in R0.
+        /* Compare TOS against R0, and store the boolean result in R0.
+         * Pops TOS.
          * op specifies the comparison.
          */
         virtual void gcmp(int op) = 0;
 
-        /* Perform the arithmetic op specified by op. R1 is the
+        /* Perform the arithmetic op specified by op. TOS is the
          * left argument, R0 is the right argument.
+         * Pops TOS.
          */
         virtual void genOp(int op) = 0;
 
-        /* Set R1 to 0.
+        /* Compare 0 against R0, and store the boolean result in R0.
+         * op specifies the comparison.
          */
-        virtual void clearR1() = 0;
+        virtual void gUnaryCmp(int op) = 0;
+
+        /* Perform the arithmetic op specified by op. 0 is the
+         * left argument, R0 is the right argument.
+         */
+        virtual void genUnaryOp(int op) = 0;
 
         /* Push R0 onto the stack.
          */
         virtual void pushR0() = 0;
 
-        /* Pop R1 off of the stack.
+        /* Store R0 to the address stored in TOS.
+         * The TOS is popped.
+         * pPointerType is the type of the pointer (of the input R0).
          */
-        virtual void popR1() = 0;
-
-        /* Store R0 to the address stored in R1.
-         * isInt is true if a whole 4-byte integer value
-         * should be stored, otherwise a 1-byte character
-         * value should be stored.
-         */
-        virtual void storeR0ToR1(bool isInt) = 0;
+        virtual void storeR0ToTOS(Type* pPointerType) = 0;
 
         /* Load R0 from the address stored in R0.
-         * isInt is true if a whole 4-byte integer value
-         * should be loaded, otherwise a 1-byte character
-         * value should be loaded.
+         * pPointerType is the type of the pointer (of the input R0).
          */
-        virtual void loadR0FromR0(bool isInt) = 0;
+        virtual void loadR0FromR0(Type* pPointerType) = 0;
 
         /* Load the absolute address of a variable to R0.
          * If ea <= LOCAL, then this is a local variable, or an
@@ -362,6 +364,16 @@
          */
         virtual int jumpOffset() = 0;
 
+        /**
+         * Stack alignment (in bytes) for this type of data
+         */
+        virtual size_t stackAlignment(Type* type) = 0;
+
+        /**
+         * Array element alignment (in bytes) for this type of data.
+         */
+        virtual size_t sizeOf(Type* type) = 0;
+
     protected:
         /*
          * Output a byte. Handles all values, 0..ff.
@@ -392,6 +404,12 @@
             mErrorSink->verror(fmt, ap);
             va_end(ap);
         }
+
+        void assert(bool test) {
+            if (!test) {
+                error("code generator assertion failed.");
+            }
+        }
     private:
         CodeBuf* pCodeBuf;
         ErrorSink* mErrorSink;
@@ -489,6 +507,8 @@
 
         virtual void gcmp(int op) {
             LOG_API("gcmp(%d);\n", op);
+            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
+            mStackUse -= 4;
             o4(0xE1510000); // cmp r1, r1
             switch(op) {
             case OP_EQUALS:
@@ -523,6 +543,8 @@
 
         virtual void genOp(int op) {
             LOG_API("genOp(%d);\n", op);
+            o4(0xE8BD0002);  // ldmfd   sp!,{r1}
+            mStackUse -= 4;
             switch(op) {
             case OP_MUL:
                 o4(0x0E0000091); // mul     r0,r1,r0
@@ -563,9 +585,38 @@
             }
         }
 
-        virtual void clearR1() {
-            LOG_API("clearR1();\n");
+        virtual void gUnaryCmp(int op) {
+            LOG_API("gcmp(%d);\n", op);
             o4(0xE3A01000);  // mov    r1, #0
+            o4(0xE1510000); // cmp r1, r1
+            switch(op) {
+            case OP_NOT_EQUALS:
+                o4(0x03A00000); // moveq r0,#0
+                o4(0x13A00001); // movne r0,#1
+                break;
+             default:
+                error("Unknown unary comparison op %d", op);
+                break;
+            }
+        }
+
+        virtual void genUnaryOp(int op) {
+            LOG_API("genOp(%d);\n", op);
+            switch(op) {
+            case OP_PLUS:
+                // Do nothing
+                break;
+            case OP_MINUS:
+                o4(0xE3A01000);  // mov    r1, #0
+                o4(0xE0410000);  // sub     r0,r1,r0
+                break;
+            case OP_BIT_NOT:
+                o4(0xE1E00000);  // mvn     r0, r0
+                break;
+            default:
+                error("Unknown unary op %d\n", op);
+                break;
+            }
         }
 
         virtual void pushR0() {
@@ -575,28 +626,38 @@
             LOG_STACK("pushR0: %d\n", mStackUse);
         }
 
-        virtual void popR1() {
-            LOG_API("popR1();\n");
+        virtual void storeR0ToTOS(Type* pPointerType) {
+            LOG_API("storeR0ToTOS(%d);\n", isInt);
+            assert(pPointerType->tag == TY_POINTER);
             o4(0xE8BD0002);  // ldmfd   sp!,{r1}
             mStackUse -= 4;
-            LOG_STACK("popR1: %d\n", mStackUse);
-        }
-
-        virtual void storeR0ToR1(bool isInt) {
-            LOG_API("storeR0ToR1(%d);\n", isInt);
-            if (isInt) {
-                o4(0xE5810000); // str r0, [r1]
-            } else {
-                o4(0xE5C10000); // strb r0, [r1]
+            switch (pPointerType->pHead->tag) {
+                case TY_INT:
+                    o4(0xE5810000); // str r0, [r1]
+                    break;
+                case TY_CHAR:
+                    o4(0xE5C10000); // strb r0, [r1]
+                    break;
+                default:
+                    assert(false);
+                    break;
             }
         }
 
-        virtual void loadR0FromR0(bool isInt) {
-            LOG_API("loadR0FromR0(%d);\n", isInt);
-            if (isInt)
-                o4(0xE5900000); // ldr r0, [r0]
-            else
-                o4(0xE5D00000); // ldrb r0, [r0]
+        virtual void loadR0FromR0(Type* pPointerType) {
+            LOG_API("loadR0FromR0(%d);\n", pPointerType);
+            assert(pPointerType->tag == TY_POINTER);
+            switch (pPointerType->pHead->tag) {
+                case TY_INT:
+                    o4(0xE5900000); // ldr r0, [r0]
+                    break;
+                case TY_CHAR:
+                    o4(0xE5D00000); // ldrb r0, [r0]
+                    break;
+                default:
+                    assert(false);
+                    break;
+            }
         }
 
         virtual void leaR0(int ea) {
@@ -834,6 +895,37 @@
             return 0;
         }
 
+        /**
+         * Stack alignment (in bytes) for this type of data
+         */
+        virtual size_t stackAlignment(Type* pType){
+            switch(pType->tag) {
+                case TY_DOUBLE:
+                    return 8;
+                default:
+                    return 4;
+            }
+        }
+
+        /**
+         * Array element alignment (in bytes) for this type of data.
+         */
+        virtual size_t sizeOf(Type* pType){
+            switch(pType->tag) {
+                case TY_INT:
+                    return 4;
+                case TY_CHAR:
+                    return 1;
+                default:
+                    return 0;
+                case TY_FLOAT:
+                    return 4;
+                case TY_DOUBLE:
+                    return 8;
+                case TY_POINTER:
+                    return 4;
+            }
+        }
     private:
         static FILE* disasmOut;
 
@@ -937,6 +1029,7 @@
 
         virtual void gcmp(int op) {
             int t = decodeOp(op);
+            o(0x59); /* pop %ecx */
             o(0xc139); /* cmp %eax,%ecx */
             li(0);
             o(0x0f); /* setxx %al */
@@ -945,32 +1038,60 @@
         }
 
         virtual void genOp(int op) {
+            o(0x59); /* pop %ecx */
             o(decodeOp(op));
             if (op == OP_MOD)
                 o(0x92); /* xchg %edx, %eax */
         }
 
-        virtual void clearR1() {
+        virtual void gUnaryCmp(int op) {
             oad(0xb9, 0); /* movl $0, %ecx */
+            int t = decodeOp(op);
+            o(0xc139); /* cmp %eax,%ecx */
+            li(0);
+            o(0x0f); /* setxx %al */
+            o(t + 0x90);
+            o(0xc0);
+        }
+
+        virtual void genUnaryOp(int op) {
+            oad(0xb9, 0); /* movl $0, %ecx */
+            o(decodeOp(op));
         }
 
         virtual void pushR0() {
             o(0x50); /* push %eax */
         }
 
-        virtual void popR1() {
+        virtual void storeR0ToTOS(Type* pPointerType) {
+            assert(pPointerType->tag == TY_POINTER);
             o(0x59); /* pop %ecx */
+            switch (pPointerType->pHead->tag) {
+                case TY_INT:
+                    o(0x0189); /* movl %eax/%al, (%ecx) */
+                    break;
+                case TY_CHAR:
+                    o(0x0188); /* movl %eax/%al, (%ecx) */
+                    break;
+                default:
+                    assert(false);
+                    break;
+            }
         }
 
-        virtual void storeR0ToR1(bool isInt) {
-            o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */
-        }
-
-        virtual void loadR0FromR0(bool isInt) {
-            if (isInt)
-                o(0x8b); /* mov (%eax), %eax */
-            else
-                o(0xbe0f); /* movsbl (%eax), %eax */
+        virtual void loadR0FromR0(Type* pPointerType) {
+            assert(pPointerType->tag == TY_POINTER);
+            switch (pPointerType->pHead->tag) {
+                case TY_INT:
+                    o(0x8b); /* mov (%eax), %eax */
+                    break;
+                case TY_CHAR:
+                    o(0xbe0f); /* movsbl (%eax), %eax */
+                    break;
+                default:
+                    assert(false);
+                    break;
+            }
             ob(0); /* add zero in code */
         }
 
@@ -1055,6 +1176,38 @@
             return err;
         }
 
+        /**
+         * Stack alignment (in bytes) for this type of data
+         */
+        virtual size_t stackAlignment(Type* pType){
+            switch(pType->tag) {
+                case TY_DOUBLE:
+                    return 8;
+                default:
+                    return 4;
+            }
+        }
+
+        /**
+         * Array element alignment (in bytes) for this type of data.
+         */
+        virtual size_t sizeOf(Type* pType){
+            switch(pType->tag) {
+                case TY_INT:
+                    return 4;
+                case TY_CHAR:
+                    return 1;
+                default:
+                    return 0;
+                case TY_FLOAT:
+                    return 4;
+                case TY_DOUBLE:
+                    return 8;
+                case TY_POINTER:
+                    return 4;
+            }
+        }
+
     private:
 
         /** Output 1 to 4 bytes.
@@ -1166,9 +1319,15 @@
             mpBase->genOp(op);
         }
 
-        virtual void clearR1() {
-            fprintf(stderr, "clearR1()\n");
-            mpBase->clearR1();
+
+        virtual void gUnaryCmp(int op) {
+            fprintf(stderr, "gUnaryCmp(%d)\n", op);
+            mpBase->gUnaryCmp(op);
+        }
+
+        virtual void genUnaryOp(int op) {
+            fprintf(stderr, "genUnaryOp(%d)\n", op);
+            mpBase->genUnaryOp(op);
         }
 
         virtual void pushR0() {
@@ -1176,19 +1335,14 @@
             mpBase->pushR0();
         }
 
-        virtual void popR1() {
-            fprintf(stderr, "popR1()\n");
-            mpBase->popR1();
+        virtual void storeR0ToTOS(Type* pPointerType) {
+            fprintf(stderr, "storeR0ToTOS(%d)\n", pPointerType);
+            mpBase->storeR0ToTOS(pPointerType);
         }
 
-        virtual void storeR0ToR1(bool isInt) {
-            fprintf(stderr, "storeR0ToR1(%d)\n", isInt);
-            mpBase->storeR0ToR1(isInt);
-        }
-
-        virtual void loadR0FromR0(bool isInt) {
-            fprintf(stderr, "loadR0FromR0(%d)\n", isInt);
-            mpBase->loadR0FromR0(isInt);
+        virtual void loadR0FromR0(Type* pPointerType) {
+            fprintf(stderr, "loadR0FromR0(%d)\n", pPointerType);
+            mpBase->loadR0FromR0(pPointerType);
         }
 
         virtual void leaR0(int ea) {
@@ -1262,6 +1416,20 @@
             fprintf(stderr, "finishCompile() = %d\n", result);
             return result;
         }
+
+        /**
+         * Stack alignment (in bytes) for this type of data
+         */
+        virtual size_t stackAlignment(Type* pType){
+            return mpBase->stackAlignment(pType);
+        }
+
+        /**
+         * Array element alignment (in bytes) for this type of data.
+         */
+        virtual size_t sizeOf(Type* pType){
+            return mpBase->sizeOf(pType);
+        }
     };
 
 #endif // PROVIDE_TRACE_CODEGEN
@@ -1760,8 +1928,6 @@
         int oldCh;
     };
 
-    struct Type;
-
     struct VariableInfo {
         void* pAddress;
         void* pForward; // For a forward direction, linked list of data to fix up
@@ -1876,9 +2042,9 @@
     SymbolStack mLocals;
 
     // Prebuilt types, makes things slightly faster.
-    Type* mkpInt;
-    Type* mkpChar;
-    Type* mkpVoid;
+    Type* mkpInt;        // int
+    Type* mkpChar;       // char
+    Type* mkpVoid;       // void
     Type* mkpFloat;
     Type* mkpDouble;
     Type* mkpIntPtr;
@@ -2381,11 +2547,10 @@
             } else if (c == 2) {
                 /* -, +, !, ~ */
                 unary(false);
-                pGen->clearR1();
                 if (t == '!')
-                    pGen->gcmp(a);
+                    pGen->gUnaryCmp(a);
                 else
-                    pGen->genOp(a);
+                    pGen->genUnaryOp(a);
             } else if (t == '(') {
                 expr();
                 skip(')');
@@ -2415,10 +2580,9 @@
                 if (accept('=')) {
                     pGen->pushR0();
                     expr();
-                    pGen->popR1();
-                    pGen->storeR0ToR1(t == TOK_INT);
+                    pGen->storeR0ToTOS(pCast);
                 } else if (t) {
-                    pGen->loadR0FromR0(t == TOK_INT);
+                    pGen->loadR0FromR0(pCast);
                 }
                 // Else we fall through to the function call below, with
                 // t == 0 to trigger an indirect function call. Hack!
@@ -2515,7 +2679,6 @@
                 } else {
                     pGen->pushR0();
                     binaryOp(level);
-                    pGen->popR1();
 
                     if ((level == 4) | (level == 5)) {
                         pGen->gcmp(t);
@@ -2958,6 +3121,7 @@
                 }
                 int variableAddress = 0;
                 addLocalSymbol(pDecl);
+                loc = loc + pGen->sizeOf(pDecl);
                 loc = loc + 4;
                 variableAddress = -loc;
                 VI(pDecl->id)->pAddress = (void*) variableAddress;