]> git.sur5r.net Git - cc65/blobdiff - src/cc65/locals.c
Working on the new backend
[cc65] / src / cc65 / locals.c
index 6a6f2bbb067e411bb32690822230b35bb611f43a..02841b9dfd35cd297c497efb2fa5df346dd7943f 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000     Ullrich von Bassewitz                                        */
-/*              Wacholderweg 14                                              */
-/*              D-70597 Stuttgart                                            */
-/* EMail:       uz@musoftware.de                                             */
+/* (C) 2000-2001 Ullrich von Bassewitz                                       */
+/*               Wacholderweg 14                                             */
+/*               D-70597 Stuttgart                                           */
+/* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 
 
 
-#include "../common/xmalloc.h"
+/* common */
+#include "xmalloc.h"
+#include "xsprintf.h"
 
+/* cc65 */
 #include "anonname.h"
 #include "asmlabel.h"
 #include "codegen.h"
 #include "declare.h"
+#include "error.h"
 #include "expr.h"
 #include "function.h"
 #include "global.h"
@@ -80,7 +84,7 @@ void InitRegVars (void)
      * will usually waste some space but we don't need to dynamically
      * grow the array.
      */
-    RegSyms = xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
+    RegSyms = (const SymEntry**) xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
     RegOffs = MaxRegSpace;
 }
 
@@ -129,276 +133,253 @@ static int AllocRegVar (const SymEntry* Sym, const type* tarray)
 
 
 
-void DeclareLocals (void)
-/* Declare local variables and types. */
+static void ParseOneDecl (const DeclSpec* Spec)
+/* Parse one variable declaration */
 {
-    int offs = oursp;                  /* Current stack offset for variable */
-    int AutoSpace = 0;                 /* Unallocated space on the stack */
-    int Size;                  /* Size of an auto variable */
-    int Reg;                   /* Register variable offset */
-    unsigned flags = 0;                /* Code generator flags */
-    int SymbolSC;                      /* Storage class for symbol */
-    int ldata = 0;                     /* Local symbol data temp storage */
-
-    /* Loop until we don't find any more variables */
-    while (1) {
-
-       /* Check variable declarations. We need to distinguish between a
-        * default int type and the end of variable declarations. So we
-        * will do the following: If there is no explicit storage class
-        * specifier *and* no explicit type given, it is assume that we
-                * have reached the end of declarations.
-        */
-       DeclSpec Spec;
-       ParseDeclSpec (&Spec, SC_AUTO, T_INT);
-               if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) {
-           break;
+    int        Size;           /* Size of an auto variable */
+    int        SC;             /* Storage class for symbol */
+    int                SymData = 0;    /* Symbol data (offset, label name, ...) */
+    unsigned   flags = 0;      /* Code generator flags */
+    Declaration Decl;          /* Declaration data structure */
+
+    /* Remember the storage class for the new symbol */
+    SC = Spec->StorageClass;
+
+    /* Read the declaration */
+    ParseDecl (Spec, &Decl, DM_NEED_IDENT);
+
+    /* Set the correct storage class for functions */
+    if (IsTypeFunc (Decl.Type)) {
+       /* Function prototypes are always external */
+       if ((SC & SC_EXTERN) == 0) {
+                   Warning ("Function must be extern");
        }
+               SC |= SC_FUNC | SC_EXTERN;
 
-       /* Accept type only declarations */
-       if (curtok == TOK_SEMI) {
-           /* Type declaration only */
-           CheckEmptyDecl (&Spec);
-           NextToken ();
-           continue;
-       }
-
-       /* Parse a comma separated variable list */
-       while (1) {
-
-           Declaration Decl;
-
-           /* Remember the storage class for the new symbol */
-           SymbolSC = Spec.StorageClass;
-
-           /* Read the declaration */
-           ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
-
-           /* If we don't have a name, this was flagged as an error earlier.
-            * To avoid problems later, use an anonymous name here.
-            */
-                   if (Decl.Ident[0] == '\0') {
-               AnonName (Decl.Ident, "param");
-           }
-
-                   if (!IsFunc (Decl.Type) && (SymbolSC & SC_TYPEDEF) != SC_TYPEDEF) {
-
-               /* Get the size of the variable */
-               Size = SizeOf (Decl.Type);
-
-#if 0
-               /* Check the storage class */
-               if ((SymbolSC & SC_REGISTER) && (Reg = AllocRegVar (psym, tarray)) >= 0) {
-
-                   /* We will store the current value of the register onto the
-                    * stack, thus making functions with register variables
-                    * reentrant. If we have pending auto variables, emit them
-                    * now.
-                    */
-                   g_usecode ();
-                   g_space (AutoSpace);
-                   oursp -= AutoSpace;
-                   AutoSpace = 0;
+    }
 
-                   /* Remember the register bank offset */
-                   ldata = Reg;
+    /* If we don't have a name, this was flagged as an error earlier.
+     * To avoid problems later, use an anonymous name here.
+     */
+    if (Decl.Ident[0] == '\0') {
+       AnonName (Decl.Ident, "param");
+    }
 
-                   /* Save the current register value onto the stack */
-                   g_save_regvars (Reg, Size);
+    /* Handle anything that needs storage (no functions, no typdefs) */
+    if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
 
-                   /* Allow variable initialization */
-                   if (curtok == TOK_ASSIGN) {
+       /* Get the size of the variable */
+       Size = SizeOf (Decl.Type);
 
-                       struct expent lval;
+               if (SC & (SC_AUTO | SC_REGISTER)) {
 
-                       /* Skip the '=' */
-                       NextToken ();
+           /* Auto variable */
+           if (StaticLocals == 0) {
 
-                       /* Get the expression into the primary */
-                       expression1 (&lval);
+               /* Change SC in case it was register */
+               SC = (SC & ~SC_REGISTER) | SC_AUTO;
+               if (curtok == TOK_ASSIGN) {
 
-                       /* Make type adjustments if needed */
-                       assignadjust (tarray, &lval);
+                   struct expent lval;
 
-                       /* Setup the type flags for the assignment */
-                       flags = TypeOf (tarray) | CF_REGVAR;
-                       if (Size == 1) {
-                           flags |= CF_FORCECHAR;
-                       }
+                   /* Allocate previously reserved local space */
+                   AllocLocalSpace (CurrentFunc);
 
-                               /* Store the value into the register */
-                               g_putstatic (flags, Reg, 0);
+                   /* Switch to the code segment. */
+                   g_usecode ();
 
-                       /* Mark the variable as referenced */
-                       SymbolSC |= SC_REF;
+                   /* Skip the '=' */
+                   NextToken ();
 
-                   }
+                   /* Setup the type flags for the assignment */
+                   flags = Size == 1? CF_FORCECHAR : CF_NONE;
 
-                   /* Account for the stack space needed and remember the
-                    * stack offset of the save area.
-                    */
-                   offs -= Size;
-                   psym->h_lattr = offs;
+                   /* Get the expression into the primary */
+                   if (evalexpr (flags, hie1, &lval) == 0) {
+                       /* Constant expression. Adjust the types */
+                       assignadjust (Decl.Type, &lval);
+                       flags |= CF_CONST;
+                   } else {
+                       /* Expression is not constant and in the primary */
+                       assignadjust (Decl.Type, &lval);
+                   }
 
-               } else if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
-#endif
-               if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
+                   /* Push the value */
+                   g_push (flags | TypeOf (Decl.Type), lval.e_const);
 
-                   /* Auto variable */
-                   if (LocalsAreStatic == 0) {
+                   /* Mark the variable as referenced */
+                   SC |= SC_REF;
 
-                       /* Change SC in case it was register */
-                               SymbolSC = (SymbolSC & ~SC_REGISTER) | SC_AUTO;
-                       if (curtok == TOK_ASSIGN) {
+                   /* Variable is located at the current SP */
+                   SymData = oursp;
 
-                           struct expent lval;
+               } else {
+                   /* Non-initialized local variable. Just keep track of
+                    * the space needed.
+                    */
+                   SymData = ReserveLocalSpace (CurrentFunc, Size);
+               }
 
-                           /* Switch to the code segment, allocate space for
-                            * uninitialized variables.
-                            */
-                           g_usecode ();
-                           g_space (AutoSpace);
-                           oursp -= AutoSpace;
-                           AutoSpace = 0;
+           } else {
 
-                           /* Skip the '=' */
-                           NextToken ();
+               /* Static local variables. */
+               SC = (SC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
 
-                           /* Setup the type flags for the assignment */
-                           flags = Size == 1? CF_FORCECHAR : CF_NONE;
+               /* Put them into the BSS */
+               g_usebss ();
 
-                           /* Get the expression into the primary */
-                           if (evalexpr (flags, hie1, &lval) == 0) {
-                               /* Constant expression. Adjust the types */
-                               assignadjust (Decl.Type, &lval);
-                               flags |= CF_CONST;
-                           } else {
-                               /* Expression is not constant and in the primary */
-                               assignadjust (Decl.Type, &lval);
-                           }
+               /* Define the variable label */
+               SymData = GetLocalLabel ();
+               g_defloclabel (SymData);
 
-                           /* Push the value */
-                           g_push (flags | TypeOf (Decl.Type), lval.e_const);
+               /* Reserve space for the data */
+               g_res (Size);
 
-                           /* Mark the variable as referenced */
-                           SymbolSC |= SC_REF;
+               /* Allow assignments */
+               if (curtok == TOK_ASSIGN) {
 
-                       } else {
-                           /* Non-initialized local variable. Just keep track of
-                            * the space needed.
-                            */
-                           AutoSpace += Size;
-                       }
+                   struct expent lval;
 
-                       /* Allocate space on the stack, assign the offset */
-                       offs -= Size;
-                       ldata = offs;
+                   /* Switch to the code segment. */
+                   g_usecode ();
 
-                   } else {
+                   /* Skip the '=' */
+                   NextToken ();
 
-                       /* Static local variables. */
-                               SymbolSC = (SymbolSC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
+                   /* Get the expression into the primary */
+                   expression1 (&lval);
 
-                       /* Put them into the BSS */
-                       g_usebss ();
+                   /* Make type adjustments if needed */
+                   assignadjust (Decl.Type, &lval);
 
-                       /* Define the variable label */
-                       g_defloclabel (ldata = GetLabel ());
+                   /* Setup the type flags for the assignment */
+                   flags = TypeOf (Decl.Type);
+                   if (Size == 1) {
+                       flags |= CF_FORCECHAR;
+                   }
 
-                       /* Reserve space for the data */
-                       g_res (Size);
+                   /* Store the value into the variable */
+                   g_putstatic (flags, SymData, 0);
 
-                       /* Allow assignments */
-                       if (curtok == TOK_ASSIGN) {
+                   /* Mark the variable as referenced */
+                   SC |= SC_REF;
+               }
+           }
 
-                           struct expent lval;
+       } else if ((SC & SC_STATIC) == SC_STATIC) {
 
-                           /* Switch to the code segment. */
-                           g_usecode ();
+           /* Static data */
+           if (curtok == TOK_ASSIGN) {
 
-                           /* Skip the '=' */
-                           NextToken ();
+               /* Initialization ahead, switch to data segment */
+               if (IsQualConst (Decl.Type)) {
+                   g_userodata ();
+               } else {
+                   g_usedata ();
+               }
 
-                           /* Get the expression into the primary */
-                           expression1 (&lval);
+               /* Define the variable label */
+               SymData = GetLocalLabel ();
+               g_defloclabel (SymData);
 
-                           /* Make type adjustments if needed */
-                           assignadjust (Decl.Type, &lval);
+               /* Skip the '=' */
+               NextToken ();
 
-                           /* Setup the type flags for the assignment */
-                           flags = TypeOf (Decl.Type);
-                           if (Size == 1) {
-                               flags |= CF_FORCECHAR;
-                           }
+               /* Allow initialization of static vars */
+               ParseInit (Decl.Type);
 
-                           /* Store the value into the variable */
-                           g_putstatic (flags, ldata, 0);
+               /* Mark the variable as referenced */
+               SC |= SC_REF;
 
-                           /* Mark the variable as referenced */
-                           SymbolSC |= SC_REF;
-                       }
-                   }
+           } else {
 
-               } else if ((SymbolSC & SC_STATIC) == SC_STATIC) {
+               /* Uninitialized data, use BSS segment */
+               g_usebss ();
 
-                   /* Static data */
-                   if (curtok == TOK_ASSIGN) {
+               /* Define the variable label */
+               SymData = GetLocalLabel ();
+               g_defloclabel (SymData);
 
-                       /* Initialization ahead, switch to data segment */
-                       g_usedata ();
+               /* Reserve space for the data */
+               g_res (Size);
 
-                       /* Define the variable label */
-                       g_defloclabel (ldata = GetLabel ());
+           }
+       }
 
-                       /* Skip the '=' */
-                       NextToken ();
+    }
 
-                       /* Allow initialization of static vars */
-                       ParseInit (Decl.Type);
+    /* If the symbol is not marked as external, it will be defined */
+    if ((SC & SC_EXTERN) == 0) {
+       SC |= SC_DEF;
+    }
 
-                       /* Mark the variable as referenced */
-                       SymbolSC |= SC_REF;
+    /* Add the symbol to the symbol table */
+    AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
+}
 
-                   } else {
 
-                       /* Uninitialized data, use BSS segment */
-                       g_usebss ();
 
-                       /* Define the variable label */
-                       g_defloclabel (ldata = GetLabel ());
+void DeclareLocals (void)
+/* Declare local variables and types. */
+{
+    /* Remember the current stack pointer */
+    int InitialStack = oursp;
 
-                       /* Reserve space for the data */
-                       g_res (Size);
+    /* Loop until we don't find any more variables */
+    while (1) {
 
-                   }
-               }
+       /* Check variable declarations. We need to distinguish between a
+        * default int type and the end of variable declarations. So we
+        * will do the following: If there is no explicit storage class
+        * specifier *and* no explicit type given, it is assume that we
+                * have reached the end of declarations.
+        */
+       DeclSpec Spec;
+       ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+               if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) {
+           break;
+       }
 
-           }
+       /* Accept type only declarations */
+       if (curtok == TOK_SEMI) {
+           /* Type declaration only */
+           CheckEmptyDecl (&Spec);
+           NextToken ();
+           continue;
+       }
 
-           /* If the symbol is not marked as external, it will be defined */
-           if ((SymbolSC & SC_EXTERN) == 0) {
-               SymbolSC |= SC_DEF;
-           }
+       /* Parse a comma separated variable list */
+       while (1) {
 
-           /* Add the symbol to the symbol table */
-           AddLocalSym (Decl.Ident, Decl.Type, SymbolSC, ldata);
+           /* Parse one declaration */
+           ParseOneDecl (&Spec);
 
-           if (curtok != TOK_COMMA) {
+           /* Check if there is more */
+           if (curtok == TOK_COMMA) {
+               /* More to come */
+               NextToken ();
+           } else {
+               /* Done */
                break;
            }
-           NextToken ();
                }
-       if (curtok == TOK_SEMI) {
-           NextToken ();
-       }
+
+       /* A semicolon must follow */
+       ConsumeSemi ();
     }
 
+    /* Be sure to allocate any reserved space for locals */
+    AllocLocalSpace (CurrentFunc);
+
     /* In case we switched away from code segment, switch back now */
     g_usecode ();
 
-    /* Create space for locals */
-    g_space (AutoSpace);
-    oursp -= AutoSpace;
+    /* In case we've allocated local variables in this block, emit a call to
+     * the stack checking routine if stack checks are enabled.
+     */
+    if (CheckStack && InitialStack != oursp) {
+               g_cstackcheck ();
+    }
 }