]> git.sur5r.net Git - cc65/blobdiff - src/cc65/declare.c
Move default segment names into segnames.h
[cc65] / src / cc65 / declare.c
index c05322f2f74743a808e48d5dbce982fdf7e7b755..b6e78e27c5ddddea7b19e4d0f041aca5bb33a2cf 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2002 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* (C) 1998-2003 Ullrich von Bassewitz                                       */
+/*               Römerstrasse 52                                             */
+/*               D-70794 Filderstadt                                         */
+/* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -67,6 +67,9 @@
 static void ParseTypeSpec (DeclSpec* D, int Default);
 /* Parse a type specificier */
 
+static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers);
+/* Parse initialization of variables. Return the number of data bytes. */
+
 
 
 /*****************************************************************************/
@@ -83,7 +86,7 @@ static type OptionalQualifiers (type Q)
        switch (CurTok.Tok) {
 
            case TOK_CONST:
-               if (Q & T_QUAL_CONST) {
+               if (Q & T_QUAL_CONST) {
                    Error ("Duplicate qualifier: `const'");
                }
                Q |= T_QUAL_CONST;
@@ -251,8 +254,10 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
 /* Parse a struct/union declaration. */
 {
 
-    unsigned Size;
-    unsigned Offs;
+    unsigned  StructSize;
+    unsigned  FieldSize;
+    unsigned  Offs;
+    int       FlexibleMember;
     SymTable* FieldTab;
     SymEntry* Entry;
 
@@ -282,7 +287,8 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
     EnterStructLevel ();
 
     /* Parse struct fields */
-    Size = 0;
+    FlexibleMember = 0;
+    StructSize     = 0;
     while (CurTok.Tok != TOK_RCURLY) {
 
        /* Get the type of the entry */
@@ -293,25 +299,55 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
        /* 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 */
+                    Encode (Decl.Type + 1, FLEXIBLE);
+                } else {
+                    StructSize += CheckedSizeOf (Decl.Type);
+                }
 
-           /* Calculate offset of next field/size of the union */
-           Offs = CheckedSizeOf (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 != 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 ();
@@ -325,7 +361,7 @@ 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);
 }
 
 
@@ -336,7 +372,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
     ident      Ident;
     SymEntry*  Entry;
     type       StructType;
-    type       Qualifiers;     /* Type qualifiers */
+    type       Qualifiers;     /* Type qualifiers */
 
     /* Assume we have an explicit type */
     D->Flags &= ~DS_DEF_TYPE;
@@ -417,14 +453,14 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
                    optionalint ();
                    D->Type[0] = T_LONG;
                    D->Type[1] = T_END;
-                   break;
+                   break;
 
                case TOK_INT:
                    NextToken ();
                    /* FALL THROUGH */
 
                default:
-                   D->Type[0] = T_INT;
+                   D->Type[0] = T_INT;
                    D->Type[1] = T_END;
                    break;
            }
@@ -454,13 +490,13 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
                    D->Type[1] = 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[1] = T_END;
                    break;
            }
            break;
@@ -497,7 +533,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
                        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 */
@@ -516,7 +552,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
 
         case TOK_IDENT:
            Entry = FindSym (CurTok.Ident);
-           if (Entry && IsTypeDef (Entry)) {
+           if (Entry && SymIsTypeDef (Entry)) {
                        /* It's a typedef */
                NextToken ();
                TypeCpy (D->Type, Entry->Type);
@@ -626,7 +662,7 @@ static void ParseOldStyleParamList (FuncDesc* F)
            }
 
            if (CurTok.Tok == TOK_COMMA) {
-               NextToken ();
+               NextToken ();
            } else {
                break;
            }
@@ -660,14 +696,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.
@@ -720,7 +757,7 @@ static void ParseAnsiParamList (FuncDesc* F)
 
 
 
-static FuncDesc* ParseFuncDecl (void)
+static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
 /* Parse the argument list of a function. */
 {
     unsigned Offs;
@@ -741,15 +778,23 @@ static FuncDesc* ParseFuncDecl (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 || !IsTypeDef (Sym)) {
-           /* Old style (K&R) function. Assume variable param list. */
-           F->Flags |= (FD_OLDSTYLE | FD_VARIADIC);
-       }
+              (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. Assume variable param list. */
+           F->Flags |= (FD_OLDSTYLE | FD_VARIADIC);
+       }
+    }
+
+    /* Check for an implicit int return in the function */
+    if ((Spec->Flags & DS_DEF_TYPE) != 0 &&
+        Spec->Type[0] == T_INT                  &&
+        Spec->Type[1] == T_END) {
+        /* Function has an implicit int return */
+        F->Flags |= FD_OLDSTYLE_INTRET;
     }
 
     /* Parse params */
@@ -768,7 +813,11 @@ static FuncDesc* ParseFuncDecl (void)
     Sym = GetSymTab()->SymTail;
     while (Sym) {
        unsigned Size = CheckedSizeOf (Sym->Type);
-       Sym->V.Offs = Offs;
+        if (SymIsRegVar (Sym)) {
+            Sym->V.R.SaveOffs = Offs;
+        } else {
+           Sym->V.Offs = Offs;
+        }
                Offs += Size;
        F->ParamSize += Size;
        Sym = Sym->PrevSym;
@@ -783,21 +832,21 @@ static FuncDesc* ParseFuncDecl (void)
 
 
 
-static void Decl (Declaration* D, unsigned Mode)
+static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
 /* Recursively process declarators. Build a type array in reverse order. */
 {
 
     if (CurTok.Tok == TOK_STAR) {
-       type T = T_PTR;
+       type T = T_PTR;
                NextToken ();
-       /* Allow optional const or volatile qualifiers */
-       T |= OptionalQualifiers (T_QUAL_NONE);
-               Decl (D, Mode);
+       /* Allow optional const or volatile qualifiers */
+       T |= OptionalQualifiers (T_QUAL_NONE);
+               Decl (Spec, D, Mode);
                *D->T++ = T;
                return;
     } else if (CurTok.Tok == TOK_LPAREN) {
                NextToken ();
-               Decl (D, Mode);
+               Decl (Spec, D, Mode);
                ConsumeRParen ();
     } else if (CurTok.Tok == TOK_FASTCALL) {
        /* Remember the current type pointer */
@@ -805,7 +854,7 @@ static void Decl (Declaration* D, unsigned Mode)
        /* Skip the fastcall token */
        NextToken ();
        /* Parse the function */
-       Decl (D, Mode);
+       Decl (Spec, D, Mode);
        /* Set the fastcall flag */
        if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) {
            Error ("__fastcall__ modifier applied to non function");
@@ -821,11 +870,11 @@ static void Decl (Declaration* D, unsigned Mode)
                 *  - 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';
@@ -837,7 +886,6 @@ static void Decl (Declaration* D, unsigned Mode)
                Error ("Identifier expected");
            }
            D->Ident[0] = '\0';
-           return;
        }
     }
 
@@ -847,18 +895,26 @@ static void Decl (Declaration* D, unsigned Mode)
            FuncDesc* F;
                    NextToken ();
            /* Parse the function declaration */
-                   F = ParseFuncDecl ();
+                   F = ParseFuncDecl (Spec);
            *D->T++ = T_FUNC;
            EncodePtr (D->T, F);
            D->T += DECODE_SIZE;
                } else {
            /* Array declaration */
-                   unsigned long Size = 0;
+                   long Size = UNSPECIFIED;
                    NextToken ();
            /* Read the size if it is given */
                    if (CurTok.Tok != TOK_RBRACK) {
                ExprDesc lval;
                        ConstExpr (&lval);
+                if (lval.ConstVal <= 0) {
+                    if (D->Ident[0] != '\0') {
+                        Error ("Size of array `%s' is invalid", D->Ident);
+                    } else {
+                        Error ("Size of array is invalid");
+                    }
+                    lval.ConstVal = 1;
+                }
                        Size = lval.ConstVal;
                    }
                    ConsumeRBrack ();
@@ -907,18 +963,18 @@ 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);
 
     /* 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 (D->Ident[0] != '\0') {
+           Error ("Size of `%s' is invalid", D->Ident);
+       } else {
+           Error ("Invalid size");
+       }
     }
 }
 
@@ -952,16 +1008,21 @@ void CheckEmptyDecl (const DeclSpec* D)
 
 
 
-static void ParseVoidInit (void)
-/* Parse an initialization of a void variable (special cc65 extension) */
+static unsigned ParseVoidInit (void)
+/* Parse an initialization of a void variable (special cc65 extension).
+ * Return the number of bytes initialized.
+ */
 {
     ExprDesc lval;
+    unsigned Size;
 
-    /* Allow an arbitrary list of values */
     ConsumeLCurly ();
+
+    /* Allow an arbitrary list of values */
+    Size = 0;
     do {
        ConstExpr (&lval);
-       switch (lval.Type[0]) {
+       switch (UnqualifiedType (lval.Type[0])) {
 
            case T_SCHAR:
            case T_UCHAR:
@@ -970,7 +1031,8 @@ static void ParseVoidInit (void)
                    lval.ConstVal &= 0xFF;
                }
                DefineData (&lval);
-               break;
+                Size += SIZEOF_CHAR;
+                break;
 
            case T_SHORT:
            case T_USHORT:
@@ -978,47 +1040,58 @@ static void ParseVoidInit (void)
            case T_UINT:
            case T_PTR:
            case T_ARRAY:
-               if ((lval.Flags & E_MCTYPE) == E_TCONST) {
-                   /* Make it word sized */
-                   lval.ConstVal &= 0xFFFF;
-               }
-               DefineData (&lval);
-               break;
+               if ((lval.Flags & E_MCTYPE) == E_TCONST) {
+                   /* Make it word sized */
+                   lval.ConstVal &= 0xFFFF;
+               }
+               DefineData (&lval);
+               Size += SIZEOF_INT;
+                break;
 
            case T_LONG:
            case T_ULONG:
-               DefineData (&lval);
-               break;
+               DefineData (&lval);
+               Size += SIZEOF_LONG;
+                break;
 
            default:
-               Error ("Illegal type in initialization");
+               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 ();
+
+    /* Return the number of bytes initialized */
+    return Size;
 }
 
 
 
-static void ParseStructInit (type* Type)
-/* Parse initialization of a struct or union */
+static unsigned ParseStructInit (type* Type, 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 = DecodePtr (Type + 1);
+
+    /* 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.
@@ -1026,44 +1099,58 @@ 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;
+       /* Returning here will cause lots of errors, but recovery is difficult */
+       return 0;
     }
 
     /* Get a pointer to the list of symbols */
     Entry = Tab->SymHead;
+
+    /* Initialize fields */
+    Size = 0;
     while (CurTok.Tok != TOK_RCURLY) {
-       if (Entry == 0) {
-           Error ("Too many initializers");
-           return;
-       }
-       ParseInit (Entry->Type);
-       Entry = Entry->NextSym;
-       if (CurTok.Tok != TOK_COMMA)
-           break;
-       NextToken ();
+       if (Entry == 0) {
+           Error ("Too many initializers");
+           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 (CheckedSizeOf (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 ParseInitInternal (type* T, int AllowFlexibleMembers)
+/* Parse initialization of variables. Return the number of data bytes. */
 {
-    ExprDesc lval;
-    type* t;
+    ExprDesc    lval;
     const char* str;
-    int Count;
-    int Size;
+    int         Count;
+    type*       ElementType;
+    unsigned    ElementSize;
+    long        ElementCount;
 
     switch (UnqualifiedType (*T)) {
 
@@ -1076,7 +1163,7 @@ void ParseInit (type* T)
            }
            assignadjust (T, &lval);
            DefineData (&lval);
-           break;
+           return SIZEOF_CHAR;
 
        case T_SHORT:
        case T_USHORT:
@@ -1090,7 +1177,7 @@ void ParseInit (type* T)
            }
            assignadjust (T, &lval);
            DefineData (&lval);
-           break;
+           return SIZEOF_INT;
 
        case T_LONG:
        case T_ULONG:
@@ -1101,23 +1188,31 @@ void ParseInit (type* T)
            }
            assignadjust (T, &lval);
            DefineData (&lval);
-           break;
+           return SIZEOF_LONG;
 
        case T_ARRAY:
-           Size = Decode (T + 1);
-           t = T + DECODE_SIZE + 1;
-                   if (IsTypeChar(t) && CurTok.Tok == TOK_SCONST) {
+            ElementType  = GetElementType (T);
+            ElementSize  = CheckedSizeOf (ElementType);
+           ElementCount = GetElementCount (T);
+                   if (IsTypeChar (ElementType) && CurTok.Tok == TOK_SCONST) {
+                /* Char array initialized by string constant */
                str = GetLiteral (CurTok.IVal);
-               Count = strlen (str) + 1;
-               TranslateLiteralPool (CurTok.IVal);     /* Translate into target charset */
+               Count = GetLiteralPoolOffs () - CurTok.IVal;
+                /* Translate into target charset */
+               TranslateLiteralPool (CurTok.IVal);
                g_defbytes (str, Count);
-               ResetLiteralPoolOffs (CurTok.IVal);     /* Remove string from pool */
+                /* Remove string from pool */
+               ResetLiteralPoolOffs (CurTok.IVal);
                NextToken ();
            } else {
                ConsumeLCurly ();
                Count = 0;
                while (CurTok.Tok != TOK_RCURLY) {
-                   ParseInit (T + DECODE_SIZE + 1);
+                    /* 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;
@@ -1125,34 +1220,47 @@ void ParseInit (type* T)
                }
                ConsumeRCurly ();
            }
-           if (Size == 0) {
+           if (ElementCount == UNSPECIFIED) {
+                /* Number of elements determined by initializer */
                Encode (T + 1, Count);
-           } else if (Count < Size) {
-               g_zerobytes ((Size - Count) * CheckedSizeOf (T + DECODE_SIZE + 1));
-           } else if (Count > Size) {
+                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");
            }
-           break;
+            return ElementCount * ElementSize;
 
         case T_STRUCT:
         case T_UNION:
-           ParseStructInit (T);
-           break;
+           return ParseStructInit (T, AllowFlexibleMembers);
 
        case T_VOID:
            if (!ANSI) {
                /* 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. */
+{
+    return ParseInitInternal (T, !ANSI);
+}
+
+
+