]> git.sur5r.net Git - cc65/blobdiff - src/ca65/symentry.c
Allow conditional directives within .STRUCT7:UNION and .ENUM
[cc65] / src / ca65 / symentry.c
index 35e60b5efad61779d737a1bed820c9257535fc17..a47fde9a64237f25ff6c35cc7ce616894a496368 100644 (file)
@@ -44,6 +44,7 @@
 #include "expr.h"
 #include "global.h"
 #include "scanner.h"
+#include "segment.h"
 #include "spool.h"
 #include "symentry.h"
 #include "symtab.h"
@@ -94,8 +95,8 @@ static unsigned SymAddrSize (const SymEntry* S)
         return ADDR_SIZE_ABS;
     }
 
-    /* Return the address size of the enclosing scope */
-    return S->SymTab->AddrSize;
+    /* Return the address size of the segment */
+    return GetCurrentSegAddrSize ();
 }
 
 
@@ -130,6 +131,43 @@ SymEntry* NewSymEntry (const char* Name)
 
 
 
+int SymSearchTree (SymEntry* T, const char* Name, SymEntry** E)
+/* Search in the given tree for a name. If we find the symbol, the function
+ * will return 0 and put the entry pointer into E. If we did not find the
+ * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
+ * E will be set to the last entry, and the result of the function is <0 if
+ * the entry should be inserted on the left side, and >0 if it should get
+ * inserted on the right side.
+ */
+{
+    /* Is there a tree? */
+    if (T == 0) {
+       *E = 0;
+       return 1;
+    }
+
+    /* We have a table, search it */
+    while (1) {
+
+        /* Get the symbol name */
+        const char* SymName = GetString (T->Name);
+
+       /* Choose next entry */
+        int Cmp = strcmp (Name, SymName);
+               if (Cmp < 0 && T->Left) {
+           T = T->Left;
+       } else if (Cmp > 0&& T->Right) {
+           T = T->Right;
+       } else {
+           /* Found or end of search, return the result */
+            *E = T;
+            return Cmp;
+               }
+    }
+}
+
+
+
 void SymRef (SymEntry* S)
 /* Mark the given symbol as referenced */
 {
@@ -139,7 +177,7 @@ void SymRef (SymEntry* S)
 
 
 
-void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
+void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
 /* Define a new symbol */
 {
     if (S->Flags & SF_IMPORT) {
@@ -156,11 +194,16 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
 
     /* Map a default address size to a real value */
     if (AddrSize == ADDR_SIZE_DEFAULT) {
-        AddrSize = SymAddrSize (S);
+        long Val;
+        if (IsConstExpr (Expr, &Val) && IsByteRange (Val)) {
+            AddrSize = ADDR_SIZE_ZP;
+        } else {
+            AddrSize = SymAddrSize (S);
+        }
     }
 
     /* Set the symbol value */
-    S->V.Expr  = Expr;
+    S->V.Expr = Expr;
 
     /* If the symbol is marked as global, export it */
     if (S->Flags & SF_GLOBAL) {
@@ -178,7 +221,9 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
             /* Use the real size of the symbol */
             S->ExportSize = S->AddrSize;
         } else if (S->AddrSize > S->ExportSize) {
-            Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S));
+            PWarning (GetSymPos (S), 1, "Symbol `%s' is %s but exported as %s",
+                      GetSymName (S), AddrSizeToStr (S->AddrSize),
+                      AddrSizeToStr (S->ExportSize));
         }
     }
 
@@ -198,7 +243,7 @@ void SymDef (SymEntry* S, ExprNode* Expr, unsigned AddrSize, unsigned Flags)
 
 
 
-void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
+void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
 /* Mark the given symbol as an imported symbol */
 {
     /* Don't accept local symbols */
@@ -226,11 +271,18 @@ void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
     /* If the symbol is marked as import or global, check the symbol flags,
      * then do silently remove the global flag
      */
-    if (S->Flags & (SF_IMPORT | SF_GLOBAL)) {
-       if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED) ||
-            AddrSize != S->AddrSize) {
+    if (S->Flags & SF_IMPORT) {
+       if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
                    Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
        }
+        if (AddrSize != S->AddrSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        }
+    }
+    if (S->Flags & SF_GLOBAL) {
+        if (S->AddrSize != ADDR_SIZE_DEFAULT && S->AddrSize != AddrSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+       }
         S->Flags &= ~SF_GLOBAL;
     }
 
@@ -241,7 +293,7 @@ void SymImport (SymEntry* S, unsigned AddrSize, unsigned Flags)
 
 
 
-void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
+void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
 /* Mark the given symbol as an exported symbol */
 {
     /* Don't accept local symbols */
@@ -257,15 +309,25 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
        return;
     }
 
-    /* If the symbol was already marked as an export or global, check if
-     * this was done specifiying the same address size. In case of a global
-     * declaration, silently remove the global flag.
+    /* If the symbol was marked as global before, make it an export */
+    if (S->Flags & SF_GLOBAL) {
+        S->ExportSize = S->AddrSize;
+        S->Flags &= ~SF_GLOBAL;
+    }
+
+    /* If the symbol was already marked as an export, check if this was done
+     * specifiying the same address size. If the old spec had no explicit
+     * address size, use the new one.
      */
-    if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
-        if (S->ExportSize != AddrSize) {
+    if (S->Flags & SF_EXPORT) {
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            S->ExportSize = AddrSize;
+        } else if (AddrSize == ADDR_SIZE_DEFAULT) {
+            AddrSize = S->ExportSize;
+        }
+        if (S->ExportSize != ADDR_SIZE_DEFAULT && S->ExportSize != AddrSize) {
             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
         }
-        S->Flags &= ~SF_GLOBAL;
     }
     S->ExportSize = AddrSize;
 
@@ -274,10 +336,12 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
      */
     if (S->Flags & SF_DEFINED) {
         if (S->ExportSize == ADDR_SIZE_DEFAULT) {
-            /* Use the real size of the symbol */
+            /* No export size given, use the real size of the symbol */
             S->ExportSize = S->AddrSize;
         } else if (S->AddrSize > S->ExportSize) {
-            Warning (1, "Address size mismatch for symbol `%s'", GetSymName (S));
+            Warning (1, "Symbol `%s' is %s but exported as %s",
+                     GetSymName (S), AddrSizeToStr (S->AddrSize),
+                     AddrSizeToStr (S->ExportSize));
         }
     }
 
@@ -287,7 +351,7 @@ void SymExport (SymEntry* S, unsigned AddrSize, unsigned Flags)
 
 
 
-void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags)
+void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
 /* Mark the given symbol as a global symbol, that is, as a symbol that is
  * either imported or exported.
  */
@@ -298,21 +362,22 @@ void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags)
        return;
     }
 
-    /* Map a default address size to a real value */
-    if (AddrSize == ADDR_SIZE_DEFAULT) {
-        AddrSize = SymAddrSize (S);
-    }
-
     /* If the symbol is already marked as import or export, check the
      * size of the definition, then bail out.
      */
     if (S->Flags & SF_IMPORT) {
-        if (AddrSize != S->AddrSize) {
+        if (AddrSize != ADDR_SIZE_DEFAULT && AddrSize != S->AddrSize) {
             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
         }
         return;
     }
     if (S->Flags & SF_EXPORT) {
+        /* If the old symbol had no explicit address size spec, use the
+         * new one.
+         */
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            S->ExportSize = AddrSize;
+        }
         if (AddrSize != S->ExportSize) {
             Error ("Address size mismatch for symbol `%s'", GetSymName (S));
         }
@@ -324,8 +389,14 @@ void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags)
      */
     if (S->Flags & SF_DEFINED) {
         /* The symbol is defined, export it */
-        if (S->ExportSize != AddrSize) {
-            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        S->ExportSize = AddrSize;
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            /* No export size given, use the real size of the symbol */
+            S->ExportSize = S->AddrSize;
+        } else if (S->AddrSize > S->ExportSize) {
+            Warning (1, "Symbol `%s' is %s but exported as %s",
+                     GetSymName (S), AddrSizeToStr (S->AddrSize),
+                     AddrSizeToStr (S->ExportSize));
         }
         S->Flags |= (SF_EXPORT | Flags);
         S->ExportSize = AddrSize;
@@ -337,6 +408,72 @@ void SymGlobal (SymEntry* S, unsigned AddrSize, unsigned Flags)
 
 
 
+void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
+/* Mark the given symbol as a module constructor/destructor. This will also
+ * mark the symbol as an export. Initializers may never be zero page symbols.
+ */
+{
+    /* Check the parameters */
+#if (CD_TYPE_MIN != 0)
+    CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
+#else
+    CHECK (Type <= CD_TYPE_MAX);
+#endif
+    CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
+
+    /* Don't accept local symbols */
+    if (IsLocalNameId (S->Name)) {
+               Error ("Illegal use of a local symbol");
+               return;
+    }
+
+    /* Check for errors */
+    if (S->Flags & SF_IMPORT) {
+               /* The symbol is already marked as imported external symbol */
+               Error ("Symbol `%s' is already an import", GetSymName (S));
+               return;
+    }
+
+    /* If the symbol was already marked as an export or global, check if
+     * this was done specifiying the same address size. In case of a global
+     * declaration, silently remove the global flag.
+     */
+    if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
+        if (S->ExportSize != AddrSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        }
+        S->Flags &= ~SF_GLOBAL;
+    }
+    S->ExportSize = AddrSize;
+
+    /* If the symbol is already defined, check symbol size against the
+     * exported size.
+     */
+    if (S->Flags & SF_DEFINED) {
+        if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+            /* Use the real size of the symbol */
+            S->ExportSize = S->AddrSize;
+        } else if (S->AddrSize != S->ExportSize) {
+            Error ("Address size mismatch for symbol `%s'", GetSymName (S));
+        }
+    }
+
+    /* If the symbol was already declared as a condes, check if the new
+     * priority value is the same as the old one.
+     */
+    if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
+       if (S->ConDesPrio[Type] != Prio) {
+           Error ("Redeclaration mismatch for symbol `%s'", GetSymName (S));
+       }
+    }
+    S->ConDesPrio[Type] = Prio;
+
+    /* Set the symbol data */
+    S->Flags |= (SF_EXPORT | SF_REFERENCED);
+}
+
+
+
 int SymIsDef (const SymEntry* S)
 /* Return true if the given symbol is already defined */
 {
@@ -480,7 +617,7 @@ const char* GetSymName (const SymEntry* S)
 
 
 
-unsigned GetSymAddrSize (const SymEntry* S)
+unsigned char GetSymAddrSize (const SymEntry* S)
 /* Return the address size of the symbol. Beware: This function will just
  * return the AddrSize member, it will not look at the expression!
  */
@@ -493,6 +630,18 @@ unsigned GetSymAddrSize (const SymEntry* S)
 
 
 
+long GetSymVal (SymEntry* S)
+/* Return the value of a symbol assuming it's constant. FAIL will be called
+ * in case the symbol is undefined or not constant.
+ */
+{
+    long Val;
+    CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
+    return Val;
+}
+
+
+
 unsigned GetSymIndex (const SymEntry* S)
 /* Return the symbol index for the given symbol */
 {