]> git.sur5r.net Git - cc65/blobdiff - src/cc65/declare.c
Restructured search path handling.
[cc65] / src / cc65 / declare.c
index 47ac9431df68bf6cd1ecd5e421df0d78c9ab3659..587d7ce74b34a2ab84cf0fb83ae0e1d4b2069dbe 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2008 Ullrich von Bassewitz                                       */
-/*               Roemerstrasse 52                                            */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2010, 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                                  */
 /*****************************************************************************/
 
 
@@ -77,7 +93,7 @@ static unsigned ParseInitInternal (Type* T, int AllowFlexibleMembers);
 
 
 /*****************************************************************************/
-/*                           internal functions                             */
+/*                           Internal functions                             */
 /*****************************************************************************/
 
 
@@ -169,6 +185,17 @@ static TypeCode OptionalQualifiers (TypeCode Allowed)
                 }
                 break;
 
+            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;
 
@@ -192,6 +219,19 @@ Done:
             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;
 }
@@ -233,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;
 }
 
 
@@ -278,7 +319,7 @@ static void FixQualifiers (Type* DataType)
     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 */
@@ -601,7 +642,6 @@ static SymEntry* ParseStructDecl (const char* Name)
 
     unsigned  StructSize;
     int       FlexibleMember;
-    unsigned  Offs;
     int       BitOffs;          /* Bit offset for bit-fields */
     int       FieldWidth;       /* Width in bits, -1 if not a bit-field */
     SymTable* FieldTab;
@@ -637,6 +677,7 @@ static SymEntry* ParseStructDecl (const char* Name)
        while (1) {
 
            Declaration Decl;
+            ident       Ident;
 
             /* If we had a flexible array member before, no other fields can
              * follow.
@@ -654,10 +695,21 @@ static SymEntry* ParseStructDecl (const char* Name)
 
             /* 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
+             * 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) {
+
+                    /* 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;
                 }
@@ -677,19 +729,11 @@ static SymEntry* ParseStructDecl (const char* Name)
                     Warning ("Declaration does not declare anything");
                     goto NextMember;
                 } else {
-                    /* A bit-field without a name will just increase the
-                     * offset
-                     */
-                    BitOffs += FieldWidth;
-                    goto NextMember;
+                    /* A bit-field without a name will get an anonymous one */
+                    AnonName (Decl.Ident, "bit-field");
                 }
             }
 
-            /* Byte offset of this member is the current struct size plus any
-             * full bytes from the bit offset in case of bit-fields.
-             */
-            Offs = StructSize + (BitOffs / CHAR_BITS);
-
             /* Check if this field is a flexible array member, and
              * calculate the size of the field.
              */
@@ -701,16 +745,27 @@ static SymEntry* ParseStructDecl (const char* Name)
                 FlexibleMember = 1;
                 /* Assume zero for size calculations */
                 SetElementCount (Decl.Type, FLEXIBLE);
-            } else if (FieldWidth < 0) {
-                StructSize += CheckedSizeOf (Decl.Type);
             }
 
             /* Add a field entry to the table */
             if (FieldWidth > 0) {
+                /* 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, Offs);
+                AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, StructSize);
+                if (!FlexibleMember) {
+                    StructSize += CheckedSizeOf (Decl.Type);
+                }
             }
 
 NextMember: if (CurTok.Tok != TOK_COMMA) {
@@ -1093,7 +1148,7 @@ static void ParseAnsiParamList (FuncDesc* F)
 
        DeclSpec        Spec;
        Declaration     Decl;
-       DeclAttr        Attr;
+        SymEntry*       Sym;
 
        /* Allow an ellipsis as last parameter */
        if (CurTok.Tok == TOK_ELLIPSIS) {
@@ -1131,11 +1186,21 @@ static void ParseAnsiParamList (FuncDesc* F)
            Decl.StorageClass &= ~SC_DEF;
        }
 
-       /* Parse an attribute ### */
-       ParseAttribute (&Decl, &Attr);
+       /* Parse attributes for this parameter */
+       ParseAttribute (&Decl);
 
        /* Create a symbol table entry */
-       AddLocalSym (Decl.Ident, ParamTypeCvt (Decl.Type), Decl.StorageClass, 0);
+        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;
@@ -1152,17 +1217,6 @@ static void ParseAnsiParamList (FuncDesc* F)
      * 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");
-       }
-    }
 }
 
 
@@ -1201,8 +1255,10 @@ static FuncDesc* ParseFuncDecl (void)
 
     /* Parse params */
     if ((F->Flags & FD_OLDSTYLE) == 0) {
+
        /* New style function */
        ParseAnsiParamList (F);
+
     } else {
        /* Old style function */
        ParseOldStyleParamList (F);
@@ -1373,6 +1429,9 @@ static void Declarator (const DeclSpec* Spec, Declaration* D, declmode_t Mode)
     if (Qualifiers & T_QUAL_FASTCALL) {
         Error ("Invalid `__fastcall__' qualifier");
     }
+    if (Qualifiers & T_QUAL_CDECL) {
+        Error ("Invalid `__cdecl__' qualifier");
+    }
 }
 
 
@@ -1429,6 +1488,9 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, declmode_t 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)) {
 
@@ -1633,11 +1695,29 @@ static void DefineData (ExprDesc* 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);
 
@@ -1649,14 +1729,25 @@ static unsigned ParseScalarInit (Type* T)
     }
 
     /* 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);
@@ -1699,12 +1790,12 @@ 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.
@@ -1714,16 +1805,13 @@ static unsigned ParseArrayInit (Type* T, int AllowFlexibleMembers)
             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.
          */
+        Count = GetLiteralSize (CurTok.SVal);
         if (ElementCount != UNSPECIFIED &&
             ElementCount != FLEXIBLE    &&
             Count        == ElementCount + 1) {
@@ -1732,10 +1820,9 @@ 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
@@ -1790,10 +1877,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 */
@@ -1803,68 +1889,139 @@ 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.
      */
     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;
+           return SI.Offs;
        }
-        /* 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).
+
+        /* Parse initialization of one field. Bit-fields need a special
+         * handling.
          */
-       Size += ParseInitInternal (Entry->Type, AllowFlexibleMembers && Entry->NextSym == 0);
+        if (SymIsBitField (Entry)) {
 
-        /* For unions, only the first member can be initialized */
-        if (IsTypeStruct (T)) {
-            /* Struct */
-            Entry = Entry->NextSym;
-        } else {        
-            /* Union */
-            Entry = 0;
+            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) {
-           NextToken ();
-        } else {
+               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).
+     * larger than sizeof (Struct) if flexible array members are present and
+     * were initialized (possible in non ANSI mode).
      */
-    return Size;
+    return SI.Offs;
 }