]> git.sur5r.net Git - cc65/blobdiff - src/cc65/declare.c
Made C's sizeof operator work with initialized void variables.
[cc65] / src / cc65 / declare.c
index 640a04f69da1e3c2aecba0fb0b2ab2623aa6bfd5..7b543aa55aa913c52ac21af66656a273c61021f6 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                declare.c                                 */
+/*                                 declare.c                                 */
 /*                                                                           */
-/*                Parse variable and function declarations                  */
+/*                 Parse variable and function declarations                  */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2008 Ullrich von Bassewitz                                       */
-/*               Roemerstrasse 52                                            */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2015, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 
 
 /*****************************************************************************/
-/*                                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                                  */
 /*****************************************************************************/
 
 
 
 static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
-/* Parse a type specificier */
+/* Parse a type specifier */
 
 static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
 /* Parse initialization of variables. Return the number of data bytes. */
@@ -77,7 +93,7 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
 
 
 /*****************************************************************************/
-/*                           internal functions                             */
+/*                            Internal functions                             */
 /*****************************************************************************/
 
 
@@ -90,14 +106,20 @@ static void DuplicateQualifier (const char* Name)
 
 
 
-static TypeCode OptionalQualifiers (TypeCode Q, TypeCode Allowed)
-/* Read type qualifiers if we have any */
+static TypeCode OptionalQualifiers (TypeCode Allowed)
+/* Read type qualifiers if we have any. Allowed specifies the allowed
+** qualifiers.
+*/
 {
+    /* We start without any qualifiers */
+    TypeCode Q = T_QUAL_NONE;
+
+    /* Check for more qualifiers */
     while (1) {
 
-       switch (CurTok.Tok) {
+        switch (CurTok.Tok) {
 
-           case TOK_CONST:
+            case TOK_CONST:
                 if (Allowed & T_QUAL_CONST) {
                     if (Q & T_QUAL_CONST) {
                         DuplicateQualifier ("const");
@@ -108,7 +130,7 @@ static TypeCode OptionalQualifiers (TypeCode Q, TypeCode Allowed)
                 }
                 break;
 
-           case TOK_VOLATILE:
+            case TOK_VOLATILE:
                 if (Allowed & T_QUAL_VOLATILE) {
                     if (Q & T_QUAL_VOLATILE) {
                         DuplicateQualifier ("volatile");
@@ -117,7 +139,7 @@ static TypeCode OptionalQualifiers (TypeCode Q, TypeCode Allowed)
                 } else {
                     goto Done;
                 }
-               break;
+                break;
 
             case TOK_RESTRICT:
                 if (Allowed & T_QUAL_RESTRICT) {
@@ -163,16 +185,53 @@ static TypeCode OptionalQualifiers (TypeCode Q, TypeCode Allowed)
                 }
                 break;
 
-           default:
-               goto Done;
+            case TOK_CDECL:
+                if (Allowed & T_QUAL_CDECL) {
+                    if (Q & T_QUAL_CDECL) {
+                        DuplicateQualifier ("cdecl");
+                    }
+                    Q |= T_QUAL_CDECL;
+                } else {
+                    goto Done;
+                }
+                break;
+
+            default:
+                goto Done;
 
-       }
+        }
 
-       /* Skip the token */
-       NextToken ();
+        /* Skip the token */
+        NextToken ();
     }
 
 Done:
+    /* We cannot have more than one address size far qualifier */
+    switch (Q & T_QUAL_ADDRSIZE) {
+
+        case T_QUAL_NONE:
+        case T_QUAL_NEAR:
+        case T_QUAL_FAR:
+            break;
+
+        default:
+            Error ("Cannot specify more than one address size qualifier");
+            Q &= ~T_QUAL_ADDRSIZE;
+    }
+
+    /* We cannot have more than one calling convention specifier */
+    switch (Q & T_QUAL_CCONV) {
+
+        case T_QUAL_NONE:
+        case T_QUAL_FASTCALL:
+        case T_QUAL_CDECL:
+            break;
+
+        default:
+            Error ("Cannot specify more than one calling convention qualifier");
+            Q &= ~T_QUAL_CCONV;
+    }
+
     /* Return the qualifiers read */
     return Q;
 }
@@ -183,8 +242,8 @@ static void OptionalInt (void)
 /* Eat an optional "int" token */
 {
     if (CurTok.Tok == TOK_INT) {
-       /* Skip it */
-       NextToken ();
+        /* Skip it */
+        NextToken ();
     }
 }
 
@@ -194,8 +253,8 @@ static void OptionalSigned (void)
 /* Eat an optional "signed" token */
 {
     if (CurTok.Tok == TOK_SIGNED) {
-       /* Skip it */
-       NextToken ();
+        /* Skip it */
+        NextToken ();
     }
 }
 
@@ -214,9 +273,10 @@ static void InitDeclSpec (DeclSpec* D)
 static void InitDeclaration (Declaration* D)
 /* Initialize the Declaration struct for use */
 {
-    D->Ident[0]  = '\0';
-    D->Type[0].C = T_END;
-    D->Index     = 0;
+    D->Ident[0]   = '\0';
+    D->Type[0].C  = T_END;
+    D->Index      = 0;
+    D->Attributes = 0;
 }
 
 
@@ -225,11 +285,11 @@ static void NeedTypeSpace (Declaration* D, unsigned Count)
 /* Check if there is enough space for Count type specifiers within D */
 {
     if (D->Index + Count >= MAXTYPELEN) {
-       /* We must call Fatal() here, since calling Error() will try to
-        * continue, and the declaration type is not correctly terminated
-        * in case we come here.
-        */
-       Fatal ("Too many type specifiers");
+        /* We must call Fatal() here, since calling Error() will try to
+        ** continue, and the declaration type is not correctly terminated
+        ** in case we come here.
+        */
+        Fatal ("Too many type specifiers");
     }
 }
 
@@ -251,15 +311,15 @@ static void FixQualifiers (Type* DataType)
     TypeCode Q;
 
     /* Using typedefs, it is possible to generate declarations that have
-     * type qualifiers attached to an array, not the element type. Go and
-     * fix these here.
-     */
+    ** type qualifiers attached to an array, not the element type. Go and
+    ** fix these here.
+    */
     T = DataType;
     Q = T_QUAL_NONE;
     while (T->C != T_END) {
         if (IsTypeArray (T)) {
             /* Extract any type qualifiers */
-            Q |= T->C & T_MASK_QUAL;
+            Q |= GetQualifier (T);
             T->C = UnqualifiedType (T->C);
         } else {
             /* Add extracted type qualifiers here */
@@ -275,18 +335,30 @@ static void FixQualifiers (Type* DataType)
     T = DataType;
     while (T->C != T_END) {
         if (IsTypePtr (T)) {
-
-            /* Fastcall qualifier on the pointer? */
-            if (IsQualFastcall (T)) {
-                /* Pointer to function which is not fastcall? */
-                if (IsTypeFunc (T+1) && !IsQualFastcall (T+1)) {
-                    /* Move the fastcall qualifier from the pointer to
-                     * the function.
-                     */
-                    T[0].C &= ~T_QUAL_FASTCALL;
-                    T[1].C |= T_QUAL_FASTCALL;
+            /* Calling convention qualifier on the pointer? */
+            if (IsQualCConv (T)) {
+                /* Pull the convention off of the pointer */
+                Q = T[0].C & T_QUAL_CCONV;
+                T[0].C &= ~T_QUAL_CCONV;
+
+                /* Pointer to a function which doesn't have an explicit convention? */
+                if (IsTypeFunc (T + 1)) {
+                    if (IsQualCConv (T + 1)) {
+                        if ((T[1].C & T_QUAL_CCONV) == Q) {
+                            Warning ("Pointer duplicates function's calling convention");
+                        } else {
+                            Error ("Function's and pointer's calling conventions are different");
+                        }
+                    } else {
+                        if (Q == T_QUAL_FASTCALL && IsVariadicFunc (T + 1)) {
+                            Error ("Variadic-function pointers cannot be __fastcall__");
+                        } else {
+                            /* Move the qualifier from the pointer to the function. */
+                            T[1].C |= Q;
+                        }
+                    }
                 } else {
-                    Error ("Invalid `_fastcall__' qualifier for pointer");
+                    Error ("Not pointer to a function; can't use a calling convention");
                 }
             }
 
@@ -295,9 +367,9 @@ static void FixQualifiers (Type* DataType)
             if (Q == T_QUAL_NONE) {
                 /* No address size qualifiers specified */
                 if (IsTypeFunc (T+1)) {
-                    /* Pointer to function. Use the qualifier from the function
-                     * or the default if the function don't has one.
-                     */
+                    /* Pointer to function. Use the qualifier from the function,
+                    ** or the default if the function doesn't have one.
+                    */
                     Q = (T[1].C & T_QUAL_ADDRSIZE);
                     if (Q == T_QUAL_NONE) {
                         Q = CodeAddrSizeQualifier ();
@@ -308,8 +380,8 @@ static void FixQualifiers (Type* DataType)
                 T[0].C |= Q;
             } else {
                 /* We have address size qualifiers. If followed by a function,
-                 * apply these also to the function.
-                 */
+                ** apply them to the function also.
+                */
                 if (IsTypeFunc (T+1)) {
                     TypeCode FQ = (T[1].C & T_QUAL_ADDRSIZE);
                     if (FQ == T_QUAL_NONE) {
@@ -344,36 +416,36 @@ static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
     /* Check the storage class given */
     switch (CurTok.Tok) {
 
-       case TOK_EXTERN:
-           D->StorageClass = SC_EXTERN | SC_STATIC;
-           NextToken ();
-           break;
-
-       case TOK_STATIC:
-           D->StorageClass = SC_STATIC;
-           NextToken ();
-           break;
-
-       case TOK_REGISTER:
-           D->StorageClass = SC_REGISTER | SC_STATIC;
-           NextToken ();
-           break;
-
-       case TOK_AUTO:
-           D->StorageClass = SC_AUTO;
-           NextToken ();
-           break;
-
-       case TOK_TYPEDEF:
-           D->StorageClass = SC_TYPEDEF;
-           NextToken ();
-           break;
-
-       default:
-           /* No storage class given, use default */
-                   D->Flags |= DS_DEF_STORAGE;
-           D->StorageClass = DefStorage;
-           break;
+        case TOK_EXTERN:
+            D->StorageClass = SC_EXTERN | SC_STATIC;
+            NextToken ();
+            break;
+
+        case TOK_STATIC:
+            D->StorageClass = SC_STATIC;
+            NextToken ();
+            break;
+
+        case TOK_REGISTER:
+            D->StorageClass = SC_REGISTER | SC_STATIC;
+            NextToken ();
+            break;
+
+        case TOK_AUTO:
+            D->StorageClass = SC_AUTO;
+            NextToken ();
+            break;
+
+        case TOK_TYPEDEF:
+            D->StorageClass = SC_TYPEDEF;
+            NextToken ();
+            break;
+
+        default:
+            /* No storage class given, use default */
+            D->Flags |= DS_DEF_STORAGE;
+            D->StorageClass = DefStorage;
+            break;
     }
 }
 
@@ -387,7 +459,7 @@ static void ParseEnumDecl (void)
 
     /* Accept forward definitions */
     if (CurTok.Tok != TOK_LCURLY) {
-       return;
+        return;
     }
 
     /* Skip the opening curly brace */
@@ -397,66 +469,259 @@ static void ParseEnumDecl (void)
     EnumVal = 0;
     while (CurTok.Tok != TOK_RCURLY) {
 
-       /* We expect an identifier */
-       if (CurTok.Tok != TOK_IDENT) {
-           Error ("Identifier expected");
-           continue;
-       }
-
-       /* Remember the identifier and skip it */
-       strcpy (Ident, CurTok.Ident);
-       NextToken ();
-
-       /* Check for an assigned value */
-       if (CurTok.Tok == TOK_ASSIGN) {
-           ExprDesc Expr;
-           NextToken ();
-           ConstAbsIntExpr (hie1, &Expr);
-           EnumVal = Expr.IVal;
-       }
-
-       /* Add an entry to the symbol table */
-       AddConstSym (Ident, type_int, SC_ENUM, EnumVal++);
-
-       /* Check for end of definition */
-       if (CurTok.Tok != TOK_COMMA)
-           break;
-       NextToken ();
+        /* We expect an identifier */
+        if (CurTok.Tok != TOK_IDENT) {
+            Error ("Identifier expected");
+            continue;
+        }
+
+        /* Remember the identifier and skip it */
+        strcpy (Ident, CurTok.Ident);
+        NextToken ();
+
+        /* Check for an assigned value */
+        if (CurTok.Tok == TOK_ASSIGN) {
+            ExprDesc Expr;
+            NextToken ();
+            ConstAbsIntExpr (hie1, &Expr);
+            EnumVal = Expr.IVal;
+        }
+
+        /* Add an entry to the symbol table */
+        AddConstSym (Ident, type_int, SC_ENUM, EnumVal++);
+
+        /* Check for end of definition */
+        if (CurTok.Tok != TOK_COMMA)
+            break;
+        NextToken ();
     }
     ConsumeRCurly ();
 }
 
 
 
-static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType)
-/* Parse a struct/union declaration. */
+static int ParseFieldWidth (Declaration* Decl)
+/* Parse an optional field width. Returns -1 if no field width is specified,
+** otherwise the width of the field.
+*/
 {
+    ExprDesc Expr;
 
-    unsigned  StructSize;
+    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) 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* StructOrUnionForwardDecl (const char* Name, unsigned Type)
+/* Handle a struct or union forward decl */
+{
+    /* Try to find a struct/union 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, Type, 0, 0);
+    } else if ((Entry->Flags & SC_TYPEMASK) != Type) {
+        /* Already defined, but no struct */
+        Error ("Symbol `%s' is already different kind", Name);
+    }
+    return Entry;
+}
+
+
+
+static unsigned CopyAnonStructFields (const Declaration* Decl, int Offs)
+/* Copy fields from an anon union/struct into the current lexical level. The
+** function returns the size of the embedded struct/union.
+*/
+{
+    /* Get the pointer to the symbol table entry of the anon struct */
+    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
+    ** been an error before, so bail out.
+    */
+    SymTable* Tab = Entry->V.S.SymTab;
+    if (Tab == 0) {
+        /* Incomplete definition - has been flagged before */
+        return Size;
+    }
+
+    /* Get a pointer to the list of symbols. Then walk the list adding copies
+    ** of the embedded struct to the current level.
+    */
+    Entry = Tab->SymHead;
+    while (Entry) {
+
+        /* Enter a copy of this symbol adjusting the offset. We will just
+        ** reuse the type string here.
+        */
+        AddLocalSym (Entry->Name, Entry->Type, SC_STRUCTFIELD, Offs + Entry->V.Offs);
+
+        /* Currently, there can not be any attributes, but if there will be
+        ** some in the future, we want to know this.
+        */
+        CHECK (Entry->Attr == 0);
+
+        /* Next entry */
+        Entry = Entry->NextSym;
+    }
+
+    /* Return the size of the embedded struct */
+    return Size;
+}
+
+
+
+static SymEntry* ParseUnionDecl (const char* Name)
+/* Parse a union declaration. */
+{
+
+    unsigned  UnionSize;
     unsigned  FieldSize;
-    unsigned  Offs;
+    int       FieldWidth;       /* Width in bits, -1 if not a bit-field */
+    SymTable* FieldTab;
+
+
+    if (CurTok.Tok != TOK_LCURLY) {
+        /* Just a forward declaration. */
+        return StructOrUnionForwardDecl (Name, SC_UNION);
+    }
+
+    /* Add a forward declaration for the struct in the current lexical level */
+    AddStructSym (Name, SC_UNION, 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') {
+                /* In cc65 mode, we allow anonymous structs/unions within
+                ** a struct.
+                */
+                if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) {
+                    /* This is an anonymous struct or union. Copy the fields
+                    ** into the current level.
+                    */
+                    CopyAnonStructFields (&Decl, 0);
+
+                } else {
+                    /* A non bit-field without a name is legal but useless */
+                    Warning ("Declaration does not declare anything");
+                }
+                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, SC_UNION, UnionSize, FieldTab);
+}
+
+
+
+static SymEntry* ParseStructDecl (const char* Name)
+/* Parse a struct declaration. */
+{
+
+    unsigned  StructSize;
     int       FlexibleMember;
+    int       BitOffs;          /* Bit offset for bit-fields */
+    int       FieldWidth;       /* Width in bits, -1 if not a bit-field */
     SymTable* FieldTab;
-    SymEntry* Entry;
 
 
     if (CurTok.Tok != TOK_LCURLY) {
-       /* Just a forward declaration. Try to find a struct with the given
-        * name. If there is none, insert a forward declaration into the
-        * 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;
+        /* Just a forward declaration. */
+        return StructOrUnionForwardDecl (Name, SC_STRUCT);
     }
 
     /* Add a forward declaration for the struct in the current lexical level */
-    Entry = AddStructSym (Name, 0, 0);
+    AddStructSym (Name, SC_STRUCT, 0, 0);
 
     /* Skip the curly brace */
     NextToken ();
@@ -467,68 +732,132 @@ 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 */
-       DeclSpec Spec;
-       InitDeclSpec (&Spec);
-       ParseTypeSpec (&Spec, -1, T_QUAL_NONE);
+        /* Get the type of the entry */
+        DeclSpec Spec;
+        InitDeclSpec (&Spec);
+        ParseTypeSpec (&Spec, -1, T_QUAL_NONE);
 
-       /* Read fields with this type */
-       while (1) {
+        /* Read fields with this type */
+        while (1) {
 
-           Declaration Decl;
+            Declaration Decl;
+            ident       Ident;
 
             /* If we had a flexible array member before, no other fields can
-             * follow.
-             */
+            ** follow.
+            */
             if (FlexibleMember) {
                 Error ("Flexible array member must be last field");
                 FlexibleMember = 0;     /* Avoid further errors */
             }
 
-           /* Get type and name of the struct field */
-           ParseDecl (&Spec, &Decl, 0);
+            /* Get type and name of the struct field */
+            ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
 
-            /* Get the offset of this field */
-            Offs = (StructType == T_STRUCT)? StructSize : 0;
+            /* Check for a bit-field declaration */
+            FieldWidth = ParseFieldWidth (&Decl);
 
-            /* Calculate the sizes, handle flexible array members */
-            if (StructType == T_STRUCT) {
+            /* 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 by adding
+            ** a member with an anonymous name.
+            */
+            if (BitOffs > 0) {
+                if (FieldWidth <= 0 || (BitOffs + FieldWidth) > (int) INT_BITS) {
 
-                /* It's a struct. 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 {
-                    StructSize += CheckedSizeOf (Decl.Type);
+                    /* 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;
+                }
+            }
+
+            /* Apart from the above, a bit field with width 0 is not processed
+            ** further.
+            */
+            if (FieldWidth == 0) {
+                goto NextMember;
+            }
+
+            /* 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);
+            }
+
+            /* Check for fields without names */
+            if (Decl.Ident[0] == '\0') {
+                if (FieldWidth < 0) {
+                    /* In cc65 mode, we allow anonymous structs/unions within
+                    ** a struct.
+                    */
+                    if (IS_Get (&Standard) >= STD_CC65 && IsClassStruct (Decl.Type)) {
 
-           } else {
+                        /* This is an anonymous struct or union. Copy the
+                        ** fields into the current level.
+                        */
+                        StructSize += CopyAnonStructFields (&Decl, StructSize);
 
-                /* It's a union */
-                FieldSize = CheckedSizeOf (Decl.Type);
-               if (FieldSize > StructSize) {
-                   StructSize = FieldSize;
-               }
-           }
+                    } else {
+                        /* 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 will get an anonymous one */
+                    AnonName (Decl.Ident, "bit-field");
+                }
+            }
 
-           /* 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) {
+                /* 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, StructSize);
+                if (!FlexibleMember) {
+                    StructSize += CheckedSizeOf (Decl.Type);
+                }
+            }
 
-           if (CurTok.Tok != TOK_COMMA) {
-               break;
+NextMember: if (CurTok.Tok != TOK_COMMA) {
+                break;
             }
-           NextToken ();
-       }
-       ConsumeSemi ();
+            NextToken ();
+        }
+        ConsumeSemi ();
+    }
+
+    /* If we have bits from bit-fields left, add them to the size. */
+    if (BitOffs > 0) {
+        StructSize += ((BitOffs + CHAR_BITS - 1) / CHAR_BITS);
     }
 
     /* Skip the closing brace */
@@ -539,242 +868,259 @@ static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType)
     LeaveStructLevel ();
 
     /* Make a real entry from the forward decl and return it */
-    return AddStructSym (Name, StructSize, FieldTab);
+    return AddStructSym (Name, SC_STRUCT, StructSize, FieldTab);
 }
 
 
 
 static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
-/* Parse a type specificier */
+/* Parse a type specifier */
 {
-    ident      Ident;
-    SymEntry*  Entry;
-    TypeCode    StructType;
+    ident       Ident;
+    SymEntry*   Entry;
 
     /* Assume we have an explicit type */
     D->Flags &= ~DS_DEF_TYPE;
 
     /* Read type qualifiers if we have any */
-    Qualifiers = OptionalQualifiers (Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE);
+    Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE);
 
     /* Look at the data type */
     switch (CurTok.Tok) {
 
-       case TOK_VOID:
-           NextToken ();
-           D->Type[0].C = T_VOID;
-           D->Type[1].C = T_END;
-           break;
-
-       case TOK_CHAR:
-           NextToken ();
-           D->Type[0].C = GetDefaultChar();
-           D->Type[1].C = T_END;
-           break;
-
-       case TOK_LONG:
-           NextToken ();
-           if (CurTok.Tok == TOK_UNSIGNED) {
-               NextToken ();
-               OptionalInt ();
-               D->Type[0].C = T_ULONG;
-               D->Type[1].C = T_END;
-           } else {
-               OptionalSigned ();
-               OptionalInt ();
-               D->Type[0].C = T_LONG;
-               D->Type[1].C = T_END;
-           }
-           break;
-
-       case TOK_SHORT:
-           NextToken ();
-           if (CurTok.Tok == TOK_UNSIGNED) {
-               NextToken ();
-               OptionalInt ();
-               D->Type[0].C = T_USHORT;
-               D->Type[1].C = T_END;
-           } else {
-               OptionalSigned ();
-               OptionalInt ();
-               D->Type[0].C = T_SHORT;
-               D->Type[1].C = T_END;
-           }
-           break;
-
-       case TOK_INT:
-           NextToken ();
-           D->Type[0].C = T_INT;
-           D->Type[1].C = T_END;
-           break;
+        case TOK_VOID:
+            NextToken ();
+            D->Type[0].C = T_VOID;
+            D->Type[0].A.U = 0;
+            D->Type[1].C = T_END;
+            break;
+
+        case TOK_CHAR:
+            NextToken ();
+            D->Type[0].C = GetDefaultChar();
+            D->Type[1].C = T_END;
+            break;
+
+        case TOK_LONG:
+            NextToken ();
+            if (CurTok.Tok == TOK_UNSIGNED) {
+                NextToken ();
+                OptionalInt ();
+                D->Type[0].C = T_ULONG;
+                D->Type[1].C = T_END;
+            } else {
+                OptionalSigned ();
+                OptionalInt ();
+                D->Type[0].C = T_LONG;
+                D->Type[1].C = T_END;
+            }
+            break;
+
+        case TOK_SHORT:
+            NextToken ();
+            if (CurTok.Tok == TOK_UNSIGNED) {
+                NextToken ();
+                OptionalInt ();
+                D->Type[0].C = T_USHORT;
+                D->Type[1].C = T_END;
+            } else {
+                OptionalSigned ();
+                OptionalInt ();
+                D->Type[0].C = T_SHORT;
+                D->Type[1].C = T_END;
+            }
+            break;
+
+        case TOK_INT:
+            NextToken ();
+            D->Type[0].C = T_INT;
+            D->Type[1].C = T_END;
+            break;
 
        case TOK_SIGNED:
-           NextToken ();
-           switch (CurTok.Tok) {
-
-                       case TOK_CHAR:
-                   NextToken ();
-                   D->Type[0].C = T_SCHAR;
-                   D->Type[1].C = T_END;
-                   break;
-
-               case TOK_SHORT:
-                   NextToken ();
-                   OptionalInt ();
-                   D->Type[0].C = T_SHORT;
-                   D->Type[1].C = T_END;
-                   break;
-
-               case TOK_LONG:
-                   NextToken ();
-                   OptionalInt ();
-                   D->Type[0].C = T_LONG;
-                   D->Type[1].C = T_END;
-                   break;
-
-               case TOK_INT:
-                   NextToken ();
-                   /* FALL THROUGH */
-
-               default:
-                   D->Type[0].C = T_INT;
-                   D->Type[1].C = T_END;
-                   break;
-           }
-           break;
-
-       case TOK_UNSIGNED:
-           NextToken ();
-           switch (CurTok.Tok) {
-
-                       case TOK_CHAR:
-                   NextToken ();
-                   D->Type[0].C = T_UCHAR;
-                   D->Type[1].C = T_END;
-                   break;
-
-               case TOK_SHORT:
-                   NextToken ();
-                   OptionalInt ();
-                   D->Type[0].C = T_USHORT;
-                   D->Type[1].C = T_END;
-                   break;
-
-               case TOK_LONG:
-                   NextToken ();
-                   OptionalInt ();
-                   D->Type[0].C = T_ULONG;
-                   D->Type[1].C = T_END;
-                   break;
-
-               case TOK_INT:
-                   NextToken ();
-                   /* FALL THROUGH */
-
-               default:
-                   D->Type[0].C = T_UINT;
-                   D->Type[1].C = T_END;
-                   break;
-           }
-           break;
+            NextToken ();
+            switch (CurTok.Tok) {
+
+                case TOK_CHAR:
+                    NextToken ();
+                    D->Type[0].C = T_SCHAR;
+                    D->Type[1].C = T_END;
+                    break;
+
+                case TOK_SHORT:
+                    NextToken ();
+                    OptionalInt ();
+                    D->Type[0].C = T_SHORT;
+                    D->Type[1].C = T_END;
+                    break;
+
+                case TOK_LONG:
+                    NextToken ();
+                    OptionalInt ();
+                    D->Type[0].C = T_LONG;
+                    D->Type[1].C = T_END;
+                    break;
+
+                case TOK_INT:
+                    NextToken ();
+                    /* FALL THROUGH */
+
+                default:
+                    D->Type[0].C = T_INT;
+                    D->Type[1].C = T_END;
+                    break;
+            }
+            break;
+
+        case TOK_UNSIGNED:
+            NextToken ();
+            switch (CurTok.Tok) {
+
+                case TOK_CHAR:
+                    NextToken ();
+                    D->Type[0].C = T_UCHAR;
+                    D->Type[1].C = T_END;
+                    break;
+
+                case TOK_SHORT:
+                    NextToken ();
+                    OptionalInt ();
+                    D->Type[0].C = T_USHORT;
+                    D->Type[1].C = T_END;
+                    break;
+
+                case TOK_LONG:
+                    NextToken ();
+                    OptionalInt ();
+                    D->Type[0].C = T_ULONG;
+                    D->Type[1].C = T_END;
+                    break;
+
+                case TOK_INT:
+                    NextToken ();
+                    /* FALL THROUGH */
+
+                default:
+                    D->Type[0].C = T_UINT;
+                    D->Type[1].C = T_END;
+                    break;
+            }
+            break;
 
         case TOK_FLOAT:
-           NextToken ();
-           D->Type[0].C = T_FLOAT;
-           D->Type[1].C = T_END;
-           break;
+            NextToken ();
+            D->Type[0].C = T_FLOAT;
+            D->Type[1].C = T_END;
+            break;
 
         case TOK_DOUBLE:
-           NextToken ();
-           D->Type[0].C = T_DOUBLE;
-           D->Type[1].C = T_END;
-           break;
-
-       case TOK_STRUCT:
-       case TOK_UNION:
-           StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION;
-           NextToken ();
-           /* */
-           if (CurTok.Tok == TOK_IDENT) {
-               strcpy (Ident, CurTok.Ident);
-               NextToken ();
-           } else {
-               AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
-           }
-           /* Remember we have an extra type decl */
-           D->Flags |= DS_EXTRA_TYPE;
-           /* Declare the struct in the current scope */
-           Entry = ParseStructDecl (Ident, StructType);
-                   /* Encode the struct entry into the type */
-           D->Type[0].C = StructType;
-           SetSymEntry (D->Type, Entry);
-           D->Type[1].C = T_END;
-           break;
-
-       case TOK_ENUM:
-           NextToken ();
-           if (CurTok.Tok != TOK_LCURLY) {
-               /* Named enum */
-               if (CurTok.Tok == TOK_IDENT) {
-                   /* Find an entry with this name */
-                   Entry = FindTagSym (CurTok.Ident);
-                   if (Entry) {
-                       if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
-                           Error ("Symbol `%s' is already different kind", Entry->Name);
-                       }
-                   } else {
-                       /* Insert entry into table ### */
-                   }
-                   /* Skip the identifier */
-                   NextToken ();
-               } else {
-                   Error ("Identifier expected");
-               }
-           }
-           /* Remember we have an extra type decl */
-           D->Flags |= DS_EXTRA_TYPE;
-           /* Parse the enum decl */
-           ParseEnumDecl ();
-           D->Type[0].C = T_INT;
-           D->Type[1].C = T_END;
-           break;
+            NextToken ();
+            D->Type[0].C = T_DOUBLE;
+            D->Type[1].C = T_END;
+            break;
+
+        case TOK_UNION:
+            NextToken ();
+            /* */
+            if (CurTok.Tok == TOK_IDENT) {
+                strcpy (Ident, CurTok.Ident);
+                NextToken ();
+            } else {
+                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 */
+            D->Flags |= DS_EXTRA_TYPE;
+            /* Declare the struct in the current scope */
+            Entry = ParseStructDecl (Ident);
+            /* Encode the struct entry into the type */
+            D->Type[0].C = T_STRUCT;
+            SetSymEntry (D->Type, Entry);
+            D->Type[1].C = T_END;
+            break;
+
+        case TOK_ENUM:
+            NextToken ();
+            if (CurTok.Tok != TOK_LCURLY) {
+                /* Named enum */
+                if (CurTok.Tok == TOK_IDENT) {
+                    /* Find an entry with this name */
+                    Entry = FindTagSym (CurTok.Ident);
+                    if (Entry) {
+                        if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
+                            Error ("Symbol `%s' is already different kind", Entry->Name);
+                        }
+                    } else {
+                        /* Insert entry into table ### */
+                    }
+                    /* Skip the identifier */
+                    NextToken ();
+                } else {
+                    Error ("Identifier expected");
+                }
+            }
+            /* Remember we have an extra type decl */
+            D->Flags |= DS_EXTRA_TYPE;
+            /* Parse the enum decl */
+            ParseEnumDecl ();
+            D->Type[0].C = T_INT;
+            D->Type[1].C = T_END;
+            break;
 
         case TOK_IDENT:
-           Entry = FindSym (CurTok.Ident);
-           if (Entry && SymIsTypeDef (Entry)) {
-                       /* It's a typedef */
-               NextToken ();
-               TypeCpy (D->Type, Entry->Type);
-               break;
-           }
-           /* FALL THROUGH */
-
-       default:
-           if (Default < 0) {
-               Error ("Type expected");
-               D->Type[0].C = T_INT;
-               D->Type[1].C = T_END;
-           } else {
-               D->Flags |= DS_DEF_TYPE;
-               D->Type[0].C = (TypeCode) Default;
-               D->Type[1].C = T_END;
-           }
-           break;
+            Entry = FindSym (CurTok.Ident);
+            if (Entry && SymIsTypeDef (Entry)) {
+                /* It's a typedef */
+                NextToken ();
+                TypeCopy (D->Type, Entry->Type);
+                break;
+            }
+            /* FALL THROUGH */
+
+        default:
+            if (Default < 0) {
+                Error ("Type expected");
+                D->Type[0].C = T_INT;
+                D->Type[1].C = T_END;
+            } else {
+                D->Flags |= DS_DEF_TYPE;
+                D->Type[0].C = (TypeCode) Default;
+                D->Type[1].C = T_END;
+            }
+            break;
     }
 
     /* There may also be qualifiers *after* the initial type */
-    D->Type[0].C |= OptionalQualifiers (Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE);
+    D->Type[0].C |= (Qualifiers | OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE));
 }
 
 
 
 static Type* ParamTypeCvt (Type* T)
 /* If T is an array, convert it to a pointer else do nothing. Return the
- * resulting type.
- */
+** resulting type.
+*/
 {
     if (IsTypeArray (T)) {
-               T->C = T_PTR;
+        T->C = T_PTR;
     }
     return T;
 }
@@ -784,67 +1130,76 @@ static Type* ParamTypeCvt (Type* T)
 static void ParseOldStyleParamList (FuncDesc* F)
 /* Parse an old style (K&R) parameter list */
 {
+    /* Some fix point tokens that are used for error recovery */
+    static const token_t TokenList[] = { TOK_COMMA, TOK_RPAREN, TOK_SEMI };
+
     /* Parse params */
     while (CurTok.Tok != TOK_RPAREN) {
 
-       /* List of identifiers expected */
-       if (CurTok.Tok != TOK_IDENT) {
-           Error ("Identifier expected");
-       }
+        /* List of identifiers expected */
+        if (CurTok.Tok == TOK_IDENT) {
+
+            /* Create a symbol table entry with type int */
+            AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF | SC_DEFTYPE, 0);
+
+            /* Count arguments */
+            ++F->ParamCount;
 
-       /* Create a symbol table entry with type int */
-       AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF | SC_DEFTYPE, 0);
+            /* Skip the identifier */
+            NextToken ();
 
-       /* Count arguments */
-               ++F->ParamCount;
+        } else {
+            /* Not a parameter name */
+            Error ("Identifier expected");
 
-       /* Skip the identifier */
-       NextToken ();
+            /* Try some smart error recovery */
+            SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
+        }
 
-       /* Check for more parameters */
-       if (CurTok.Tok == TOK_COMMA) {
-           NextToken ();
-       } else {
-           break;
-       }
+        /* Check for more parameters */
+        if (CurTok.Tok == TOK_COMMA) {
+            NextToken ();
+        } else {
+            break;
+        }
     }
 
     /* Skip right paren. We must explicitly check for one here, since some of
-     * the breaks above bail out without checking.
-     */
+    ** the breaks above bail out without checking.
+    */
     ConsumeRParen ();
 
     /* An optional list of type specifications follows */
     while (CurTok.Tok != TOK_LCURLY) {
 
-       DeclSpec        Spec;
+        DeclSpec        Spec;
 
-       /* Read the declaration specifier */
-       ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+        /* Read the declaration specifier */
+        ParseDeclSpec (&Spec, SC_AUTO, T_INT);
 
-               /* We accept only auto and register as storage class specifiers, but
-        * we ignore all this, since we use auto anyway.
-        */
-       if ((Spec.StorageClass & SC_AUTO) == 0 &&
-           (Spec.StorageClass & SC_REGISTER) == 0) {
-           Error ("Illegal storage class");
-       }
+        /* We accept only auto and register as storage class specifiers, but
+        ** we ignore all this, since we use auto anyway.
+        */
+        if ((Spec.StorageClass & SC_AUTO) == 0 &&
+            (Spec.StorageClass & SC_REGISTER) == 0) {
+            Error ("Illegal storage class");
+        }
 
-       /* Parse a comma separated variable list */
-       while (1) {
+        /* Parse a comma separated variable list */
+        while (1) {
 
-           Declaration         Decl;
+            Declaration         Decl;
 
-           /* Read the parameter */
-           ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
-           if (Decl.Ident[0] != '\0') {
+            /* Read the parameter */
+            ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
+            if (Decl.Ident[0] != '\0') {
 
-               /* We have a name given. Search for the symbol */
-               SymEntry* Sym = FindLocalSym (Decl.Ident);
-               if (Sym) {
+                /* We have a name given. Search for the symbol */
+                SymEntry* Sym = FindLocalSym (Decl.Ident);
+                if (Sym) {
                     /* Check if we already changed the type for this
-                     * parameter
-                     */
+                    ** parameter
+                    */
                     if (Sym->Flags & SC_DEFTYPE) {
                         /* Found it, change the default type to the one given */
                         ChangeSymType (Sym, ParamTypeCvt (Decl.Type));
@@ -854,21 +1209,21 @@ static void ParseOldStyleParamList (FuncDesc* F)
                         /* Type has already been changed */
                         Error ("Redefinition for parameter `%s'", Sym->Name);
                     }
-               } else {
-                   Error ("Unknown identifier: `%s'", Decl.Ident);
-               }
-           }
+                } else {
+                    Error ("Unknown identifier: `%s'", Decl.Ident);
+                }
+            }
 
-           if (CurTok.Tok == TOK_COMMA) {
-               NextToken ();
-           } else {
-               break;
-           }
+            if (CurTok.Tok == TOK_COMMA) {
+                NextToken ();
+            } else {
+                break;
+            }
 
-       }
+        }
 
-       /* Variable list must be semicolon terminated */
-       ConsumeSemi ();
+        /* Variable list must be semicolon terminated */
+        ConsumeSemi ();
     }
 }
 
@@ -880,78 +1235,77 @@ static void ParseAnsiParamList (FuncDesc* F)
     /* Parse params */
     while (CurTok.Tok != TOK_RPAREN) {
 
-       DeclSpec        Spec;
-       Declaration     Decl;
-       DeclAttr        Attr;
+        DeclSpec        Spec;
+        Declaration     Decl;
+        SymEntry*       Sym;
 
-       /* Allow an ellipsis as last parameter */
-       if (CurTok.Tok == TOK_ELLIPSIS) {
-           NextToken ();
-           F->Flags |= FD_VARIADIC;
-           break;
-       }
+        /* Allow an ellipsis as last parameter */
+        if (CurTok.Tok == TOK_ELLIPSIS) {
+            NextToken ();
+            F->Flags |= FD_VARIADIC;
+            break;
+        }
 
-       /* Read the declaration specifier */
-       ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+        /* Read the declaration specifier */
+        ParseDeclSpec (&Spec, SC_AUTO, T_INT);
 
-               /* We accept only auto and register as storage class specifiers */
+        /* We accept only auto and register as storage class specifiers */
         if ((Spec.StorageClass & SC_AUTO) == SC_AUTO) {
             Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
         } else if ((Spec.StorageClass & SC_REGISTER) == SC_REGISTER) {
             Spec.StorageClass = SC_REGISTER | SC_STATIC | SC_PARAM | SC_DEF;
         } else {
-           Error ("Illegal storage class");
+            Error ("Illegal storage class");
             Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
-       }
-
-       /* Allow parameters without a name, but remember if we had some to
-        * eventually print an error message later.
-        */
-       ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
-               if (Decl.Ident[0] == '\0') {
-
-           /* Unnamed symbol. Generate a name that is not user accessible,
-            * then handle the symbol normal.
-            */
-           AnonName (Decl.Ident, "param");
-           F->Flags |= FD_UNNAMED_PARAMS;
-
-           /* Clear defined bit on nonames */
-           Decl.StorageClass &= ~SC_DEF;
-       }
-
-       /* Parse an attribute ### */
-       ParseAttribute (&Decl, &Attr);
-
-       /* Create a symbol table entry */
-       AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0);
-
-       /* Count arguments */
-               ++F->ParamCount;
-
-       /* Check for more parameters */
-       if (CurTok.Tok == TOK_COMMA) {
-           NextToken ();
-       } else {
-           break;
-       }
+        }
+
+        /* Allow parameters without a name, but remember if we had some to
+        ** eventually print an error message later.
+        */
+        ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
+        if (Decl.Ident[0] == '\0') {
+
+            /* Unnamed symbol. Generate a name that is not user accessible,
+            ** then handle the symbol normal.
+            */
+            AnonName (Decl.Ident, "param");
+            F->Flags |= FD_UNNAMED_PARAMS;
+
+            /* Clear defined bit on nonames */
+            Decl.StorageClass &= ~SC_DEF;
+        }
+
+        /* Parse attributes for this parameter */
+        ParseAttribute (&Decl);
+
+        /* Create a symbol table entry */
+        Sym = AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0);
+
+        /* Add attributes if we have any */
+        SymUseAttr (Sym, &Decl);
+
+        /* If the parameter is a struct or union, emit a warning */
+        if (IsClassStruct (Decl.Type)) {
+            if (IS_Get (&WarnStructParam)) {
+                Warning ("Passing struct by value for parameter `%s'", Decl.Ident);
+            }
+        }
+
+        /* Count arguments */
+        ++F->ParamCount;
+
+        /* Check for more parameters */
+        if (CurTok.Tok == TOK_COMMA) {
+            NextToken ();
+        } else {
+            break;
+        }
     }
 
     /* Skip right paren. We must explicitly check for one here, since some of
-     * the breaks above bail out without checking.
-     */
+    ** the breaks above bail out without checking.
+    */
     ConsumeRParen ();
-
-    /* Check if this is a function definition */
-    if (CurTok.Tok == TOK_LCURLY) {
-       /* Print an error if we have unnamed parameters and cc65 extensions
-         * are disabled.
-        */
-               if (IS_Get (&Standard) != STD_CC65 &&
-            (F->Flags & FD_UNNAMED_PARAMS) != 0) {
-           Error ("Parameter name omitted");
-       }
-    }
 }
 
 
@@ -970,55 +1324,57 @@ static FuncDesc* ParseFuncDecl (void)
 
     /* Check for several special parameter lists */
     if (CurTok.Tok == TOK_RPAREN) {
-       /* Parameter list is empty */
-       F->Flags |= (FD_EMPTY | FD_VARIADIC);
+        /* Parameter list is empty */
+        F->Flags |= (FD_EMPTY | FD_VARIADIC);
     } else if (CurTok.Tok == TOK_VOID && NextTok.Tok == TOK_RPAREN) {
-       /* Parameter list declared as void */
-       NextToken ();
-       F->Flags |= FD_VOID_PARAM;
+        /* Parameter list declared as void */
+        NextToken ();
+        F->Flags |= FD_VOID_PARAM;
     } else if (CurTok.Tok == TOK_IDENT &&
-              (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) {
-       /* If the identifier is a typedef, we have a new style parameter list,
-        * if it's some other identifier, it's an old style parameter list.
-        */
-       Sym = FindSym (CurTok.Ident);
-       if (Sym == 0 || !SymIsTypeDef (Sym)) {
-           /* Old style (K&R) function. */
-           F->Flags |= FD_OLDSTYLE;
-       }
+               (NextTok.Tok == TOK_COMMA || NextTok.Tok == TOK_RPAREN)) {
+        /* If the identifier is a typedef, we have a new style parameter list,
+        ** if it's some other identifier, it's an old style parameter list.
+        */
+        Sym = FindSym (CurTok.Ident);
+        if (Sym == 0 || !SymIsTypeDef (Sym)) {
+            /* Old style (K&R) function. */
+            F->Flags |= FD_OLDSTYLE;
+        }
     }
 
     /* Parse params */
     if ((F->Flags & FD_OLDSTYLE) == 0) {
-       /* New style function */
-       ParseAnsiParamList (F);
+
+        /* New style function */
+        ParseAnsiParamList (F);
+
     } else {
-       /* Old style function */
-       ParseOldStyleParamList (F);
+        /* Old style function */
+        ParseOldStyleParamList (F);
     }
 
     /* Remember the last function parameter. We need it later for several
-     * purposes, for example when passing stuff to fastcall functions. Since
-     * more symbols are added to the table, it is easier if we remember it
-     * now, since it is currently the last entry in the symbol table.
-     */
+    ** purposes, for example when passing stuff to fastcall functions. Since
+    ** more symbols are added to the table, it is easier if we remember it
+    ** now, since it is currently the last entry in the symbol table.
+    */
     F->LastParam = GetSymTab()->SymTail;
 
     /* Assign offsets. If the function has a variable parameter list,
-     * there's one additional byte (the arg size).
-     */
+    ** there's one additional byte (the arg size).
+    */
     Offs = (F->Flags & FD_VARIADIC)? 1 : 0;
     Sym = F->LastParam;
     while (Sym) {
-       unsigned Size = CheckedSizeOf (Sym->Type);
+        unsigned Size = CheckedSizeOf (Sym->Type);
         if (SymIsRegVar (Sym)) {
             Sym->V.R.SaveOffs = Offs;
         } else {
-           Sym->V.Offs = Offs;
+            Sym->V.Offs = Offs;
         }
-               Offs += Size;
-       F->ParamSize += Size;
-       Sym = Sym->PrevSym;
+        Offs += Size;
+        F->ParamSize += Size;
+        Sym = Sym->PrevSym;
     }
 
     /* Leave the lexical level remembering the symbol tables */
@@ -1030,95 +1386,81 @@ static FuncDesc* ParseFuncDecl (void)
 
 
 
-static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
+static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
 /* Recursively process declarators. Build a type array in reverse order. */
 {
-    /* Read optional function or pointer qualifiers. These modify the
-     * identifier or token to the right. For convenience, we allow the fastcall
-     * qualifier also for pointers here. If it is a pointer-to-function, the
-     * qualifier will later be transfered to the function itself. If it's a
-     * pointer to something else, it will be flagged as an error.
-     */
-    TypeCode Qualifiers =
-        OptionalQualifiers (T_QUAL_NONE, T_QUAL_ADDRSIZE | T_QUAL_FASTCALL);
-
-    /* We cannot have more than one address size far qualifier */
-    switch (Qualifiers & T_QUAL_ADDRSIZE) {
-                  
-        case T_QUAL_NONE:
-        case T_QUAL_NEAR:
-        case T_QUAL_FAR:
-            break;
-
-        default:
-            Error ("Cannot specify more than one address size qualifier");
-            Qualifiers &= ~T_QUAL_ADDRSIZE;
-    }
+    /* Read optional function or pointer qualifiers. They modify the
+    ** identifier or token to the right. For convenience, we allow a calling
+    ** convention also for pointers here. If it's a pointer-to-function, the
+    ** qualifier later will be transfered to the function itself. If it's a
+    ** pointer to something else, it will be flagged as an error.
+    */
+    TypeCode Qualifiers = OptionalQualifiers (T_QUAL_ADDRSIZE | T_QUAL_CCONV);
 
     /* Pointer to something */
     if (CurTok.Tok == TOK_STAR) {
 
         /* Skip the star */
-               NextToken ();
+        NextToken ();
 
-       /* Allow optional pointer qualifiers */
-        Qualifiers = OptionalQualifiers (Qualifiers, T_QUAL_CONST | T_QUAL_VOLATILE);
+        /* Allow const, restrict, and volatile qualifiers */
+        Qualifiers |= OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE | T_QUAL_RESTRICT);
 
-        /* Parse the type, the pointer points to */
-               Decl (Spec, D, Mode);
+        /* Parse the type that the pointer points to */
+        Declarator (Spec, D, Mode);
 
-       /* Add the type */
-       AddTypeToDeclaration (D, T_PTR | Qualifiers);
-               return;
+        /* Add the type */
+        AddTypeToDeclaration (D, T_PTR | Qualifiers);
+        return;
     }
 
     if (CurTok.Tok == TOK_LPAREN) {
-               NextToken ();
-               Decl (Spec, D, Mode);
-               ConsumeRParen ();
+        NextToken ();
+        Declarator (Spec, D, Mode);
+        ConsumeRParen ();
     } else {
-       /* Things depend on Mode now:
-                *  - Mode == DM_NEED_IDENT means:
-        *      we *must* have a type and a variable identifer.
-        *  - Mode == DM_NO_IDENT means:
-        *      we must have a type but no variable identifer
-        *      (if there is one, it's not read).
-        *  - Mode == DM_ACCEPT_IDENT means:
-        *      we *may* have an identifier. If there is an identifier,
-        *      it is read, but it is no error, if there is none.
-        */
-       if (Mode == DM_NO_IDENT) {
-           D->Ident[0] = '\0';
-       } else if (CurTok.Tok == TOK_IDENT) {
-                   strcpy (D->Ident, CurTok.Ident);
-           NextToken ();
-       } else {
-           if (Mode == DM_NEED_IDENT) {
-               Error ("Identifier expected");
-           }
-           D->Ident[0] = '\0';
-       }
+        /* Things depend on Mode now:
+        **  - Mode == DM_NEED_IDENT means:
+        **      we *must* have a type and a variable identifer.
+        **  - Mode == DM_NO_IDENT means:
+        **      we must have a type but no variable identifer
+        **      (if there is one, it's not read).
+        **  - Mode == DM_ACCEPT_IDENT means:
+        **      we *may* have an identifier. If there is an identifier,
+        **      it is read, but it is no error, if there is none.
+        */
+        if (Mode == DM_NO_IDENT) {
+            D->Ident[0] = '\0';
+        } else if (CurTok.Tok == TOK_IDENT) {
+            strcpy (D->Ident, CurTok.Ident);
+            NextToken ();
+        } else {
+            if (Mode == DM_NEED_IDENT) {
+                Error ("Identifier expected");
+            }
+            D->Ident[0] = '\0';
+        }
     }
 
     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
-               if (CurTok.Tok == TOK_LPAREN) {
+        if (CurTok.Tok == TOK_LPAREN) {
 
-                   /* Function declaration */
-           FuncDesc* F;
+            /* Function declaration */
+            FuncDesc* F;
 
             /* Skip the opening paren */
-                   NextToken ();
+            NextToken ();
 
-           /* Parse the function declaration */
-                   F = ParseFuncDecl ();
+            /* Parse the function declaration */
+            F = ParseFuncDecl ();
 
             /* We cannot specify fastcall for variadic functions */
             if ((F->Flags & FD_VARIADIC) && (Qualifiers & T_QUAL_FASTCALL)) {
-                Error ("Variadic functions cannot be `__fastcall'");
+                Error ("Variadic functions cannot be __fastcall__");
                 Qualifiers &= ~T_QUAL_FASTCALL;
             }
 
-           /* Add the function type. Be sure to bounds check the type buffer */
+            /* Add the function type. Be sure to bounds check the type buffer */
             NeedTypeSpace (D, 1);
             D->Type[D->Index].C = T_FUNC | Qualifiers;
             D->Type[D->Index].A.P = F;
@@ -1127,9 +1469,9 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
             /* Qualifiers now used */
             Qualifiers = T_QUAL_NONE;
 
-               } else {
-           /* Array declaration. */
-                   long Size = UNSPECIFIED;
+        } else {
+            /* Array declaration. */
+            long Size = UNSPECIFIED;
 
             /* We cannot have any qualifiers for an array */
             if (Qualifiers != T_QUAL_NONE) {
@@ -1138,12 +1480,12 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
             }
 
             /* Skip the left bracket */
-                   NextToken ();
+            NextToken ();
 
-           /* Read the size if it is given */
-                   if (CurTok.Tok != TOK_RBRACK) {
-               ExprDesc Expr;
-                       ConstAbsIntExpr (hie1, &Expr);
+            /* Read the size if it is given */
+            if (CurTok.Tok != TOK_RBRACK) {
+                ExprDesc Expr;
+                ConstAbsIntExpr (hie1, &Expr);
                 if (Expr.IVal <= 0) {
                     if (D->Ident[0] != '\0') {
                         Error ("Size of array `%s' is invalid", D->Ident);
@@ -1152,18 +1494,18 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
                     }
                     Expr.IVal = 1;
                 }
-                       Size = Expr.IVal;
-                   }
+                Size = Expr.IVal;
+            }
 
             /* Skip the right bracket */
-                   ConsumeRBrack ();
+            ConsumeRBrack ();
 
-           /* Add the array type with the size to the type */
+            /* Add the array type with the size to the type */
             NeedTypeSpace (D, 1);
             D->Type[D->Index].C = T_ARRAY;
             D->Type[D->Index].A.L = Size;
             ++D->Index;
-               }
+        }
     }
 
     /* If we have remaining qualifiers, flag them as invalid */
@@ -1176,12 +1518,15 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
     if (Qualifiers & T_QUAL_FASTCALL) {
         Error ("Invalid `__fastcall__' qualifier");
     }
+    if (Qualifiers & T_QUAL_CDECL) {
+        Error ("Invalid `__cdecl__' qualifier");
+    }
 }
 
 
 
 /*****************************************************************************/
-/*                                  code                                    */
+/*                                   code                                    */
 /*****************************************************************************/
 
 
@@ -1200,7 +1545,7 @@ Type* ParseType (Type* T)
     ParseDecl (&Spec, &Decl, DM_NO_IDENT);
 
     /* Copy the type to the target buffer */
-    TypeCpy (T, Decl.Type);
+    TypeCopy (T, Decl.Type);
 
     /* Return a pointer to the target buffer */
     return T;
@@ -1208,18 +1553,18 @@ Type* ParseType (Type* T)
 
 
 
-void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
+void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
 /* Parse a variable, type or function declaration */
 {
     /* Initialize the Declaration struct */
     InitDeclaration (D);
 
     /* Get additional declarators and the identifier */
-    Decl (Spec, D, Mode);
+    Declarator (Spec, D, Mode);
 
     /* Add the base type. */
-    NeedTypeSpace (D, TypeLen (Spec->Type) + 1);       /* Bounds check */
-    TypeCpy (D->Type + D->Index, Spec->Type);
+    NeedTypeSpace (D, TypeLen (Spec->Type) + 1);        /* Bounds check */
+    TypeCopy (D->Type + D->Index, Spec->Type);
 
     /* Use the storage class from the declspec */
     D->StorageClass = Spec->StorageClass;
@@ -1232,6 +1577,9 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
         D->StorageClass |= SC_FUNC;
     }
 
+    /* Parse attributes for this declaration */
+    ParseAttribute (D);
+
     /* Check several things for function or function pointer types */
     if (IsTypeFunc (D->Type) || IsTypeFuncPtr (D->Type)) {
 
@@ -1262,8 +1610,8 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
         if ((Spec->Flags & DS_DEF_TYPE) != 0 &&
             RetType[0].C == T_INT && RetType[1].C == T_END) {
             /* Function has an implicit int return. Output a warning if we don't
-             * have the C89 standard enabled explicitly.
-             */
+            ** have the C89 standard enabled explicitly.
+            */
             if (IS_Get (&Standard) >= STD_C99) {
                 Warning ("Implicit `int' return type is an obsolete feature");
             }
@@ -1273,13 +1621,13 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
     }
 
     /* For anthing that is not a function or typedef, check for an implicit
-     * int declaration.
-     */
+    ** int declaration.
+    */
     if ((D->StorageClass & SC_FUNC) != SC_FUNC &&
-        (D->StorageClass & SC_TYPEDEF) != SC_TYPEDEF) {
+        (D->StorageClass & SC_TYPEMASK) != SC_TYPEDEF) {
         /* If the standard was not set explicitly to C89, print a warning
-         * for variables with implicit int type.
-         */
+        ** for variables with implicit int type.
+        */
         if ((Spec->Flags & DS_DEF_TYPE) != 0 && IS_Get (&Standard) >= STD_C99) {
             Warning ("Implicit `int' is an obsolete feature");
         }
@@ -1310,7 +1658,7 @@ void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType)
     InitDeclSpec (D);
 
     /* There may be qualifiers *before* the storage class specifier */
-    Qualifiers = OptionalQualifiers (T_QUAL_NONE, T_QUAL_CONST | T_QUAL_VOLATILE);
+    Qualifiers = OptionalQualifiers (T_QUAL_CONST | T_QUAL_VOLATILE);
 
     /* Now get the storage class specifier for this declaration */
     ParseStorageClass (D, DefStorage);
@@ -1323,12 +1671,12 @@ void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType)
 
 void CheckEmptyDecl (const DeclSpec* D)
 /* Called after an empty type declaration (that is, a type declaration without
- * a variable). Checks if the declaration does really make sense and issues a
- * warning if not.
- */
+** a variable). Checks if the declaration does really make sense and issues a
+** warning if not.
+*/
 {
     if ((D->Flags & DS_EXTRA_TYPE) == 0) {
-       Warning ("Useless declaration");
+        Warning ("Useless declaration");
     }
 }
 
@@ -1336,8 +1684,8 @@ void CheckEmptyDecl (const DeclSpec* D)
 
 static void SkipInitializer (unsigned BracesExpected)
 /* 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) {
         switch (CurTok.Tok) {
@@ -1353,9 +1701,9 @@ static void SkipInitializer (unsigned BracesExpected)
 
 static unsigned OpeningCurlyBraces (unsigned BracesNeeded)
 /* Accept any number of opening curly braces around an initialization, skip
- * them and return the number. If the number of curly braces is less than
- * BracesNeeded, issue a warning.
- */
+** them and return the number. If the number of curly braces is less than
+** BracesNeeded, issue a warning.
+*/
 {
     unsigned BraceCount = 0;
     while (CurTok.Tok == TOK_LCURLY) {
@@ -1372,9 +1720,9 @@ static unsigned OpeningCurlyBraces (unsigned BracesNeeded)
 
 static void ClosingCurlyBraces (unsigned BracesExpected)
 /* Accept and skip the given number of closing curly braces together with
- * an optional comma. Output an error messages, if the input does not contain
- * the expected number of braces.
- */
+** an optional comma. Output an error messages, if the input does not contain
+** the expected number of braces.
+*/
 {
     while (BracesExpected) {
         if (CurTok.Tok == TOK_RCURLY) {
@@ -1399,7 +1747,7 @@ static void DefineData (ExprDesc* Expr)
 
         case E_LOC_ABS:
             /* Absolute: numeric address or const */
-                   g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0);
+            g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0);
             break;
 
         case E_LOC_GLOBAL:
@@ -1414,12 +1762,12 @@ static void DefineData (ExprDesc* Expr)
             break;
 
         case E_LOC_REGISTER:
-                   /* Register variable. Taking the address is usually not
-                    * allowed.
-                    */
-                   if (IS_Get (&AllowRegVarAddr) == 0) {
-                       Error ("Cannot take the address of a register variable");
-                   }
+            /* Register variable. Taking the address is usually not
+            ** allowed.
+            */
+            if (IS_Get (&AllowRegVarAddr) == 0) {
+                Error ("Cannot take the address of a register variable");
+            }
             g_defdata (CF_REGVAR, Expr->Name, Expr->IVal);
             break;
 
@@ -1429,37 +1777,66 @@ static void DefineData (ExprDesc* Expr)
             Error ("Non constant initializer");
             break;
 
-               default:
-                   Internal ("Unknown constant type: 0x%04X", ED_GetLoc (Expr));
+        default:
+            Internal ("Unknown constant type: 0x%04X", ED_GetLoc (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);
 
     /* We warn if an initializer for a scalar contains braces, because this is
-     * quite unusual and often a sign for some problem in the input.
-     */
+    ** quite unusual and often a sign for some problem in the input.
+    */
     if (BraceCount > 0) {
         Warning ("Braces around scalar initializer");
     }
 
     /* 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);
@@ -1502,31 +1879,28 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
 
     /* Special handling for a character array initialized by a literal */
     if (IsTypeChar (ElementType) &&
-        (CurTok.Tok == TOK_SCONST ||
-        (CurTok.Tok == TOK_LCURLY && NextTok.Tok == TOK_SCONST))) {
+        (CurTok.Tok == TOK_SCONST || CurTok.Tok == TOK_WCSCONST ||
+        (CurTok.Tok == TOK_LCURLY &&
+         (NextTok.Tok == TOK_SCONST || NextTok.Tok == TOK_WCSCONST)))) {
 
         /* Char array initialized by string constant */
         int NeedParen;
-        const char* Str;
 
         /* If we initializer is enclosed in brackets, remember this fact and
-         * skip the opening bracket.
-         */
+        ** skip the opening bracket.
+        */
         NeedParen = (CurTok.Tok == TOK_LCURLY);
         if (NeedParen) {
             NextToken ();
         }
 
-        /* Get the initializer string and its size */
-        Str = GetLiteral (CurTok.IVal);
-        Count = GetLiteralPoolOffs () - CurTok.IVal;
-
         /* Translate into target charset */
-        TranslateLiteralPool (CurTok.IVal);
+        TranslateLiteral (CurTok.SVal);
 
         /* If the array is one too small for the string literal, omit the
-         * trailing zero.
-         */
+        ** trailing zero.
+        */
+        Count = GetLiteralSize (CurTok.SVal);
         if (ElementCount != UNSPECIFIED &&
             ElementCount != FLEXIBLE    &&
             Count        == ElementCount + 1) {
@@ -1535,15 +1909,14 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
         }
 
         /* Output the data */
-        g_defbytes (Str, Count);
+        g_defbytes (GetLiteralStr (CurTok.SVal), Count);
 
-        /* Remove string from pool */
-        ResetLiteralPoolOffs (CurTok.IVal);
+        /* Skip the string */
         NextToken ();
 
         /* If the initializer was enclosed in curly braces, we need a closing
-         * one.
-         */
+        ** one.
+        */
         if (NeedParen) {
             ConsumeRCurly ();
         }
@@ -1557,9 +1930,9 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
         Count = 0;
         while (CurTok.Tok != TOK_RCURLY) {
             /* Flexible array members may not be initialized within
-             * an array (because the size of each element may differ
-             * otherwise).
-             */
+            ** an array (because the size of each element may differ
+            ** otherwise).
+            */
             ParseInitInternal (ElementType, 0);
             ++Count;
             if (CurTok.Tok != TOK_COMMA)
@@ -1577,8 +1950,8 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
         ElementCount = Count;
     } else if (ElementCount == FLEXIBLE && AllowFlexibleMembers) {
         /* In non ANSI mode, allow initialization of flexible array
-         * members.
-         */
+        ** members.
+        */
         ElementCount = Count;
     } else if (Count < ElementCount) {
         g_zerobytes ((ElementCount - Count) * ElementSize);
@@ -1593,10 +1966,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 */
@@ -1606,64 +1978,147 @@ 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.
-     */
+    ** 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");
+
+        /* */
+        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);
-       Entry = Entry->NextSym;
-       if (CurTok.Tok != TOK_COMMA)
-           break;
-       NextToken ();
+            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) {
+            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).
-     */
-    return Size;
+    ** larger than sizeof (Struct) if flexible array members are present and
+    ** were initialized (possible in non ANSI mode).
+    */
+    return SI.Offs;
 }
 
 
 
-static unsigned ParseVoidInit (void)
+static unsigned ParseVoidInit (Type* T)
 /* Parse an initialization of a void variable (special cc65 extension).
- * Return the number of bytes initialized.
- */
+** Return the number of bytes initialized.
+*/
 {
     ExprDesc Expr;
     unsigned Size;
@@ -1674,59 +2129,62 @@ static unsigned ParseVoidInit (void)
     /* Allow an arbitrary list of values */
     Size = 0;
     do {
-       ConstExpr (hie1, &Expr);
-       switch (UnqualifiedType (Expr.Type[0].C)) {
-
-           case T_SCHAR:
-           case T_UCHAR:
-               if (ED_IsConstAbsInt (&Expr)) {
-                   /* Make it byte sized */
-                   Expr.IVal &= 0xFF;
-               }
-               DefineData (&Expr);
+        ConstExpr (hie1, &Expr);
+        switch (UnqualifiedType (Expr.Type[0].C)) {
+
+            case T_SCHAR:
+            case T_UCHAR:
+                if (ED_IsConstAbsInt (&Expr)) {
+                    /* Make it byte sized */
+                    Expr.IVal &= 0xFF;
+                }
+                DefineData (&Expr);
                 Size += SIZEOF_CHAR;
                 break;
 
-           case T_SHORT:
-           case T_USHORT:
-           case T_INT:
-           case T_UINT:
-           case T_PTR:
-           case T_ARRAY:
-               if (ED_IsConstAbsInt (&Expr)) {
-                   /* Make it word sized */
-                   Expr.IVal &= 0xFFFF;
-               }
-               DefineData (&Expr);
-               Size += SIZEOF_INT;
+            case T_SHORT:
+            case T_USHORT:
+            case T_INT:
+            case T_UINT:
+            case T_PTR:
+            case T_ARRAY:
+                if (ED_IsConstAbsInt (&Expr)) {
+                    /* Make it word sized */
+                    Expr.IVal &= 0xFFFF;
+                }
+                DefineData (&Expr);
+                Size += SIZEOF_INT;
                 break;
 
-           case T_LONG:
-           case T_ULONG:
-               if (ED_IsConstAbsInt (&Expr)) {
-                   /* Make it dword sized */
-                   Expr.IVal &= 0xFFFFFFFF;
-               }
-               DefineData (&Expr);
-               Size += SIZEOF_LONG;
+            case T_LONG:
+            case T_ULONG:
+                if (ED_IsConstAbsInt (&Expr)) {
+                    /* Make it dword sized */
+                    Expr.IVal &= 0xFFFFFFFF;
+                }
+                DefineData (&Expr);
+                Size += SIZEOF_LONG;
                 break;
 
-           default:
-               Error ("Illegal type in initialization");
-               break;
+            default:
+                Error ("Illegal type in initialization");
+                break;
 
-       }
+        }
 
-       if (CurTok.Tok != TOK_COMMA) {
-           break;
-       }
-       NextToken ();
+        if (CurTok.Tok != TOK_COMMA) {
+            break;
+        }
+        NextToken ();
 
     } while (CurTok.Tok != TOK_RCURLY);
 
     /* Closing brace */
     ConsumeRCurly ();
 
+    /* Number of bytes determined by initializer */
+    T->A.U = Size;
+
     /* Return the number of bytes initialized */
     return Size;
 }
@@ -1738,38 +2196,38 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
 {
     switch (UnqualifiedType (T->C)) {
 
-       case T_SCHAR:
-       case T_UCHAR:
-       case T_SHORT:
-       case T_USHORT:
-       case T_INT:
-       case T_UINT:
-       case T_LONG:
-       case T_ULONG:
+        case T_SCHAR:
+        case T_UCHAR:
+        case T_SHORT:
+        case T_USHORT:
+        case T_INT:
+        case T_UINT:
+        case T_LONG:
+        case T_ULONG:
         case T_FLOAT:
         case T_DOUBLE:
             return ParseScalarInit (T);
 
-       case T_PTR:
+        case T_PTR:
             return ParsePointerInit (T);
 
-       case T_ARRAY:
+        case T_ARRAY:
             return ParseArrayInit (T, AllowFlexibleMembers);
 
         case T_STRUCT:
         case T_UNION:
-           return ParseStructInit (T, AllowFlexibleMembers);
+            return ParseStructInit (T, AllowFlexibleMembers);
 
-       case T_VOID:
-           if (IS_Get (&Standard) == STD_CC65) {
-               /* Special cc65 extension in non ANSI mode */
-               return ParseVoidInit ();
-           }
-           /* FALLTHROUGH */
+        case T_VOID:
+            if (IS_Get (&Standard) == STD_CC65) {
+                /* Special cc65 extension in non-ANSI mode */
+                return ParseVoidInit (T);
+            }
+            /* FALLTHROUGH */
 
-       default:
-           Error ("Illegal type");
-           return SIZEOF_CHAR;
+        default:
+            Error ("Illegal type");
+            return SIZEOF_CHAR;
 
     }
 }
@@ -1780,13 +2238,13 @@ unsigned ParseInit (Type* T)
 /* Parse initialization of variables. Return the number of data bytes. */
 {
     /* 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);
 
     /* 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.
+    */
     if (HaveGlobalCode ()) {
         Error ("Non constant initializers");
         RemoveGlobalCode ();
@@ -1795,6 +2253,3 @@ unsigned ParseInit (Type* T)
     /* Return the size needed for the initialization */
     return Size;
 }
-
-
-