]> git.sur5r.net Git - cc65/blobdiff - src/cc65/declare.c
In an old style function definition, print a diagnostic if a type is assigned
[cc65] / src / cc65 / declare.c
index 3ef54e0597a23a5675261cb4aba8f33c6f3191bd..2b4a09a42a61f2644755c169679236b067ef2b2e 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2001 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* (C) 1998-2008 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
+/*               D-70794 Filderstadt                                         */
+/* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 #include <errno.h>
 
 /* common */
+#include "addrsize.h"
+#include "mmodel.h"
 #include "xmalloc.h"
 
 /* cc65 */
 #include "anonname.h"
 #include "codegen.h"
 #include "datatype.h"
+#include "declare.h"
 #include "declattr.h"
 #include "error.h"
 #include "expr.h"
@@ -53,8 +56,9 @@
 #include "litpool.h"
 #include "pragma.h"
 #include "scanner.h"
+#include "standard.h"
 #include "symtab.h"
-#include "declare.h"
+#include "typeconv.h"
 
 
 
 
 
 
-static void ParseTypeSpec (DeclSpec* D, int Default);
+static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers);
 /* Parse a type specificier */
 
+static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
+/* Parse initialization of variables. Return the number of data bytes. */
+
 
 
 /*****************************************************************************/
@@ -75,15 +82,15 @@ static void ParseTypeSpec (DeclSpec* D, int Default);
 
 
 
-static type OptionalQualifiers (type Q)
+static TypeCode OptionalQualifiers (TypeCode Q)
 /* Read type qualifiers if we have any */
 {
-    while (curtok == TOK_CONST || curtok == TOK_VOLATILE) {
+    while (TokIsTypeQual (&CurTok)) {
 
-       switch (curtok) {
+       switch (CurTok.Tok) {
 
            case TOK_CONST:
-               if (Q & T_QUAL_CONST) {
+               if (Q & T_QUAL_CONST) {
                    Error ("Duplicate qualifier: `const'");
                }
                Q |= T_QUAL_CONST;
@@ -96,9 +103,15 @@ static type OptionalQualifiers (type Q)
                Q |= T_QUAL_VOLATILE;
                break;
 
+            case TOK_RESTRICT:
+                if (Q & T_QUAL_RESTRICT) {
+                    Error ("Duplicate qualifier: `restrict'");
+                }
+                Q |= T_QUAL_RESTRICT;
+                break;
+
            default:
-               /* Keep gcc silent */
-               break;
+               Internal ("Unexpected type qualifier token: %d", CurTok.Tok);
 
        }
 
@@ -112,10 +125,10 @@ static type OptionalQualifiers (type Q)
 
 
 
-static void optionalint (void)
+static void OptionalInt (void)
 /* Eat an optional "int" token */
 {
-    if (curtok == TOK_INT) {
+    if (CurTok.Tok == TOK_INT) {
        /* Skip it */
        NextToken ();
     }
@@ -123,10 +136,10 @@ static void optionalint (void)
 
 
 
-static void optionalsigned (void)
+static void OptionalSigned (void)
 /* Eat an optional "signed" token */
 {
-    if (curtok == TOK_SIGNED) {
+    if (CurTok.Tok == TOK_SIGNED) {
        /* Skip it */
        NextToken ();
     }
@@ -137,9 +150,9 @@ static void optionalsigned (void)
 static void InitDeclSpec (DeclSpec* D)
 /* Initialize the DeclSpec struct for use */
 {
-    D->StorageClass    = 0;
-    D->Type[0]         = T_END;
-    D->Flags           = 0;
+    D->StorageClass     = 0;
+    D->Type[0].C        = T_END;
+    D->Flags            = 0;
 }
 
 
@@ -147,9 +160,80 @@ static void InitDeclSpec (DeclSpec* D)
 static void InitDeclaration (Declaration* D)
 /* Initialize the Declaration struct for use */
 {
-    D->Ident[0]                = '\0';
-    D->Type[0]         = T_END;
-    D->T               = D->Type;
+    D->Ident[0]  = '\0';
+    D->Type[0].C = T_END;
+    D->Index     = 0;
+}
+
+
+
+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");
+    }
+}
+
+
+
+static void AddTypeToDeclaration (Declaration* D, TypeCode T)
+/* Add a type specifier to the type of a declaration */
+{
+    NeedTypeSpace (D, 1);
+    D->Type[D->Index++].C = T;
+}
+
+
+
+static void AddFuncTypeToDeclaration (Declaration* D, FuncDesc* F)
+/* Add a function type plus function descriptor to the type of a declaration */
+{
+    NeedTypeSpace (D, 1);
+    D->Type[D->Index].C = T_FUNC;
+    SetFuncDesc (D->Type + D->Index, F);
+    ++D->Index;
+}
+
+
+
+static void AddArrayToDeclaration (Declaration* D, long Size)
+/* Add an array type plus size to the type of a declaration */
+{
+    NeedTypeSpace (D, 1);
+    D->Type[D->Index].C = T_ARRAY;
+    D->Type[D->Index].A.L = Size;
+    ++D->Index;
+}
+
+
+
+static void FixArrayQualifiers (Type* T)
+/* 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.
+ */
+{
+    TypeCode Q = T_QUAL_NONE;
+    while (T->C != T_END) {
+        if (IsTypeArray (T)) {
+            /* Extract any type qualifiers */
+            Q |= T->C & T_MASK_QUAL;
+            T->C = UnqualifiedType (T->C);
+        } else {
+            /* Add extracted type qualifiers here */
+            T->C |= Q;
+            Q = T_QUAL_NONE;
+        }
+        ++T;
+    }
+
+    /* Q must be empty now */
+    CHECK (Q == T_QUAL_NONE);
 }
 
 
@@ -161,7 +245,7 @@ static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
     D->Flags &= ~DS_DEF_STORAGE;
 
     /* Check the storage class given */
-    switch (curtok) {
+    switch (CurTok.Tok) {
 
        case TOK_EXTERN:
            D->StorageClass = SC_EXTERN | SC_STATIC;
@@ -205,7 +289,7 @@ static void ParseEnumDecl (void)
     ident Ident;
 
     /* Accept forward definitions */
-    if (curtok != TOK_LCURLY) {
+    if (CurTok.Tok != TOK_LCURLY) {
        return;
     }
 
@@ -214,12 +298,12 @@ static void ParseEnumDecl (void)
 
     /* Read the enum tags */
     EnumVal = 0;
-    while (curtok != TOK_RCURLY) {
+    while (CurTok.Tok != TOK_RCURLY) {
 
        /* We expect an identifier */
-       if (curtok != TOK_IDENT) {
+       if (CurTok.Tok != TOK_IDENT) {
            Error ("Identifier expected");
-           continue;
+           continue;
        }
 
        /* Remember the identifier and skip it */
@@ -227,18 +311,18 @@ static void ParseEnumDecl (void)
        NextToken ();
 
        /* Check for an assigned value */
-       if (curtok == TOK_ASSIGN) {
-           struct expent lval;
+       if (CurTok.Tok == TOK_ASSIGN) {
+           ExprDesc Expr;
            NextToken ();
-           constexpr (&lval);
-           EnumVal = lval.e_const;
+           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_COMMA)
+       /* Check for end of definition */
+       if (CurTok.Tok != TOK_COMMA)
            break;
        NextToken ();
     }
@@ -247,17 +331,19 @@ static void ParseEnumDecl (void)
 
 
 
-static SymEntry* ParseStructDecl (const char* Name, type StructType)
+static SymEntry* ParseStructDecl (const char* Name, TypeCode StructType)
 /* Parse a struct/union declaration. */
 {
 
-    unsigned Size;
-    unsigned Offs;
+    unsigned  StructSize;
+    unsigned  FieldSize;
+    unsigned  Offs;
+    int       FlexibleMember;
     SymTable* FieldTab;
     SymEntry* Entry;
 
 
-    if (curtok != TOK_LCURLY) {
+    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.
@@ -282,39 +368,70 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
     EnterStructLevel ();
 
     /* Parse struct fields */
-    Size = 0;
-    while (curtok != TOK_RCURLY) {
+    FlexibleMember = 0;
+    StructSize     = 0;
+    while (CurTok.Tok != TOK_RCURLY) {
 
        /* Get the type of the entry */
        DeclSpec Spec;
        InitDeclSpec (&Spec);
-       ParseTypeSpec (&Spec, -1);
+       ParseTypeSpec (&Spec, -1, T_QUAL_NONE);
 
        /* Read fields with this type */
        while (1) {
 
-           /* Get type and name of the struct field */
            Declaration Decl;
+
+            /* If we had a flexible array member before, no other fields can
+             * 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);
 
-           /* Add a field entry to the table */
-           AddLocalSym (Decl.Ident, Decl.Type, SC_SFLD, (StructType == T_STRUCT)? Size : 0);
+            /* Get the offset of this field */
+            Offs = (StructType == T_STRUCT)? StructSize : 0;
+
+            /* 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.
+                 */
+                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);
+                }
 
-           /* Calculate offset of next field/size of the union */
-           Offs = SizeOf (Decl.Type);
-           if (StructType == T_STRUCT) {
-               Size += Offs;
            } else {
-               if (Offs > Size) {
-                   Size = Offs;
+
+                /* It's a union */
+                FieldSize = CheckedSizeOf (Decl.Type);
+               if (FieldSize > StructSize) {
+                   StructSize = FieldSize;
                }
-           }
+           }
 
-           if (curtok != TOK_COMMA)
+           /* Add a field entry to the table */
+           AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs);
+
+           if (CurTok.Tok != TOK_COMMA) {
                break;
+            }
            NextToken ();
        }
-       ConsumeSemi ();
+       ConsumeSemi ();
     }
 
     /* Skip the closing brace */
@@ -325,152 +442,163 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
     LeaveStructLevel ();
 
     /* Make a real entry from the forward decl and return it */
-    return AddStructSym (Name, Size, FieldTab);
+    return AddStructSym (Name, StructSize, FieldTab);
 }
 
 
 
-static void ParseTypeSpec (DeclSpec* D, int Default)
+static void ParseTypeSpec (DeclSpec* D, long Default, TypeCode Qualifiers)
 /* Parse a type specificier */
 {
     ident      Ident;
     SymEntry*  Entry;
-    type       StructType;
-    type       Qualifiers;     /* Type qualifiers */
+    TypeCode    StructType;
 
     /* Assume we have an explicit type */
     D->Flags &= ~DS_DEF_TYPE;
 
     /* Read type qualifiers if we have any */
-    Qualifiers = OptionalQualifiers (T_QUAL_NONE);
+    Qualifiers = OptionalQualifiers (Qualifiers);
 
     /* Look at the data type */
-    switch (curtok) {
+    switch (CurTok.Tok) {
 
        case TOK_VOID:
            NextToken ();
-           D->Type[0] = T_VOID;
-           D->Type[1] = T_END;
+           D->Type[0].C = T_VOID;
+           D->Type[1].C = T_END;
            break;
 
        case TOK_CHAR:
            NextToken ();
-           D->Type[0] = GetDefaultChar();
-           D->Type[1] = T_END;
+           D->Type[0].C = GetDefaultChar();
+           D->Type[1].C = T_END;
            break;
 
        case TOK_LONG:
            NextToken ();
-           if (curtok == TOK_UNSIGNED) {
+           if (CurTok.Tok == TOK_UNSIGNED) {
                NextToken ();
-               optionalint ();
-               D->Type[0] = T_ULONG;
-               D->Type[1] = T_END;
+               OptionalInt ();
+               D->Type[0].C = T_ULONG;
+               D->Type[1].C = T_END;
            } else {
-               optionalsigned ();
-               optionalint ();
-               D->Type[0] = T_LONG;
-               D->Type[1] = T_END;
+               OptionalSigned ();
+               OptionalInt ();
+               D->Type[0].C = T_LONG;
+               D->Type[1].C = T_END;
            }
            break;
 
        case TOK_SHORT:
            NextToken ();
-           if (curtok == TOK_UNSIGNED) {
+           if (CurTok.Tok == TOK_UNSIGNED) {
                NextToken ();
-               optionalint ();
-               D->Type[0] = T_USHORT;
-               D->Type[1] = T_END;
+               OptionalInt ();
+               D->Type[0].C = T_USHORT;
+               D->Type[1].C = T_END;
            } else {
-               optionalsigned ();
-               optionalint ();
-               D->Type[0] = T_SHORT;
-               D->Type[1] = T_END;
+               OptionalSigned ();
+               OptionalInt ();
+               D->Type[0].C = T_SHORT;
+               D->Type[1].C = T_END;
            }
-           break;
+           break;
 
        case TOK_INT:
            NextToken ();
-           D->Type[0] = T_INT;
-           D->Type[1] = T_END;
+           D->Type[0].C = T_INT;
+           D->Type[1].C = T_END;
            break;
 
        case TOK_SIGNED:
            NextToken ();
-           switch (curtok) {
+           switch (CurTok.Tok) {
 
                        case TOK_CHAR:
                    NextToken ();
-                   D->Type[0] = T_SCHAR;
-                   D->Type[1] = T_END;
+                   D->Type[0].C = T_SCHAR;
+                   D->Type[1].C = T_END;
                    break;
 
                case TOK_SHORT:
                    NextToken ();
-                   optionalint ();
-                   D->Type[0] = T_SHORT;
-                   D->Type[1] = T_END;
+                   OptionalInt ();
+                   D->Type[0].C = T_SHORT;
+                   D->Type[1].C = T_END;
                    break;
 
                case TOK_LONG:
                    NextToken ();
-                   optionalint ();
-                   D->Type[0] = T_LONG;
-                   D->Type[1] = T_END;
-                   break;
+                   OptionalInt ();
+                   D->Type[0].C = T_LONG;
+                   D->Type[1].C = T_END;
+                   break;
 
                case TOK_INT:
                    NextToken ();
                    /* FALL THROUGH */
 
-               default:
-                   D->Type[0] = T_INT;
-                   D->Type[1] = T_END;
+               default:
+                   D->Type[0].C = T_INT;
+                   D->Type[1].C = T_END;
                    break;
            }
            break;
 
        case TOK_UNSIGNED:
            NextToken ();
-           switch (curtok) {
+           switch (CurTok.Tok) {
 
                        case TOK_CHAR:
                    NextToken ();
-                   D->Type[0] = T_UCHAR;
-                   D->Type[1] = T_END;
+                   D->Type[0].C = T_UCHAR;
+                   D->Type[1].C = T_END;
                    break;
 
                case TOK_SHORT:
                    NextToken ();
-                   optionalint ();
-                   D->Type[0] = T_USHORT;
-                   D->Type[1] = T_END;
+                   OptionalInt ();
+                   D->Type[0].C = T_USHORT;
+                   D->Type[1].C = T_END;
                    break;
 
                case TOK_LONG:
                    NextToken ();
-                   optionalint ();
-                   D->Type[0] = T_ULONG;
-                   D->Type[1] = T_END;
+                   OptionalInt ();
+                   D->Type[0].C = T_ULONG;
+                   D->Type[1].C = T_END;
                    break;
 
-               case TOK_INT:
+               case TOK_INT:
                    NextToken ();
                    /* FALL THROUGH */
 
                default:
-                   D->Type[0] = T_UINT;
-                   D->Type[1] = T_END;
+                   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;
+
+        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_STRUCT)? T_STRUCT : T_UNION;
+           StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION;
            NextToken ();
            /* */
-           if (curtok == TOK_IDENT) {
+           if (CurTok.Tok == TOK_IDENT) {
                strcpy (Ident, CurTok.Ident);
                NextToken ();
            } else {
@@ -481,45 +609,45 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
            /* Declare the struct in the current scope */
            Entry = ParseStructDecl (Ident, StructType);
                    /* Encode the struct entry into the type */
-           D->Type[0] = StructType;
-           EncodePtr (D->Type+1, Entry);
-           D->Type[DECODE_SIZE+1] = T_END;
+           D->Type[0].C = StructType;
+           SetSymEntry (D->Type, Entry);
+           D->Type[1].C = T_END;
            break;
 
        case TOK_ENUM:
            NextToken ();
-           if (curtok != TOK_LCURLY) {
+           if (CurTok.Tok != TOK_LCURLY) {
                /* Named enum */
-               if (curtok == TOK_IDENT) {
+               if (CurTok.Tok == TOK_IDENT) {
                    /* Find an entry with this name */
-                   Entry = FindTagSym (CurTok.Ident);
+                   Entry = FindTagSym (CurTok.Ident);
                    if (Entry) {
                        if (SymIsLocal (Entry) && (Entry->Flags & SC_ENUM) == 0) {
                            Error ("Symbol `%s' is already different kind", Entry->Name);
                        }
-                   } else {
+                   } else {
                        /* Insert entry into table ### */
                    }
                    /* Skip the identifier */
                    NextToken ();
-               } else {
+               } else {
                    Error ("Identifier expected");
-               }
-           }
-           /* Remember we have an extra type decl */
-           D->Flags |= DS_EXTRA_TYPE;
-           /* Parse the enum decl */
+               }
+           }
+           /* Remember we have an extra type decl */
+           D->Flags |= DS_EXTRA_TYPE;
+           /* Parse the enum decl */
            ParseEnumDecl ();
-           D->Type[0] = T_INT;
-           D->Type[1] = T_END;
+           D->Type[0].C = T_INT;
+           D->Type[1].C = T_END;
            break;
 
         case TOK_IDENT:
-           Entry = FindSym (CurTok.Ident);
-           if (Entry && IsTypeDef (Entry)) {
+           Entry = FindSym (CurTok.Ident);
+           if (Entry && SymIsTypeDef (Entry)) {
                        /* It's a typedef */
                NextToken ();
-               TypeCpy (D->Type, Entry->Type);
+               TypeCpy (D->Type, Entry->Type);
                break;
            }
            /* FALL THROUGH */
@@ -527,30 +655,29 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
        default:
            if (Default < 0) {
                Error ("Type expected");
-               D->Type[0] = T_INT;
-               D->Type[1] = T_END;
+               D->Type[0].C = T_INT;
+               D->Type[1].C = T_END;
            } else {
-               D->Flags  |= DS_DEF_TYPE;
-               D->Type[0] = (type) Default;
-               D->Type[1] = T_END;
-           }
-           break;
+               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] |= OptionalQualifiers (Qualifiers);
+    D->Type[0].C |= OptionalQualifiers (Qualifiers);
 }
 
 
 
-static type* ParamTypeCvt (type* T)
+static Type* ParamTypeCvt (Type* T)
 /* If T is an array, convert it to a pointer else do nothing. Return the
  * resulting type.
  */
 {
     if (IsTypeArray (T)) {
-               T += DECODE_SIZE;
-       T[0] = T_PTR;
+               T->C = T_PTR;
     }
     return T;
 }
@@ -561,15 +688,15 @@ static void ParseOldStyleParamList (FuncDesc* F)
 /* Parse an old style (K&R) parameter list */
 {
     /* Parse params */
-    while (curtok != TOK_RPAREN) {
+    while (CurTok.Tok != TOK_RPAREN) {
 
        /* List of identifiers expected */
-       if (curtok != TOK_IDENT) {
+       if (CurTok.Tok != TOK_IDENT) {
            Error ("Identifier expected");
        }
 
        /* Create a symbol table entry with type int */
-       AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF, 0);
+       AddLocalSym (CurTok.Ident, type_int, SC_AUTO | SC_PARAM | SC_DEF | SC_DEFTYPE, 0);
 
        /* Count arguments */
                ++F->ParamCount;
@@ -578,7 +705,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
        NextToken ();
 
        /* Check for more parameters */
-       if (curtok == TOK_COMMA) {
+       if (CurTok.Tok == TOK_COMMA) {
            NextToken ();
        } else {
            break;
@@ -591,7 +718,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
     ConsumeRParen ();
 
     /* An optional list of type specifications follows */
-    while (curtok != TOK_LCURLY) {
+    while (CurTok.Tok != TOK_LCURLY) {
 
        DeclSpec        Spec;
 
@@ -602,31 +729,41 @@ static void ParseOldStyleParamList (FuncDesc* F)
         * we ignore all this, since we use auto anyway.
         */
        if ((Spec.StorageClass & SC_AUTO) == 0 &&
-           (Spec.StorageClass & SC_REGISTER) == 0) {
+           (Spec.StorageClass & SC_REGISTER) == 0) {
            Error ("Illegal storage class");
        }
 
        /* 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') {
 
-               /* We have a name given. Search for the symbol */
+               /* We have a name given. Search for the symbol */
                SymEntry* Sym = FindLocalSym (Decl.Ident);
                if (Sym) {
-                   /* Found it, change the default type to the one given */
-                   ChangeSymType (Sym, ParamTypeCvt (Decl.Type));
+                    /* Check if we already changed the type for this
+                     * parameter
+                     */
+                    if (Sym->Flags & SC_DEFTYPE) {
+                        /* Found it, change the default type to the one given */
+                        ChangeSymType (Sym, ParamTypeCvt (Decl.Type));
+                        /* Reset the "default type" flag */
+                        Sym->Flags &= ~SC_DEFTYPE;
+                    } else {
+                        /* Type has already been changed */
+                        Error ("Redefinition for parameter `%s'", Sym->Name);
+                    }
                } else {
                    Error ("Unknown identifier: `%s'", Decl.Ident);
                }
            }
 
-           if (curtok == TOK_COMMA) {
-               NextToken ();
+           if (CurTok.Tok == TOK_COMMA) {
+               NextToken ();
            } else {
                break;
            }
@@ -644,15 +781,15 @@ static void ParseAnsiParamList (FuncDesc* F)
 /* Parse a new style (ANSI) parameter list */
 {
     /* Parse params */
-    while (curtok != TOK_RPAREN) {
+    while (CurTok.Tok != TOK_RPAREN) {
 
        DeclSpec        Spec;
        Declaration     Decl;
        DeclAttr        Attr;
 
        /* Allow an ellipsis as last parameter */
-       if (curtok == TOK_ELLIPSIS) {
-           NextToken ();
+       if (CurTok.Tok == TOK_ELLIPSIS) {
+           NextToken ();
            F->Flags |= FD_VARIADIC;
            break;
        }
@@ -660,14 +797,15 @@ static void ParseAnsiParamList (FuncDesc* F)
        /* 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 and use auto.
-        */
-       if ((Spec.StorageClass & SC_AUTO) == 0 &&
-           (Spec.StorageClass & SC_REGISTER) == 0) {
+               /* 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");
+            Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
        }
-       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.
@@ -695,7 +833,7 @@ static void ParseAnsiParamList (FuncDesc* F)
                ++F->ParamCount;
 
        /* Check for more parameters */
-       if (curtok == TOK_COMMA) {
+       if (CurTok.Tok == TOK_COMMA) {
            NextToken ();
        } else {
            break;
@@ -708,11 +846,12 @@ static void ParseAnsiParamList (FuncDesc* F)
     ConsumeRParen ();
 
     /* Check if this is a function definition */
-    if (curtok == TOK_LCURLY) {
-       /* Print an error if in strict ANSI mode and we have unnamed
-        * parameters.
+    if (CurTok.Tok == TOK_LCURLY) {
+       /* Print an error if we have unnamed parameters and cc65 extensions
+         * are disabled.
         */
-               if (ANSI && (F->Flags & FD_UNNAMED_PARAMS) != 0) {
+               if (IS_Get (&Standard) != STD_CC65 &&
+            (F->Flags & FD_UNNAMED_PARAMS) != 0) {
            Error ("Parameter name omitted");
        }
     }
@@ -733,22 +872,23 @@ static FuncDesc* ParseFuncDecl (void)
     EnterFunctionLevel ();
 
     /* Check for several special parameter lists */
-    if (curtok == TOK_RPAREN) {
+    if (CurTok.Tok == TOK_RPAREN) {
        /* Parameter list is empty */
        F->Flags |= (FD_EMPTY | FD_VARIADIC);
-    } else if (curtok == TOK_VOID && nxttok == TOK_RPAREN) {
+    } else if (CurTok.Tok == TOK_VOID && NextTok.Tok == TOK_RPAREN) {
        /* Parameter list declared as void */
        NextToken ();
        F->Flags |= FD_VOID_PARAM;
-    } else if (curtok == TOK_IDENT && (nxttok == TOK_COMMA || nxttok == 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 || !IsTypeDef (Sym)) {
-           /* Old style (K&R) function. Assume variable param list. */
-           F->Flags |= (FD_OLDSTYLE | FD_VARIADIC);
-       }
+    } 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;
+       }
     }
 
     /* Parse params */
@@ -760,19 +900,37 @@ static FuncDesc* ParseFuncDecl (void)
        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.
+     */
+    F->LastParam = GetSymTab()->SymTail;
+
     /* Assign offsets. If the function has a variable parameter list,
      * there's one additional byte (the arg size).
      */
     Offs = (F->Flags & FD_VARIADIC)? 1 : 0;
-    Sym = GetSymTab()->SymTail;
+    Sym = F->LastParam;
     while (Sym) {
-       unsigned Size = SizeOf (Sym->Type);
-       Sym->V.Offs = Offs;
+       unsigned Size = CheckedSizeOf (Sym->Type);
+        if (SymIsRegVar (Sym)) {
+            Sym->V.R.SaveOffs = Offs;
+        } else {
+           Sym->V.Offs = Offs;
+        }
                Offs += Size;
        F->ParamSize += Size;
        Sym = Sym->PrevSym;
     }
 
+    /* Add the default address size for the function */
+    if (CodeAddrSize == ADDR_SIZE_FAR) {
+        F->Flags |= FD_FAR;
+    } else {
+        F->Flags |= FD_NEAR;
+    }
+
     /* Leave the lexical level remembering the symbol tables */
     RememberFunctionLevel (F);
 
@@ -782,53 +940,129 @@ static FuncDesc* ParseFuncDecl (void)
 
 
 
-static void Decl (Declaration* D, unsigned Mode)
+static unsigned FunctionModifierFlags (void)
+/* Parse __fastcall__, __near__ and __far__ and return the matching FD_ flags */
+{
+    /* Read the flags */
+    unsigned Flags = FD_NONE;
+    while (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) {
+
+        /* Get the flag bit for the next token */
+        unsigned F = FD_NONE;
+        switch (CurTok.Tok) {
+            case TOK_FASTCALL:  F = FD_FASTCALL; break;
+            case TOK_NEAR:             F = FD_NEAR;     break;
+            case TOK_FAR:      F = FD_FAR;      break;
+            default:            Internal ("Unexpected token: %d", CurTok.Tok);
+        }
+
+        /* Remember the flag for this modifier */
+        if (Flags & F) {
+            Error ("Duplicate modifier");
+        }
+        Flags |= F;
+
+        /* Skip the token */
+        NextToken ();
+    }
+
+    /* Sanity check */
+    if ((Flags & (FD_NEAR | FD_FAR)) == (FD_NEAR | FD_FAR)) {
+        Error ("Cannot specify both, `__near__' and `__far__' modifiers");
+        Flags &= ~(FD_NEAR | FD_FAR);
+    }
+
+    /* Return the flags read */
+    return Flags;
+}
+
+
+
+static void ApplyFunctionModifiers (Type* T, unsigned Flags)
+/* Apply a set of function modifier flags to a function */
+{
+    /* Get the function descriptor */
+    FuncDesc* F = GetFuncDesc (T);
+
+    /* Special check for __fastcall__ */
+    if ((Flags & FD_FASTCALL) != 0 && IsVariadicFunc (T)) {
+        Error ("Cannot apply `__fastcall__' to functions with "
+               "variable parameter list");
+        Flags &= ~FD_FASTCALL;
+    }
+
+    /* Remove the default function address size modifiers */
+    F->Flags &= ~(FD_NEAR | FD_FAR);
+
+    /* Add the new modifers */
+    F->Flags |= Flags;
+}
+
+
+
+static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
 /* Recursively process declarators. Build a type array in reverse order. */
 {
+    /* Pointer to something */
+    if (CurTok.Tok == TOK_STAR) {
+
+       TypeCode C;
 
-    if (curtok == TOK_STAR) {
-       type T = T_PTR;
+        /* Skip the star */
                NextToken ();
-       /* Allow optional const or volatile qualifiers */
-       T |= OptionalQualifiers (T_QUAL_NONE);
-               Decl (D, Mode);
-               *D->T++ = T;
+
+       /* Allow optional const or volatile qualifiers */
+               C = T_PTR | OptionalQualifiers (T_QUAL_NONE);
+
+        /* Parse the type, the pointer points to */
+               Decl (Spec, D, Mode);
+
+       /* Add the type */
+       AddTypeToDeclaration (D, C);
                return;
-    } else if (curtok == TOK_LPAREN) {
+    }
+
+    /* Function modifiers */
+    if (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) {
+
+       /* Remember the current type pointer */
+       Type* T = D->Type + D->Index;
+
+       /* Read the flags */
+       unsigned Flags = FunctionModifierFlags ();
+
+       /* Parse the function */
+       Decl (Spec, D, Mode);
+
+       /* Check that we have a function */
+       if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) {
+           Error ("Function modifier applied to non function");
+       } else {
+            ApplyFunctionModifiers (T, Flags);
+        }
+
+       /* Done */
+       return;
+    }
+
+    if (CurTok.Tok == TOK_LPAREN) {
                NextToken ();
-               Decl (D, Mode);
+               Decl (Spec, D, Mode);
                ConsumeRParen ();
-    } else if (curtok == TOK_FASTCALL) {
-       /* Remember the current type pointer */
-       type* T = D->T;
-       /* Skip the fastcall token */
-       NextToken ();
-       /* Parse the function */
-       Decl (D, Mode);
-       /* Set the fastcall flag */
-       if (!IsTypeFunc (T)) {
-           Error ("__fastcall__ modifier applied to non function");
-       } else if (IsVariadicFunc (T)) {
-           Error ("Cannot apply __fastcall__ to functions with variable parameter list");
-       } else {
-           FuncDesc* F = (FuncDesc*) DecodePtr (T+1);
-                   F->Flags |= FD_FASTCALL;
-       }
-       return;
     } 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
+        *      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.
+        *      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_IDENT) {
+       } else if (CurTok.Tok == TOK_IDENT) {
                    strcpy (D->Ident, CurTok.Ident);
            NextToken ();
        } else {
@@ -836,34 +1070,43 @@ static void Decl (Declaration* D, unsigned Mode)
                Error ("Identifier expected");
            }
            D->Ident[0] = '\0';
-           return;
        }
     }
 
-    while (curtok == TOK_LBRACK || curtok == TOK_LPAREN) {
-               if (curtok == TOK_LPAREN) {
+    while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
+               if (CurTok.Tok == TOK_LPAREN) {
+
                    /* Function declaration */
-           FuncDesc* F;
+           FuncDesc* F;
                    NextToken ();
-           /* Parse the function declaration */
+
+           /* Parse the function declaration */
                    F = ParseFuncDecl ();
-           *D->T++ = T_FUNC;
-           EncodePtr (D->T, F);
-           D->T += DECODE_SIZE;
+
+           /* Add the function type. Be sure to bounds check the type buffer */
+           AddFuncTypeToDeclaration (D, F);
                } else {
-           /* Array declaration */
-                   unsigned long Size = 0;
+           /* Array declaration */
+                   long Size = UNSPECIFIED;
                    NextToken ();
-           /* Read the size if it is given */
-                   if (curtok != TOK_RBRACK) {
-               struct expent lval;
-                       constexpr (&lval);
-                       Size = lval.e_const;
+           /* 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);
+                    } else {
+                        Error ("Size of array is invalid");
+                    }
+                    Expr.IVal = 1;
+                }
+                       Size = Expr.IVal;
                    }
                    ConsumeRBrack ();
-                   *D->T++ = T_ARRAY;
-                   Encode (D->T, Size);
-                   D->T += DECODE_SIZE;
+
+           /* Add the array type with the size */
+           AddArrayToDeclaration (D, Size);
                }
     }
 }
@@ -876,7 +1119,7 @@ static void Decl (Declaration* D, unsigned Mode)
 
 
 
-type* ParseType (type* Type)
+Type* ParseType (Type* T)
 /* Parse a complete type specification */
 {
     DeclSpec Spec;
@@ -884,17 +1127,16 @@ type* ParseType (type* Type)
 
     /* Get a type without a default */
     InitDeclSpec (&Spec);
-    ParseTypeSpec (&Spec, -1);
+    ParseTypeSpec (&Spec, -1, T_QUAL_NONE);
 
     /* Parse additional declarators */
-    InitDeclaration (&Decl);
     ParseDecl (&Spec, &Decl, DM_NO_IDENT);
 
     /* Copy the type to the target buffer */
-    TypeCpy (Type, Decl.Type);
+    TypeCpy (T, Decl.Type);
 
     /* Return a pointer to the target buffer */
-    return Type;
+    return T;
 }
 
 
@@ -906,34 +1148,87 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
     InitDeclaration (D);
 
     /* Get additional declarators and the identifier */
-    Decl (D, Mode);
+    Decl (Spec, D, Mode);
 
     /* Add the base type. */
-    TypeCpy (D->T, Spec->Type);
+    NeedTypeSpace (D, TypeLen (Spec->Type) + 1);       /* Bounds check */
+    TypeCpy (D->Type + D->Index, Spec->Type);
+
+    /* Fix any type qualifiers attached to an array type */
+    FixArrayQualifiers (D->Type);
+
+    /* Check several things for function or function pointer types */
+    if (IsTypeFunc (D->Type) || IsTypeFuncPtr (D->Type)) {
+
+        /* A function. Check the return type */
+        Type* RetType = GetFuncReturn (D->Type);
+
+        /* Functions may not return functions or arrays */
+        if (IsTypeFunc (RetType)) {
+            Error ("Functions are not allowed to return functions");
+        } else if (IsTypeArray (RetType)) {
+            Error ("Functions are not allowed to return arrays");
+        }
+
+        /* The return type must not be qualified */
+        if (GetQualifier (RetType) != T_QUAL_NONE && RetType[1].C == T_END) {
+
+            if (GetType (RetType) == T_TYPE_VOID) {
+                /* A qualified void type is always an error */
+                Error ("function definition has qualified void return type");
+            } else {
+                /* For others, qualifiers are ignored */
+                Warning ("type qualifiers ignored on function return type");
+                RetType[0].C = UnqualifiedType (RetType[0].C);
+            }
+        }
+
+        /* Warn about an implicit int return in the function */
+        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.
+             */
+            if (IS_Get (&Standard) >= STD_C99) {
+                Warning ("Implicit `int' return type is an obsolete feature");
+            }
+            GetFuncDesc (D->Type)->Flags |= FD_OLDSTYLE_INTRET;
+        }
+
+    }
 
     /* Check the size of the generated type */
-    if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type) && SizeOf (D->Type) >= 0x10000) {
-       if (D->Ident[0] != '\0') {
-           Error ("Size of `%s' is invalid", D->Ident);
-       } else {
-           Error ("Invalid size");
-       }
+    if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type)) {
+        unsigned Size = SizeOf (D->Type);
+        if (Size >= 0x10000) {
+            if (D->Ident[0] != '\0') {
+                Error ("Size of `%s' is invalid (0x%06X)", D->Ident, Size);
+            } else {
+                Error ("Invalid size in declaration (0x%06X)", Size);
+            }
+        }
     }
+
 }
 
 
 
-void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
+void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, long DefType)
 /* Parse a declaration specification */
 {
+    TypeCode Qualifiers;
+
     /* Initialize the DeclSpec struct */
     InitDeclSpec (D);
 
-    /* First, get the storage class specifier for this declaration */
+    /* There may be qualifiers *before* the storage class specifier */
+    Qualifiers = OptionalQualifiers (T_QUAL_NONE);
+
+    /* Now get the storage class specifier for this declaration */
     ParseStorageClass (D, DefStorage);
 
-    /* Parse the type specifiers */
-    ParseTypeSpec (D, DefType);
+    /* Parse the type specifiers passing any initial type qualifiers */
+    ParseTypeSpec (D, DefType, Qualifiers);
 }
 
 
@@ -951,73 +1246,279 @@ void CheckEmptyDecl (const DeclSpec* D)
 
 
 
-static void ParseVoidInit (void)
-/* Parse an initialization of a void variable (special cc65 extension) */
+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.
+ */
 {
-    struct expent lval;
+    while (CurTok.Tok != TOK_CEOF && CurTok.Tok != TOK_SEMI && BracesExpected > 0) {
+        switch (CurTok.Tok) {
+            case TOK_RCURLY:    --BracesExpected;   break;
+            case TOK_LCURLY:    ++BracesExpected;   break;
+            default:                                break;
+        }
+        NextToken ();
+    }
+}
 
-    /* Allow an arbitrary list of values */
-    ConsumeLCurly ();
-    do {
-       constexpr (&lval);
-       switch (lval.e_tptr[0]) {
 
-           case T_SCHAR:
-           case T_UCHAR:
-               if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
-                   /* Make it byte sized */
-                   lval.e_const &= 0xFF;
-               }
-               DefineData (&lval);
-               break;
 
-           case T_SHORT:
-           case T_USHORT:
-           case T_INT:
-           case T_UINT:
-           case T_PTR:
-           case T_ARRAY:
-               if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
-                   /* Make it word sized */
-                   lval.e_const &= 0xFFFF;
-               }
-               DefineData (&lval);
-               break;
+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.
+ */
+{
+    unsigned BraceCount = 0;
+    while (CurTok.Tok == TOK_LCURLY) {
+        ++BraceCount;
+        NextToken ();
+    }
+    if (BraceCount < BracesNeeded) {
+        Error ("`{' expected");
+    }
+    return BraceCount;
+}
 
-           case T_LONG:
-           case T_ULONG:
-               DefineData (&lval);
-               break;
 
-           default:
-               Error ("Illegal type in initialization");
-               break;
 
-       }
+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.
+ */
+{
+    while (BracesExpected) {
+        if (CurTok.Tok == TOK_RCURLY) {
+            NextToken ();
+        } else if (CurTok.Tok == TOK_COMMA && NextTok.Tok == TOK_RCURLY) {
+            NextToken ();
+            NextToken ();
+        } else {
+            Error ("`}' expected");
+            return;
+        }
+        --BracesExpected;
+    }
+}
 
-       if (curtok != TOK_COMMA) {
-           break;
-       }
-       NextToken ();
 
-    } while (curtok != TOK_RCURLY);
 
-    ConsumeRCurly ();
+static void DefineData (ExprDesc* Expr)
+/* Output a data definition for the given expression */
+{
+    switch (ED_GetLoc (Expr)) {
+
+        case E_LOC_ABS:
+            /* Absolute: numeric address or const */
+                   g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->IVal, 0);
+            break;
+
+        case E_LOC_GLOBAL:
+            /* Global variable */
+            g_defdata (CF_EXTERNAL, Expr->Name, Expr->IVal);
+            break;
+
+        case E_LOC_STATIC:
+        case E_LOC_LITERAL:
+            /* Static variable or literal in the literal pool */
+            g_defdata (CF_STATIC, Expr->Name, Expr->IVal);
+            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");
+                   }
+            g_defdata (CF_REGVAR, Expr->Name, Expr->IVal);
+            break;
+
+        case E_LOC_STACK:
+        case E_LOC_PRIMARY:
+        case E_LOC_EXPR:
+            Error ("Non constant initializer");
+            break;
+
+               default:
+                   Internal ("Unknown constant type: 0x%04X", ED_GetLoc (Expr));
+    }
 }
 
 
 
-static void ParseStructInit (type* Type)
-/* Parse initialization of a struct or union */
+static unsigned ParseScalarInit (Type* T)
+/* Parse initializaton for scalar data types. Return the number of data bytes. */
+{
+    ExprDesc 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.
+     */
+    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);
+
+    /* Close eventually opening braces */
+    ClosingCurlyBraces (BraceCount);
+
+    /* Done */
+    return SizeOf (T);
+}
+
+
+
+static unsigned ParsePointerInit (Type* T)
+/* Parse initializaton for pointer data types. Return the number of data bytes. */
+{
+    /* Optional opening brace */
+    unsigned BraceCount = OpeningCurlyBraces (0);
+
+    /* Expression */
+    ExprDesc ED;
+    ConstExpr (hie1, &ED);
+    TypeConversion (&ED, T);
+
+    /* Output the data */
+    DefineData (&ED);
+
+    /* Close eventually opening braces */
+    ClosingCurlyBraces (BraceCount);
+
+    /* Done */
+    return SIZEOF_PTR;
+}
+
+
+
+static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
+/* Parse initializaton for arrays. Return the number of data bytes. */
+{
+    int Count;
+
+    /* Get the array data */
+    Type* ElementType    = GetElementType (T);
+    unsigned ElementSize = CheckedSizeOf (ElementType);
+    long ElementCount    = GetElementCount (T);
+
+    /* 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))) {
+
+        /* 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.
+         */
+        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);
+
+        /* If the array is one too small for the string literal, omit the
+         * trailing zero.
+         */
+        if (ElementCount != UNSPECIFIED &&
+            ElementCount != FLEXIBLE    &&
+            Count        == ElementCount + 1) {
+            /* Omit the trailing zero */
+            --Count;
+        }
+
+        /* Output the data */
+        g_defbytes (Str, Count);
+
+        /* Remove string from pool */
+        ResetLiteralPoolOffs (CurTok.IVal);
+        NextToken ();
+
+        /* If the initializer was enclosed in curly braces, we need a closing
+         * one.
+         */
+        if (NeedParen) {
+            ConsumeRCurly ();
+        }
+
+    } else {
+
+        /* Curly brace */
+        ConsumeLCurly ();
+
+        /* Initialize the array members */
+        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).
+             */
+            ParseInitInternal (ElementType, 0);
+            ++Count;
+            if (CurTok.Tok != TOK_COMMA)
+                break;
+            NextToken ();
+        }
+
+        /* Closing curly braces */
+        ConsumeRCurly ();
+    }
+
+    if (ElementCount == UNSPECIFIED) {
+        /* Number of elements determined by initializer */
+        SetElementCount (T, Count);
+        ElementCount = Count;
+    } else if (ElementCount == FLEXIBLE && AllowFlexibleMembers) {
+        /* In non ANSI mode, allow initialization of flexible array
+         * members.
+         */
+        ElementCount = Count;
+    } else if (Count < ElementCount) {
+        g_zerobytes ((ElementCount - Count) * ElementSize);
+    } else if (Count > ElementCount) {
+        Error ("Too many initializers");
+    }
+    return ElementCount * ElementSize;
+}
+
+
+
+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;
+
 
     /* Consume the opening curly brace */
     ConsumeLCurly ();
 
     /* Get a pointer to the struct entry from the type */
-    Entry = (SymEntry*) Decode (Type + 1);
+    Entry = GetSymEntry (T);
+
+    /* Get the size of the struct from the symbol table entry */
+    StructSize = Entry->V.S.Size;
 
     /* Check if this struct definition has a field table. If it doesn't, it
      * is an incomplete definition.
@@ -1025,133 +1526,185 @@ static void ParseStructInit (type* Type)
     Tab = Entry->V.S.SymTab;
     if (Tab == 0) {
        Error ("Cannot initialize variables with incomplete type");
-       /* Returning here will cause lots of errors, but recovery is difficult */
-       return;
+        /* Try error recovery */
+        SkipInitializer (1);
+       /* Nothing initialized */
+       return 0;
     }
 
     /* Get a pointer to the list of symbols */
     Entry = Tab->SymHead;
-    while (curtok != TOK_RCURLY) {
-       if (Entry == 0) {
-           Error ("Too many initializers");
-           return;
-       }
-       ParseInit (Entry->Type);
-       Entry = Entry->NextSym;
-       if (curtok != TOK_COMMA)
-           break;
-       NextToken ();
+
+    /* Initialize fields */
+    Size = 0;
+    while (CurTok.Tok != TOK_RCURLY) {
+       if (Entry == 0) {
+           Error ("Too many initializers");
+            SkipInitializer (1);
+           return Size;
+       }
+        /* Parse initialization of one field. Flexible array members may
+         * only be initialized if they are the last field (or part of the
+         * last struct field).
+         */
+       Size += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0);
+       Entry = Entry->NextSym;
+       if (CurTok.Tok != TOK_COMMA)
+           break;
+       NextToken ();
     }
 
     /* Consume the closing curly brace */
     ConsumeRCurly ();
 
     /* If there are struct fields left, reserve additional storage */
-    while (Entry) {
-       g_zerobytes (SizeOf (Entry->Type));
-       Entry = Entry->NextSym;
+    if (Size < StructSize) {
+       g_zerobytes (StructSize - Size);
+        Size = StructSize;
     }
+
+    /* 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;
 }
 
 
 
-void ParseInit (type* T)
-/* Parse initialization of variables. */
+static unsigned ParseVoidInit (void)
+/* Parse an initialization of a void variable (special cc65 extension).
+ * Return the number of bytes initialized.
+ */
 {
-    struct expent lval;
-    type* t;
-    const char* str;
-    int Count;
-    int Size;
+    ExprDesc Expr;
+    unsigned Size;
+
+    /* Opening brace */
+    ConsumeLCurly ();
+
+    /* 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);
+                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;
+                break;
+
+           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;
+
+       }
+
+       if (CurTok.Tok != TOK_COMMA) {
+           break;
+       }
+       NextToken ();
+
+    } while (CurTok.Tok != TOK_RCURLY);
+
+    /* Closing brace */
+    ConsumeRCurly ();
+
+    /* Return the number of bytes initialized */
+    return Size;
+}
+
 
-    switch (UnqualifiedType (*T)) {
+
+static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers)
+/* Parse initialization of variables. Return the number of data bytes. */
+{
+    switch (UnqualifiedType (T->C)) {
 
        case T_SCHAR:
        case T_UCHAR:
-           constexpr (&lval);
-           if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
-               /* Make it byte sized */
-               lval.e_const &= 0xFF;
-           }
-           assignadjust (T, &lval);
-           DefineData (&lval);
-           break;
-
        case T_SHORT:
        case T_USHORT:
        case T_INT:
        case T_UINT:
-       case T_PTR:
-           constexpr (&lval);
-           if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
-               /* Make it word sized */
-               lval.e_const &= 0xFFFF;
-           }
-           assignadjust (T, &lval);
-           DefineData (&lval);
-           break;
-
        case T_LONG:
        case T_ULONG:
-           constexpr (&lval);
-           if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
-               /* Make it long sized */
-               lval.e_const &= 0xFFFFFFFF;
-           }
-           assignadjust (T, &lval);
-           DefineData (&lval);
-           break;
+            return ParseScalarInit (T);
+
+       case T_PTR:
+            return ParsePointerInit (T);
 
        case T_ARRAY:
-           Size = Decode (T + 1);
-           t = T + DECODE_SIZE + 1;
-                   if (IsTypeChar(t) && curtok == TOK_SCONST) {
-               str = GetLiteral (curval);
-               Count = strlen (str) + 1;
-               TranslateLiteralPool (curval);  /* Translate into target charset */
-               g_defbytes (str, Count);
-               ResetLiteralPoolOffs (curval);  /* Remove string from pool */
-               NextToken ();
-           } else {
-               ConsumeLCurly ();
-               Count = 0;
-               while (curtok != TOK_RCURLY) {
-                   ParseInit (T + DECODE_SIZE + 1);
-                   ++Count;
-                   if (curtok != TOK_COMMA)
-                       break;
-                   NextToken ();
-               }
-               ConsumeRCurly ();
-           }
-           if (Size == 0) {
-               Encode (T + 1, Count);
-           } else if (Count < Size) {
-               g_zerobytes ((Size - Count) * SizeOf (T + DECODE_SIZE + 1));
-           } else if (Count > Size) {
-               Error ("Too many initializers");
-           }
-           break;
+            return ParseArrayInit (T, AllowFlexibleMembers);
 
         case T_STRUCT:
         case T_UNION:
-           ParseStructInit (T);
-           break;
+           return ParseStructInit (T, AllowFlexibleMembers);
 
        case T_VOID:
-           if (!ANSI) {
+           if (IS_Get (&Standard) == STD_CC65) {
                /* Special cc65 extension in non ANSI mode */
-               ParseVoidInit ();
-               break;
+               return ParseVoidInit ();
            }
            /* FALLTHROUGH */
 
        default:
            Error ("Illegal type");
-           break;
+           return SIZEOF_CHAR;
 
     }
 }
 
 
 
+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.
+     */
+    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.
+     */
+    if (HaveGlobalCode ()) {
+        Error ("Non constant initializers");
+        RemoveGlobalCode ();
+    }
+
+    /* Return the size needed for the initialization */
+    return Size;
+}
+
+
+