From bd872a6324f7c28ba8574541486c6aee7926c43f Mon Sep 17 00:00:00 2001 From: uz Date: Sat, 29 Aug 2009 17:38:53 +0000 Subject: [PATCH] Added code to parse bit fields and enter them into the symbol table. They're not supported in code generation until now. git-svn-id: svn://svn.cc65.org/cc65/trunk@4072 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/datatype.h | 10 ++++ src/cc65/declare.c | 131 +++++++++++++++++++++++++++++++++++++------- src/cc65/expr.c | 9 ++- src/cc65/symentry.c | 9 +-- src/cc65/symentry.h | 12 +++- src/cc65/symtab.c | 51 +++++++++++++---- src/cc65/symtab.h | 11 ++-- 7 files changed, 189 insertions(+), 44 deletions(-) diff --git a/src/cc65/datatype.h b/src/cc65/datatype.h index ea2117772..f9dd78313 100644 --- a/src/cc65/datatype.h +++ b/src/cc65/datatype.h @@ -174,6 +174,16 @@ struct Type { #define SIZEOF_DOUBLE (FP_D_Size()) #define SIZEOF_PTR 2 +/* Bit sizes */ +#define CHAR_BITS (8 * SIZEOF_CHAR) +#define SHORT_BITS (8 * SIZEOF_SHORT) +#define INT_BITS (8 * SIZEOF_INT) +#define LONG_BITS (8 * SIZEOF_LONG) +#define LONGLONG_BITS (8 * SIZEOF_LONGLONG) +#define FLOAT_BITS (8 * SIZEOF_FLOAT) +#define DOUBLE_BITS (8 * SIZEOF_DOUBLE) +#define PTR_BITS (8 * SIZEOF_PTR) + /* Predefined type strings */ extern Type type_schar[]; extern Type type_uchar[]; diff --git a/src/cc65/declare.c b/src/cc65/declare.c index 09a3f0020..36fa272d2 100644 --- a/src/cc65/declare.c +++ b/src/cc65/declare.c @@ -447,14 +447,55 @@ static void ParseEnumDecl (void) +static int ParseFieldWidth (Declaration* Decl) +/* Parse an optional field width. Returns -1 if no field width is speficied, + * otherwise the width of the field. + */ +{ + ExprDesc Expr; + + if (CurTok.Tok != TOK_COLON) { + /* No bit-field declaration */ + return -1; + } + + /* Read the width */ + NextToken (); + ConstAbsIntExpr (hie1, &Expr); + if (Expr.IVal < 0) { + Error ("Negative width in bit-field"); + return -1; + } + if (Expr.IVal > INT_BITS) { + Error ("Width of bit-field exceeds its type"); + return -1; + } + if (Expr.IVal == 0 && Decl->Ident[0] != '\0') { + Error ("Zero width for named bit-field"); + return -1; + } + if (!IsTypeInt (Decl->Type)) { + /* Only integer types may be used for bit-fields */ + Error ("Bit-field has invalid type"); + return -1; + } + + /* Return the field width */ + return (int) Expr.IVal; +} + + + static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType) /* Parse a struct/union declaration. */ { unsigned StructSize; unsigned FieldSize; - unsigned Offs; int FlexibleMember; + unsigned Offs; + int BitOffs; /* Bit offset for bit-fields */ + int FieldWidth; /* Width in bits, -1 if not a bit-field */ SymTable* FieldTab; SymEntry* Entry; @@ -486,6 +527,7 @@ static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType) /* Parse struct fields */ FlexibleMember = 0; StructSize = 0; + BitOffs = 0; while (CurTok.Tok != TOK_RCURLY) { /* Get the type of the entry */ @@ -507,16 +549,52 @@ static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType) } /* Get type and name of the struct field */ - ParseDecl (&Spec, &Decl, DM_NEED_IDENT); + ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT); + + /* Check for a bit-field declaration */ + FieldWidth = ParseFieldWidth (&Decl); - /* Get the offset of this field */ - Offs = (StructType == T_STRUCT)? StructSize : 0; + /* 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 + * the remainder of the current member, or we have a bit field + * with width zero, align the struct to the next member + */ + if (BitOffs > 0) { + if (FieldWidth <= 0 || (BitOffs + FieldWidth) > INT_BITS) { + /* BitOffs > 0, so this can only be a struct */ + StructSize += SIZEOF_INT; + BitOffs = 0; + } + } + + /* Apart from the above, a bit field with width 0 is not processed + * further. An unnamed bit field will just increase the bit offset. + */ + if (FieldWidth == 0) { + 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 */ if (StructType == T_STRUCT) { - /* It's a struct. Check if this field is a flexible array - * member, and calculate the size of the field. + /* It's a struct. 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); + + /* 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 */ @@ -526,28 +604,41 @@ static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType) FlexibleMember = 1; /* Assume zero for size calculations */ SetElementCount (Decl.Type, FLEXIBLE); - } else { + } else if (FieldWidth < 0) { StructSize += CheckedSizeOf (Decl.Type); } - } else { + /* 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); + } + + } else { - /* It's a union */ + /* It's a union. Offset of this member is always zero */ + Offs = 0; FieldSize = CheckedSizeOf (Decl.Type); - if (FieldSize > StructSize) { - StructSize = FieldSize; - } - } + if (FieldSize > StructSize) { + StructSize = FieldSize; + } - /* Add a field entry to the table */ - AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs); + /* 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); + } + } - if (CurTok.Tok != TOK_COMMA) { - break; +NextMember: if (CurTok.Tok != TOK_COMMA) { + break; } - NextToken (); - } - ConsumeSemi (); + NextToken (); + } + ConsumeSemi (); } /* Skip the closing brace */ diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 6c6268cc1..1d5dd9ccd 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1066,6 +1066,11 @@ static void StructRef (ExprDesc* Expr) Error ("Struct/union has no field named `%s'", Ident); Expr->Type = type_int; return; + } + if ((Field->Flags & SC_BITFIELD) == SC_BITFIELD) { + Error ("Bit-fields are currently unsupported - sorry"); + Expr->Type = type_int; + return; } /* If we have a struct pointer that is an lvalue and not already in the @@ -1884,8 +1889,8 @@ static void hie_compare (const GenDesc* Ops, /* List of generators */ /* Check for const operands */ if (ED_IsConstAbs (Expr) && rconst) { - - /* If the result is constant, this is suspicious when not in + + /* If the result is constant, this is suspicious when not in * preprocessor mode. */ if (!Preprocessing) { diff --git a/src/cc65/symentry.c b/src/cc65/symentry.c index 230362b56..718cd470e 100644 --- a/src/cc65/symentry.c +++ b/src/cc65/symentry.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000-2006 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2000-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -95,6 +95,7 @@ void DumpSymEntry (FILE* F, const SymEntry* E) } Flags [] = { /* Beware: Order is important! */ { "SC_TYPEDEF", SC_TYPEDEF }, + { "SC_BITFIELD", SC_BITFIELD }, { "SC_STRUCTFIELD", SC_STRUCTFIELD }, { "SC_STRUCT", SC_STRUCT }, { "SC_AUTO", SC_AUTO }, diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h index a43356cc9..d9139a8b7 100644 --- a/src/cc65/symentry.h +++ b/src/cc65/symentry.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2000-2008 Ullrich von Bassewitz */ +/* (C) 2000-2009 Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -86,7 +86,8 @@ struct Segments; #define SC_TYPE 0x4000U /* This is a type, struct, typedef, etc. */ #define SC_STRUCT 0x4001U /* Struct or union */ #define SC_STRUCTFIELD 0x4002U /* Struct or union field */ -#define SC_TYPEDEF 0x4003U /* A typedef */ +#define SC_BITFIELD 0x4004U /* A bit-field inside a struct or union */ +#define SC_TYPEDEF 0x4008U /* A typedef */ #define SC_ZEROPAGE 0x8000U /* Symbol marked as zeropage */ @@ -130,6 +131,13 @@ struct SymEntry { unsigned Size; /* Size of the union/struct */ } S; + /* Data for bit fields */ + struct { + unsigned Offs; /* Byte offset into struct */ + unsigned BitOffs; /* Bit offset into last byte */ + unsigned Width; /* Width in bits */ + } B; + /* Data for functions */ struct { struct FuncDesc* Func; /* Function descriptor */ diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index 0a03cabca..c3ca6ba94 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000-2006 Ullrich von Bassewitz */ -/* Römerstrasse 52 */ -/* D-70794 Filderstadt */ -/* EMail: uz@cc65.org */ +/* (C) 2000-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -485,19 +485,14 @@ SymEntry* FindStructField (const Type* T, const char* Name) /* Non-structs do not have any struct fields... */ if (IsClassStruct (T)) { - const SymTable* Tab; - /* Get a pointer to the struct/union type */ const SymEntry* Struct = GetSymEntry (T); CHECK (Struct != 0); - /* Get the field symbol table from the struct entry. - * Beware: The table may not exist. + /* Now search in the struct symbol table. Beware: The table may not + * exist. */ - Tab = Struct->V.S.SymTab; - - /* Now search in the struct symbol table */ - if (Tab) { + if (Struct->V.S.SymTab) { Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name)); } } @@ -582,6 +577,38 @@ SymEntry* AddStructSym (const char* Name, unsigned Size, SymTable* Tab) +SymEntry* AddBitField (const char* Name, unsigned Offs, unsigned BitOffs, unsigned Width) +/* Add a bit field to the local symbol table and return the symbol entry */ +{ + /* Do we have an entry with this name already? */ + SymEntry* Entry = FindSymInTable (SymTab, Name, HashStr (Name)); + if (Entry) { + + /* We have a symbol with this name already */ + Error ("Multiple definition for `%s'", Name); + + } else { + + /* Create a new entry */ + Entry = NewSymEntry (Name, SC_BITFIELD); + + /* Set the symbol attributes. Bit-fields are always of type unsigned */ + Entry->Type = type_uint; + Entry->V.B.Offs = Offs; + Entry->V.B.BitOffs = BitOffs; + Entry->V.B.Width = Width; + + /* Add the entry to the symbol table */ + AddSymEntry (SymTab, Entry); + + } + + /* Return the entry */ + return Entry; +} + + + SymEntry* AddConstSym (const char* Name, const Type* T, unsigned Flags, long Val) /* Add an constant symbol to the symbol table and return it */ { diff --git a/src/cc65/symtab.h b/src/cc65/symtab.h index f3d3656a0..18c8ce141 100644 --- a/src/cc65/symtab.h +++ b/src/cc65/symtab.h @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 2000-2009, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -147,6 +147,9 @@ SymEntry* FindStructField (const Type* TypeArray, const char* Name); SymEntry* AddStructSym (const char* Name, unsigned Size, SymTable* Tab); /* Add a struct/union entry and return it */ +SymEntry* AddBitField (const char* Name, unsigned Offs, unsigned BitOffs, unsigned Width); +/* Add a bit field to the local symbol table and return the symbol entry */ + SymEntry* AddConstSym (const char* Name, const Type* T, unsigned Flags, long Val); /* Add an constant symbol to the symbol table and return it */ -- 2.39.5