#include "asmlabel.h"
#include "codegen.h"
#include "declare.h"
+#include "error.h"
#include "expr.h"
#include "function.h"
#include "global.h"
-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;
- }
-
- /* Accept type only declarations */
- if (curtok == TOK_SEMI) {
- /* Type declaration only */
- CheckEmptyDecl (&Spec);
- NextToken ();
- continue;
+ 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 (IsFunc (Decl.Type)) {
+ /* Function prototypes are always external */
+ if ((SC & SC_EXTERN) == 0) {
+ Warning (WARN_FUNC_MUST_BE_EXTERN);
}
+ SC |= SC_FUNC | SC_EXTERN;
- /* 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;
-
- /* Save the current register value onto the stack */
- g_save_regvars (Reg, Size);
+ }
- /* Allow variable initialization */
- if (curtok == TOK_ASSIGN) {
+ /* 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");
+ }
- struct expent lval;
+ /* Handle anything that needs storage (no functions, no typdefs) */
+ if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
- /* Skip the '=' */
- NextToken ();
+ /* Get the size of the variable */
+ Size = SizeOf (Decl.Type);
- /* Get the expression into the primary */
- expression1 (&lval);
+ if (SC & (SC_AUTO | SC_REGISTER)) {
- /* Make type adjustments if needed */
- assignadjust (tarray, &lval);
+ /* Auto variable */
+ if (StaticLocals == 0) {
- /* Setup the type flags for the assignment */
- flags = TypeOf (tarray) | CF_REGVAR;
- if (Size == 1) {
- flags |= CF_FORCECHAR;
- }
+ /* Change SC in case it was register */
+ SC = (SC & ~SC_REGISTER) | SC_AUTO;
+ if (curtok == TOK_ASSIGN) {
- /* Store the value into the register */
- g_putstatic (flags, Reg, 0);
+ struct expent lval;
- /* Mark the variable as referenced */
- SymbolSC |= SC_REF;
+ /* Allocate previously reserved local space */
+ AllocLocalSpace (CurrentFunc);
- }
+ /* Skip the '=' */
+ NextToken ();
- /* Account for the stack space needed and remember the
- * stack offset of the save area.
- */
- offs -= Size;
- psym->h_lattr = offs;
+ /* Setup the type flags for the assignment */
+ flags = Size == 1? CF_FORCECHAR : CF_NONE;
- } else if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
-#endif
- if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
+ /* 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);
+ }
- /* Auto variable */
- if (StaticLocals == 0) {
+ /* Push the value */
+ g_push (flags | TypeOf (Decl.Type), lval.e_const);
- /* Change SC in case it was register */
- SymbolSC = (SymbolSC & ~SC_REGISTER) | SC_AUTO;
- if (curtok == TOK_ASSIGN) {
+ /* Mark the variable as referenced */
+ SC |= SC_REF;
- struct expent lval;
+ /* Variable is located at the current SP */
+ SymData = oursp;
- /* Switch to the code segment, allocate space for
- * uninitialized variables.
- */
- g_usecode ();
- g_space (AutoSpace);
- oursp -= AutoSpace;
- AutoSpace = 0;
+ } else {
+ /* Non-initialized local variable. Just keep track of
+ * the space needed.
+ */
+ SymData = ReserveLocalSpace (CurrentFunc, Size);
+ }
- /* Skip the '=' */
- NextToken ();
+ } else {
- /* Setup the type flags for the assignment */
- flags = Size == 1? CF_FORCECHAR : CF_NONE;
+ /* Static local variables. */
+ SC = (SC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
- /* 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);
- }
+ /* Put them into the BSS */
+ g_usebss ();
- /* Push the value */
- g_push (flags | TypeOf (Decl.Type), lval.e_const);
+ /* Define the variable label */
+ SymData = GetLabel ();
+ g_defloclabel (SymData);
- /* Mark the variable as referenced */
- SymbolSC |= SC_REF;
+ /* Reserve space for the data */
+ g_res (Size);
- } else {
- /* Non-initialized local variable. Just keep track of
- * the space needed.
- */
- AutoSpace += Size;
- }
+ /* Allow assignments */
+ if (curtok == TOK_ASSIGN) {
- /* Allocate space on the stack, assign the offset */
- offs -= Size;
- ldata = offs;
+ struct expent lval;
- } else {
+ /* Switch to the code segment. */
+ g_usecode ();
- /* Static local variables. */
- SymbolSC = (SymbolSC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
+ /* Skip the '=' */
+ NextToken ();
- /* Put them into the BSS */
- g_usebss ();
+ /* Get the expression into the primary */
+ expression1 (&lval);
- /* Define the variable label */
- g_defloclabel (ldata = GetLabel ());
+ /* Make type adjustments if needed */
+ assignadjust (Decl.Type, &lval);
- /* Reserve space for the data */
- g_res (Size);
+ /* Setup the type flags for the assignment */
+ flags = TypeOf (Decl.Type);
+ if (Size == 1) {
+ flags |= CF_FORCECHAR;
+ }
- /* Allow assignments */
- if (curtok == TOK_ASSIGN) {
+ /* Store the value into the variable */
+ g_putstatic (flags, SymData, 0);
- struct expent lval;
+ /* Mark the variable as referenced */
+ SC |= SC_REF;
+ }
+ }
- /* Switch to the code segment. */
- g_usecode ();
+ } else if ((SC & SC_STATIC) == SC_STATIC) {
- /* Skip the '=' */
- NextToken ();
+ /* Static data */
+ if (curtok == TOK_ASSIGN) {
- /* Get the expression into the primary */
- expression1 (&lval);
+ /* Initialization ahead, switch to data segment */
+ g_usedata ();
- /* Make type adjustments if needed */
- assignadjust (Decl.Type, &lval);
+ /* Define the variable label */
+ SymData = GetLabel ();
+ g_defloclabel (SymData);
- /* Setup the type flags for the assignment */
- flags = TypeOf (Decl.Type);
- if (Size == 1) {
- flags |= CF_FORCECHAR;
- }
+ /* Skip the '=' */
+ NextToken ();
- /* Store the value into the variable */
- g_putstatic (flags, ldata, 0);
+ /* Allow initialization of static vars */
+ ParseInit (Decl.Type);
- /* Mark the variable as referenced */
- SymbolSC |= SC_REF;
- }
- }
+ /* Mark the variable as referenced */
+ SC |= SC_REF;
- } else if ((SymbolSC & SC_STATIC) == SC_STATIC) {
+ } else {
- /* Static data */
- if (curtok == TOK_ASSIGN) {
+ /* Uninitialized data, use BSS segment */
+ g_usebss ();
- /* Initialization ahead, switch to data segment */
- g_usedata ();
+ /* Define the variable label */
+ SymData = GetLabel ();
+ g_defloclabel (SymData);
- /* Define the variable label */
- g_defloclabel (ldata = GetLabel ());
+ /* Reserve space for the data */
+ g_res (Size);
- /* Skip the '=' */
- NextToken ();
+ }
+ }
- /* Allow initialization of static vars */
- ParseInit (Decl.Type);
+ }
- /* Mark the variable as referenced */
- SymbolSC |= SC_REF;
+ /* If the symbol is not marked as external, it will be defined */
+ if ((SC & SC_EXTERN) == 0) {
+ SC |= SC_DEF;
+ }
- } else {
+ /* Add the symbol to the symbol table */
+ AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
+}
- /* Uninitialized data, use BSS segment */
- g_usebss ();
- /* Define the variable label */
- g_defloclabel (ldata = GetLabel ());
- /* Reserve space for the data */
- g_res (Size);
+void DeclareLocals (void)
+/* Declare local variables and types. */
+{
+ /* 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;
}