mirror of
https://github.com/cc65/cc65.git
synced 2025-01-12 17:30:50 +00:00
Separate the functions that parse unions and structs, because they became too
different. git-svn-id: svn://svn.cc65.org/cc65/trunk@4085 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
829cb7de4c
commit
a09c71b3ff
@ -486,12 +486,125 @@ static int ParseFieldWidth (Declaration* Decl)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType)
|
static SymEntry* StructOrUnionForwardDecl (const char* Name)
|
||||||
/* Parse a struct/union declaration. */
|
/* Handle a struct or union forward decl */
|
||||||
|
{
|
||||||
|
/* Try to find a struct with the given name. If there is none,
|
||||||
|
* insert a forward declaration into the current lexical level.
|
||||||
|
*/
|
||||||
|
SymEntry* Entry = FindTagSym (Name);
|
||||||
|
if (Entry == 0) {
|
||||||
|
Entry = AddStructSym (Name, 0, 0);
|
||||||
|
} else if (SymIsLocal (Entry) && (Entry->Flags & SC_STRUCT) != SC_STRUCT) {
|
||||||
|
/* Already defined in the level, but no struct */
|
||||||
|
Error ("Symbol `%s' is already different kind", Name);
|
||||||
|
}
|
||||||
|
return Entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static SymEntry* ParseUnionDecl (const char* Name)
|
||||||
|
/* Parse a union declaration. */
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned UnionSize;
|
||||||
|
unsigned FieldSize;
|
||||||
|
int FieldWidth; /* Width in bits, -1 if not a bit-field */
|
||||||
|
SymTable* FieldTab;
|
||||||
|
SymEntry* Entry;
|
||||||
|
|
||||||
|
|
||||||
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
|
/* Just a forward declaration. */
|
||||||
|
return StructOrUnionForwardDecl (Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a forward declaration for the struct in the current lexical level */
|
||||||
|
Entry = AddStructSym (Name, 0, 0);
|
||||||
|
|
||||||
|
/* Skip the curly brace */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Enter a new lexical level for the struct */
|
||||||
|
EnterStructLevel ();
|
||||||
|
|
||||||
|
/* Parse union fields */
|
||||||
|
UnionSize = 0;
|
||||||
|
while (CurTok.Tok != TOK_RCURLY) {
|
||||||
|
|
||||||
|
/* Get the type of the entry */
|
||||||
|
DeclSpec Spec;
|
||||||
|
InitDeclSpec (&Spec);
|
||||||
|
ParseTypeSpec (&Spec, -1, T_QUAL_NONE);
|
||||||
|
|
||||||
|
/* Read fields with this type */
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
Declaration Decl;
|
||||||
|
|
||||||
|
/* Get type and name of the struct field */
|
||||||
|
ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
|
||||||
|
|
||||||
|
/* Check for a bit-field declaration */
|
||||||
|
FieldWidth = ParseFieldWidth (&Decl);
|
||||||
|
|
||||||
|
/* Ignore zero sized bit fields in a union */
|
||||||
|
if (FieldWidth == 0) {
|
||||||
|
goto NextMember;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for fields without a name */
|
||||||
|
if (Decl.Ident[0] == '\0') {
|
||||||
|
if (FieldWidth < 0) {
|
||||||
|
/* A non bit-field without a name is legal but useless */
|
||||||
|
Warning ("Declaration does not declare anything");
|
||||||
|
goto NextMember;
|
||||||
|
} else {
|
||||||
|
/* A bit-field without a name does nothing in a union */
|
||||||
|
goto NextMember;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle sizes */
|
||||||
|
FieldSize = CheckedSizeOf (Decl.Type);
|
||||||
|
if (FieldSize > UnionSize) {
|
||||||
|
UnionSize = FieldSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a field entry to the table */
|
||||||
|
if (FieldWidth > 0) {
|
||||||
|
AddBitField (Decl.Ident, 0, 0, FieldWidth);
|
||||||
|
} else {
|
||||||
|
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
NextMember: if (CurTok.Tok != TOK_COMMA) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NextToken ();
|
||||||
|
}
|
||||||
|
ConsumeSemi ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip the closing brace */
|
||||||
|
NextToken ();
|
||||||
|
|
||||||
|
/* Remember the symbol table and leave the struct level */
|
||||||
|
FieldTab = GetSymTab ();
|
||||||
|
LeaveStructLevel ();
|
||||||
|
|
||||||
|
/* Make a real entry from the forward decl and return it */
|
||||||
|
return AddStructSym (Name, UnionSize, FieldTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static SymEntry* ParseStructDecl (const char* Name)
|
||||||
|
/* Parse a struct declaration. */
|
||||||
{
|
{
|
||||||
|
|
||||||
unsigned StructSize;
|
unsigned StructSize;
|
||||||
unsigned FieldSize;
|
|
||||||
int FlexibleMember;
|
int FlexibleMember;
|
||||||
unsigned Offs;
|
unsigned Offs;
|
||||||
int BitOffs; /* Bit offset for bit-fields */
|
int BitOffs; /* Bit offset for bit-fields */
|
||||||
@ -501,18 +614,8 @@ static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType)
|
|||||||
|
|
||||||
|
|
||||||
if (CurTok.Tok != TOK_LCURLY) {
|
if (CurTok.Tok != TOK_LCURLY) {
|
||||||
/* Just a forward declaration. Try to find a struct with the given
|
/* Just a forward declaration. */
|
||||||
* name. If there is none, insert a forward declaration into the
|
return StructOrUnionForwardDecl (Name);
|
||||||
* current lexical level.
|
|
||||||
*/
|
|
||||||
Entry = FindTagSym (Name);
|
|
||||||
if (Entry == 0) {
|
|
||||||
Entry = AddStructSym (Name, 0, 0);
|
|
||||||
} else if (SymIsLocal (Entry) && (Entry->Flags & SC_STRUCT) == 0) {
|
|
||||||
/* Already defined in the level but no struct */
|
|
||||||
Error ("Symbol `%s' is already different kind", Name);
|
|
||||||
}
|
|
||||||
return Entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a forward declaration for the struct in the current lexical level */
|
/* Add a forward declaration for the struct in the current lexical level */
|
||||||
@ -554,84 +657,66 @@ static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType)
|
|||||||
/* Check for a bit-field declaration */
|
/* Check for a bit-field declaration */
|
||||||
FieldWidth = ParseFieldWidth (&Decl);
|
FieldWidth = ParseFieldWidth (&Decl);
|
||||||
|
|
||||||
/* A non bit-field without a name is legal but useless */
|
|
||||||
if (FieldWidth < 0 && Decl.Ident[0] == '\0') {
|
|
||||||
Warning ("Declaration does not declare anything");
|
|
||||||
goto NextMember;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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
|
||||||
*/
|
*/
|
||||||
if (BitOffs > 0) {
|
if (BitOffs > 0) {
|
||||||
if (FieldWidth <= 0 || (BitOffs + FieldWidth) > INT_BITS) {
|
if (FieldWidth <= 0 || (BitOffs + FieldWidth) > INT_BITS) {
|
||||||
/* BitOffs > 0, so this can only be a struct */
|
|
||||||
StructSize += SIZEOF_INT;
|
StructSize += SIZEOF_INT;
|
||||||
BitOffs = 0;
|
BitOffs = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apart from the above, a bit field with width 0 is not processed
|
/* Apart from the above, a bit field with width 0 is not processed
|
||||||
* further. An unnamed bit field will just increase the bit offset.
|
* further.
|
||||||
*/
|
*/
|
||||||
if (FieldWidth == 0) {
|
if (FieldWidth == 0) {
|
||||||
goto NextMember;
|
goto NextMember;
|
||||||
} else if (FieldWidth > 0 && Decl.Ident[0] == '\0') {
|
|
||||||
if (StructType == T_STRUCT) {
|
|
||||||
BitOffs += FieldWidth;
|
|
||||||
}
|
|
||||||
goto NextMember;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the sizes, handle flexible array members */
|
/* Check for fields without names */
|
||||||
if (StructType == T_STRUCT) {
|
if (Decl.Ident[0] == '\0') {
|
||||||
|
if (FieldWidth < 0) {
|
||||||
/* It's a struct. Offset of this member is the current struct
|
/* A non bit-field without a name is legal but useless */
|
||||||
* size plus any full bytes from the bit offset in case of
|
Warning ("Declaration does not declare anything");
|
||||||
* bit-fields.
|
goto NextMember;
|
||||||
*/
|
} else {
|
||||||
Offs = StructSize + (BitOffs >> 3);
|
/* A bit-field without a name will just increase the
|
||||||
|
* offset
|
||||||
/* Check if this field is a flexible array member, and
|
*/
|
||||||
* calculate the size of the field.
|
|
||||||
*/
|
|
||||||
if (IsTypeArray (Decl.Type) && GetElementCount (Decl.Type) == UNSPECIFIED) {
|
|
||||||
/* Array with unspecified size */
|
|
||||||
if (StructSize == 0) {
|
|
||||||
Error ("Flexible array member cannot be first struct field");
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
AddBitField (Decl.Ident, Offs, BitOffs & 0x07, FieldWidth);
|
|
||||||
BitOffs += FieldWidth;
|
BitOffs += FieldWidth;
|
||||||
} else {
|
goto NextMember;
|
||||||
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
/* 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 >> 3);
|
||||||
|
|
||||||
/* It's a union. Offset of this member is always zero */
|
/* Check if this field is a flexible array member, and
|
||||||
Offs = 0;
|
* calculate the size of the field.
|
||||||
FieldSize = CheckedSizeOf (Decl.Type);
|
*/
|
||||||
if (FieldSize > StructSize) {
|
if (IsTypeArray (Decl.Type) && GetElementCount (Decl.Type) == UNSPECIFIED) {
|
||||||
StructSize = FieldSize;
|
/* Array with unspecified size */
|
||||||
}
|
if (StructSize == 0) {
|
||||||
|
Error ("Flexible array member cannot be first struct field");
|
||||||
/* Add a field entry to the table */
|
|
||||||
if (FieldWidth > 0) {
|
|
||||||
AddBitField (Decl.Ident, 0, 0, FieldWidth);
|
|
||||||
} else {
|
|
||||||
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs);
|
|
||||||
}
|
}
|
||||||
}
|
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) {
|
||||||
|
AddBitField (Decl.Ident, Offs, BitOffs & 0x07, FieldWidth);
|
||||||
|
BitOffs += FieldWidth;
|
||||||
|
} else {
|
||||||
|
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs);
|
||||||
|
}
|
||||||
|
|
||||||
NextMember: if (CurTok.Tok != TOK_COMMA) {
|
NextMember: if (CurTok.Tok != TOK_COMMA) {
|
||||||
break;
|
break;
|
||||||
@ -641,6 +726,11 @@ NextMember: if (CurTok.Tok != TOK_COMMA) {
|
|||||||
ConsumeSemi ();
|
ConsumeSemi ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we have bits from bit-fields left, add them to the size. */
|
||||||
|
if (BitOffs > 0) {
|
||||||
|
StructSize += ((BitOffs + CHAR_BITS - 1) >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
/* Skip the closing brace */
|
/* Skip the closing brace */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
|
|
||||||
@ -659,7 +749,6 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
|
|||||||
{
|
{
|
||||||
ident Ident;
|
ident Ident;
|
||||||
SymEntry* Entry;
|
SymEntry* Entry;
|
||||||
TypeCode StructType;
|
|
||||||
|
|
||||||
/* Assume we have an explicit type */
|
/* Assume we have an explicit type */
|
||||||
D->Flags &= ~DS_DEF_TYPE;
|
D->Flags &= ~DS_DEF_TYPE;
|
||||||
@ -800,23 +889,40 @@ static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
|
|||||||
D->Type[1].C = T_END;
|
D->Type[1].C = T_END;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TOK_STRUCT:
|
|
||||||
case TOK_UNION:
|
case TOK_UNION:
|
||||||
StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION;
|
|
||||||
NextToken ();
|
NextToken ();
|
||||||
/* */
|
/* */
|
||||||
if (CurTok.Tok == TOK_IDENT) {
|
if (CurTok.Tok == TOK_IDENT) {
|
||||||
strcpy (Ident, CurTok.Ident);
|
strcpy (Ident, CurTok.Ident);
|
||||||
NextToken ();
|
NextToken ();
|
||||||
} else {
|
} else {
|
||||||
AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
|
AnonName (Ident, "union");
|
||||||
|
}
|
||||||
|
/* Remember we have an extra type decl */
|
||||||
|
D->Flags |= DS_EXTRA_TYPE;
|
||||||
|
/* Declare the union in the current scope */
|
||||||
|
Entry = ParseUnionDecl (Ident);
|
||||||
|
/* Encode the union entry into the type */
|
||||||
|
D->Type[0].C = T_UNION;
|
||||||
|
SetSymEntry (D->Type, Entry);
|
||||||
|
D->Type[1].C = T_END;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TOK_STRUCT:
|
||||||
|
NextToken ();
|
||||||
|
/* */
|
||||||
|
if (CurTok.Tok == TOK_IDENT) {
|
||||||
|
strcpy (Ident, CurTok.Ident);
|
||||||
|
NextToken ();
|
||||||
|
} else {
|
||||||
|
AnonName (Ident, "struct");
|
||||||
}
|
}
|
||||||
/* Remember we have an extra type decl */
|
/* Remember we have an extra type decl */
|
||||||
D->Flags |= DS_EXTRA_TYPE;
|
D->Flags |= DS_EXTRA_TYPE;
|
||||||
/* Declare the struct in the current scope */
|
/* Declare the struct in the current scope */
|
||||||
Entry = ParseStructDecl (Ident, StructType);
|
Entry = ParseStructDecl (Ident);
|
||||||
/* Encode the struct entry into the type */
|
/* Encode the struct entry into the type */
|
||||||
D->Type[0].C = StructType;
|
D->Type[0].C = T_STRUCT;
|
||||||
SetSymEntry (D->Type, Entry);
|
SetSymEntry (D->Type, Entry);
|
||||||
D->Type[1].C = T_END;
|
D->Type[1].C = T_END;
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user