Fixed nested struct/union initialization.
Fixed bit-fields offsets in anonymous structs.
This commit is contained in:
@@ -61,6 +61,17 @@ static const char AnonTag[] = "$anon";
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char* AnonFieldName (char* Buf, const char* Spec, int ANumber)
|
||||||
|
/* Get a name for an anonymous field of a struct or union. The given buffer is
|
||||||
|
** expected to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
xsprintf (Buf, IDENTSIZE, "%s-%s-%04X", AnonTag, Spec, ANumber);
|
||||||
|
return Buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char* AnonName (char* Buf, const char* Spec)
|
char* AnonName (char* Buf, const char* Spec)
|
||||||
/* Get a name for an anonymous variable or type. The given buffer is expected
|
/* Get a name for an anonymous variable or type. The given buffer is expected
|
||||||
** to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
** to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||||
|
|||||||
@@ -44,6 +44,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char* AnonFieldName (char* Buf, const char* Spec, int ANumber);
|
||||||
|
/* Get a name for an anonymous field of a struct or union. The given buffer is
|
||||||
|
** expected to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
char* AnonName (char* Buf, const char* Spec);
|
char* AnonName (char* Buf, const char* Spec);
|
||||||
/* Get a name for an anonymous variable or type. The given buffer is expected
|
/* Get a name for an anonymous variable or type. The given buffer is expected
|
||||||
** to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
** to be IDENTSIZE characters long. A pointer to the buffer is returned.
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ struct StructInitData {
|
|||||||
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
|
static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
|
||||||
/* Parse a type specifier */
|
/* Parse a type specifier */
|
||||||
|
|
||||||
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
|
static unsigned ParseInitInternal (Type* T, int* Braces, int AllowFlexibleMembers);
|
||||||
/* Parse initialization of variables. Return the number of data bytes. */
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
|
|
||||||
|
|
||||||
@@ -717,24 +717,24 @@ static int ParseFieldWidth (Declaration* Decl)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
|
static unsigned AliasAnonStructFields (const Declaration* Decl, SymEntry* Anon)
|
||||||
/* Copy fields from an anon union/struct into the current lexical level. The
|
/* Create alias fields from an anon union/struct in the current lexical level.
|
||||||
** function returns the size of the embedded struct/union.
|
** The function returns the count of created aliases.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
unsigned Count = 0;
|
||||||
|
SymEntry* Alias;
|
||||||
|
|
||||||
/* Get the pointer to the symbol table entry of the anon struct */
|
/* Get the pointer to the symbol table entry of the anon struct */
|
||||||
SymEntry* Entry = GetSymEntry (Decl->Type);
|
SymEntry* Entry = GetSymEntry (Decl->Type);
|
||||||
|
|
||||||
/* Get the size of the anon struct */
|
|
||||||
unsigned Size = Entry->V.S.Size;
|
|
||||||
|
|
||||||
/* Get the symbol table containing the fields. If it is empty, there has
|
/* Get the symbol table containing the fields. If it is empty, there has
|
||||||
** been an error before, so bail out.
|
** been an error before, so bail out.
|
||||||
*/
|
*/
|
||||||
SymTable* Tab = Entry->V.S.SymTab;
|
SymTable* Tab = Entry->V.S.SymTab;
|
||||||
if (Tab == 0) {
|
if (Tab == 0) {
|
||||||
/* Incomplete definition - has been flagged before */
|
/* Incomplete definition - has been flagged before */
|
||||||
return Size;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get a pointer to the list of symbols. Then walk the list adding copies
|
/* Get a pointer to the list of symbols. Then walk the list adding copies
|
||||||
@@ -743,10 +743,13 @@ static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
|
|||||||
Entry = Tab->SymHead;
|
Entry = Tab->SymHead;
|
||||||
while (Entry) {
|
while (Entry) {
|
||||||
|
|
||||||
/* Enter a copy of this symbol adjusting the offset. We will just
|
/* Enter an alias of this symbol */
|
||||||
** reuse the type string here.
|
if (!IsAnonName (Entry->Name)) {
|
||||||
*/
|
Alias = AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD|SC_ALIAS, 0);
|
||||||
AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD, Offs + Entry->V.Offs);
|
Alias->V.A.Field = Entry;
|
||||||
|
Alias->V.A.Offs = Anon->V.Offs + Entry->V.Offs;
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
|
||||||
/* Currently, there can not be any attributes, but if there will be
|
/* Currently, there can not be any attributes, but if there will be
|
||||||
** some in the future, we want to know this.
|
** some in the future, we want to know this.
|
||||||
@@ -757,8 +760,8 @@ static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
|
|||||||
Entry = Entry->NextSym;
|
Entry = Entry->NextSym;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the size of the embedded struct */
|
/* Return the count of created aliases */
|
||||||
return Size;
|
return Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -771,6 +774,8 @@ static SymEntry* ParseUnionDecl (const char* Name)
|
|||||||
unsigned FieldSize;
|
unsigned FieldSize;
|
||||||
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;
|
||||||
|
SymEntry* StructTypeEntry;
|
||||||
|
SymEntry* Entry;
|
||||||
|
|
||||||
|
|
||||||
if (CurTok.Tok != TOK_LCURLY) {
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
@@ -779,7 +784,9 @@ static SymEntry* ParseUnionDecl (const char* Name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add a forward declaration for the struct in the current lexical level */
|
/* Add a forward declaration for the struct in the current lexical level */
|
||||||
AddStructSym (Name, SC_UNION, 0, 0);
|
StructTypeEntry = AddStructSym (Name, SC_UNION, 0, 0);
|
||||||
|
|
||||||
|
StructTypeEntry->V.S.ACount = 0;
|
||||||
|
|
||||||
/* Skip the curly brace */
|
/* Skip the curly brace */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
@@ -821,16 +828,11 @@ static SymEntry* ParseUnionDecl (const char* Name)
|
|||||||
/* This is an anonymous struct or union. Copy the fields
|
/* This is an anonymous struct or union. Copy the fields
|
||||||
** into the current level.
|
** into the current level.
|
||||||
*/
|
*/
|
||||||
FieldSize = CopyAnonStructFields (&Decl, 0);
|
AnonFieldName (Decl.Ident, "field", StructTypeEntry->V.S.ACount);
|
||||||
if (FieldSize > UnionSize) {
|
|
||||||
UnionSize = FieldSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* A non bit-field without a name is legal but useless */
|
/* A non bit-field without a name is legal but useless */
|
||||||
Warning ("Declaration does not declare anything");
|
Warning ("Declaration does not declare anything");
|
||||||
}
|
}
|
||||||
goto NextMember;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle sizes */
|
/* Handle sizes */
|
||||||
@@ -843,7 +845,13 @@ static SymEntry* ParseUnionDecl (const char* Name)
|
|||||||
if (FieldWidth > 0) {
|
if (FieldWidth > 0) {
|
||||||
AddBitField (Decl.Ident, 0, 0, FieldWidth);
|
AddBitField (Decl.Ident, 0, 0, FieldWidth);
|
||||||
} else {
|
} else {
|
||||||
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
if (IsAnonName (Decl.Ident)) {
|
||||||
|
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
||||||
|
Entry->V.A.ANumber = StructTypeEntry->V.S.ACount++;
|
||||||
|
AliasAnonStructFields (&Decl, Entry);
|
||||||
|
} else {
|
||||||
|
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NextMember: if (CurTok.Tok != TOK_COMMA) {
|
NextMember: if (CurTok.Tok != TOK_COMMA) {
|
||||||
@@ -876,6 +884,8 @@ static SymEntry* ParseStructDecl (const char* Name)
|
|||||||
unsigned BitOffs; /* Bit offset for bit-fields */
|
unsigned 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;
|
||||||
|
SymEntry* StructTypeEntry;
|
||||||
|
SymEntry* Entry;
|
||||||
|
|
||||||
|
|
||||||
if (CurTok.Tok != TOK_LCURLY) {
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
@@ -884,7 +894,9 @@ static SymEntry* ParseStructDecl (const char* Name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add a forward declaration for the struct in the current lexical level */
|
/* Add a forward declaration for the struct in the current lexical level */
|
||||||
AddStructSym (Name, SC_STRUCT, 0, 0);
|
StructTypeEntry = AddStructSym (Name, SC_STRUCT, 0, 0);
|
||||||
|
|
||||||
|
StructTypeEntry->V.S.ACount = 0;
|
||||||
|
|
||||||
/* Skip the curly brace */
|
/* Skip the curly brace */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
@@ -981,13 +993,11 @@ static SymEntry* ParseStructDecl (const char* Name)
|
|||||||
/* This is an anonymous struct or union. Copy the
|
/* This is an anonymous struct or union. Copy the
|
||||||
** fields into the current level.
|
** fields into the current level.
|
||||||
*/
|
*/
|
||||||
StructSize += CopyAnonStructFields (&Decl, StructSize);
|
AnonFieldName (Decl.Ident, "field", StructTypeEntry->V.S.ACount);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* A non bit-field without a name is legal but useless */
|
/* A non bit-field without a name is legal but useless */
|
||||||
Warning ("Declaration does not declare anything");
|
Warning ("Declaration does not declare anything");
|
||||||
}
|
}
|
||||||
goto NextMember;
|
|
||||||
} else {
|
} else {
|
||||||
/* A bit-field without a name will get an anonymous one */
|
/* A bit-field without a name will get an anonymous one */
|
||||||
AnonName (Decl.Ident, "bit-field");
|
AnonName (Decl.Ident, "bit-field");
|
||||||
@@ -1009,7 +1019,13 @@ static SymEntry* ParseStructDecl (const char* Name)
|
|||||||
StructSize += BitOffs / CHAR_BITS;
|
StructSize += BitOffs / CHAR_BITS;
|
||||||
BitOffs %= CHAR_BITS;
|
BitOffs %= CHAR_BITS;
|
||||||
} else {
|
} else {
|
||||||
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
|
if (IsAnonName (Decl.Ident)) {
|
||||||
|
Entry = AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
|
||||||
|
Entry->V.A.ANumber = StructTypeEntry->V.S.ACount++;
|
||||||
|
AliasAnonStructFields (&Decl, Entry);
|
||||||
|
} else {
|
||||||
|
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
|
||||||
|
}
|
||||||
if (!FlexibleMember) {
|
if (!FlexibleMember) {
|
||||||
StructSize += CheckedSizeOf (Decl.Type);
|
StructSize += CheckedSizeOf (Decl.Type);
|
||||||
}
|
}
|
||||||
@@ -1874,18 +1890,20 @@ void CheckEmptyDecl (const DeclSpec* D)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void SkipInitializer (unsigned BracesExpected)
|
static void SkipInitializer (int BracesExpected)
|
||||||
/* Skip the remainder of an initializer in case of errors. Try to be somewhat
|
/* Skip the remainder of an initializer in case of errors. Try to be somewhat
|
||||||
** smart so we don't have too many following errors.
|
** smart so we don't have too many following errors.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected > 0) {
|
while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected >= 0) {
|
||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
case TOK_RCURLY: --BracesExpected; break;
|
case TOK_RCURLY: --BracesExpected; break;
|
||||||
case TOK_LCURLY: ++BracesExpected; break;
|
case TOK_LCURLY: ++BracesExpected; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
NextToken ();
|
if (BracesExpected >= 0) {
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1917,6 +1935,7 @@ static void ClosingCurlyBraces (unsigned BracesExpected)
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
while (BracesExpected) {
|
while (BracesExpected) {
|
||||||
|
/* TODO: Skip all excess initializers until next closing curly brace */
|
||||||
if (CurTok.Tok == TOK_RCURLY) {
|
if (CurTok.Tok == TOK_RCURLY) {
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else if (CurTok.Tok == TOK_COMMA && NextTok.Tok == TOK_RCURLY) {
|
} else if (CurTok.Tok == TOK_COMMA && NextTok.Tok == TOK_RCURLY) {
|
||||||
@@ -2069,7 +2088,7 @@ static unsigned ParsePointerInit (Type* T)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
|
static unsigned ParseArrayInit (Type* T, int* Braces, int AllowFlexibleMembers)
|
||||||
/* Parse initializaton for arrays. Return the number of data bytes. */
|
/* Parse initializaton for arrays. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
int Count;
|
int Count;
|
||||||
@@ -2135,7 +2154,7 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
|
|||||||
** an array (because the size of each element may differ
|
** an array (because the size of each element may differ
|
||||||
** otherwise).
|
** otherwise).
|
||||||
*/
|
*/
|
||||||
ParseInitInternal (ElementType, 0);
|
ParseInitInternal (ElementType, Braces, 0);
|
||||||
++Count;
|
++Count;
|
||||||
if (CurTok.Tok != TOK_COMMA)
|
if (CurTok.Tok != TOK_COMMA)
|
||||||
break;
|
break;
|
||||||
@@ -2158,23 +2177,29 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
|
|||||||
} 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) {
|
||||||
Error ("Too many initializers");
|
Error ("Excess elements in array initializer");
|
||||||
}
|
}
|
||||||
return ElementCount * ElementSize;
|
return ElementCount * ElementSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
|
static unsigned ParseStructInit (Type* T, int* Braces, 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;
|
||||||
StructInitData SI;
|
StructInitData SI;
|
||||||
|
int HasCurly = 0;
|
||||||
|
int SkipComma = 0;
|
||||||
|
|
||||||
|
|
||||||
/* Consume the opening curly brace */
|
/* Fields can be initialized without a pair of curly braces */
|
||||||
ConsumeLCurly ();
|
if (*Braces == 0 || CurTok.Tok == TOK_LCURLY) {
|
||||||
|
/* Consume the opening curly brace */
|
||||||
|
HasCurly = ConsumeLCurly ();
|
||||||
|
*Braces += HasCurly;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get a pointer to the struct entry from the type */
|
/* Get a pointer to the struct entry from the type */
|
||||||
Entry = GetSymEntry (T);
|
Entry = GetSymEntry (T);
|
||||||
@@ -2189,7 +2214,7 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
|
|||||||
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 (HasCurly);
|
||||||
/* Nothing initialized */
|
/* Nothing initialized */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2203,18 +2228,50 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
|
|||||||
SI.ValBits = 0;
|
SI.ValBits = 0;
|
||||||
while (CurTok.Tok != TOK_RCURLY) {
|
while (CurTok.Tok != TOK_RCURLY) {
|
||||||
|
|
||||||
/* */
|
/* Check for excess elements */
|
||||||
if (Entry == 0) {
|
if (Entry == 0) {
|
||||||
Error ("Too many initializers");
|
if (HasCurly) {
|
||||||
SkipInitializer (1);
|
Error ("Excess elements in %s initializer", GetBasicTypeName (T));
|
||||||
|
SkipInitializer (HasCurly);
|
||||||
|
}
|
||||||
return SI.Offs;
|
return SI.Offs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse initialization of one field. Bit-fields need a special
|
/* Check for special members that don't consume the initializer */
|
||||||
** handling.
|
if ((Entry->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||||
|
/* Just skip */
|
||||||
|
goto NextMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This may be an anonymous bit-field, in which case it doesn't
|
||||||
|
** have an initializer.
|
||||||
*/
|
*/
|
||||||
|
if (SymIsBitField (Entry) && (IsAnonName (Entry->Name))) {
|
||||||
|
/* Account for the data and output it if we have at least a full
|
||||||
|
** word. We may have more if there was storage unit overlap, for
|
||||||
|
** example two consecutive 10 bit fields. These will be packed
|
||||||
|
** into 3 bytes.
|
||||||
|
*/
|
||||||
|
SI.ValBits += Entry->V.B.BitWidth;
|
||||||
|
CHECK (SI.ValBits <= CHAR_BITS + INT_BITS - 2);
|
||||||
|
while (SI.ValBits >= CHAR_BITS) {
|
||||||
|
OutputBitFieldData (&SI);
|
||||||
|
}
|
||||||
|
/* Avoid consuming the comma if any */
|
||||||
|
goto NextMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip comma this round */
|
||||||
|
if (SkipComma) {
|
||||||
|
NextToken ();
|
||||||
|
SkipComma = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (SymIsBitField (Entry)) {
|
if (SymIsBitField (Entry)) {
|
||||||
|
|
||||||
|
/* Parse initialization of one field. Bit-fields need a special
|
||||||
|
** handling.
|
||||||
|
*/
|
||||||
ExprDesc ED;
|
ExprDesc ED;
|
||||||
unsigned Val;
|
unsigned Val;
|
||||||
unsigned Shift;
|
unsigned Shift;
|
||||||
@@ -2226,36 +2283,17 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
|
|||||||
CHECK (Entry->V.B.Offs * CHAR_BITS + Entry->V.B.BitOffs ==
|
CHECK (Entry->V.B.Offs * CHAR_BITS + Entry->V.B.BitOffs ==
|
||||||
SI.Offs * CHAR_BITS + SI.ValBits);
|
SI.Offs * CHAR_BITS + SI.ValBits);
|
||||||
|
|
||||||
/* This may be an anonymous bit-field, in which case it doesn't
|
/* Read the data, check for a constant integer, do a range check */
|
||||||
** have an initializer.
|
ParseScalarInitInternal (type_uint, &ED);
|
||||||
*/
|
if (!ED_IsConstAbsInt (&ED)) {
|
||||||
if (IsAnonName (Entry->Name)) {
|
Error ("Constant initializer expected");
|
||||||
/* Account for the data and output it if we have at least a
|
ED_MakeConstAbsInt (&ED, 1);
|
||||||
** full word. We may have more if there was storage unit
|
|
||||||
** overlap, for example two consecutive 10 bit fields.
|
|
||||||
** These will be packed into 3 bytes.
|
|
||||||
*/
|
|
||||||
SI.ValBits += Entry->V.B.BitWidth;
|
|
||||||
CHECK (SI.ValBits <= CHAR_BITS + INT_BITS - 2);
|
|
||||||
while (SI.ValBits >= CHAR_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;
|
|
||||||
}
|
}
|
||||||
|
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 */
|
/* Add the value to the currently stored bit-field value */
|
||||||
Shift = (Entry->V.B.Offs - SI.Offs) * CHAR_BITS + Entry->V.B.BitOffs;
|
Shift = (Entry->V.B.Offs - SI.Offs) * CHAR_BITS + Entry->V.B.BitOffs;
|
||||||
@@ -2285,7 +2323,7 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
|
|||||||
/* Flexible array members may only be initialized if they are
|
/* Flexible array members may only be initialized if they are
|
||||||
** the last field (or part of the last struct field).
|
** the last field (or part of the last struct field).
|
||||||
*/
|
*/
|
||||||
SI.Offs += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0);
|
SI.Offs += ParseInitInternal (Entry->Type, Braces, AllowFlexibleMembers && Entry->NextSym == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* More initializers? */
|
/* More initializers? */
|
||||||
@@ -2293,8 +2331,8 @@ static unsigned ParseStructInit (Type* T, int AllowFlexibleMembers)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip the comma */
|
/* Skip the comma next round */
|
||||||
NextToken ();
|
SkipComma = 1;
|
||||||
|
|
||||||
NextMember:
|
NextMember:
|
||||||
/* Next member. For unions, only the first one can be initialized */
|
/* Next member. For unions, only the first one can be initialized */
|
||||||
@@ -2307,8 +2345,10 @@ NextMember:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Consume the closing curly brace */
|
if (HasCurly) {
|
||||||
ConsumeRCurly ();
|
/* Consume the closing curly brace */
|
||||||
|
ConsumeRCurly ();
|
||||||
|
}
|
||||||
|
|
||||||
/* If we have data from a bit-field left, output it now */
|
/* If we have data from a bit-field left, output it now */
|
||||||
CHECK (SI.ValBits < CHAR_BITS);
|
CHECK (SI.ValBits < CHAR_BITS);
|
||||||
@@ -2405,7 +2445,7 @@ static unsigned ParseVoidInit (Type* T)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
|
static unsigned ParseInitInternal (Type* T, int *Braces, int AllowFlexibleMembers)
|
||||||
/* Parse initialization of variables. Return the number of data bytes. */
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
switch (GetUnderlyingTypeCode (T)) {
|
switch (GetUnderlyingTypeCode (T)) {
|
||||||
@@ -2426,11 +2466,11 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
|
|||||||
return ParsePointerInit (T);
|
return ParsePointerInit (T);
|
||||||
|
|
||||||
case T_ARRAY:
|
case T_ARRAY:
|
||||||
return ParseArrayInit (T, AllowFlexibleMembers);
|
return ParseArrayInit (T, Braces, AllowFlexibleMembers);
|
||||||
|
|
||||||
case T_STRUCT:
|
case T_STRUCT:
|
||||||
case T_UNION:
|
case T_UNION:
|
||||||
return ParseStructInit (T, AllowFlexibleMembers);
|
return ParseStructInit (T, Braces, AllowFlexibleMembers);
|
||||||
|
|
||||||
case T_VOID:
|
case T_VOID:
|
||||||
if (IS_Get (&Standard) == STD_CC65) {
|
if (IS_Get (&Standard) == STD_CC65) {
|
||||||
@@ -2451,10 +2491,13 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
|
|||||||
unsigned ParseInit (Type* T)
|
unsigned ParseInit (Type* T)
|
||||||
/* Parse initialization of variables. Return the number of data bytes. */
|
/* Parse initialization of variables. Return the number of data bytes. */
|
||||||
{
|
{
|
||||||
|
/* Current curly braces layers */
|
||||||
|
int Braces = 0;
|
||||||
|
|
||||||
/* Parse the initialization. Flexible array members can only be initialized
|
/* Parse the initialization. Flexible array members can only be initialized
|
||||||
** in cc65 mode.
|
** in cc65 mode.
|
||||||
*/
|
*/
|
||||||
unsigned Size = ParseInitInternal (T, IS_Get (&Standard) == STD_CC65);
|
unsigned Size = ParseInitInternal (T, &Braces, IS_Get (&Standard) == STD_CC65);
|
||||||
|
|
||||||
/* The initialization may not generate code on global level, because code
|
/* The initialization may not generate code on global level, because code
|
||||||
** outside function scope will never get executed.
|
** outside function scope will never get executed.
|
||||||
|
|||||||
@@ -1201,7 +1201,6 @@ static void StructRef (ExprDesc* Expr)
|
|||||||
/* Process struct/union field after . or ->. */
|
/* Process struct/union field after . or ->. */
|
||||||
{
|
{
|
||||||
ident Ident;
|
ident Ident;
|
||||||
SymEntry* Field;
|
|
||||||
Type* FinalType;
|
Type* FinalType;
|
||||||
TypeCode Q;
|
TypeCode Q;
|
||||||
|
|
||||||
@@ -1217,8 +1216,8 @@ static void StructRef (ExprDesc* Expr)
|
|||||||
/* Get the symbol table entry and check for a struct/union field */
|
/* Get the symbol table entry and check for a struct/union field */
|
||||||
strcpy (Ident, CurTok.Ident);
|
strcpy (Ident, CurTok.Ident);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
Field = FindStructField (Expr->Type, Ident);
|
const SymEntry Field = FindStructField (Expr->Type, Ident);
|
||||||
if (Field == 0) {
|
if (Field.Type == 0) {
|
||||||
Error ("No field named '%s' found in %s", Ident, GetBasicTypeName (Expr->Type));
|
Error ("No field named '%s' found in %s", Ident, GetBasicTypeName (Expr->Type));
|
||||||
/* Make the expression an integer at address zero */
|
/* Make the expression an integer at address zero */
|
||||||
ED_MakeConstAbs (Expr, 0, type_int);
|
ED_MakeConstAbs (Expr, 0, type_int);
|
||||||
@@ -1264,10 +1263,10 @@ static void StructRef (ExprDesc* Expr)
|
|||||||
} else {
|
} else {
|
||||||
Q = GetQualifier (Indirect (Expr->Type));
|
Q = GetQualifier (Indirect (Expr->Type));
|
||||||
}
|
}
|
||||||
if (GetQualifier (Field->Type) == (GetQualifier (Field->Type) | Q)) {
|
if (GetQualifier (Field.Type) == (GetQualifier (Field.Type) | Q)) {
|
||||||
FinalType = Field->Type;
|
FinalType = Field.Type;
|
||||||
} else {
|
} else {
|
||||||
FinalType = TypeDup (Field->Type);
|
FinalType = TypeDup (Field.Type);
|
||||||
FinalType->C |= Q;
|
FinalType->C |= Q;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1278,10 +1277,10 @@ static void StructRef (ExprDesc* Expr)
|
|||||||
|
|
||||||
/* Get the size of the type */
|
/* Get the size of the type */
|
||||||
unsigned StructSize = SizeOf (Expr->Type);
|
unsigned StructSize = SizeOf (Expr->Type);
|
||||||
unsigned FieldSize = SizeOf (Field->Type);
|
unsigned FieldSize = SizeOf (Field.Type);
|
||||||
|
|
||||||
/* Safety check */
|
/* Safety check */
|
||||||
CHECK (Field->V.Offs + FieldSize <= StructSize);
|
CHECK (Field.V.Offs + FieldSize <= StructSize);
|
||||||
|
|
||||||
/* The type of the operation depends on the type of the struct/union */
|
/* The type of the operation depends on the type of the struct/union */
|
||||||
switch (StructSize) {
|
switch (StructSize) {
|
||||||
@@ -1304,16 +1303,16 @@ static void StructRef (ExprDesc* Expr)
|
|||||||
/* Generate a shift to get the field in the proper position in the
|
/* Generate a shift to get the field in the proper position in the
|
||||||
** primary. For bit fields, mask the value.
|
** primary. For bit fields, mask the value.
|
||||||
*/
|
*/
|
||||||
BitOffs = Field->V.Offs * CHAR_BITS;
|
BitOffs = Field.V.Offs * CHAR_BITS;
|
||||||
if (SymIsBitField (Field)) {
|
if (SymIsBitField (&Field)) {
|
||||||
BitOffs += Field->V.B.BitOffs;
|
BitOffs += Field.V.B.BitOffs;
|
||||||
g_asr (Flags, BitOffs);
|
g_asr (Flags, BitOffs);
|
||||||
/* Mask the value. This is unnecessary if the shift executed above
|
/* Mask the value. This is unnecessary if the shift executed above
|
||||||
** moved only zeroes into the value.
|
** moved only zeroes into the value.
|
||||||
*/
|
*/
|
||||||
if (BitOffs + Field->V.B.BitWidth != FieldSize * CHAR_BITS) {
|
if (BitOffs + Field.V.B.BitWidth != FieldSize * CHAR_BITS) {
|
||||||
g_and (CF_INT | CF_UNSIGNED | CF_CONST,
|
g_and (CF_INT | CF_UNSIGNED | CF_CONST,
|
||||||
(0x0001U << Field->V.B.BitWidth) - 1U);
|
(0x0001U << Field.V.B.BitWidth) - 1U);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g_asr (Flags, BitOffs);
|
g_asr (Flags, BitOffs);
|
||||||
@@ -1325,7 +1324,7 @@ static void StructRef (ExprDesc* Expr)
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Set the struct/union field offset */
|
/* Set the struct/union field offset */
|
||||||
Expr->IVal += Field->V.Offs;
|
Expr->IVal += Field.V.Offs;
|
||||||
|
|
||||||
/* Use the new type */
|
/* Use the new type */
|
||||||
Expr->Type = FinalType;
|
Expr->Type = FinalType;
|
||||||
@@ -1341,8 +1340,8 @@ static void StructRef (ExprDesc* Expr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make the expression a bit field if necessary */
|
/* Make the expression a bit field if necessary */
|
||||||
if (SymIsBitField (Field)) {
|
if (SymIsBitField (&Field)) {
|
||||||
ED_MakeBitField (Expr, Field->V.B.BitOffs, Field->V.B.BitWidth);
|
ED_MakeBitField (Expr, Field.V.B.BitOffs, Field.V.B.BitWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ struct CodeEntry;
|
|||||||
#define SC_SPADJUSTMENT 0x400000U
|
#define SC_SPADJUSTMENT 0x400000U
|
||||||
#define SC_GOTO_IND 0x800000U /* Indirect goto */
|
#define SC_GOTO_IND 0x800000U /* Indirect goto */
|
||||||
|
|
||||||
|
#define SC_ALIAS 0x01000000U /* Alias of anonymous field */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -138,6 +139,14 @@ struct SymEntry {
|
|||||||
/* Offset for locals or struct members */
|
/* Offset for locals or struct members */
|
||||||
int Offs;
|
int Offs;
|
||||||
|
|
||||||
|
/* Data for anonymous struct or union members */
|
||||||
|
struct {
|
||||||
|
int Offs; /* Byte offset into struct */
|
||||||
|
unsigned ANumber; /* Numeric ID */
|
||||||
|
SymEntry* Field; /* The real field aliased */
|
||||||
|
} A;
|
||||||
|
|
||||||
|
|
||||||
/* Label name for static symbols */
|
/* Label name for static symbols */
|
||||||
struct {
|
struct {
|
||||||
unsigned Label;
|
unsigned Label;
|
||||||
@@ -163,6 +172,7 @@ struct SymEntry {
|
|||||||
struct {
|
struct {
|
||||||
struct SymTable* SymTab; /* Member symbol table */
|
struct SymTable* SymTab; /* Member symbol table */
|
||||||
unsigned Size; /* Size of the union/struct */
|
unsigned Size; /* Size of the union/struct */
|
||||||
|
unsigned ACount; /* Count of anonymous fields */
|
||||||
} S;
|
} S;
|
||||||
|
|
||||||
/* Data for enums */
|
/* Data for enums */
|
||||||
|
|||||||
@@ -490,10 +490,15 @@ SymEntry* FindTagSym (const char* Name)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
SymEntry* FindStructField (const Type* T, const char* Name)
|
SymEntry FindStructField (const Type* T, const char* Name)
|
||||||
/* Find a struct/union field in the fields list */
|
/* Find a struct/union field in the fields list.
|
||||||
|
** Return the info about the found field symbol filled in an entry struct by
|
||||||
|
** value, or an empty entry struct if the field is not found.
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
SymEntry* Field = 0;
|
SymEntry* Entry = 0;
|
||||||
|
SymEntry Field;
|
||||||
|
int Offs = 0;
|
||||||
|
|
||||||
/* The given type may actually be a pointer to struct/union */
|
/* The given type may actually be a pointer to struct/union */
|
||||||
if (IsTypePtr (T)) {
|
if (IsTypePtr (T)) {
|
||||||
@@ -511,10 +516,26 @@ SymEntry* FindStructField (const Type* T, const char* Name)
|
|||||||
** not exist.
|
** not exist.
|
||||||
*/
|
*/
|
||||||
if (Struct->V.S.SymTab) {
|
if (Struct->V.S.SymTab) {
|
||||||
Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
|
Entry = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
|
||||||
|
|
||||||
|
if (Entry != 0) {
|
||||||
|
Offs = Entry->V.Offs;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Entry != 0 && (Entry->Flags & SC_ALIAS) == SC_ALIAS) {
|
||||||
|
/* Get the real field */
|
||||||
|
Entry = Entry->V.A.Field;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Entry != 0) {
|
||||||
|
Field = *Entry;
|
||||||
|
Field.V.Offs = Offs;
|
||||||
|
} else {
|
||||||
|
memset (&Field, 0, sizeof(SymEntry));
|
||||||
|
}
|
||||||
|
|
||||||
return Field;
|
return Field;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1001,7 +1022,13 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
|||||||
|
|
||||||
/* Set the symbol attributes */
|
/* Set the symbol attributes */
|
||||||
Entry->Type = TypeDup (T);
|
Entry->Type = TypeDup (T);
|
||||||
if ((Flags & SC_AUTO) == SC_AUTO || (Flags & SC_TYPEMASK) == SC_TYPEDEF) {
|
|
||||||
|
if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD ||
|
||||||
|
(Flags & SC_TYPEDEF) == SC_TYPEDEF) {
|
||||||
|
if ((Flags & SC_ALIAS) != SC_ALIAS) {
|
||||||
|
Entry->V.Offs = Offs;
|
||||||
|
}
|
||||||
|
} else if ((Flags & SC_AUTO) == SC_AUTO) {
|
||||||
Entry->V.Offs = Offs;
|
Entry->V.Offs = Offs;
|
||||||
} else if ((Flags & SC_REGISTER) == SC_REGISTER) {
|
} else if ((Flags & SC_REGISTER) == SC_REGISTER) {
|
||||||
Entry->V.R.RegOffs = Offs;
|
Entry->V.R.RegOffs = Offs;
|
||||||
@@ -1013,8 +1040,6 @@ SymEntry* AddLocalSym (const char* Name, const Type* T, unsigned Flags, int Offs
|
|||||||
/* Generate the assembler name from the label number */
|
/* Generate the assembler name from the label number */
|
||||||
Entry->V.L.Label = Offs;
|
Entry->V.L.Label = Offs;
|
||||||
Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label));
|
Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label));
|
||||||
} else if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD) {
|
|
||||||
Entry->V.Offs = Offs;
|
|
||||||
} else {
|
} else {
|
||||||
Internal ("Invalid flags in AddLocalSym: %04X", Flags);
|
Internal ("Invalid flags in AddLocalSym: %04X", Flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,8 +133,11 @@ SymEntry* FindLocalSym (const char* Name);
|
|||||||
SymEntry* FindTagSym (const char* Name);
|
SymEntry* FindTagSym (const char* Name);
|
||||||
/* Find the symbol with the given name in the tag table */
|
/* Find the symbol with the given name in the tag table */
|
||||||
|
|
||||||
SymEntry* FindStructField (const Type* TypeArray, const char* Name);
|
SymEntry FindStructField (const Type* TypeArray, const char* Name);
|
||||||
/* Find a struct/union field in the fields list */
|
/* Find a struct/union field in the fields list.
|
||||||
|
** Return the info about the found field symbol filled in an entry struct by
|
||||||
|
** value, or an empty entry struct if the field is not found.
|
||||||
|
*/
|
||||||
|
|
||||||
unsigned short FindSPAdjustment (const char* Name);
|
unsigned short FindSPAdjustment (const char* Name);
|
||||||
/* Search for an entry in the table of SP adjustments */
|
/* Search for an entry in the table of SP adjustments */
|
||||||
|
|||||||
Reference in New Issue
Block a user