Merge changes 6249,6250

* changes:
  Initial support for float, double.
  Implement our hard casts using our type system.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 5731f31..0209031 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1854,11 +1854,6 @@
         Vector<Mark> mLevelStack;
     };
 
-    struct Value {
-        Type* pType;
-        bool mLValue; // This is the L-value (true means the lvalue)
-    };
-
     int ch; // Current input character, or EOF
     tokenid_t tok;      // token
     intptr_t tokc;    // token extra info
@@ -1884,9 +1879,11 @@
     Type* mkpInt;
     Type* mkpChar;
     Type* mkpVoid;
-
-    // Track what's on the expression stack
-    Vector<Value> mValueStack;
+    Type* mkpFloat;
+    Type* mkpDouble;
+    Type* mkpIntPtr;
+    Type* mkpCharPtr;
+    Type* mkpPtrIntFn;
 
     InputStream* file;
 
@@ -2011,7 +2008,7 @@
 
     bool isSymbolOrKeyword(tokenid_t t) {
         return t >= TOK_KEYWORD &&
-            ((size_t) (t-TOK_SYMBOL)) < mTokenTable.size();
+            ((size_t) (t-TOK_KEYWORD)) < mTokenTable.size();
     }
 
     VariableInfo* VI(tokenid_t t) {
@@ -2393,23 +2390,29 @@
                 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);
-                if (tok == '=') {
-                    next();
+                if (accept('=')) {
                     pGen->pushR0();
                     expr();
                     pGen->popR1();
@@ -2417,6 +2420,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();
@@ -2467,9 +2472,12 @@
             while (tok != ')' && tok != EOF) {
                 expr();
                 pGen->storeR0ToArg(l);
-                if (tok == ',')
-                    next();
                 l = l + 4;
+                if (accept(',')) {
+                    // fine
+                } else if ( tok != ')') {
+                    error("Expected ',' or ')'");
+                }
             }
             pGen->endFunctionCallArguments(a, l);
             skip(')');
@@ -2539,9 +2547,10 @@
     void block(intptr_t l, bool outermostFunctionBlock) {
         intptr_t a, n, t;
 
-        if (tok == TOK_INT || tok == TOK_CHAR) {
+        Type* pBaseType;
+        if ((pBaseType = acceptPrimitiveType(mLocalArena))) {
             /* declarations */
-            localDeclarations();
+            localDeclarations(pBaseType);
         } else if (tok == TOK_IF) {
             next();
             skip('(');
@@ -2597,13 +2606,11 @@
                 mLocals.popLevel();
             }
         } else {
-            if (tok == TOK_RETURN) {
-                next();
+            if (accept(TOK_RETURN)) {
                 if (tok != ';')
                     expr();
                 rsym = pGen->gjmp(rsym); /* jmp */
-            } else if (tok == TOK_BREAK) {
-                next();
+            } else if (accept(TOK_BREAK)) {
                 *(int *) l = pGen->gjmp(*(int *) l);
             } else if (tok != ';')
                 expr();
@@ -2612,7 +2619,8 @@
     }
 
     enum TypeTag {
-        TY_INT, TY_CHAR, TY_VOID, TY_POINTER, TY_FUNC, TY_PARAM
+        TY_INT, TY_CHAR, TY_VOID, TY_FLOAT, TY_DOUBLE,
+        TY_POINTER, TY_FUNC, TY_PARAM
     };
 
     struct Type {
@@ -2622,6 +2630,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 +2660,83 @@
         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;
+                case TY_FLOAT:
+                    buffer.appendCStr("float");
+                    break;
+                case TY_DOUBLE:
+                    buffer.appendCStr("double");
+                    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;
+            case TY_FLOAT:
+                 break;
+            case TY_DOUBLE:
                 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 +2744,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) {
@@ -2701,6 +2785,10 @@
             pType = mkpChar;
         } else if (tok == TOK_VOID) {
             pType = mkpVoid;
+        } else if (tok == TOK_FLOAT) {
+            pType = mkpFloat;
+        } else if (tok == TOK_DOUBLE) {
+            pType = mkpDouble;
         } else {
             return NULL;
         }
@@ -2708,60 +2796,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) {
@@ -2811,11 +2947,10 @@
         mLocals.add(pDecl);
     }
 
-    void localDeclarations() {
+    void localDeclarations(Type* pBaseType) {
         intptr_t a;
-        Type* pBaseType;
 
-        while ((pBaseType = acceptPrimitiveType(mLocalArena)) != NULL) {
+        while (pBaseType) {
             while (tok != ';' && tok != EOF) {
                 Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
                 if (!pDecl) {
@@ -2835,6 +2970,7 @@
                     next();
             }
             skip(';');
+            pBaseType = acceptPrimitiveType(mLocalArena);
         }
     }
 
@@ -2875,10 +3011,6 @@
         if (tok >= TOK_SYMBOL) {
             result = tok;
             next();
-        } else {
-            String temp;
-            decodeToken(temp, tok);
-            error("Expected symbol. Got %s", temp.getUnwrapped());
         }
         return result;
     }
@@ -2931,31 +3063,35 @@
                 skip(';');
             } else {
                 // Function declaration
-                if (name) {
-                    /* patch forward references (XXX: does not work for function
-                     pointers) */
-                    pGen->gsym((int) name->pForward);
-                    /* put function address */
-                    name->pAddress = (void*) codeBuf.getPC();
+                if (accept(';')) {
+                    // forward declaration.
+                } else {
+                    if (name) {
+                        /* patch forward references (XXX: does not work for function
+                         pointers) */
+                        pGen->gsym((int) name->pForward);
+                        /* put function address */
+                        name->pAddress = (void*) codeBuf.getPC();
+                    }
+                    // Calculate stack offsets for parameters
+                    mLocals.pushLevel();
+                    intptr_t a = 8;
+                    int argCount = 0;
+                    for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
+                        Type* pArg = pP->pHead;
+                        addLocalSymbol(pArg);
+                        /* read param name and compute offset */
+                        VI(pArg->id)->pAddress = (void*) a;
+                        a = a + 4;
+                        argCount++;
+                    }
+                    rsym = loc = 0;
+                    a = pGen->functionEntry(argCount);
+                    block(0, true);
+                    pGen->gsym(rsym);
+                    pGen->functionExit(argCount, a, loc);
+                    mLocals.popLevel();
                 }
-                // Calculate stack offsets for parameters
-                mLocals.pushLevel();
-                intptr_t a = 8;
-                int argCount = 0;
-                for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
-                    Type* pArg = pP->pHead;
-                    addLocalSymbol(pArg);
-                    /* read param name and compute offset */
-                    VI(pArg->id)->pAddress = (void*) a;
-                    a = a + 4;
-                    argCount++;
-                }
-                rsym = loc = 0;
-                a = pGen->functionEntry(argCount);
-                block(0, true);
-                pGen->gsym(rsym);
-                pGen->functionExit(argCount, a, loc);
-                mLocals.popLevel();
             }
         }
     }
@@ -3094,6 +3230,13 @@
         mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
         mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
         mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
+        mkpFloat = createType(TY_FLOAT, NULL, NULL, mGlobalArena);
+        mkpDouble = createType(TY_DOUBLE, NULL, NULL, mGlobalArena);
+        mkpIntPtr = createPtrType(mkpInt, mGlobalArena);
+        mkpCharPtr = createPtrType(mkpChar, mGlobalArena);
+        mkpPtrIntFn = createPtrType(
+                  createType(TY_FUNC, mkpInt, NULL, mGlobalArena),
+                  mGlobalArena);
     }
 
     void checkForUndefinedForwardReferences() {
diff --git a/libacc/tests/data/double.c b/libacc/tests/data/double.c
new file mode 100644
index 0000000..5bc20a3
--- /dev/null
+++ b/libacc/tests/data/double.c
@@ -0,0 +1,7 @@
+double atof(char *nptr);
+
+int main() {
+    printf("Value = %g\n", atof("10.42"));
+    return 0;
+}
+