]> git.sur5r.net Git - cc65/blobdiff - src/ca65/symtab.c
New module strstack
[cc65] / src / ca65 / symtab.c
index 4fab0d7bc7a20f6fe5fadd11cfadc0497b8d9546..5d7e864c6db5c00c29fe79efa34666210aae321b 100644 (file)
@@ -50,7 +50,9 @@
 #include "objfile.h"
 #include "scanner.h"
 #include "segment.h"
+#include "sizeof.h"
 #include "spool.h"
+#include "studyexpr.h"
 #include "symtab.h"
 
 
@@ -64,7 +66,7 @@
 /* Combined symbol entry flags used within this module */
 #define SF_UNDEFMASK   (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
 #define SF_UNDEFVAL    (SF_REFERENCED)
-#define SF_DBGINFOMASK         (SF_UNUSED | SF_DEFINED | SF_EXPORT | SF_IMPORT)
+#define SF_DBGINFOMASK         (SF_UNUSED | SF_DEFINED | SF_IMPORT)
 #define SF_DBGINFOVAL  (SF_DEFINED)
 
 /* Symbol tables */
@@ -109,6 +111,7 @@ static SymTable* NewSymTable (SymTable* Parent, const char* Name)
     S->Left         = 0;
     S->Right        = 0;
     S->Childs       = 0;
+    S->SegRanges    = AUTO_COLLECTION_INITIALIZER;
     S->Flags        = ST_NONE;
     S->AddrSize     = ADDR_SIZE_DEFAULT;
     S->Type         = ST_UNDEF;
@@ -195,6 +198,16 @@ void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char Add
     CurrentScope->Flags    |= ST_DEFINED;
     CurrentScope->AddrSize = AddrSize;
     CurrentScope->Type     = Type;
+
+    /* If this is a scope that allows to emit data into segments, add segment
+     * ranges for all currently existing segments. Doing this for just a few
+     * scope types is not really necessary but an optimization, because it
+     * does not allocate memory for useless data (unhandled types here don't
+     * occupy space in any segment).
+     */
+    if (CurrentScope->Type <= ST_SCOPE_HAS_DATA) {
+        AddSegRanges (&CurrentScope->SegRanges);
+    }
 }
 
 
@@ -202,6 +215,21 @@ void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char Add
 void SymLeaveLevel (void)
 /* Leave the current lexical level */
 {
+    /* Close the segment ranges. We don't care about the scope type here,
+     * since types without segment ranges will just have an empty list.
+     */
+    CloseSegRanges (&CurrentScope->SegRanges);
+
+    /* If we have segment ranges, the first one is the segment that was
+     * active, when the scope was opened. Set the size of the scope to the
+     * number of data bytes emitted into this segment.
+     */
+    if (CollCount (&CurrentScope->SegRanges) > 0) {
+        const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
+        DefSizeOfScope (CurrentScope, GetSegRangeSize (R));
+    }
+
+    /* Leave the scope */
     CurrentScope = CurrentScope->Parent;
 }
 
@@ -345,7 +373,7 @@ SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
 
 
 
-static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
+SymEntry* SymFindAny (SymTable* Scope, const char* Name)
 /* Find a symbol in the given or any of its parent scopes. The function will
  * never create a new symbol, since this can only be done in one specific
  * scope.
@@ -357,40 +385,16 @@ static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
        Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
                if (Sym) {
            /* Found, return it */
-           return Sym;
-       } else {
-           /* Not found, search in the parent scope, if we have one */
-           Scope = Scope->Parent;
+           break;
        }
-    } while (Sym == 0 && Scope != 0);
-
-    /* Not found */
-    return 0;
-}
-
-
 
-int SymIsZP (SymEntry* S)
-/* Return true if the symbol is explicitly marked as zeropage symbol */
-{
-    /* If the symbol is not a global symbol, was not defined before, check the
-     * enclosing scope for a symbol with the same name, and return the ZP
-     * attribute of this symbol if we find one.
-     */
-    if ((S->Flags & (SF_DEFINED | SF_IMPORT | SF_LOCAL)) == 0 &&
-       S->SymTab->Parent != 0) {
+        /* Not found, search in the parent scope, if we have one */
+       Scope = Scope->Parent;
 
-       /* Try to find a symbol with the same name in the enclosing scope */
-       SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name));
-
-       /* If we found one, use the ZP flag */
-               if (E && E->AddrSize == ADDR_SIZE_ZP) {
-            S->AddrSize = ADDR_SIZE_ZP;
-       }
-    }
+    } while (Sym == 0 && Scope != 0);
 
-    /* Check the ZP flag */
-    return (S->AddrSize == ADDR_SIZE_ZP);
+    /* Return the result */
+    return Sym;
 }
 
 
@@ -418,26 +422,17 @@ static void SymCheckUndefined (SymEntry* S)
      *     AutoImport flag is not set, it's an error.
      */
     SymEntry* Sym = 0;
-    if (S->SymTab) {
-       /* It's a global symbol, get the higher level table */
-       SymTable* Tab = S->SymTab->Parent;
-       while (Tab) {
-           Sym = SymFindAny (Tab, GetString (S->Name));
-           if (Sym) {
-               if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
-                   /* We've found a symbol in a higher level that is
-                    * either defined in the source, or an import.
-                    */
-                    break;
-               } else {
-                   /* The symbol found is undefined itself. Look further */
-                   Tab = Sym->SymTab->Parent;
-               }
-           } else {
-               /* No symbol found */
-               break;
-           }
-       }
+    SymTable* Tab = GetSymParentScope (S);
+    while (Tab) {
+        Sym = SymFind (Tab, GetString (S->Name), SYM_FIND_EXISTING);
+        if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
+            /* We've found a symbol in a higher level that is
+             * either defined in the source, or an import.
+             */
+             break;
+        }
+        /* No matching symbol found in this level. Look further */
+        Tab = Tab->Parent;
     }
 
     if (Sym) {
@@ -527,9 +522,9 @@ void SymCheck (void)
        if (S->Flags & SF_GLOBAL) {
            S->Flags &= ~SF_GLOBAL;
            if (S->Flags & SF_DEFINED) {
-               S->Flags |= SF_EXPORT;
+               S->Flags |= SF_EXPORT;
            } else {
-               S->Flags |= SF_IMPORT;
+               S->Flags |= SF_IMPORT;
            }
        }
 
@@ -543,20 +538,24 @@ void SymCheck (void)
        S = S->List;
     }
 
-    /* Second pass: Walk again through the symbols. Ignore undefined's, since
-     * we handled them in the last pass, and ignore unused symbols, since
-     * we handled them in the last pass, too.
+    /* Second pass: Walk again through the symbols. Count exports and imports
+     * and set address sizes where this has not happened before. Ignore
+     * undefined's, since we handled them in the last pass, and ignore unused
+     * symbols, since we handled them in the last pass, too.
      */
     S = SymList;
     while (S) {
        if ((S->Flags & SF_UNUSED) == 0 &&
            (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+
+            /* Check for defined symbols that were never referenced */
            if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
-               /* Symbol was defined but never referenced */
                PWarning (&S->Pos, 2,
                           "Symbol `%s' is defined but never used",
                           GetString (S->Name));
            }
+
+            /* Assign an index to all imports */
            if (S->Flags & SF_IMPORT) {
                if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
                    /* Imported symbol is not referenced */
@@ -569,11 +568,24 @@ void SymCheck (void)
                    S->Flags |= SF_INDEXED;
                }
            }
+
+            /* Assign an index to all exports */
            if (S->Flags & SF_EXPORT) {
                /* Give the export an index, count exports */
                S->Index = ExportCount++;
                S->Flags |= SF_INDEXED;
            }
+
+            /* If the symbol is defined but has an unknown address size,
+             * recalculate it.
+             */
+            if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
+                ExprDesc ED;
+                ED_Init (&ED);
+                StudyExpr (S->Expr, &ED);
+                S->AddrSize = ED.AddrSize;
+                ED_Done (&ED);
+            }
        }
 
        /* Next symbol */
@@ -694,7 +706,7 @@ void WriteExports (void)
                ObjWrite32 (ConstVal);
            } else {
                /* Expression involved */
-               WriteExpr (S->V.Expr);
+               WriteExpr (S->Expr);
             }
 
            /* Write the source file position */
@@ -760,7 +772,7 @@ void WriteDbgSyms (void)
                    ObjWrite32 (ConstVal);
                } else {
                    /* Expression involved */
-                   WriteExpr (S->V.Expr);
+                   WriteExpr (S->Expr);
                }
 
                /* Write the source file position */