1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-01 03:30:20 +00:00

Added initialization of bit-fields.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4130 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
uz 2009-09-07 16:59:46 +00:00
parent f5ca779b9b
commit 9f7ca16001

View File

@ -63,7 +63,23 @@
/*****************************************************************************/ /*****************************************************************************/
/* Forwards */ /* Data */
/*****************************************************************************/
typedef struct StructInitData StructInitData;
struct StructInitData {
unsigned Size; /* Size of struct */
unsigned Offs; /* Current offset in struct */
unsigned BitVal; /* Summed up bit-field value */
unsigned ValBits; /* Valid bits in Val */
};
/*****************************************************************************/
/* Forwards */
/*****************************************************************************/ /*****************************************************************************/
@ -77,7 +93,7 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
/*****************************************************************************/ /*****************************************************************************/
/* internal functions */ /* Internal functions */
/*****************************************************************************/ /*****************************************************************************/
@ -601,7 +617,6 @@ static SymEntry* ParseStructDecl (const char* Name)
unsigned StructSize; unsigned StructSize;
int FlexibleMember; int FlexibleMember;
unsigned Offs;
int BitOffs; /* Bit offset for bit-fields */ int BitOffs; /* Bit offset for bit-fields */
int FieldWidth; /* Width in bits, -1 if not a bit-field */ int FieldWidth; /* Width in bits, -1 if not a bit-field */
SymTable* FieldTab; SymTable* FieldTab;
@ -637,6 +652,7 @@ static SymEntry* ParseStructDecl (const char* Name)
while (1) { while (1) {
Declaration Decl; Declaration Decl;
ident Ident;
/* If we had a flexible array member before, no other fields can /* If we had a flexible array member before, no other fields can
* follow. * follow.
@ -654,10 +670,21 @@ static SymEntry* ParseStructDecl (const char* Name)
/* If this is not a bit field, or the bit field is too large for /* If this is not a bit field, or the bit field is too large for
* the remainder of the current member, or we have a bit field * the remainder of the current member, or we have a bit field
* with width zero, align the struct to the next member * with width zero, align the struct to the next member by adding
* a member with an anonymous name.
*/ */
if (BitOffs > 0) { if (BitOffs > 0) {
if (FieldWidth <= 0 || (BitOffs + FieldWidth) > (int) INT_BITS) { if (FieldWidth <= 0 || (BitOffs + FieldWidth) > (int) INT_BITS) {
/* We need an anonymous name */
AnonName (Ident, "bit-field");
/* Add an anonymous bit-field that aligns to the next
* storage unit.
*/
AddBitField (Ident, StructSize, BitOffs, INT_BITS - BitOffs);
/* No bits left */
StructSize += SIZEOF_INT; StructSize += SIZEOF_INT;
BitOffs = 0; BitOffs = 0;
} }
@ -677,19 +704,11 @@ static SymEntry* ParseStructDecl (const char* Name)
Warning ("Declaration does not declare anything"); Warning ("Declaration does not declare anything");
goto NextMember; goto NextMember;
} else { } else {
/* A bit-field without a name will just increase the /* A bit-field without a name will get an anonymous one */
* offset AnonName (Decl.Ident, "bit-field");
*/
BitOffs += FieldWidth;
goto NextMember;
} }
} }
/* Byte offset of this member is the current struct size plus any
* full bytes from the bit offset in case of bit-fields.
*/
Offs = StructSize + (BitOffs / CHAR_BITS);
/* Check if this field is a flexible array member, and /* Check if this field is a flexible array member, and
* calculate the size of the field. * calculate the size of the field.
*/ */
@ -701,16 +720,25 @@ static SymEntry* ParseStructDecl (const char* Name)
FlexibleMember = 1; FlexibleMember = 1;
/* Assume zero for size calculations */ /* Assume zero for size calculations */
SetElementCount (Decl.Type, FLEXIBLE); SetElementCount (Decl.Type, FLEXIBLE);
} else if (FieldWidth < 0) {
StructSize += CheckedSizeOf (Decl.Type);
} }
/* Add a field entry to the table */ /* Add a field entry to the table */
if (FieldWidth > 0) { if (FieldWidth > 0) {
/* Add full byte from the bit offset to the variable offset.
* This simplifies handling he bit-field as a char type
* in expressions.
*/
unsigned Offs = StructSize + (BitOffs / CHAR_BITS);
AddBitField (Decl.Ident, Offs, BitOffs % CHAR_BITS, FieldWidth); AddBitField (Decl.Ident, Offs, BitOffs % CHAR_BITS, FieldWidth);
BitOffs += FieldWidth; BitOffs += FieldWidth;
CHECK (BitOffs <= (int) INT_BITS);
if (BitOffs == INT_BITS) {
StructSize += SIZEOF_INT;
BitOffs = 0;
}
} else { } else {
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs); AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
StructSize += CheckedSizeOf (Decl.Type);
} }
NextMember: if (CurTok.Tok != TOK_COMMA) { NextMember: if (CurTok.Tok != TOK_COMMA) {
@ -1633,11 +1661,29 @@ static void DefineData (ExprDesc* Expr)
static unsigned ParseScalarInit (Type* T) static void OutputBitFieldData (StructInitData* SI)
/* Parse initializaton for scalar data types. Return the number of data bytes. */ /* Output bit field data */
{ {
ExprDesc ED; /* Ignore if we have no data */
if (SI->ValBits > 0) {
/* Output the data */
g_defdata (CF_INT | CF_UNSIGNED | CF_CONST, SI->BitVal, 0);
/* Clear the data from SI and account for the size */
SI->BitVal = 0;
SI->ValBits = 0;
SI->Offs += SIZEOF_INT;
}
}
static void ParseScalarInitInternal (Type* T, ExprDesc* ED)
/* Parse initializaton for scalar data types. This function will not output the
* data but return it in ED.
*/
{
/* Optional opening brace */ /* Optional opening brace */
unsigned BraceCount = OpeningCurlyBraces (0); unsigned BraceCount = OpeningCurlyBraces (0);
@ -1649,14 +1695,25 @@ static unsigned ParseScalarInit (Type* T)
} }
/* Get the expression and convert it to the target type */ /* Get the expression and convert it to the target type */
ConstExpr (hie1, &ED); ConstExpr (hie1, ED);
TypeConversion (&ED, T); TypeConversion (ED, T);
/* Output the data */
DefineData (&ED);
/* Close eventually opening braces */ /* Close eventually opening braces */
ClosingCurlyBraces (BraceCount); ClosingCurlyBraces (BraceCount);
}
static unsigned ParseScalarInit (Type* T)
/* Parse initializaton for scalar data types. Return the number of data bytes. */
{
ExprDesc ED;
/* Parse initialization */
ParseScalarInitInternal (T, &ED);
/* Output the data */
DefineData (&ED);
/* Done */ /* Done */
return SizeOf (T); return SizeOf (T);
@ -1790,10 +1847,9 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers) static unsigned ParseStructInit (Type* T, 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;
SymTable* Tab; SymTable* Tab;
unsigned StructSize; StructInitData SI;
unsigned Size;
/* Consume the opening curly brace */ /* Consume the opening curly brace */
@ -1803,68 +1859,139 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
Entry = GetSymEntry (T); Entry = GetSymEntry (T);
/* Get the size of the struct from the symbol table entry */ /* Get the size of the struct from the symbol table entry */
StructSize = Entry->V.S.Size; SI.Size = Entry->V.S.Size;
/* Check if this struct definition has a field table. If it doesn't, it /* Check if this struct definition has a field table. If it doesn't, it
* is an incomplete definition. * is an incomplete definition.
*/ */
Tab = Entry->V.S.SymTab; Tab = Entry->V.S.SymTab;
if (Tab == 0) { if (Tab == 0) {
Error ("Cannot initialize variables with incomplete type"); Error ("Cannot initialize variables with incomplete type");
/* Try error recovery */ /* Try error recovery */
SkipInitializer (1); SkipInitializer (1);
/* Nothing initialized */ /* Nothing initialized */
return 0; return 0;
} }
/* Get a pointer to the list of symbols */ /* Get a pointer to the list of symbols */
Entry = Tab->SymHead; Entry = Tab->SymHead;
/* Initialize fields */ /* Initialize fields */
Size = 0; SI.Offs = 0;
SI.BitVal = 0;
SI.ValBits = 0;
while (CurTok.Tok != TOK_RCURLY) { while (CurTok.Tok != TOK_RCURLY) {
if (Entry == 0) {
Error ("Too many initializers");
SkipInitializer (1);
return Size;
}
/* 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);
/* For unions, only the first member can be initialized */ /* */
if (IsTypeStruct (T)) { if (Entry == 0) {
/* Struct */ Error ("Too many initializers");
Entry = Entry->NextSym; SkipInitializer (1);
} else { return SI.Offs;
/* Union */ }
Entry = 0;
/* Parse initialization of one field. Bit-fields need a special
* handling.
*/
if (SymIsBitField (Entry)) {
ExprDesc ED;
unsigned Val;
unsigned Shift;
/* Calculate the bitmask from the bit-field data */
unsigned Mask = (1U << Entry->V.B.BitWidth) - 1U;
/* Safety ... */
CHECK (Entry->V.B.Offs * CHAR_BITS + Entry->V.B.BitOffs ==
SI.Offs * CHAR_BITS + SI.ValBits);
/* This may be an anonymous bit-field, in which case it doesn't
* have an initializer.
*/
if (IsAnonName (Entry->Name)) {
/* Account for the data and output it if we have a full word */
SI.ValBits += Entry->V.B.BitWidth;
CHECK (SI.ValBits <= INT_BITS);
if (SI.ValBits == INT_BITS) {
OutputBitFieldData (&SI);
}
goto NextMember;
} else {
/* Read the data, check for a constant integer, do a range
* check.
*/
ParseScalarInitInternal (type_uint, &ED);
if (!ED_IsConstAbsInt (&ED)) {
Error ("Constant initializer expected");
ED_MakeConstAbsInt (&ED, 1);
}
if (ED.IVal > (long) Mask) {
Warning ("Truncating value in bit-field initializer");
ED.IVal &= (long) Mask;
}
Val = (unsigned) ED.IVal;
}
/* Add the value to the currently stored bit-field value */
Shift = (Entry->V.B.Offs - SI.Offs) * CHAR_BITS + Entry->V.B.BitOffs;
SI.BitVal |= (Val << Shift);
/* Account for the data and output it if we have a full word */
SI.ValBits += Entry->V.B.BitWidth;
CHECK (SI.ValBits <= INT_BITS);
if (SI.ValBits == INT_BITS) {
OutputBitFieldData (&SI);
}
} else {
/* Standard member. We should never have stuff from a
* bit-field left
*/
CHECK (SI.ValBits == 0);
/* Flexible array members may only be initialized if they are
* the last field (or part of the last struct field).
*/
SI.Offs += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0);
} }
/* More initializers? */ /* More initializers? */
if (CurTok.Tok == TOK_COMMA) { if (CurTok.Tok != TOK_COMMA) {
NextToken ();
} else {
break; break;
} }
/* Skip the comma */
NextToken ();
NextMember:
/* Next member. For unions, only the first one can be initialized */
if (IsTypeUnion (T)) {
/* Union */
Entry = 0;
} else {
/* Struct */
Entry = Entry->NextSym;
}
} }
/* Consume the closing curly brace */ /* Consume the closing curly brace */
ConsumeRCurly (); ConsumeRCurly ();
/* If we have data from a bit-field left, output it now */
OutputBitFieldData (&SI);
/* If there are struct fields left, reserve additional storage */ /* If there are struct fields left, reserve additional storage */
if (Size < StructSize) { if (SI.Offs < SI.Size) {
g_zerobytes (StructSize - Size); g_zerobytes (SI.Size - SI.Offs);
Size = StructSize; SI.Offs = SI.Size;
} }
/* Return the actual number of bytes initialized. This number may be /* Return the actual number of bytes initialized. This number may be
* larger than StructSize if flexible array members are present and were * larger than sizeof (Struct) if flexible array members are present and
* initialized (possible in non ANSI mode). * were initialized (possible in non ANSI mode).
*/ */
return Size; return SI.Offs;
} }