]> git.sur5r.net Git - cc65/blobdiff - src/cc65/compile.c
Typo
[cc65] / src / cc65 / compile.c
index c84082f4b0faab8347de2a2466b30eb023d64b9d..d79ef350b9ff102d86afc8b45f787bf0d5c5065b 100644 (file)
@@ -141,14 +141,14 @@ static void Parse (void)
             }
 
             /* Check if we must reserve storage for the variable. We do this,
-             *
-             *   - if it is not a typedef or function,
-             *   - if we don't had a storage class given ("int i")
-             *   - if the storage class is explicitly specified as static,
-             *   - or if there is an initialization.
-             *
-             * This means that "extern int i;" will not get storage allocated.
-             */
+            **
+            **   - if it is not a typedef or function,
+            **   - if we don't had a storage class given ("int i")
+            **   - if the storage class is explicitly specified as static,
+            **   - or if there is an initialization.
+            **
+            ** This means that "extern int i;" will not get storage allocated.
+            */
             if ((Decl.StorageClass & SC_FUNC) != SC_FUNC          &&
                 (Decl.StorageClass & SC_TYPEMASK) != SC_TYPEDEF    &&
                 ((Spec.Flags & DS_DEF_STORAGE) != 0         ||
@@ -157,14 +157,14 @@ static void Parse (void)
                   CurTok.Tok == TOK_ASSIGN))) {
 
                 /* We will allocate storage */
-                Decl.StorageClass |= SC_STORAGE | SC_DEF;
+                Decl.StorageClass |= SC_STORAGE;
             }
 
             /* If this is a function declarator that is not followed by a comma
-             * or semicolon, it must be followed by a function body. If this is
-             * the case, convert an empty parameter list into one accepting no
-             * parameters (same as void) as required by the standard.
-             */
+            ** or semicolon, it must be followed by a function body. If this is
+            ** the case, convert an empty parameter list into one accepting no
+            ** parameters (same as void) as required by the standard.
+            */
             if ((Decl.StorageClass & SC_FUNC) != 0 &&
                 (CurTok.Tok != TOK_COMMA)          &&
                 (CurTok.Tok != TOK_SEMI)) {
@@ -190,9 +190,16 @@ static void Parse (void)
                 /* Allow initialization */
                 if (CurTok.Tok == TOK_ASSIGN) {
 
+                    /* This is a definition */
+                    if (SymIsDef (Entry)) {
+                        Error ("Global variable `%s' has already been defined",
+                               Entry->Name);
+                    }
+                    Entry->Flags |= SC_DEF;
+
                     /* We cannot initialize types of unknown size, or
-                     * void types in non ANSI mode.
-                     */
+                    ** void types in ISO modes.
+                    */
                     if (Size == 0) {
                         if (!IsTypeVoid (Decl.Type)) {
                             if (!IsTypeArray (Decl.Type)) {
@@ -206,9 +213,9 @@ static void Parse (void)
                     }
 
                     /* Switch to the data or rodata segment. For arrays, check
-                      * the element qualifiers, since not the array but its
-                      * elements are const.
-                      */
+                     ** the element qualifiers, since not the array but its
+                     ** elements are const.
+                     */
                     if (IsQualConst (GetBaseElementType (Decl.Type))) {
                         g_userodata ();
                     } else {
@@ -235,19 +242,24 @@ static void Parse (void)
                             Error ("Variable `%s' has unknown size", Decl.Ident);
                         }
                         Entry->Flags &= ~(SC_STORAGE | SC_DEF);
-                    }
-
-                    /* Allocate storage if it is still needed */
-                    if (Entry->Flags & SC_STORAGE) {
-
-                        /* Switch to the BSS segment */
-                        g_usebss ();
-
-                        /* Define a label */
-                        g_defgloblabel (Entry->Name);
-
-                        /* Allocate space for uninitialized variable */
-                        g_res (Size);
+                    } else {
+                        /* A global (including static) uninitialized variable is
+                        ** only a tentative definition. For example, this is valid:
+                        ** int i;
+                        ** int i;
+                        ** static int j;
+                        ** static int j = 42;
+                        ** Code for them will be generated by FinishCompile().
+                        ** For now, just save the BSS segment name
+                        ** (can be set by #pragma bss-name).
+                        */
+                        const char* bssName = GetSegName (SEG_BSS);
+
+                        if (Entry->V.BssName && strcmp (Entry->V.BssName, bssName) != 0) {
+                            Error ("Global variable `%s' already was defined in the `%s' segment.",
+                                   Entry->Name, Entry->V.BssName);
+                        }
+                        Entry->V.BssName = xstrdup (bssName);
                     }
                 }
 
@@ -303,8 +315,8 @@ void Compile (const char* FileName)
     struct tm*  TM;
 
     /* Since strftime is locale dependent, we need the abbreviated month names
-     * in english.
-     */
+    ** in English.
+    */
     static const char MonthNames[12][4] = {
         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
@@ -320,21 +332,26 @@ void Compile (const char* FileName)
     DefineNumericMacro ("__CC65_STD__", IS_Get (&Standard));
 
     /* Optimization macros. Since no source code has been parsed for now, the
-     * IS_Get functions access the values in effect now, regardless of any
-     * changes using #pragma later.
-     */
+    ** IS_Get functions access the values in effect now, regardless of any
+    ** changes using #pragma later.
+    */
     if (IS_Get (&Optimize)) {
-        long CodeSize = IS_Get (&CodeSizeFactor);
         DefineNumericMacro ("__OPT__", 1);
+    }
+    {
+        long CodeSize = IS_Get (&CodeSizeFactor);
         if (CodeSize > 100) {
             DefineNumericMacro ("__OPT_i__", CodeSize);
         }
-        if (IS_Get (&EnableRegVars)) {
-            DefineNumericMacro ("__OPT_r__", 1);
-        }
-        if (IS_Get (&InlineStdFuncs)) {
-            DefineNumericMacro ("__OPT_s__", 1);
-        }
+    }
+    if (IS_Get (&EnableRegVars)) {
+        DefineNumericMacro ("__OPT_r__", 1);
+    }
+    if (IS_Get (&InlineStdFuncs)) {
+        DefineNumericMacro ("__OPT_s__", 1);
+    }
+    if (IS_Get (&EagerlyInlineFuncs)) {
+        DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1);
     }
 
     /* __TIME__ and __DATE__ macros */
@@ -400,20 +417,32 @@ void Compile (const char* FileName)
 void FinishCompile (void)
 /* Emit literals, externals, debug info, do cleanup and optimizations */
 {
-    SymTable* SymTab;
-    SymEntry* Func;
-
-    /* Walk over all functions, doing cleanup, optimizations ... */
-    SymTab = GetGlobalSymTab ();
-    Func   = SymTab->SymHead;
-    while (Func) {
-        if (SymIsOutputFunc (Func)) {
+    SymEntry* Entry;
+
+    /* Walk over all global symbols:
+    ** - for functions, do clean-up and optimizations
+    ** - generate code for uninitialized global variables
+    */
+    for (Entry = GetGlobalSymTab ()->SymHead; Entry; Entry = Entry->NextSym) {
+        if (SymIsOutputFunc (Entry)) {
             /* Function which is defined and referenced or extern */
-            MoveLiteralPool (Func->V.F.LitPool);
-            CS_MergeLabels (Func->V.F.Seg->Code);
-            RunOpt (Func->V.F.Seg->Code);
+            MoveLiteralPool (Entry->V.F.LitPool);
+            CS_MergeLabels (Entry->V.F.Seg->Code);
+            RunOpt (Entry->V.F.Seg->Code);
+        } else if ((Entry->Flags & (SC_STORAGE | SC_DEF | SC_STATIC)) == (SC_STORAGE | SC_STATIC)) {
+            /* Assembly definition of uninitialized global variable */
+
+            /* Set the segment name only when it changes */
+            if (strcmp (GetSegName (SEG_BSS), Entry->V.BssName) != 0) {
+                SetSegName (SEG_BSS, Entry->V.BssName);
+                g_segname (SEG_BSS);
+            }
+            g_usebss ();
+            g_defgloblabel (Entry->Name);
+            g_res (SizeOf (Entry->Type));
+            /* Mark as defined; so that it will be exported, not imported */
+            Entry->Flags |= SC_DEF;
         }
-        Func = Func->NextSym;
     }
 
     /* Output the literal pool */