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:
parent
f5ca779b9b
commit
9f7ca16001
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user