1
0
mirror of https://github.com/cc65/cc65.git synced 2024-09-28 10:55:43 +00:00

Fixed an error when parsing local variables: Variables must be inserted into

the symbol table *before* the optional initializer is parsed, because they
might be referenced in the intializer.


git-svn-id: svn://svn.cc65.org/cc65/trunk@5648 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2012-04-22 18:08:45 +00:00
parent b0c4678ad2
commit faf58a8220
4 changed files with 114 additions and 86 deletions

View File

@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 2000-2011, Ullrich von Bassewitz */
/* (C) 2000-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@ -237,6 +237,16 @@ int F_ReserveLocalSpace (Function* F, unsigned Size)
int F_GetStackPtr (const Function* F)
/* Return the current stack pointer including reserved (but not allocated)
* space on the stack.
*/
{
return StackPtr - F->Reserved;
}
void F_AllocLocalSpace (Function* F)
/* Allocate any local space previously reserved. The function will do
* nothing if there is no reserved local space.
@ -361,7 +371,7 @@ static void F_RestoreRegVars (Function* F)
static void F_EmitDebugInfo (void)
/* Emit debug infos for the current function */
{
{
if (DebugInfo) {
/* Get the current fuction */
const SymEntry* Sym = CurrentFunc->FuncEntry;

View File

@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 1998-2009, Ullrich von Bassewitz */
/* (C) 1998-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
@ -102,6 +102,11 @@ int F_ReserveLocalSpace (Function* F, unsigned Size);
* offset.
*/
int F_GetStackPtr (const Function* F);
/* Return the current stack pointer including reserved (but not allocated)
* space on the stack.
*/
void F_AllocLocalSpace (Function* F);
/* Allocate any local space previously reserved. The function will do
* nothing if there is no reserved local space.

View File

@ -79,29 +79,27 @@ static unsigned AllocLabel (void (*UseSeg) ())
static unsigned AllocStorage (void (*UseSeg) (), unsigned Size)
/* Reserve Size bytes of BSS storage prefixed by a local label. Return the
* label.
*/
static void AllocStorage (unsigned Label, void (*UseSeg) (), unsigned Size)
/* Reserve Size bytes of BSS storage prefixed by a local label. */
{
/* Switch to the segment and define the label */
unsigned Label = AllocLabel (UseSeg);
/* Switch to the segment */
UseSeg ();
/* Define the variable label */
g_defdatalabel (Label);
/* Reserve space for the data */
g_res (Size);
/* Return the label */
return Label;
}
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.
static void ParseRegisterDecl (Declaration* Decl, int Reg)
/* Parse the declaration of a register variable. Reg is the offset of the
* variable in the register bank.
*/
{
unsigned InitLabel;
SymEntry* Sym;
/* Determine if this is a compound variable */
int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
@ -113,6 +111,12 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
F_AllocLocalSpace (CurrentFunc);
g_save_regvars (Reg, Size);
/* Add the symbol to the symbol table. We do that now, because for register
* variables the current stack pointer is implicitly used as location for
* the save area.
*/
Sym = AddLocalSym (Decl->Ident, Decl->Type, Decl->StorageClass, Reg);
/* Check for an optional initialization */
if (CurTok.Tok == TOK_ASSIGN) {
@ -127,7 +131,7 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
/* Switch to read only data and define a label for the
* initialization data.
*/
InitLabel = AllocLabel (g_userodata);
unsigned InitLabel = AllocLabel (g_userodata);
/* Parse the initialization generating a memory image of the
* data in the RODATA segment. The function does return the size
@ -137,7 +141,7 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
* know the size of the data in advance for register variables,
* we cannot allow that here.
*/
if (ParseInit (Decl->Type) != Size) {
if (ParseInit (Sym->Type) != Size) {
Error ("Cannot initialize flexible array members of storage class `register'");
}
@ -150,39 +154,33 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
hie1 (&Expr);
/* Convert it to the target type */
TypeConversion (&Expr, Decl->Type);
TypeConversion (&Expr, Sym->Type);
/* Load the value into the primary */
LoadExpr (CF_NONE, &Expr);
/* Store the value into the variable */
g_putstatic (CF_REGVAR | TypeOf (Decl->Type), Reg, 0);
g_putstatic (CF_REGVAR | TypeOf (Sym->Type), Reg, 0);
}
/* Mark the variable as referenced */
*SC |= SC_REF;
Sym->Flags |= 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;
}
static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
/* 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.
*/
static void ParseAutoDecl (Declaration* Decl)
/* Parse the declaration of an auto variable. */
{
unsigned Flags;
unsigned SymData;
unsigned Flags;
SymEntry* Sym;
/* Determine if this is a compound variable */
int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
@ -193,6 +191,13 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
/* Check if this is a variable on the stack or in static memory */
if (IS_Get (&StaticLocals) == 0) {
/* Add the symbol to the symbol table. The stack offset we use here
* may get corrected later.
*/
Sym = AddLocalSym (Decl->Ident, Decl->Type,
Decl->StorageClass,
F_GetStackPtr (CurrentFunc) - (int) Size);
/* Check for an optional initialization */
if (CurTok.Tok == TOK_ASSIGN) {
@ -216,10 +221,12 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
* that contains a flexible array member and we're not in
* ANSI mode.
*/
Size = ParseInit (Decl->Type);
Size = ParseInit (Sym->Type);
/* Now reserve space for the variable on the stack */
SymData = F_ReserveLocalSpace (CurrentFunc, Size);
/* Now reserve space for the variable on the stack and correct
* the offset in the symbol table entry.
*/
Sym->V.Offs = 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.
@ -243,7 +250,7 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
hie1 (&Expr);
/* Convert it to the target type */
TypeConversion (&Expr, Decl->Type);
TypeConversion (&Expr, Sym->Type);
/* If the value is not const, load it into the primary.
* Otherwise pass the information to the code generator.
@ -256,27 +263,33 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
}
/* Push the value */
g_push (Flags | TypeOf (Decl->Type), Expr.IVal);
g_push (Flags | TypeOf (Sym->Type), Expr.IVal);
}
/* Mark the variable as referenced */
*SC |= SC_REF;
/* Variable is located at the current SP */
SymData = StackPtr;
Sym->Flags |= SC_REF;
} else {
/* Non-initialized local variable. Just keep track of
* the space needed.
*/
SymData = F_ReserveLocalSpace (CurrentFunc, Size);
F_ReserveLocalSpace (CurrentFunc, Size);
}
} else {
unsigned DataLabel;
/* Static local variables. */
*SC = (*SC & ~SC_AUTO) | SC_STATIC;
Decl->StorageClass = (Decl->StorageClass & ~SC_AUTO) | SC_STATIC;
/* Generate a label, but don't define it */
DataLabel = GetLocalLabel ();
/* Add the symbol to the symbol table. */
Sym = AddLocalSym (Decl->Ident, Decl->Type, Decl->StorageClass, DataLabel);
/* Allow assignments */
if (CurTok.Tok == TOK_ASSIGN) {
@ -296,39 +309,39 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
/* Parse the initialization generating a memory image of the
* data in the RODATA segment.
*/
Size = ParseInit (Decl->Type);
Size = ParseInit (Sym->Type);
/* Allocate a label and space for the variable */
SymData = AllocStorage (g_usebss, Size);
/* Allocate space for the variable */
AllocStorage (DataLabel, g_usebss, Size);
/* Generate code to copy this data into the variable space */
g_initstatic (InitLabel, SymData, Size);
g_initstatic (InitLabel, DataLabel, Size);
} else {
/* Allocate a label and space for the variable */
SymData = AllocStorage (g_usebss, Size);
/* Allocate space for the variable */
AllocStorage (DataLabel, g_usebss, Size);
/* Parse the expression */
hie1 (&Expr);
/* Convert it to the target type */
TypeConversion (&Expr, Decl->Type);
TypeConversion (&Expr, Sym->Type);
/* Load the value into the primary */
LoadExpr (CF_NONE, &Expr);
/* Store the value into the variable */
g_putstatic (TypeOf (Decl->Type), SymData, 0);
g_putstatic (TypeOf (Sym->Type), DataLabel, 0);
}
/* Mark the variable as referenced */
*SC |= SC_REF;
Sym->Flags |= SC_REF;
} else {
/* No assignment - allocate a label and space for the variable */
SymData = AllocStorage (g_usebss, Size);
AllocStorage (DataLabel, g_usebss, Size);
}
}
@ -337,50 +350,50 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
if (Size == 0) {
Error ("Variable `%s' has unknown size", Decl->Ident);
}
/* Return the symbol data */
return SymData;
}
static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC)
/* Parse the declaration of a static variable. The function returns the symbol
* data, which is the asm label of the variable.
*/
static void ParseStaticDecl (Declaration* Decl)
/* Parse the declaration of a static variable. */
{
unsigned SymData;
unsigned Size;
/* Generate a label, but don't define it */
unsigned DataLabel = GetLocalLabel ();
/* Add the symbol to the symbol table. */
SymEntry* Sym = AddLocalSym (Decl->Ident, Decl->Type,
Decl->StorageClass,
DataLabel);
/* Static data */
if (CurTok.Tok == TOK_ASSIGN) {
/* Initialization ahead, switch to data segment and define a label.
/* Initialization ahead, switch to data segment and define the label.
* For arrays, we need to check the elements of the array for
* constness, not the array itself.
*/
if (IsQualConst (GetBaseElementType (Decl->Type))) {
SymData = AllocLabel (g_userodata);
if (IsQualConst (GetBaseElementType (Sym->Type))) {
g_userodata ();
} else {
SymData = AllocLabel (g_usedata);
g_usedata ();
}
g_defdatalabel (DataLabel);
/* Skip the '=' */
NextToken ();
/* Allow initialization of static vars */
Size = ParseInit (Decl->Type);
Size = ParseInit (Sym->Type);
/* Mark the variable as referenced */
*SC |= SC_REF;
Sym->Flags |= SC_REF;
} else {
/* Get the size of the variable */
Size = SizeOf (Decl->Type);
/* Allocate a label and space for the variable in the BSS segment */
SymData = AllocStorage (g_usebss, Size);
AllocStorage (DataLabel, g_usebss, SizeOf (Sym->Type));
}
@ -388,9 +401,6 @@ static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC)
if (Size == 0) {
Error ("Variable `%s' has unknown size", Decl->Ident);
}
/* Return the symbol data */
return SymData;
}
@ -398,7 +408,6 @@ static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC)
static void ParseOneDecl (const DeclSpec* Spec)
/* Parse one variable declaration */
{
unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
Declaration Decl; /* Declaration data structure */
@ -421,6 +430,11 @@ static void ParseOneDecl (const DeclSpec* Spec)
AnonName (Decl.Ident, "param");
}
/* If the symbol is not marked as external, it will be defined now */
if ((Decl.StorageClass & SC_EXTERN) == 0) {
Decl.StorageClass |= SC_DEF;
}
/* Handle anything that needs storage (no functions, no typdefs) */
if ((Decl.StorageClass & SC_FUNC) != SC_FUNC &&
(Decl.StorageClass & SC_TYPEDEF) != SC_TYPEDEF) {
@ -438,31 +452,30 @@ static void ParseOneDecl (const DeclSpec* Spec)
/* Check the variable type */
if ((Decl.StorageClass & SC_REGISTER) == SC_REGISTER) {
/* Register variable */
SymData = ParseRegisterDecl (&Decl, &Decl.StorageClass, Reg);
ParseRegisterDecl (&Decl, Reg);
} else if ((Decl.StorageClass & SC_AUTO) == SC_AUTO) {
/* Auto variable */
SymData = ParseAutoDecl (&Decl, &Decl.StorageClass);
ParseAutoDecl (&Decl);
} else if ((Decl.StorageClass & SC_EXTERN) == SC_EXTERN) {
/* External identifier - may not get initialized */
if (CurTok.Tok == TOK_ASSIGN) {
Error ("Cannot initialize externals");
}
SymData = 0;
/* Add the external symbol to the symbol table */
AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, 0);
} else if ((Decl.StorageClass & SC_STATIC) == SC_STATIC) {
/* Static variable */
SymData = ParseStaticDecl (&Decl, &Decl.StorageClass);
ParseStaticDecl (&Decl);
} else {
Internal ("Invalid storage class in ParseOneDecl: %04X", Decl.StorageClass);
}
}
/* If the symbol is not marked as external, it will be defined now */
if ((Decl.StorageClass & SC_EXTERN) == 0) {
Decl.StorageClass |= SC_DEF;
}
} else {
/* Add the symbol to the symbol table */
AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, SymData);
/* Add the symbol to the symbol table */
AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, 0);
}
}

View File

@ -19,7 +19,7 @@ CC65_INC = \"/usr/lib/cc65/include/\"
#
CC = gcc
CFLAGS = -O2 -g -Wall -W -std=c89
CFLAGS = -g -Wall -W -std=c89
override CFLAGS += -I$(COMMON)
override CFLAGS += -DCC65_INC=$(CC65_INC)
EBIND = emxbind