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 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* 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) void F_AllocLocalSpace (Function* F)
/* Allocate any local space previously reserved. The function will do /* Allocate any local space previously reserved. The function will do
* nothing if there is no reserved local space. * nothing if there is no reserved local space.
@ -361,7 +371,7 @@ static void F_RestoreRegVars (Function* F)
static void F_EmitDebugInfo (void) static void F_EmitDebugInfo (void)
/* Emit debug infos for the current function */ /* Emit debug infos for the current function */
{ {
if (DebugInfo) { if (DebugInfo) {
/* Get the current fuction */ /* Get the current fuction */
const SymEntry* Sym = CurrentFunc->FuncEntry; 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 */ /* Roemerstrasse 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
@ -102,6 +102,11 @@ int F_ReserveLocalSpace (Function* F, unsigned Size);
* offset. * 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); void F_AllocLocalSpace (Function* F);
/* Allocate any local space previously reserved. The function will do /* Allocate any local space previously reserved. The function will do
* nothing if there is no reserved local space. * 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) static void AllocStorage (unsigned Label, void (*UseSeg) (), unsigned Size)
/* Reserve Size bytes of BSS storage prefixed by a local label. Return the /* Reserve Size bytes of BSS storage prefixed by a local label. */
* label.
*/
{ {
/* Switch to the segment and define the label */ /* Switch to the segment */
unsigned Label = AllocLabel (UseSeg); UseSeg ();
/* Define the variable label */
g_defdatalabel (Label);
/* Reserve space for the data */ /* Reserve space for the data */
g_res (Size); g_res (Size);
/* Return the label */
return Label;
} }
static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg) static void ParseRegisterDecl (Declaration* Decl, int Reg)
/* Parse the declaration of a register variable. The function returns the /* Parse the declaration of a register variable. Reg is the offset of the
* symbol data, which is the offset of the variable in the register bank. * variable in the register bank.
*/ */
{ {
unsigned InitLabel; SymEntry* Sym;
/* Determine if this is a compound variable */ /* Determine if this is a compound variable */
int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type); int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
@ -113,6 +111,12 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
F_AllocLocalSpace (CurrentFunc); F_AllocLocalSpace (CurrentFunc);
g_save_regvars (Reg, Size); 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 */ /* Check for an optional initialization */
if (CurTok.Tok == TOK_ASSIGN) { 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 /* Switch to read only data and define a label for the
* initialization data. * initialization data.
*/ */
InitLabel = AllocLabel (g_userodata); unsigned InitLabel = AllocLabel (g_userodata);
/* Parse the initialization generating a memory image of the /* Parse the initialization generating a memory image of the
* data in the RODATA segment. The function does return the size * 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, * know the size of the data in advance for register variables,
* we cannot allow that here. * 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'"); 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); hie1 (&Expr);
/* Convert it to the target type */ /* Convert it to the target type */
TypeConversion (&Expr, Decl->Type); TypeConversion (&Expr, Sym->Type);
/* Load the value into the primary */ /* Load the value into the primary */
LoadExpr (CF_NONE, &Expr); LoadExpr (CF_NONE, &Expr);
/* Store the value into the variable */ /* 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 */ /* Mark the variable as referenced */
*SC |= SC_REF; Sym->Flags |= SC_REF;
} }
/* Cannot allocate a variable of zero size */ /* Cannot allocate a variable of zero size */
if (Size == 0) { if (Size == 0) {
Error ("Variable `%s' has unknown size", Decl->Ident); Error ("Variable `%s' has unknown size", Decl->Ident);
} }
/* Return the symbol data */
return Reg;
} }
static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC) static void ParseAutoDecl (Declaration* Decl)
/* Parse the declaration of an auto variable. The function returns the symbol /* Parse the declaration of an auto variable. */
* data, which is the offset for variables on the stack, and the label for
* static variables.
*/
{ {
unsigned Flags; unsigned Flags;
unsigned SymData; SymEntry* Sym;
/* Determine if this is a compound variable */ /* Determine if this is a compound variable */
int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type); 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 */ /* Check if this is a variable on the stack or in static memory */
if (IS_Get (&StaticLocals) == 0) { 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 */ /* Check for an optional initialization */
if (CurTok.Tok == TOK_ASSIGN) { 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 * that contains a flexible array member and we're not in
* ANSI mode. * ANSI mode.
*/ */
Size = ParseInit (Decl->Type); Size = ParseInit (Sym->Type);
/* Now reserve space for the variable on the stack */ /* Now reserve space for the variable on the stack and correct
SymData = F_ReserveLocalSpace (CurrentFunc, Size); * 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 /* Next, allocate the space on the stack. This means that the
* variable is now located at offset 0 from the current sp. * variable is now located at offset 0 from the current sp.
@ -243,7 +250,7 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
hie1 (&Expr); hie1 (&Expr);
/* Convert it to the target type */ /* 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. /* If the value is not const, load it into the primary.
* Otherwise pass the information to the code generator. * Otherwise pass the information to the code generator.
@ -256,27 +263,33 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
} }
/* Push the value */ /* Push the value */
g_push (Flags | TypeOf (Decl->Type), Expr.IVal); g_push (Flags | TypeOf (Sym->Type), Expr.IVal);
} }
/* Mark the variable as referenced */ /* Mark the variable as referenced */
*SC |= SC_REF; Sym->Flags |= SC_REF;
/* Variable is located at the current SP */
SymData = StackPtr;
} else { } else {
/* Non-initialized local variable. Just keep track of /* Non-initialized local variable. Just keep track of
* the space needed. * the space needed.
*/ */
SymData = F_ReserveLocalSpace (CurrentFunc, Size); F_ReserveLocalSpace (CurrentFunc, Size);
} }
} else { } else {
unsigned DataLabel;
/* Static local variables. */ /* 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 */ /* Allow assignments */
if (CurTok.Tok == TOK_ASSIGN) { 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 /* Parse the initialization generating a memory image of the
* data in the RODATA segment. * data in the RODATA segment.
*/ */
Size = ParseInit (Decl->Type); Size = ParseInit (Sym->Type);
/* Allocate a label and space for the variable */ /* Allocate space for the variable */
SymData = AllocStorage (g_usebss, Size); AllocStorage (DataLabel, g_usebss, Size);
/* Generate code to copy this data into the variable space */ /* Generate code to copy this data into the variable space */
g_initstatic (InitLabel, SymData, Size); g_initstatic (InitLabel, DataLabel, Size);
} else { } else {
/* Allocate a label and space for the variable */ /* Allocate space for the variable */
SymData = AllocStorage (g_usebss, Size); AllocStorage (DataLabel, g_usebss, Size);
/* Parse the expression */ /* Parse the expression */
hie1 (&Expr); hie1 (&Expr);
/* Convert it to the target type */ /* Convert it to the target type */
TypeConversion (&Expr, Decl->Type); TypeConversion (&Expr, Sym->Type);
/* Load the value into the primary */ /* Load the value into the primary */
LoadExpr (CF_NONE, &Expr); LoadExpr (CF_NONE, &Expr);
/* Store the value into the variable */ /* 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 */ /* Mark the variable as referenced */
*SC |= SC_REF; Sym->Flags |= SC_REF;
} else { } else {
/* No assignment - allocate a label and space for the variable */ /* 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) { if (Size == 0) {
Error ("Variable `%s' has unknown size", Decl->Ident); Error ("Variable `%s' has unknown size", Decl->Ident);
} }
/* Return the symbol data */
return SymData;
} }
static unsigned ParseStaticDecl (Declaration* Decl, unsigned* SC) static void ParseStaticDecl (Declaration* Decl)
/* Parse the declaration of a static variable. The function returns the symbol /* Parse the declaration of a static variable. */
* data, which is the asm label of the variable.
*/
{ {
unsigned SymData;
unsigned Size; 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 */ /* Static data */
if (CurTok.Tok == TOK_ASSIGN) { 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 * For arrays, we need to check the elements of the array for
* constness, not the array itself. * constness, not the array itself.
*/ */
if (IsQualConst (GetBaseElementType (Decl->Type))) { if (IsQualConst (GetBaseElementType (Sym->Type))) {
SymData = AllocLabel (g_userodata); g_userodata ();
} else { } else {
SymData = AllocLabel (g_usedata); g_usedata ();
} }
g_defdatalabel (DataLabel);
/* Skip the '=' */ /* Skip the '=' */
NextToken (); NextToken ();
/* Allow initialization of static vars */ /* Allow initialization of static vars */
Size = ParseInit (Decl->Type); Size = ParseInit (Sym->Type);
/* Mark the variable as referenced */ /* Mark the variable as referenced */
*SC |= SC_REF; Sym->Flags |= SC_REF;
} else { } else {
/* Get the size of the variable */
Size = SizeOf (Decl->Type);
/* Allocate a label and space for the variable in the BSS segment */ /* 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) { if (Size == 0) {
Error ("Variable `%s' has unknown size", Decl->Ident); 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) static void ParseOneDecl (const DeclSpec* Spec)
/* Parse one variable declaration */ /* Parse one variable declaration */
{ {
unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
Declaration Decl; /* Declaration data structure */ Declaration Decl; /* Declaration data structure */
@ -421,6 +430,11 @@ static void ParseOneDecl (const DeclSpec* Spec)
AnonName (Decl.Ident, "param"); 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) */ /* Handle anything that needs storage (no functions, no typdefs) */
if ((Decl.StorageClass & SC_FUNC) != SC_FUNC && if ((Decl.StorageClass & SC_FUNC) != SC_FUNC &&
(Decl.StorageClass & SC_TYPEDEF) != SC_TYPEDEF) { (Decl.StorageClass & SC_TYPEDEF) != SC_TYPEDEF) {
@ -438,31 +452,30 @@ static void ParseOneDecl (const DeclSpec* Spec)
/* Check the variable type */ /* Check the variable type */
if ((Decl.StorageClass & SC_REGISTER) == SC_REGISTER) { if ((Decl.StorageClass & SC_REGISTER) == SC_REGISTER) {
/* Register variable */ /* Register variable */
SymData = ParseRegisterDecl (&Decl, &Decl.StorageClass, Reg); ParseRegisterDecl (&Decl, Reg);
} else if ((Decl.StorageClass & SC_AUTO) == SC_AUTO) { } else if ((Decl.StorageClass & SC_AUTO) == SC_AUTO) {
/* Auto variable */ /* Auto variable */
SymData = ParseAutoDecl (&Decl, &Decl.StorageClass); ParseAutoDecl (&Decl);
} else if ((Decl.StorageClass & SC_EXTERN) == SC_EXTERN) { } else if ((Decl.StorageClass & SC_EXTERN) == SC_EXTERN) {
/* External identifier - may not get initialized */ /* External identifier - may not get initialized */
if (CurTok.Tok == TOK_ASSIGN) { if (CurTok.Tok == TOK_ASSIGN) {
Error ("Cannot initialize externals"); 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) { } else if ((Decl.StorageClass & SC_STATIC) == SC_STATIC) {
/* Static variable */ /* Static variable */
SymData = ParseStaticDecl (&Decl, &Decl.StorageClass); ParseStaticDecl (&Decl);
} else { } else {
Internal ("Invalid storage class in ParseOneDecl: %04X", Decl.StorageClass); Internal ("Invalid storage class in ParseOneDecl: %04X", Decl.StorageClass);
} }
}
/* If the symbol is not marked as external, it will be defined now */ } else {
if ((Decl.StorageClass & SC_EXTERN) == 0) {
Decl.StorageClass |= SC_DEF;
}
/* Add the symbol to the symbol table */ /* Add the symbol to the symbol table */
AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, SymData); AddLocalSym (Decl.Ident, Decl.Type, Decl.StorageClass, 0);
}
} }

View File

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