1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-28 22:30:12 +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;
int FlexibleMember;
unsigned Offs;
int BitOffs; /* Bit offset for bit-fields */
int FieldWidth; /* Width in bits, -1 if not a bit-field */
SymTable* FieldTab;
@ -637,6 +652,7 @@ static SymEntry* ParseStructDecl (const char* Name)
while (1) {
Declaration Decl;
ident Ident;
/* If we had a flexible array member before, no other fields can
* 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
* 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 (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;
BitOffs = 0;
}
@ -677,19 +704,11 @@ static SymEntry* ParseStructDecl (const char* Name)
Warning ("Declaration does not declare anything");
goto NextMember;
} else {
/* A bit-field without a name will just increase the
* offset
*/
BitOffs += FieldWidth;
goto NextMember;
/* A bit-field without a name will get an anonymous one */
AnonName (Decl.Ident, "bit-field");
}
}
/* 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
* calculate the size of the field.
*/
@ -701,16 +720,25 @@ static SymEntry* ParseStructDecl (const char* Name)
FlexibleMember = 1;
/* Assume zero for size calculations */
SetElementCount (Decl.Type, FLEXIBLE);
} else if (FieldWidth < 0) {
StructSize += CheckedSizeOf (Decl.Type);
}
/* 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);
BitOffs += FieldWidth;
CHECK (BitOffs <= (int) INT_BITS);
if (BitOffs == INT_BITS) {
StructSize += SIZEOF_INT;
BitOffs = 0;
}
} 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) {
@ -1633,11 +1661,29 @@ static void DefineData (ExprDesc* Expr)
static unsigned ParseScalarInit (Type* T)
/* Parse initializaton for scalar data types. Return the number of data bytes. */
static void OutputBitFieldData (StructInitData* SI)
/* 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 */
unsigned BraceCount = OpeningCurlyBraces (0);
@ -1649,14 +1695,25 @@ static unsigned ParseScalarInit (Type* T)
}
/* Get the expression and convert it to the target type */
ConstExpr (hie1, &ED);
TypeConversion (&ED, T);
/* Output the data */
DefineData (&ED);
ConstExpr (hie1, ED);
TypeConversion (ED, T);
/* Close eventually opening braces */
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 */
return SizeOf (T);
@ -1790,10 +1847,9 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
/* Parse initialization of a struct or union. Return the number of data bytes. */
{
SymEntry* Entry;
SymTable* Tab;
unsigned StructSize;
unsigned Size;
SymEntry* Entry;
SymTable* Tab;
StructInitData SI;
/* Consume the opening curly brace */
@ -1803,68 +1859,139 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
Entry = GetSymEntry (T);
/* 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
* is an incomplete definition.
*/
Tab = Entry->V.S.SymTab;
if (Tab == 0) {
Error ("Cannot initialize variables with incomplete type");
Error ("Cannot initialize variables with incomplete type");
/* Try error recovery */
SkipInitializer (1);
/* Nothing initialized */
return 0;
/* Nothing initialized */
return 0;
}
/* Get a pointer to the list of symbols */
Entry = Tab->SymHead;
/* Initialize fields */
Size = 0;
SI.Offs = 0;
SI.BitVal = 0;
SI.ValBits = 0;
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)) {
/* Struct */
Entry = Entry->NextSym;
} else {
/* Union */
Entry = 0;
/* */
if (Entry == 0) {
Error ("Too many initializers");
SkipInitializer (1);
return SI.Offs;
}
/* 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? */
if (CurTok.Tok == TOK_COMMA) {
NextToken ();
} else {
if (CurTok.Tok != TOK_COMMA) {
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 */
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 (Size < StructSize) {
g_zerobytes (StructSize - Size);
Size = StructSize;
if (SI.Offs < SI.Size) {
g_zerobytes (SI.Size - SI.Offs);
SI.Offs = SI.Size;
}
/* Return the actual number of bytes initialized. This number may be
* larger than StructSize if flexible array members are present and were
* initialized (possible in non ANSI mode).
* larger than sizeof (Struct) if flexible array members are present and
* were initialized (possible in non ANSI mode).
*/
return Size;
return SI.Offs;
}