Implement our hard casts using our type system.

Doesn't add any new capabilities, but we now generate error
messages if you attempt casts we don't support,
and we also found and fixed some bugs in declaration parsing.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 5731f31..523c67e 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1884,6 +1884,9 @@
     Type* mkpInt;
     Type* mkpChar;
     Type* mkpVoid;
+    Type* mkpIntPtr;
+    Type* mkpCharPtr;
+    Type* mkpPtrIntFn;
 
     // Track what's on the expression stack
     Vector<Value> mValueStack;
@@ -2393,18 +2396,25 @@
                 expr();
                 skip(')');
             } else if (t == '*') {
-                /* parse cast */
+                /* This is a pointer dereference, but we currently only
+                 * support a pointer dereference if it's immediately
+                 * in front of a cast. So parse the cast right here.
+                 */
                 skip('(');
-                t = tok; /* get type */
-                next(); /* skip int/char/void */
-                next(); /* skip '*' or '(' */
-                if (tok == '*') {
-                    /* function type */
-                    skip('*');
-                    skip(')');
-                    skip('(');
-                    skip(')');
+                Type* pCast = expectCastTypeDeclaration(mLocalArena);
+                // We currently only handle 3 types of cast:
+                // (int*), (char*) , (int (*)())
+                if(typeEqual(pCast, mkpIntPtr)) {
+                    t = TOK_INT;
+                } else if (typeEqual(pCast, mkpCharPtr)) {
+                    t = TOK_CHAR;
+                } else if (typeEqual(pCast, mkpPtrIntFn)){
                     t = 0;
+                } else {
+                    String buffer;
+                    decodeType(buffer, pCast);
+                    error("Unsupported cast type %s", buffer.getUnwrapped());
+                    decodeType(buffer, mkpPtrIntFn);
                 }
                 skip(')');
                 unary(false);
@@ -2417,6 +2427,8 @@
                 } else if (t) {
                     pGen->loadR0FromR0(t == TOK_INT);
                 }
+                // Else we fall through to the function call below, with
+                // t == 0 to trigger an indirect function call. Hack!
             } else if (t == '&') {
                 pGen->leaR0((int) VI(tok)->pAddress);
                 next();
@@ -2622,6 +2634,26 @@
         Type* pTail;
     };
 
+    bool typeEqual(Type* a, Type* b) {
+        if (a == b) {
+            return true;
+        }
+        if (a == NULL || b == NULL) {
+            return false;
+        }
+        TypeTag at = a->tag;
+        if (at != b->tag) {
+            return false;
+        }
+        if (at == TY_POINTER) {
+            return typeEqual(a->pHead, b->pHead);
+        } else if (at == TY_FUNC || at == TY_PARAM) {
+            return typeEqual(a->pHead, b->pHead)
+                && typeEqual(a->pTail, b->pTail);
+        }
+        return true;
+    }
+
     Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
         assert(tag >= TY_INT && tag <= TY_PARAM);
         Type* pType = (Type*) arena.alloc(sizeof(Type));
@@ -2632,43 +2664,73 @@
         return pType;
     }
 
+    Type* createPtrType(Type* pType, Arena& arena) {
+        return createType(TY_POINTER, pType, NULL, arena);
+    }
+
+    /**
+     * Try to print a type in declaration order
+     */
     void decodeType(String& buffer, Type* pType) {
+        buffer.clear();
         if (pType == NULL) {
             buffer.appendCStr("null");
             return;
         }
-        buffer.append('(');
+        decodeTypeImp(buffer, pType);
+    }
+
+    void decodeTypeImp(String& buffer, Type* pType) {
+        decodeTypeImpPrefix(buffer, pType);
+
         String temp;
         if (pType->id != 0) {
             decodeToken(temp, pType->id);
             buffer.append(temp);
+        }
+
+        decodeTypeImpPostfix(buffer, pType);
+    }
+
+    void decodeTypeImpPrefix(String& buffer, Type* pType) {
+        TypeTag tag = pType->tag;
+
+        if (tag >= TY_INT && tag <= TY_VOID) {
+            switch (tag) {
+                case TY_INT:
+                    buffer.appendCStr("int");
+                    break;
+                case TY_CHAR:
+                    buffer.appendCStr("char");
+                    break;
+                case TY_VOID:
+                    buffer.appendCStr("void");
+                    break;
+                default:
+                    break;
+            }
             buffer.append(' ');
         }
-        bool printHead = false;
-        bool printTail = false;
-        switch (pType->tag) {
+
+        switch (tag) {
             case TY_INT:
-                buffer.appendCStr("int");
                 break;
             case TY_CHAR:
-                buffer.appendCStr("char");
                 break;
             case TY_VOID:
-                buffer.appendCStr("void");
-                break;
+                 break;
             case TY_POINTER:
-                buffer.appendCStr("*");
-                printHead = true;
+                decodeTypeImpPrefix(buffer, pType->pHead);
+                if(pType->pHead && pType->pHead->tag == TY_FUNC) {
+                    buffer.append('(');
+                }
+                buffer.append('*');
                 break;
             case TY_FUNC:
-                buffer.appendCStr("func");
-                printHead = true;
-                printTail = true;
+                decodeTypeImp(buffer, pType->pHead);
                 break;
             case TY_PARAM:
-                buffer.appendCStr("param");
-                printHead = true;
-                printTail = true;
+                decodeTypeImp(buffer, pType->pHead);
                 break;
             default:
                 String temp;
@@ -2676,15 +2738,31 @@
                 buffer.append(temp);
                 break;
         }
-        if (printHead) {
-            buffer.append(' ');
-            decodeType(buffer, pType->pHead);
+    }
+
+    void decodeTypeImpPostfix(String& buffer, Type* pType) {
+        TypeTag tag = pType->tag;
+
+        switch(tag) {
+            case TY_POINTER:
+                if(pType->pHead && pType->pHead->tag == TY_FUNC) {
+                    buffer.append(')');
+                }
+                decodeTypeImpPostfix(buffer, pType->pHead);
+                break;
+            case TY_FUNC:
+                buffer.append('(');
+                for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
+                    decodeTypeImp(buffer, pArg);
+                    if (pArg->pTail) {
+                        buffer.appendCStr(", ");
+                    }
+                }
+                buffer.append(')');
+                break;
+            default:
+                break;
         }
-        if (printTail) {
-            buffer.append(' ');
-            decodeType(buffer, pType->pTail);
-        }
-        buffer.append(')');
     }
 
     void printType(Type* pType) {
@@ -2708,60 +2786,108 @@
         return pType;
     }
 
-    Type* acceptDeclaration(const Type* pBaseType, Arena& arena) {
-        Type* pType = createType(pBaseType->tag, pBaseType->pHead,
-                                 pBaseType->pTail, arena);
-        tokenid_t declName;
-        if (pType) {
-            pType = acceptDecl2(pType, declName, arena);
+    Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired,
+                            Arena& arena) {
+        tokenid_t declName = 0;
+        pType = acceptDecl2(pType, declName, nameAllowed,
+                                  nameRequired, arena);
+        if (declName) {
+            // Clone the parent type so we can set a unique ID
+            pType = createType(pType->tag, pType->pHead,
+                                      pType->pTail, arena);
+
             pType->id = declName;
-            // fprintf(stderr, "Parsed a declaration:       ");
-            // printType(pType);
         }
+        // fprintf(stderr, "Parsed a declaration:       ");
+        // printType(pType);
         return pType;
     }
 
-    Type* expectDeclaration(const Type* pBaseType, Arena& arena) {
-        Type* pType = acceptDeclaration(pBaseType, arena);
+    Type* expectDeclaration(Type* pBaseType, Arena& arena) {
+        Type* pType = acceptDeclaration(pBaseType, true, true, arena);
         if (! pType) {
             error("Expected a declaration");
         }
         return pType;
     }
 
-    Type* acceptDecl2(Type* pType, tokenid_t& declName, Arena& arena) {
-        while (tok == '*') {
-            pType = createType(TY_POINTER, pType, NULL, arena);
-            next();
+    /* Used for accepting types that appear in casts */
+    Type* acceptCastTypeDeclaration(Arena& arena) {
+        Type* pType = acceptPrimitiveType(arena);
+        if (pType) {
+            pType = acceptDeclaration(pType, false, false, arena);
         }
-        pType = acceptDecl3(pType, declName, arena);
         return pType;
     }
 
-    Type* acceptDecl3(Type* pType, tokenid_t& declName, Arena& arena) {
-        if (accept('(')) {
-            pType = acceptDecl2(pType, declName, arena);
-            skip(')');
-        } else {
-            declName = acceptSymbol();
+    Type* expectCastTypeDeclaration(Arena& arena) {
+        Type* pType = acceptCastTypeDeclaration(arena);
+        if (! pType) {
+            error("Expected a declaration");
         }
-        while (tok == '(') {
+        return pType;
+    }
+
+    Type* acceptDecl2(Type* pType, tokenid_t& declName,
+                      bool nameAllowed, bool nameRequired, Arena& arena) {
+        int ptrCounter = 0;
+        while (accept('*')) {
+            ptrCounter++;
+        }
+        pType = acceptDecl3(pType, declName, nameAllowed, nameRequired, arena);
+        while (ptrCounter-- > 0) {
+            pType = createType(TY_POINTER, pType, NULL, arena);
+        }
+        return pType;
+    }
+
+    Type* acceptDecl3(Type* pType, tokenid_t& declName,
+                      bool nameAllowed, bool nameRequired, Arena& arena) {
+        // direct-dcl :
+        //   name
+        //  (dcl)
+        //   direct-dcl()
+        //   direct-dcl[]
+        Type* pNewHead = NULL;
+        if (accept('(')) {
+            pNewHead = acceptDecl2(pNewHead, declName, nameAllowed,
+                                nameRequired, arena);
+            skip(')');
+        } else if ((declName = acceptSymbol()) != 0) {
+            if (nameAllowed == false && declName) {
+                error("Symbol %s not allowed here", nameof(declName));
+            } else if (nameRequired && ! declName) {
+                String temp;
+                decodeToken(temp, tok);
+                error("Expected symbol. Got %s", temp.getUnwrapped());
+            }
+        }
+        while (accept('(')) {
             // Function declaration
-            skip('(');
-            Type* pTail = acceptArgs(arena);
+            Type* pTail = acceptArgs(nameAllowed, arena);
             pType = createType(TY_FUNC, pType, pTail, arena);
             skip(')');
         }
+
+        if (pNewHead) {
+            Type* pA = pNewHead;
+            while (pA->pHead) {
+                pA = pA->pHead;
+            }
+            pA->pHead = pType;
+            pType = pNewHead;
+        }
         return pType;
     }
 
-    Type* acceptArgs(Arena& arena) {
+    Type* acceptArgs(bool nameAllowed, Arena& arena) {
         Type* pHead = NULL;
         Type* pTail = NULL;
         for(;;) {
             Type* pBaseArg = acceptPrimitiveType(arena);
             if (pBaseArg) {
-                Type* pArg = acceptDeclaration(pBaseArg, arena);
+                Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false,
+                                               arena);
                 if (pArg) {
                     Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
                     if (!pHead) {
@@ -2875,10 +3001,6 @@
         if (tok >= TOK_SYMBOL) {
             result = tok;
             next();
-        } else {
-            String temp;
-            decodeToken(temp, tok);
-            error("Expected symbol. Got %s", temp.getUnwrapped());
         }
         return result;
     }
@@ -3094,6 +3216,11 @@
         mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
         mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
         mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
+        mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
+        mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
+        mkpPtrIntFn = createPtrType(
+                  createType(TY_FUNC, mkpInt, NULL, mGlobalArena),
+                  mGlobalArena);
     }
 
     void checkForUndefinedForwardReferences() {