2000-05-28 13:40:48 +00:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* */
|
|
|
|
|
/* locals.c */
|
|
|
|
|
/* */
|
|
|
|
|
/* Local variable handling for the cc65 C compiler */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
2003-01-28 16:28:41 +00:00
|
|
|
|
/* (C) 2000-2003 Ullrich von Bassewitz */
|
2003-02-01 12:38:43 +00:00
|
|
|
|
/* R<>merstrasse 52 */
|
2003-01-28 16:28:41 +00:00
|
|
|
|
/* D-70794 Filderstadt */
|
2001-05-03 17:34:54 +00:00
|
|
|
|
/* EMail: uz@cc65.org */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
|
/* */
|
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
|
/* */
|
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
|
/* distribution. */
|
|
|
|
|
/* */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-09-14 19:26:13 +00:00
|
|
|
|
/* common */
|
|
|
|
|
#include "xmalloc.h"
|
2000-10-10 20:39:04 +00:00
|
|
|
|
#include "xsprintf.h"
|
|
|
|
|
|
2000-09-14 19:26:13 +00:00
|
|
|
|
/* cc65 */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "anonname.h"
|
|
|
|
|
#include "asmlabel.h"
|
|
|
|
|
#include "codegen.h"
|
|
|
|
|
#include "declare.h"
|
2000-06-22 11:28:39 +00:00
|
|
|
|
#include "error.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "expr.h"
|
2000-06-12 18:31:40 +00:00
|
|
|
|
#include "function.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "global.h"
|
|
|
|
|
#include "locals.h"
|
2003-08-11 20:18:30 +00:00
|
|
|
|
#include "symtab.h"
|
|
|
|
|
#include "typeconv.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Code */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-11-24 23:31:54 +00:00
|
|
|
|
static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
|
|
|
|
/* Parse the declaration of a register variable. The function returns the
|
|
|
|
|
* symbol data, which is the offset of the variable in the register bank.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
unsigned InitLabel;
|
|
|
|
|
|
|
|
|
|
/* Determine if this is a compound variable */
|
|
|
|
|
int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
|
|
|
|
|
|
|
|
|
|
/* Get the size of the variable */
|
|
|
|
|
unsigned Size = SizeOf (Decl->Type);
|
|
|
|
|
|
|
|
|
|
/* Save the current contents of the register variable on stack */
|
|
|
|
|
F_AllocLocalSpace (CurrentFunc);
|
|
|
|
|
g_save_regvars (Reg, Size);
|
|
|
|
|
|
|
|
|
|
/* Check for an optional initialization */
|
|
|
|
|
if (CurTok.Tok == TOK_ASSIGN) {
|
|
|
|
|
|
|
|
|
|
ExprDesc lval;
|
|
|
|
|
|
|
|
|
|
/* Skip the '=' */
|
|
|
|
|
NextToken ();
|
|
|
|
|
|
|
|
|
|
/* Special handling for compound types */
|
|
|
|
|
if (IsCompound) {
|
|
|
|
|
|
|
|
|
|
/* Switch to read only data */
|
|
|
|
|
g_userodata ();
|
|
|
|
|
|
|
|
|
|
/* Define a label for the initialization data */
|
|
|
|
|
InitLabel = GetLocalLabel ();
|
|
|
|
|
g_defdatalabel (InitLabel);
|
|
|
|
|
|
|
|
|
|
/* Parse the initialization generating a memory image of the
|
2003-02-05 22:02:48 +00:00
|
|
|
|
* data in the RODATA segment. The function does return the size
|
2003-08-11 20:18:30 +00:00
|
|
|
|
* of the initialization data, which may be greater than the
|
|
|
|
|
* actual size of the type, if the type is a structure with a
|
2003-02-05 22:02:48 +00:00
|
|
|
|
* flexible array member that has been initialized. Since we must
|
|
|
|
|
* know the size of the data in advance for register variables,
|
|
|
|
|
* we cannot allow that here.
|
2002-11-24 23:31:54 +00:00
|
|
|
|
*/
|
2003-02-05 22:02:48 +00:00
|
|
|
|
if (ParseInit (Decl->Type) != Size) {
|
|
|
|
|
Error ("Cannot initialize flexible array members of storage class `register'");
|
|
|
|
|
}
|
2002-11-24 23:31:54 +00:00
|
|
|
|
|
|
|
|
|
/* Generate code to copy this data into the variable space */
|
|
|
|
|
g_initregister (InitLabel, Reg, Size);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* Parse the expression */
|
|
|
|
|
int k = hie1 (InitExprDesc (&lval));
|
2002-11-24 23:31:54 +00:00
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* Convert it to the target type */
|
|
|
|
|
k = TypeConversion (&lval, k, Decl->Type);
|
|
|
|
|
|
|
|
|
|
/* Load the value into the primary */
|
2003-08-29 09:16:28 +00:00
|
|
|
|
ExprLoad (CF_NONE, k, &lval);
|
2002-11-24 23:31:54 +00:00
|
|
|
|
|
|
|
|
|
/* Store the value into the variable */
|
2003-08-11 20:18:30 +00:00
|
|
|
|
g_putstatic (CF_REGVAR | TypeOf (Decl->Type), Reg, 0);
|
2002-11-24 23:31:54 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mark the variable as referenced */
|
|
|
|
|
*SC |= SC_REF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Cannot allocate a variable of zero size */
|
|
|
|
|
if (Size == 0) {
|
|
|
|
|
Error ("Variable `%s' has unknown size", Decl->Ident);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the symbol data */
|
|
|
|
|
return Reg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-10-17 21:14:40 +00:00
|
|
|
|
static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Parse the declaration of an auto variable. The function returns the symbol
|
|
|
|
|
* data, which is the offset for variables on the stack, and the label for
|
|
|
|
|
* static variables.
|
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{
|
2002-10-10 20:24:16 +00:00
|
|
|
|
unsigned Flags;
|
|
|
|
|
unsigned SymData;
|
2002-10-10 21:15:24 +00:00
|
|
|
|
unsigned InitLabel;
|
|
|
|
|
|
|
|
|
|
/* Determine if this is a compound variable */
|
|
|
|
|
int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
|
2000-06-22 11:28:39 +00:00
|
|
|
|
|
2002-10-17 21:14:40 +00:00
|
|
|
|
/* Get the size of the variable */
|
|
|
|
|
unsigned Size = SizeOf (Decl->Type);
|
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Check if this is a variable on the stack or in static memory */
|
|
|
|
|
if (StaticLocals == 0) {
|
2000-06-22 11:28:39 +00:00
|
|
|
|
|
2002-11-24 23:31:54 +00:00
|
|
|
|
/* Check for an optional initialization */
|
2002-10-10 20:24:16 +00:00
|
|
|
|
if (CurTok.Tok == TOK_ASSIGN) {
|
2000-06-22 11:28:39 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
ExprDesc lval;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Skip the '=' */
|
|
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 21:15:24 +00:00
|
|
|
|
/* Special handling for compound types */
|
|
|
|
|
if (IsCompound) {
|
|
|
|
|
|
|
|
|
|
/* Switch to read only data */
|
|
|
|
|
g_userodata ();
|
|
|
|
|
|
|
|
|
|
/* Define a label for the initialization data */
|
|
|
|
|
InitLabel = GetLocalLabel ();
|
|
|
|
|
g_defdatalabel (InitLabel);
|
|
|
|
|
|
|
|
|
|
/* Parse the initialization generating a memory image of the
|
2003-02-05 22:02:48 +00:00
|
|
|
|
* data in the RODATA segment. The function will return the
|
|
|
|
|
* actual size of the initialization data, which may be
|
|
|
|
|
* greater than the size of the variable if it is a struct
|
|
|
|
|
* that contains a flexible array member and we're not in
|
|
|
|
|
* ANSI mode.
|
2002-10-10 21:15:24 +00:00
|
|
|
|
*/
|
2003-02-05 22:02:48 +00:00
|
|
|
|
Size = ParseInit (Decl->Type);
|
2002-10-10 21:15:24 +00:00
|
|
|
|
|
2003-02-05 22:02:48 +00:00
|
|
|
|
/* Now reserve space for the variable on the stack */
|
|
|
|
|
SymData = F_ReserveLocalSpace (CurrentFunc, Size);
|
|
|
|
|
|
|
|
|
|
/* Next, allocate the space on the stack. This means that the
|
|
|
|
|
* variable is now located at offset 0 from the current sp.
|
|
|
|
|
*/
|
|
|
|
|
F_AllocLocalSpace (CurrentFunc);
|
|
|
|
|
|
|
|
|
|
/* Generate code to copy the initialization data into the
|
|
|
|
|
* variable space
|
|
|
|
|
*/
|
2002-10-10 21:15:24 +00:00
|
|
|
|
g_initauto (InitLabel, Size);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
int k;
|
|
|
|
|
|
2002-10-10 21:15:24 +00:00
|
|
|
|
/* Allocate previously reserved local space */
|
|
|
|
|
F_AllocLocalSpace (CurrentFunc);
|
|
|
|
|
|
|
|
|
|
/* Setup the type flags for the assignment */
|
2002-11-02 12:39:10 +00:00
|
|
|
|
Flags = (Size == SIZEOF_CHAR)? CF_FORCECHAR : CF_NONE;
|
2002-10-10 21:15:24 +00:00
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* Parse the expression */
|
|
|
|
|
k = hie1 (InitExprDesc (&lval));
|
|
|
|
|
|
|
|
|
|
/* Convert it to the target type */
|
|
|
|
|
k = TypeConversion (&lval, k, Decl->Type);
|
|
|
|
|
|
|
|
|
|
/* If the value is not const, load it into the primary.
|
|
|
|
|
* Otherwise pass the information to the code generator.
|
|
|
|
|
*/
|
|
|
|
|
if (k != 0 || lval.Flags != E_MCONST) {
|
2003-08-29 09:16:28 +00:00
|
|
|
|
ExprLoad (CF_NONE, k, &lval);
|
2003-08-11 20:18:30 +00:00
|
|
|
|
k = 0;
|
2002-10-10 21:15:24 +00:00
|
|
|
|
} else {
|
2003-08-11 20:18:30 +00:00
|
|
|
|
Flags |= CF_CONST;
|
2002-10-10 21:15:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Push the value */
|
|
|
|
|
g_push (Flags | TypeOf (Decl->Type), lval.ConstVal);
|
|
|
|
|
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Mark the variable as referenced */
|
|
|
|
|
*SC |= SC_REF;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Variable is located at the current SP */
|
|
|
|
|
SymData = oursp;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
} else {
|
|
|
|
|
/* Non-initialized local variable. Just keep track of
|
|
|
|
|
* the space needed.
|
|
|
|
|
*/
|
|
|
|
|
SymData = F_ReserveLocalSpace (CurrentFunc, Size);
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Static local variables. */
|
2002-11-24 23:31:54 +00:00
|
|
|
|
*SC = (*SC & ~SC_AUTO) | SC_STATIC;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Put them into the BSS */
|
|
|
|
|
g_usebss ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Define the variable label */
|
|
|
|
|
SymData = GetLocalLabel ();
|
|
|
|
|
g_defdatalabel (SymData);
|
2002-03-10 14:34:20 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Reserve space for the data */
|
|
|
|
|
g_res (Size);
|
2002-03-10 14:34:20 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Allow assignments */
|
|
|
|
|
if (CurTok.Tok == TOK_ASSIGN) {
|
2002-03-10 14:34:20 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
ExprDesc lval;
|
2002-03-10 14:34:20 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Skip the '=' */
|
|
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 21:15:24 +00:00
|
|
|
|
if (IsCompound) {
|
|
|
|
|
|
|
|
|
|
/* Switch to read only data */
|
|
|
|
|
g_userodata ();
|
|
|
|
|
|
|
|
|
|
/* Define a label for the initialization data */
|
|
|
|
|
InitLabel = GetLocalLabel ();
|
|
|
|
|
g_defdatalabel (InitLabel);
|
|
|
|
|
|
|
|
|
|
/* Parse the initialization generating a memory image of the
|
|
|
|
|
* data in the RODATA segment.
|
|
|
|
|
*/
|
|
|
|
|
ParseInit (Decl->Type);
|
|
|
|
|
|
|
|
|
|
/* Generate code to copy this data into the variable space */
|
|
|
|
|
g_initstatic (InitLabel, SymData, Size);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* Parse the expression */
|
|
|
|
|
int k = hie1 (InitExprDesc (&lval));
|
2002-10-10 21:15:24 +00:00
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* Convert it to the target type */
|
|
|
|
|
k = TypeConversion (&lval, k, Decl->Type);
|
2002-10-10 21:15:24 +00:00
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* Load the value into the primary */
|
2003-08-29 09:16:28 +00:00
|
|
|
|
ExprLoad (CF_NONE, k, &lval);
|
2002-10-10 21:15:24 +00:00
|
|
|
|
|
2003-08-11 20:18:30 +00:00
|
|
|
|
/* Store the value into the variable */
|
|
|
|
|
g_putstatic (TypeOf (Decl->Type), SymData, 0);
|
2002-10-10 21:15:24 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Mark the variable as referenced */
|
|
|
|
|
*SC |= SC_REF;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-17 21:14:40 +00:00
|
|
|
|
/* Cannot allocate a variable of zero size */
|
|
|
|
|
if (Size == 0) {
|
|
|
|
|
Error ("Variable `%s' has unknown size", Decl->Ident);
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Return the symbol data */
|
|
|
|
|
return SymData;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-10-17 21:14:40 +00:00
|
|
|
|
static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC)
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Parse the declaration of a static variable. The function returns the symbol
|
|
|
|
|
* data, which is the asm label of the variable.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
unsigned SymData;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-17 21:14:40 +00:00
|
|
|
|
/* Get the size of the variable */
|
|
|
|
|
unsigned Size = SizeOf (Decl->Type);
|
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Static data */
|
|
|
|
|
if (CurTok.Tok == TOK_ASSIGN) {
|
2001-09-21 13:48:55 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Initialization ahead, switch to data segment */
|
|
|
|
|
if (IsQualConst (Decl->Type)) {
|
|
|
|
|
g_userodata ();
|
|
|
|
|
} else {
|
|
|
|
|
g_usedata ();
|
|
|
|
|
}
|
2002-03-10 14:34:20 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Define the variable label */
|
|
|
|
|
SymData = GetLocalLabel ();
|
|
|
|
|
g_defdatalabel (SymData);
|
2002-03-10 14:34:20 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Skip the '=' */
|
|
|
|
|
NextToken ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Allow initialization of static vars */
|
|
|
|
|
ParseInit (Decl->Type);
|
|
|
|
|
|
|
|
|
|
/* If the previous size has been unknown, it must be known now */
|
|
|
|
|
if (Size == 0) {
|
|
|
|
|
Size = SizeOf (Decl->Type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mark the variable as referenced */
|
|
|
|
|
*SC |= SC_REF;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Uninitialized data, use BSS segment */
|
|
|
|
|
g_usebss ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Define the variable label */
|
|
|
|
|
SymData = GetLocalLabel ();
|
|
|
|
|
g_defdatalabel (SymData);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Reserve space for the data */
|
|
|
|
|
g_res (Size);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-17 21:14:40 +00:00
|
|
|
|
/* Cannot allocate a variable of zero size */
|
|
|
|
|
if (Size == 0) {
|
|
|
|
|
Error ("Variable `%s' has unknown size", Decl->Ident);
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Return the symbol data */
|
|
|
|
|
return SymData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ParseOneDecl (const DeclSpec* Spec)
|
|
|
|
|
/* Parse one variable declaration */
|
|
|
|
|
{
|
|
|
|
|
unsigned SC; /* Storage class for symbol */
|
|
|
|
|
unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
|
2002-11-24 23:31:54 +00:00
|
|
|
|
Declaration Decl; /* Declaration data structure */
|
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
|
|
|
|
|
/* 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)) {
|
2002-11-25 15:05:15 +00:00
|
|
|
|
/* Function prototypes are always external */
|
|
|
|
|
if ((SC & SC_EXTERN) == 0) {
|
2002-10-10 20:24:16 +00:00
|
|
|
|
Warning ("Function must be extern");
|
2002-11-25 15:05:15 +00:00
|
|
|
|
}
|
2002-10-10 20:24:16 +00:00
|
|
|
|
SC |= SC_FUNC | SC_EXTERN;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* 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') {
|
2002-11-24 23:31:54 +00:00
|
|
|
|
AnonName (Decl.Ident, "param");
|
2002-10-10 20:24:16 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Handle anything that needs storage (no functions, no typdefs) */
|
|
|
|
|
if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
|
2002-03-10 14:34:20 +00:00
|
|
|
|
|
2002-11-24 23:31:54 +00:00
|
|
|
|
/* If we have a register variable, try to allocate a register and
|
|
|
|
|
* convert the declaration to "auto" if this is not possible.
|
|
|
|
|
*/
|
|
|
|
|
int Reg = 0; /* Initialize to avoid gcc complains */
|
2002-11-25 15:05:15 +00:00
|
|
|
|
if ((SC & SC_REGISTER) != 0 && (Reg = F_AllocRegVar (CurrentFunc, Decl.Type)) < 0) {
|
2002-11-24 23:31:54 +00:00
|
|
|
|
/* No space for this register variable, convert to auto */
|
|
|
|
|
SC = (SC & ~SC_REGISTER) | SC_AUTO;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-11-24 23:31:54 +00:00
|
|
|
|
/* Check the variable type */
|
2002-11-25 15:05:15 +00:00
|
|
|
|
if ((SC & SC_REGISTER) == SC_REGISTER) {
|
2002-11-24 23:31:54 +00:00
|
|
|
|
/* Register variable */
|
|
|
|
|
SymData = ParseRegisterDecl (&Decl, &SC, Reg);
|
2002-11-25 15:05:15 +00:00
|
|
|
|
} else if ((SC & SC_AUTO) == SC_AUTO) {
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Auto variable */
|
2002-10-17 21:14:40 +00:00
|
|
|
|
SymData = ParseAutoDecl (&Decl, &SC);
|
2002-11-25 15:05:15 +00:00
|
|
|
|
} else if ((SC & SC_STATIC) == SC_STATIC) {
|
2002-10-10 20:24:16 +00:00
|
|
|
|
/* Static variable */
|
2002-10-17 21:14:40 +00:00
|
|
|
|
SymData = ParseStaticDecl (&Decl, &SC);
|
2002-11-24 23:31:54 +00:00
|
|
|
|
} else {
|
|
|
|
|
Internal ("Invalid storage class in ParseOneDecl: %04X", SC);
|
|
|
|
|
}
|
2000-06-22 11:28:39 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2002-11-24 23:31:54 +00:00
|
|
|
|
/* If the symbol is not marked as external, it will be defined now */
|
2000-06-22 11:28:39 +00:00
|
|
|
|
if ((SC & SC_EXTERN) == 0) {
|
2002-11-24 23:31:54 +00:00
|
|
|
|
SC |= SC_DEF;
|
2000-06-22 11:28:39 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Add the symbol to the symbol table */
|
2002-11-25 15:05:15 +00:00
|
|
|
|
AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
|
2000-06-22 11:28:39 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
void DeclareLocals (void)
|
|
|
|
|
/* Declare local variables and types. */
|
|
|
|
|
{
|
2001-03-19 23:01:35 +00:00
|
|
|
|
/* Remember the current stack pointer */
|
|
|
|
|
int InitialStack = oursp;
|
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Loop until we don't find any more variables */
|
|
|
|
|
while (1) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Check variable declarations. We need to distinguish between a
|
2002-03-10 14:34:20 +00:00
|
|
|
|
* default int type and the end of variable declarations. So we
|
2000-06-22 11:28:39 +00:00
|
|
|
|
* will do the following: If there is no explicit storage class
|
2003-02-01 12:38:43 +00:00
|
|
|
|
* specifier *and* no explicit type given, *and* no type qualifiers
|
|
|
|
|
* have been read, it is assumed that we have reached the end of
|
2003-01-28 16:28:41 +00:00
|
|
|
|
* declarations.
|
2000-06-22 11:28:39 +00:00
|
|
|
|
*/
|
|
|
|
|
DeclSpec Spec;
|
|
|
|
|
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
2003-01-28 16:28:41 +00:00
|
|
|
|
if ((Spec.Flags & DS_DEF_STORAGE) != 0 && /* No storage spec */
|
|
|
|
|
(Spec.Flags & DS_DEF_TYPE) != 0 && /* No type given */
|
|
|
|
|
GetQualifier (Spec.Type) == T_QUAL_NONE) { /* No type qualifier */
|
2000-06-22 11:28:39 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Accept type only declarations */
|
2001-05-22 09:32:24 +00:00
|
|
|
|
if (CurTok.Tok == TOK_SEMI) {
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Type declaration only */
|
|
|
|
|
CheckEmptyDecl (&Spec);
|
|
|
|
|
NextToken ();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Parse a comma separated variable list */
|
|
|
|
|
while (1) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Parse one declaration */
|
|
|
|
|
ParseOneDecl (&Spec);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Check if there is more */
|
2001-05-22 09:32:24 +00:00
|
|
|
|
if (CurTok.Tok == TOK_COMMA) {
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* More to come */
|
|
|
|
|
NextToken ();
|
|
|
|
|
} else {
|
|
|
|
|
/* Done */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-06-22 11:28:39 +00:00
|
|
|
|
|
|
|
|
|
/* A semicolon must follow */
|
|
|
|
|
ConsumeSemi ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-22 11:28:39 +00:00
|
|
|
|
/* Be sure to allocate any reserved space for locals */
|
2002-06-12 12:12:04 +00:00
|
|
|
|
F_AllocLocalSpace (CurrentFunc);
|
2000-06-22 11:28:39 +00:00
|
|
|
|
|
2001-03-19 23:01:35 +00:00
|
|
|
|
/* 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) {
|
2001-03-20 22:34:08 +00:00
|
|
|
|
g_cstackcheck ();
|
2001-03-19 23:01:35 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|