]> git.sur5r.net Git - cc65/blobdiff - src/cc65/declare.c
Removed unused modules
[cc65] / src / cc65 / declare.c
index 025c1046d3f82b97a30c0e3b95d1a3680b3798a1..414c353d8aa5a71ea6178af0cac78336e559d251 100644 (file)
@@ -6,8 +6,8 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
+/* (C) 1998-2004 Ullrich von Bassewitz                                       */
+/*               Römerstraße 52                                              */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 #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"
@@ -54,7 +57,7 @@
 #include "pragma.h"
 #include "scanner.h"
 #include "symtab.h"
-#include "declare.h"
+#include "typeconv.h"
 
 
 
@@ -81,7 +84,7 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers);
 static type OptionalQualifiers (type Q)
 /* Read type qualifiers if we have any */
 {
-    while (CurTok.Tok == TOK_CONST || CurTok.Tok == TOK_VOLATILE) {
+    while (TokIsTypeQual (&CurTok)) {
 
        switch (CurTok.Tok) {
 
@@ -100,8 +103,7 @@ static type OptionalQualifiers (type Q)
                break;
 
            default:
-               /* Keep gcc silent */
-               break;
+               Internal ("Unexpected type qualifier token: %d", CurTok.Tok);
 
        }
 
@@ -140,9 +142,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]          = T_END;
+    D->Flags            = 0;
 }
 
 
@@ -150,9 +152,43 @@ 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]  = 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, type T)
+/* Add a type specifier to the type of a declaration */
+{
+    NeedTypeSpace (D, 1);
+    D->Type[D->Index++] = T;
+}
+
+
+
+static void AddEncodeToDeclaration (Declaration* D, type T, unsigned long Val)
+/* Add a type plus encoding to the type of a declaration */
+{
+    NeedTypeSpace (D, DECODE_SIZE+1);
+    D->Type[D->Index++] = T;
+    Encode (D->Type + D->Index, Val);
+    D->Index += DECODE_SIZE;
 }
 
 
@@ -421,7 +457,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
                optionalsigned ();
                optionalint ();
                D->Type[0] = T_SHORT;
-               D->Type[1] = T_END;
+               D->Type[1] = T_END;
            }
            break;
 
@@ -438,7 +474,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
                        case TOK_CHAR:
                    NextToken ();
                    D->Type[0] = T_SCHAR;
-                   D->Type[1] = T_END;
+                   D->Type[1] = T_END;
                    break;
 
                case TOK_SHORT:
@@ -459,7 +495,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
                    NextToken ();
                    /* FALL THROUGH */
 
-               default:
+               default:
                    D->Type[0] = T_INT;
                    D->Type[1] = T_END;
                    break;
@@ -501,6 +537,18 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
            }
            break;
 
+        case TOK_FLOAT:
+           NextToken ();
+           D->Type[0] = T_FLOAT;
+           D->Type[1] = T_END;
+           break;
+
+        case TOK_DOUBLE:
+           NextToken ();
+           D->Type[0] = T_DOUBLE;
+           D->Type[1] = T_END;
+           break;
+
        case TOK_STRUCT:
        case TOK_UNION:
            StructType = (CurTok.Tok == TOK_STRUCT)? T_STRUCT : T_UNION;
@@ -806,11 +854,18 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
        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 = CheckedSizeOf (Sym->Type);
         if (SymIsRegVar (Sym)) {
@@ -823,6 +878,13 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
        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);
 
@@ -832,39 +894,115 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
 
 
 
+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) {
-       type T = T_PTR;
+
+       type T;
+
+        /* Skip the star */
                NextToken ();
+
        /* Allow optional const or volatile qualifiers */
-       T |= OptionalQualifiers (T_QUAL_NONE);
+               T = T_PTR | OptionalQualifiers (T_QUAL_NONE);
+
+        /* Parse the type, the pointer points to */
                Decl (Spec, D, Mode);
-               *D->T++ = T;
+
+       /* Add the type */
+       AddTypeToDeclaration (D, T);
                return;
-    } else if (CurTok.Tok == TOK_LPAREN) {
-               NextToken ();
-               Decl (Spec, D, Mode);
-               ConsumeRParen ();
-    } else if (CurTok.Tok == TOK_FASTCALL) {
+    }
+
+    /* Function modifiers */
+    if (CurTok.Tok == TOK_FASTCALL || CurTok.Tok == TOK_NEAR || CurTok.Tok == TOK_FAR) {
+
        /* Remember the current type pointer */
-       type* T = D->T;
-       /* Skip the fastcall token */
-       NextToken ();
+       type* T = D->Type + D->Index;
+
+       /* Read the flags */
+       unsigned Flags = FunctionModifierFlags ();
+
        /* Parse the function */
        Decl (Spec, D, Mode);
-       /* Set the fastcall flag */
+
+       /* Check that we have a function */
        if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) {
-           Error ("__fastcall__ modifier applied to non function");
-       } else if (IsVariadicFunc (T)) {
-           Error ("Cannot apply __fastcall__ to functions with variable parameter list");
+           Error ("Function modifier applied to non function");
        } else {
-           FuncDesc* F = GetFuncDesc (T);
-                   F->Flags |= FD_FASTCALL;
-       }
+            ApplyFunctionModifiers (T, Flags);
+        }
+
+       /* Done */
        return;
+    }
+
+    if (CurTok.Tok == TOK_LPAREN) {
+               NextToken ();
+               Decl (Spec, D, Mode);
+               ConsumeRParen ();
     } else {
        /* Things depend on Mode now:
                 *  - Mode == DM_NEED_IDENT means:
@@ -891,14 +1029,16 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
 
     while (CurTok.Tok == TOK_LBRACK || CurTok.Tok == TOK_LPAREN) {
                if (CurTok.Tok == TOK_LPAREN) {
+
                    /* Function declaration */
            FuncDesc* F;
                    NextToken ();
+
            /* Parse the function declaration */
                    F = ParseFuncDecl (Spec);
-           *D->T++ = T_FUNC;
-           EncodePtr (D->T, F);
-           D->T += DECODE_SIZE;
+
+           /* Add the function type. Be sure to bounds check the type buffer */
+           AddEncodeToDeclaration (D, T_FUNC, (unsigned long) F);
                } else {
            /* Array declaration */
                    long Size = UNSPECIFIED;
@@ -918,9 +1058,9 @@ static void Decl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
                        Size = lval.ConstVal;
                    }
                    ConsumeRBrack ();
-                   *D->T++ = T_ARRAY;
-                   Encode (D->T, Size);
-                   D->T += DECODE_SIZE;
+
+           /* Add the type */
+           AddEncodeToDeclaration (D, T_ARRAY, Size);
                }
     }
 }
@@ -944,7 +1084,6 @@ type* ParseType (type* Type)
     ParseTypeSpec (&Spec, -1);
 
     /* Parse additional declarators */
-    InitDeclaration (&Decl);
     ParseDecl (&Spec, &Decl, DM_NO_IDENT);
 
     /* Copy the type to the target buffer */
@@ -966,7 +1105,8 @@ void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned 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);
 
     /* Check the size of the generated type */
     if (!IsTypeFunc (D->Type) && !IsTypeVoid (D->Type) && SizeOf (D->Type) >= 0x10000) {
@@ -1066,28 +1206,51 @@ static void ClosingCurlyBraces (unsigned BracesExpected)
 
 
 
-static unsigned ParseSimpleInit (type* T)
-/* Parse initializaton for simple data types. Return the number of data bytes. */
+static unsigned ParseScalarInit (type* T)
+/* Parse initializaton for scalar data types. Return the number of data bytes. */
 {
-    static const unsigned long Masks[] = {
-        0x000000FFUL, 0x0000FFFFUL, 0x00FFFFFFUL, 0xFFFFFFFFUL
-    };
     ExprDesc ED;
 
     /* Optional opening brace */
     unsigned BraceCount = OpeningCurlyBraces (0);
 
-    /* Get the size of the expected type */
-    unsigned Size = SizeOf (T);
-    CHECK (Size > 0 && Size <= sizeof(Masks)/sizeof(Masks[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 (&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 (&ED);
     if ((ED.Flags & E_MCTYPE) == E_TCONST) {
         /* Make the const value the correct size */
-        ED.ConstVal &= Masks[Size-1];
+        ED.ConstVal &= 0xFFFF;
     }
-    assignadjust (T, &ED);
+    TypeConversion (&ED, T);
 
     /* Output the data */
     DefineData (&ED);
@@ -1096,7 +1259,7 @@ static unsigned ParseSimpleInit (type* T)
     ClosingCurlyBraces (BraceCount);
 
     /* Done */
-    return Size;
+    return SIZEOF_PTR;
 }
 
 
@@ -1120,6 +1283,18 @@ static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers)
 
         /* 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 */
@@ -1319,10 +1494,12 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers)
        case T_USHORT:
        case T_INT:
        case T_UINT:
-       case T_PTR:
        case T_LONG:
        case T_ULONG:
-            return ParseSimpleInit (T);
+            return ParseScalarInit (T);
+
+       case T_PTR:
+            return ParsePointerInit (T);
 
        case T_ARRAY:
             return ParseArrayInit (T, AllowFlexibleMembers);
@@ -1344,13 +1521,25 @@ static unsigned ParseInitInternal (type* T, int AllowFlexibleMembers)
 
     }
 }
-                     
+
 
 
 unsigned ParseInit (type* T)
 /* Parse initialization of variables. Return the number of data bytes. */
 {
-    return ParseInitInternal (T, !ANSI);
+    /* Parse the initialization */
+    unsigned Size = ParseInitInternal (T, !ANSI);
+
+    /* 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;
 }