Merge change 4067

* changes:
  Improve symbol-related error checking
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index 60d1ddc..4af7f25 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1312,6 +1312,12 @@
             }
         }
 
+        String& operator=(const String& other) {
+            clear();
+            appendBytes(other.getUnwrapped(), other.len());
+            return *this;
+        }
+
         inline char* getUnwrapped() const {
             return mpBase;
         }
@@ -1439,6 +1445,12 @@
             return result;
         }
 
+        void forEach(bool (*callback)(String* key, V* value, void* context),
+                     void* context) {
+            hashmapForEach(mpMap, (bool (*)(void*, void*, void*)) callback,
+                           context);
+        }
+
     protected:
 
         void init(size_t initialCapacity) {
@@ -1670,11 +1682,21 @@
             return addImp(0, pName);
         }
 
+        void forEachGlobal(
+            bool (*callback)(String* key, VariableInfo* value, void* context),
+            void* context) {
+            mStack.get(0).pTable->forEach(callback, context);
+        }
+
     private:
         VariableInfo* addImp(int entryIndex, String* pName) {
             Entry e = mStack.get(entryIndex);
             SymbolTable* pTable = e.pTable;
+            if (pTable->contains(pName)) {
+                return NULL;
+            }
             VariableInfo* v = new VariableInfo();
+
             delete pTable->put(pName, v);
 #if 0
             fprintf(stderr, "Add \"%s\" %08x level %d\n", pName->getUnwrapped(), v, e.level);
@@ -2044,6 +2066,7 @@
     void unary(intptr_t l) {
         intptr_t n, t, a;
         int c;
+        String tString;
         t = 0;
         n = 1; /* type of expression 0 = forward, 1 = value, other =
          lvalue */
@@ -2063,6 +2086,7 @@
             c = tokl;
             a = tokc;
             t = tok;
+            tString = mTokenString;
             next();
             if (t == TOK_NUM) {
                 pGen->li(a);
@@ -2112,14 +2136,15 @@
             } else {
                 if (t == TOK_UNDEFINED_SYMBOL) {
                     t = (intptr_t) mSymbolTable.addGlobal(
-                        new String(mTokenString));
+                        new String(tString));
                 }
 
-                n = *(int *) t;
+                n = (intptr_t) ((VariableInfo*) t)->pAddress;
                 /* forward reference: try dlsym */
                 if (!n) {
                     n = (intptr_t) dlsym(RTLD_DEFAULT,
-                                         mTokenString.getUnwrapped());
+                                         tString.getUnwrapped());
+                    ((VariableInfo*) t)->pAddress = (void*) n;
                 }
                 if ((tok == '=') & l) {
                     /* assignment */
@@ -2128,6 +2153,9 @@
                     pGen->storeR0(n);
                 } else if (tok != '(') {
                     /* variable */
+                    if (!n) {
+                        error("Undefined variable %s", tString.getUnwrapped());
+                    }
                     pGen->loadR0(n, tokl == 11, tokc);
                     if (tokl == 11) {
                         next();
@@ -2216,7 +2244,7 @@
         return pGen->gtst(0, 0);
     }
 
-    void block(intptr_t l) {
+    void block(intptr_t l, bool outermostFunctionBlock) {
         intptr_t a, n, t;
 
         if (tok == TOK_IF) {
@@ -2224,12 +2252,12 @@
             skip('(');
             a = test_expr();
             skip(')');
-            block(l);
+            block(l, false);
             if (tok == TOK_ELSE) {
                 next();
                 n = pGen->gjmp(0); /* jmp */
                 pGen->gsym(a);
-                block(l);
+                block(l, false);
                 pGen->gsym(n); /* patch else jmp */
             } else {
                 pGen->gsym(a); /* patch if test */
@@ -2259,18 +2287,22 @@
                 }
             }
             skip(')');
-            block((intptr_t) &a);
+            block((intptr_t) &a, false);
             pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
             pGen->gsym(a);
         } else if (tok == '{') {
-            mSymbolTable.pushLevel();
+            if (! outermostFunctionBlock) {
+                mSymbolTable.pushLevel();
+            }
             next();
             /* declarations */
             localDeclarations();
             while (tok != '}' && tok != EOF)
-                block(l);
+                block(l, false);
             skip('}');
-            mSymbolTable.popLevel();
+            if (! outermostFunctionBlock) {
+                mSymbolTable.popLevel();
+            }
         } else {
             if (tok == TOK_RETURN) {
                 next();
@@ -2350,18 +2382,22 @@
         }
     }
 
-    void defineGlobalSymbol() {
-        if (tok == TOK_UNDEFINED_SYMBOL) {
-            // TODO: don't allow multiple definitions at same level.
-            tok = (intptr_t) mSymbolTable.addGlobal(
-                new String(mTokenString));
+    void addGlobalSymbol() {
+        tok = (intptr_t) mSymbolTable.addGlobal(
+            new String(mTokenString));
+        reportIfDuplicate();
+    }
+
+    void reportIfDuplicate() {
+        if (!tok) {
+            error("Duplicate definition of %s", mTokenString.getUnwrapped());
         }
     }
 
-    void defineLocalSymbol() {
-        // TODO: don't allow multiple definitions at same level.
+    void addLocalSymbol() {
         tok = (intptr_t) mSymbolTable.addLocal(
                 new String(mTokenString));
+        reportIfDuplicate();
     }
 
     void localDeclarations() {
@@ -2371,10 +2407,11 @@
         while (acceptType(base)) {
             while (tok != ';') {
                 Type t = acceptPointerDeclaration(t);
-                defineLocalSymbol();
-                loc = loc + 4;
-                *(int *) tok = -loc;
-
+                addLocalSymbol();
+                if (tok) {
+                    loc = loc + 4;
+                    *(int *) tok = -loc;
+                }
                 next();
                 if (tok == ',')
                     next();
@@ -2388,29 +2425,39 @@
             Type base;
             expectType(base);
             Type t = acceptPointerDeclaration(t);
-            defineGlobalSymbol();
+            if (tok == TOK_UNDEFINED_SYMBOL) {
+                addGlobalSymbol();
+            }
             VariableInfo* name = (VariableInfo*) tok;
+            if (name && name->pAddress) {
+                error("Already defined global %s",
+                      mTokenString.getUnwrapped());
+            }
             next();
             if (tok == ',' || tok == ';') {
                 // it's a variable declaration
                 for(;;) {
-                    name->pAddress = (int*) allocGlobalSpace(4);
+                    if (name) {
+                        name->pAddress = (int*) allocGlobalSpace(4);
+                    }
                     if (tok != ',') {
                         break;
                     }
                     skip(',');
                     t = acceptPointerDeclaration(t);
-                    defineGlobalSymbol();
+                    addGlobalSymbol();
                     name = (VariableInfo*) tok;
                     next();
                 }
                 skip(';');
             } else {
-                /* patch forward references (XXX: does not work for function
-                 pointers) */
-                pGen->gsym((int) name->pForward);
-                /* put function address */
-                name->pAddress = (void*) codeBuf.getPC();
+                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();
+                }
                 skip('(');
                 mSymbolTable.pushLevel();
                 intptr_t a = 8;
@@ -2419,10 +2466,12 @@
                     Type aType;
                     expectType(aType);
                     aType = acceptPointerDeclaration(aType);
-                    defineLocalSymbol();
-                    /* read param name and compute offset */
-                    *(int *) tok = a;
-                    a = a + 4;
+                    addLocalSymbol();
+                    if (tok) {
+                        /* read param name and compute offset */
+                        *(int *) tok = a;
+                        a = a + 4;
+                    }
                     next();
                     if (tok == ',')
                         next();
@@ -2431,7 +2480,7 @@
                 skip(')');
                 rsym = loc = 0;
                 a = pGen->functionEntry(argCount);
-                block(0);
+                block(0, true);
                 pGen->gsym(rsym);
                 pGen->functionExit(argCount, a, loc);
                 mSymbolTable.popLevel();
@@ -2551,6 +2600,7 @@
         inp();
         next();
         globalDeclarations();
+        checkForUndefinedForwardReferences();
         result = pGen->finishCompile();
         if (result == 0) {
             if (mErrorBuf.len()) {
@@ -2560,6 +2610,27 @@
         return result;
     }
 
+    void checkForUndefinedForwardReferences() {
+        mSymbolTable.forEachGlobal(static_ufrcFn, this);
+    }
+
+    static bool static_ufrcFn(String* key, VariableInfo* value,
+                                                 void* context) {
+        Compiler* pCompiler = (Compiler*) context;
+        return pCompiler->undefinedForwardReferenceCheck(key, value);
+    }
+
+    bool undefinedForwardReferenceCheck(String* key, VariableInfo* value) {
+#if 0
+        fprintf(stderr, "%s 0x%8x 0x%08x\n", key->getUnwrapped(),
+                value->pAddress, value->pForward);
+#endif
+        if (!value->pAddress && value->pForward) {
+            error("Undefined forward reference: %s", key->getUnwrapped());
+        }
+        return true;
+    }
+
     int dump(FILE* out) {
         fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out);
         return 0;
diff --git a/libacc/tests/data/locals.c b/libacc/tests/data/locals.c
index 6982980..f1ef363 100644
--- a/libacc/tests/data/locals.c
+++ b/libacc/tests/data/locals.c
@@ -2,7 +2,9 @@
 
 int f() {
     int a;
-    printf("f 0: a = %d b = %d\n", a, b);
+    // Undefined variable b
+    // printf("f 0: a = %d b = %d\n", a, b);
+    printf("f 0: a = %d\n", a);
     a = 2;
     printf("f 1: a = %d\n", a);
 }
@@ -14,19 +16,23 @@
 }
 
 int h(int a) {
-    int a; // gcc 4.3 says error: 'a' redeclared as different kind of symbol
+    // int a; // gcc 4.3 says error: 'a' redeclared as different kind of symbol
 
     printf("h 0: a = %d\n", a);
     a = 4;
     printf("h 1: a = %d\n", a);
 }
 
+// Already defined global 
+// int h() {}
 int globCheck() {
     fprintf(stdout, "globCheck()\n");
 }
 
 int fwdCheck() {
     b();
+    // Undefined forward reference
+    // c();
 }
 
 int b() {