mirror of
https://github.com/cc65/cc65.git
synced 2025-01-20 09:31:48 +00:00
Allow initialization of flexible array struct members
git-svn-id: svn://svn.cc65.org/cc65/trunk@1928 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
0166c9f577
commit
f817b05fa9
@ -755,3 +755,12 @@ long GetElementCount (const type* T)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type* GetElementType (type* T)
|
||||||
|
/* Return the element type of the given array type. */
|
||||||
|
{
|
||||||
|
CHECK (IsTypeArray (T));
|
||||||
|
return T + DECODE_SIZE + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,8 +144,9 @@ typedef unsigned short type;
|
|||||||
/* Type elements needed for Encode/Decode */
|
/* Type elements needed for Encode/Decode */
|
||||||
#define DECODE_SIZE 5
|
#define DECODE_SIZE 5
|
||||||
|
|
||||||
/* Unspecified size for the element count of an array */
|
/* Special encodings for element counts of an array */
|
||||||
#define UNSPECIFIED -1L
|
#define UNSPECIFIED -1L /* Element count was not specified */
|
||||||
|
#define FLEXIBLE 0L /* Flexible array struct member */
|
||||||
|
|
||||||
/* Sizes */
|
/* Sizes */
|
||||||
#define SIZEOF_CHAR 1
|
#define SIZEOF_CHAR 1
|
||||||
@ -482,6 +483,9 @@ long GetElementCount (const type* T);
|
|||||||
* array type).
|
* array type).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
type* GetElementType (type* T);
|
||||||
|
/* Return the element type of the given array type. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* End of datatype.h */
|
/* End of datatype.h */
|
||||||
|
@ -67,6 +67,9 @@
|
|||||||
static void ParseTypeSpec (DeclSpec* D, int Default);
|
static void ParseTypeSpec (DeclSpec* D, int Default);
|
||||||
/* Parse a type specificier */
|
/* Parse a type specificier */
|
||||||
|
|
||||||
|
static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers);
|
||||||
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -325,7 +328,7 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
|
|||||||
}
|
}
|
||||||
FlexibleMember = 1;
|
FlexibleMember = 1;
|
||||||
/* Assume zero for size calculations */
|
/* Assume zero for size calculations */
|
||||||
Encode (Decl.Type + 1, 0);
|
Encode (Decl.Type + 1, FLEXIBLE);
|
||||||
} else {
|
} else {
|
||||||
StructSize += CheckedSizeOf (Decl.Type);
|
StructSize += CheckedSizeOf (Decl.Type);
|
||||||
}
|
}
|
||||||
@ -1037,22 +1040,22 @@ static unsigned ParseVoidInit (void)
|
|||||||
case T_UINT:
|
case T_UINT:
|
||||||
case T_PTR:
|
case T_PTR:
|
||||||
case T_ARRAY:
|
case T_ARRAY:
|
||||||
if ((lval.Flags & E_MCTYPE) == E_TCONST) {
|
if ((lval.Flags & E_MCTYPE) == E_TCONST) {
|
||||||
/* Make it word sized */
|
/* Make it word sized */
|
||||||
lval.ConstVal &= 0xFFFF;
|
lval.ConstVal &= 0xFFFF;
|
||||||
}
|
}
|
||||||
DefineData (&lval);
|
DefineData (&lval);
|
||||||
Size += SIZEOF_INT;
|
Size += SIZEOF_INT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_LONG:
|
case T_LONG:
|
||||||
case T_ULONG:
|
case T_ULONG:
|
||||||
DefineData (&lval);
|
DefineData (&lval);
|
||||||
Size += SIZEOF_LONG;
|
Size += SIZEOF_LONG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Error ("Illegal type in initialization");
|
Error ("Illegal type in initialization");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1073,7 +1076,7 @@ static unsigned ParseVoidInit (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ParseStructInit (type* Type)
|
static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers)
|
||||||
/* Parse initialization of a struct or union. Return the number of data bytes. */
|
/* Parse initialization of a struct or union. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
SymEntry* Entry;
|
SymEntry* Entry;
|
||||||
@ -1110,7 +1113,11 @@ static unsigned ParseStructInit (type* Type)
|
|||||||
Error ("Too many initializers");
|
Error ("Too many initializers");
|
||||||
return Size;
|
return Size;
|
||||||
}
|
}
|
||||||
Size += ParseInit (Entry->Type);
|
/* Parse initialization of one field. Flexible array members may
|
||||||
|
* only be initialized if they are the last field (or part of the
|
||||||
|
* last struct field).
|
||||||
|
*/
|
||||||
|
Size += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0);
|
||||||
Entry = Entry->NextSym;
|
Entry = Entry->NextSym;
|
||||||
if (CurTok.Tok != TOK_COMMA)
|
if (CurTok.Tok != TOK_COMMA)
|
||||||
break;
|
break;
|
||||||
@ -1123,23 +1130,27 @@ static unsigned ParseStructInit (type* Type)
|
|||||||
/* If there are struct fields left, reserve additional storage */
|
/* If there are struct fields left, reserve additional storage */
|
||||||
if (Size < StructSize) {
|
if (Size < StructSize) {
|
||||||
g_zerobytes (StructSize - Size);
|
g_zerobytes (StructSize - Size);
|
||||||
|
Size = StructSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the number of bytes initialized */
|
/* Return the actual number of bytes initialized. This number may be
|
||||||
return StructSize;
|
* larger than StructSize if flexible array members are present and were
|
||||||
|
* initialized (possible in non ANSI mode).
|
||||||
|
*/
|
||||||
|
return Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned ParseInit (type* T)
|
static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers)
|
||||||
/* Parse initialization of variables. Return the number of data bytes. */
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
ExprDesc lval;
|
ExprDesc lval;
|
||||||
type* t;
|
|
||||||
const char* str;
|
const char* str;
|
||||||
int Count;
|
int Count;
|
||||||
long ElementCount;
|
type* ElementType;
|
||||||
unsigned ElementSize;
|
unsigned ElementSize;
|
||||||
|
long ElementCount;
|
||||||
|
|
||||||
switch (UnqualifiedType (*T)) {
|
switch (UnqualifiedType (*T)) {
|
||||||
|
|
||||||
@ -1180,21 +1191,28 @@ unsigned ParseInit (type* T)
|
|||||||
return SIZEOF_LONG;
|
return SIZEOF_LONG;
|
||||||
|
|
||||||
case T_ARRAY:
|
case T_ARRAY:
|
||||||
|
ElementType = GetElementType (T);
|
||||||
|
ElementSize = CheckedSizeOf (ElementType);
|
||||||
ElementCount = GetElementCount (T);
|
ElementCount = GetElementCount (T);
|
||||||
ElementSize = CheckedSizeOf (T + DECODE_SIZE + 1);
|
if (IsTypeChar (ElementType) && CurTok.Tok == TOK_SCONST) {
|
||||||
t = T + DECODE_SIZE + 1;
|
/* Char array initialized by string constant */
|
||||||
if (IsTypeChar (t) && CurTok.Tok == TOK_SCONST) {
|
|
||||||
str = GetLiteral (CurTok.IVal);
|
str = GetLiteral (CurTok.IVal);
|
||||||
Count = GetLiteralPoolOffs () - CurTok.IVal;
|
Count = GetLiteralPoolOffs () - CurTok.IVal;
|
||||||
TranslateLiteralPool (CurTok.IVal); /* Translate into target charset */
|
/* Translate into target charset */
|
||||||
|
TranslateLiteralPool (CurTok.IVal);
|
||||||
g_defbytes (str, Count);
|
g_defbytes (str, Count);
|
||||||
ResetLiteralPoolOffs (CurTok.IVal); /* Remove string from pool */
|
/* Remove string from pool */
|
||||||
|
ResetLiteralPoolOffs (CurTok.IVal);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else {
|
||||||
ConsumeLCurly ();
|
ConsumeLCurly ();
|
||||||
Count = 0;
|
Count = 0;
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY) {
|
||||||
ParseInit (T + DECODE_SIZE + 1);
|
/* Flexible array members may not be initialized within
|
||||||
|
* an array (because the size of each element may differ
|
||||||
|
* otherwise).
|
||||||
|
*/
|
||||||
|
ParseInitInternal (ElementType, 0);
|
||||||
++Count;
|
++Count;
|
||||||
if (CurTok.Tok != TOK_COMMA)
|
if (CurTok.Tok != TOK_COMMA)
|
||||||
break;
|
break;
|
||||||
@ -1203,7 +1221,14 @@ unsigned ParseInit (type* T)
|
|||||||
ConsumeRCurly ();
|
ConsumeRCurly ();
|
||||||
}
|
}
|
||||||
if (ElementCount == UNSPECIFIED) {
|
if (ElementCount == UNSPECIFIED) {
|
||||||
|
/* Number of elements determined by initializer */
|
||||||
Encode (T + 1, Count);
|
Encode (T + 1, Count);
|
||||||
|
ElementCount = Count;
|
||||||
|
} else if (ElementCount == FLEXIBLE && AllowFlexibleMembers) {
|
||||||
|
/* In non ANSI mode, allow initialization of flexible array
|
||||||
|
* members.
|
||||||
|
*/
|
||||||
|
ElementCount = Count;
|
||||||
} else if (Count < ElementCount) {
|
} else if (Count < ElementCount) {
|
||||||
g_zerobytes ((ElementCount - Count) * ElementSize);
|
g_zerobytes ((ElementCount - Count) * ElementSize);
|
||||||
} else if (Count > ElementCount) {
|
} else if (Count > ElementCount) {
|
||||||
@ -1213,7 +1238,7 @@ unsigned ParseInit (type* T)
|
|||||||
|
|
||||||
case T_STRUCT:
|
case T_STRUCT:
|
||||||
case T_UNION:
|
case T_UNION:
|
||||||
return ParseStructInit (T);
|
return ParseStructInit (T, AllowFlexibleMembers);
|
||||||
|
|
||||||
case T_VOID:
|
case T_VOID:
|
||||||
if (!ANSI) {
|
if (!ANSI) {
|
||||||
@ -1231,4 +1256,11 @@ unsigned ParseInit (type* T)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned ParseInit (type* T)
|
||||||
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
|
{
|
||||||
|
return ParseInitInternal (T, !ANSI);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,9 +94,16 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
|||||||
g_defdatalabel (InitLabel);
|
g_defdatalabel (InitLabel);
|
||||||
|
|
||||||
/* 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. The function does return the size
|
||||||
|
* of the initialization data, which may be greater than the
|
||||||
|
* actual size of the type, if the type is a structure with a
|
||||||
|
* 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.
|
||||||
*/
|
*/
|
||||||
ParseInit (Decl->Type);
|
if (ParseInit (Decl->Type) != Size) {
|
||||||
|
Error ("Cannot initialize flexible array members of storage class `register'");
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate code to copy this data into the variable space */
|
/* Generate code to copy this data into the variable space */
|
||||||
g_initregister (InitLabel, Reg, Size);
|
g_initregister (InitLabel, Reg, Size);
|
||||||
@ -172,14 +179,6 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
|||||||
/* Special handling for compound types */
|
/* Special handling for compound types */
|
||||||
if (IsCompound) {
|
if (IsCompound) {
|
||||||
|
|
||||||
/* First reserve space for the variable */
|
|
||||||
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);
|
|
||||||
|
|
||||||
/* Switch to read only data */
|
/* Switch to read only data */
|
||||||
g_userodata ();
|
g_userodata ();
|
||||||
|
|
||||||
@ -188,11 +187,25 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
|||||||
g_defdatalabel (InitLabel);
|
g_defdatalabel (InitLabel);
|
||||||
|
|
||||||
/* 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. 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.
|
||||||
*/
|
*/
|
||||||
ParseInit (Decl->Type);
|
Size = ParseInit (Decl->Type);
|
||||||
|
|
||||||
/* Generate code to copy this data into the variable space */
|
/* 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
|
||||||
|
*/
|
||||||
g_initauto (InitLabel, Size);
|
g_initauto (InitLabel, Size);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user