1
0
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:
cuz 2003-02-05 22:02:48 +00:00
parent 0166c9f577
commit f817b05fa9
4 changed files with 97 additions and 39 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 {