mirror of
https://github.com/cc65/cc65.git
synced 2024-11-16 18:08:04 +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:
parent
b0c4678ad2
commit
faf58a8220
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user