]> git.sur5r.net Git - cc65/blobdiff - src/cc65/datatype.c
Made C's sizeof operator work with initialized void variables.
[cc65] / src / cc65 / datatype.c
index 4c7e23ff0890c047260237c2e3adefb3f80f5502..2d54316cd9cbba88b28f97773107e48c8e132cac 100644 (file)
@@ -1,15 +1,15 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                               datatype.c                                 */
+/*                                datatype.c                                 */
 /*                                                                           */
-/*              Type string handling for the cc65 C compiler                */
+/*               Type string handling for the cc65 C compiler                */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2006 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2015, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 #include <string.h>
 
 /* common */
+#include "addrsize.h"
 #include "check.h"
+#include "mmodel.h"
 #include "xmalloc.h"
 
 /* cc65 */
 #include "codegen.h"
 #include "datatype.h"
 #include "error.h"
+#include "fp.h"
 #include "funcdesc.h"
 #include "global.h"
 #include "symtab.h"
@@ -50,7 +53,7 @@
 
 
 /*****************************************************************************/
-/*                                  Data                                    */
+/*                                   Data                                    */
 /*****************************************************************************/
 
 
@@ -70,7 +73,7 @@ Type type_double[]      = { TYPE(T_DOUBLE), TYPE(T_END) };
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                   Code                                    */
 /*****************************************************************************/
 
 
@@ -80,23 +83,23 @@ unsigned TypeLen (const Type* T)
 {
     const Type* Start = T;
     while (T->C != T_END) {
-       ++T;
+        ++T;
     }
     return T - Start;
 }
 
 
 
-Type* TypeCpy (Type* Dest, const Type* Src)
+Type* TypeCopy (Type* Dest, const Type* Src)
 /* Copy a type string */
 {
     Type* Orig = Dest;
     while (1) {
-       *Dest = *Src;
+        *Dest = *Src;
         if (Src->C == T_END) {
             break;
         }
-       Src++;
+        Src++;
         Dest++;
     }
     return Orig;
@@ -115,8 +118,8 @@ Type* TypeDup (const Type* T)
 
 Type* TypeAlloc (unsigned Len)
 /* Allocate memory for a type string of length Len. Len *must* include the
- * trailing T_END.
- */
+** trailing T_END.
+*/
 {
     return xmalloc (Len * sizeof (Type));
 }
@@ -135,9 +138,9 @@ int SignExtendChar (int C)
 /* Do correct sign extension of a character */
 {
     if (IS_Get (&SignedChars) && (C & 0x80) != 0) {
-               return C | ~0xFF;
+        return C | ~0xFF;
     } else {
-               return C & 0xFF;
+        return C & 0xFF;
     }
 }
 
@@ -184,7 +187,7 @@ Type* GetImplicitFuncType (void)
     F->TagTab = &EmptySymTab;
 
     /* Fill the type string */
-    T[0].C   = T_FUNC;
+    T[0].C   = T_FUNC | CodeAddrSizeQualifier ();
     T[0].A.P = F;
     T[1].C   = T_INT;
     T[2].C   = T_END;
@@ -197,17 +200,17 @@ Type* GetImplicitFuncType (void)
 
 Type* PointerTo (const Type* T)
 /* Return a type string that is "pointer to T". The type string is allocated
- * on the heap and may be freed after use.
- */
+** on the heap and may be freed after use.
+*/
 {
     /* Get the size of the type string including the terminator */
     unsigned Size = TypeLen (T) + 1;
 
     /* Allocate the new type string */
-    Type* P = TypeAlloc        (Size + 1);
+    Type* P = TypeAlloc (Size + 1);
 
     /* Create the return type... */
-    P[0].C = T_PTR;
+    P[0].C = T_PTR | (T[0].C & T_QUAL_ADDRSIZE);
     memcpy (P+1, T, Size * sizeof (Type));
 
     /* ...and return it */
@@ -218,12 +221,12 @@ Type* PointerTo (const Type* T)
 
 static TypeCode PrintTypeComp (FILE* F, TypeCode C, TypeCode Mask, const char* Name)
 /* Check for a specific component of the type. If it is there, print the
- * name and remove it. Return the type with the component removed.
- */
+** name and remove it. Return the type with the component removed.
+*/
 {
     if ((C & Mask) == Mask) {
-       fprintf (F, "%s ", Name);
-       C &= ~Mask;
+        fprintf (F, "%s ", Name);
+        C &= ~Mask;
     }
     return C;
 }
@@ -239,69 +242,73 @@ void PrintType (FILE* F, const Type* T)
         /* Get the type code */
         TypeCode C = T->C;
 
-       /* Print any qualifiers */
-               C = PrintTypeComp (F, C, T_QUAL_CONST, "const");
-       C = PrintTypeComp (F, C, T_QUAL_VOLATILE, "volatile");
+        /* Print any qualifiers */
+        C = PrintTypeComp (F, C, T_QUAL_CONST, "const");
+        C = PrintTypeComp (F, C, T_QUAL_VOLATILE, "volatile");
         C = PrintTypeComp (F, C, T_QUAL_RESTRICT, "restrict");
-
-       /* Signedness. Omit the signedness specifier for long and int */
-               if ((C & T_MASK_TYPE) != T_TYPE_INT && (C & T_MASK_TYPE) != T_TYPE_LONG) {
-           C = PrintTypeComp (F, C, T_SIGN_SIGNED, "signed");
-       }
-       C = PrintTypeComp (F, C, T_SIGN_UNSIGNED, "unsigned");
-
-       /* Now check the real type */
-       switch (C & T_MASK_TYPE) {
-           case T_TYPE_CHAR:
-               fprintf (F, "char");
-               break;
-           case T_TYPE_SHORT:
-               fprintf (F, "short");
-               break;
-           case T_TYPE_INT:
-               fprintf (F, "int");
-               break;
-           case T_TYPE_LONG:
-               fprintf (F, "long");
-               break;
-           case T_TYPE_LONGLONG:
-               fprintf (F, "long long");
-               break;
-           case T_TYPE_FLOAT:
-               fprintf (F, "float");
-               break;
-           case T_TYPE_DOUBLE:
-               fprintf (F, "double");
-               break;
-           case T_TYPE_VOID:
-               fprintf (F, "void");
-               break;
-           case T_TYPE_STRUCT:
-               fprintf (F, "struct %s", ((SymEntry*) T->A.P)->Name);
-               break;
-           case T_TYPE_UNION:
-               fprintf (F, "union %s", ((SymEntry*) T->A.P)->Name);
-               break;
-           case T_TYPE_ARRAY:
-               /* Recursive call */
-               PrintType (F, T + 1);
-               if (T->A.L == UNSPECIFIED) {
-                   fprintf (F, "[]");
-               } else {
-                   fprintf (F, "[%ld]", T->A.L);
-               }
-               return;
-           case T_TYPE_PTR:
-               /* Recursive call */
-               PrintType (F, T + 1);
-               fprintf (F, "*");
-               return;
-           case T_TYPE_FUNC:
-               fprintf (F, "function returning ");
-               break;
-           default:
-               fprintf (F, "unknown type: %04lX", T->C);
-       }
+        C = PrintTypeComp (F, C, T_QUAL_NEAR, "__near__");
+        C = PrintTypeComp (F, C, T_QUAL_FAR, "__far__");
+        C = PrintTypeComp (F, C, T_QUAL_FASTCALL, "__fastcall__");
+        C = PrintTypeComp (F, C, T_QUAL_CDECL, "__cdecl__");
+
+        /* Signedness. Omit the signedness specifier for long and int */
+        if ((C & T_MASK_TYPE) != T_TYPE_INT && (C & T_MASK_TYPE) != T_TYPE_LONG) {
+            C = PrintTypeComp (F, C, T_SIGN_SIGNED, "signed");
+        }
+        C = PrintTypeComp (F, C, T_SIGN_UNSIGNED, "unsigned");
+
+        /* Now check the real type */
+        switch (C & T_MASK_TYPE) {
+            case T_TYPE_CHAR:
+                fprintf (F, "char");
+                break;
+            case T_TYPE_SHORT:
+                fprintf (F, "short");
+                break;
+            case T_TYPE_INT:
+                fprintf (F, "int");
+                break;
+            case T_TYPE_LONG:
+                fprintf (F, "long");
+                break;
+            case T_TYPE_LONGLONG:
+                fprintf (F, "long long");
+                break;
+            case T_TYPE_FLOAT:
+                fprintf (F, "float");
+                break;
+            case T_TYPE_DOUBLE:
+                fprintf (F, "double");
+                break;
+            case T_TYPE_VOID:
+                fprintf (F, "void");
+                break;
+            case T_TYPE_STRUCT:
+                fprintf (F, "struct %s", ((SymEntry*) T->A.P)->Name);
+                break;
+            case T_TYPE_UNION:
+                fprintf (F, "union %s", ((SymEntry*) T->A.P)->Name);
+                break;
+            case T_TYPE_ARRAY:
+                /* Recursive call */
+                PrintType (F, T + 1);
+                if (T->A.L == UNSPECIFIED) {
+                    fprintf (F, " []");
+                } else {
+                    fprintf (F, " [%ld]", T->A.L);
+                }
+                return;
+            case T_TYPE_PTR:
+                /* Recursive call */
+                PrintType (F, T + 1);
+                fprintf (F, " *");
+                return;
+            case T_TYPE_FUNC:
+                fprintf (F, "function returning ");
+                break;
+            default:
+                fprintf (F, "unknown type: %04lX", T->C);
+        }
 
         /* Next element */
         ++T;
@@ -318,33 +325,36 @@ void PrintFuncSig (FILE* F, const char* Name, Type* T)
 
     /* Print a comment with the function signature */
     PrintType (F, GetFuncReturn (T));
-    if (D->Flags & FD_NEAR) {
+    if (IsQualNear (T)) {
         fprintf (F, " __near__");
     }
-    if (D->Flags & FD_FAR) {
+    if (IsQualFar (T)) {
         fprintf (F, " __far__");
     }
-    if (D->Flags & FD_FASTCALL) {
-       fprintf (F, " __fastcall__");
+    if (IsQualFastcall (T)) {
+        fprintf (F, " __fastcall__");
+    }
+    if (IsQualCDecl (T)) {
+        fprintf (F, " __cdecl__");
     }
     fprintf (F, " %s (", Name);
 
     /* Parameters */
     if (D->Flags & FD_VOID_PARAM) {
-       fprintf (F, "void");
+        fprintf (F, "void");
     } else {
-       unsigned I;
-       SymEntry* E = D->SymTab->SymHead;
-       for (I = 0; I < D->ParamCount; ++I) {
-           if (I > 0) {
-               fprintf (F, ", ");
-           }
+        unsigned I;
+        SymEntry* E = D->SymTab->SymHead;
+        for (I = 0; I < D->ParamCount; ++I) {
+            if (I > 0) {
+                fprintf (F, ", ");
+            }
             if (SymIsRegVar (E)) {
                 fprintf (F, "register ");
             }
-           PrintType (F, E->Type);
-           E = E->NextSym;
-       }
+            PrintType (F, E->Type);
+            E = E->NextSym;
+        }
     }
 
     /* End of parameter list */
@@ -357,7 +367,7 @@ void PrintRawType (FILE* F, const Type* T)
 /* Print a type string in raw format (for debugging) */
 {
     while (T->C != T_END) {
-               fprintf (F, "%04lX ", T->C);
+        fprintf (F, "%04lX ", T->C);
         ++T;
     }
     fprintf (F, "\n");
@@ -378,57 +388,65 @@ unsigned SizeOf (const Type* T)
 {
     switch (UnqualifiedType (T->C)) {
 
-       case T_VOID:
-                   return 0;   /* Assume voids have size zero */
+        case T_VOID:
+            /* A void variable is a cc65 extension.
+            ** Get its size (in bytes).
+            */
+            return T->A.U;
+
+        /* Beware: There's a chance that this triggers problems in other parts
+           of the compiler. The solution is to fix the callers, because calling
+           SizeOf() with a function type as argument is bad. */
+        case T_FUNC:
+            return 0;   /* Size of function is unknown */
 
-       case T_SCHAR:
-       case T_UCHAR:
-           return SIZEOF_CHAR;
+        case T_SCHAR:
+        case T_UCHAR:
+            return SIZEOF_CHAR;
 
-               case T_SHORT:
-       case T_USHORT:
+        case T_SHORT:
+        case T_USHORT:
             return SIZEOF_SHORT;
 
-       case T_INT:
-       case T_UINT:
+        case T_INT:
+        case T_UINT:
             return SIZEOF_INT;
 
-       case T_PTR:
-       case T_FUNC:    /* Maybe pointer to function */
-           return SIZEOF_PTR;
+        case T_PTR:
+            return SIZEOF_PTR;
 
         case T_LONG:
-       case T_ULONG:
-           return SIZEOF_LONG;
+        case T_ULONG:
+            return SIZEOF_LONG;
 
-       case T_LONGLONG:
-       case T_ULONGLONG:
-           return SIZEOF_LONGLONG;
+        case T_LONGLONG:
+        case T_ULONGLONG:
+            return SIZEOF_LONGLONG;
 
         case T_ENUM:
-           return SIZEOF_INT;
+            return SIZEOF_INT;
 
-       case T_FLOAT:
+        case T_FLOAT:
             return SIZEOF_FLOAT;
 
-       case T_DOUBLE:
-           return SIZEOF_DOUBLE;
+        case T_DOUBLE:
+            return SIZEOF_DOUBLE;
 
-       case T_STRUCT:
-       case T_UNION:
+        case T_STRUCT:
+        case T_UNION:
             return ((SymEntry*) T->A.P)->V.S.Size;
 
-       case T_ARRAY:
+        case T_ARRAY:
             if (T->A.L == UNSPECIFIED) {
                 /* Array with unspecified size */
                 return 0;
             } else {
-               return T->A.L * SizeOf (T + 1);
+                return T->A.U * SizeOf (T + 1);
             }
 
-       default:
-           Internal ("Unknown type in SizeOf: %04lX", T->C);
-           return 0;
+        default:
+            Internal ("Unknown type in SizeOf: %04lX", T->C);
+            return 0;
 
     }
 }
@@ -449,9 +467,9 @@ unsigned PSizeOf (const Type* T)
 
 unsigned CheckedSizeOf (const Type* T)
 /* Return the size of a data type. If the size is zero, emit an error and
- * return some valid size instead (so the rest of the compiler doesn't have
- * to work with invalid sizes).
- */
+** return some valid size instead (so the rest of the compiler doesn't have
+** to work with invalid sizes).
+*/
 {
     unsigned Size = SizeOf (T);
     if (Size == 0) {
@@ -465,9 +483,9 @@ unsigned CheckedSizeOf (const Type* T)
 
 unsigned CheckedPSizeOf (const Type* T)
 /* Return the size of a data type that is pointed to by a pointer. If the
- * size is zero, emit an error and return some valid size instead (so the
- * rest of the compiler doesn't have to work with invalid sizes).
- */
+** size is zero, emit an error and return some valid size instead (so the
+** rest of the compiler doesn't have to work with invalid sizes).
+*/
 {
     unsigned Size = PSizeOf (T);
     if (Size == 0) {
@@ -484,28 +502,28 @@ unsigned TypeOf (const Type* T)
 {
     switch (UnqualifiedType (T->C)) {
 
-       case T_SCHAR:
-           return CF_CHAR;
+        case T_SCHAR:
+            return CF_CHAR;
 
-       case T_UCHAR:
-           return CF_CHAR | CF_UNSIGNED;
+        case T_UCHAR:
+            return CF_CHAR | CF_UNSIGNED;
 
-       case T_SHORT:
-       case T_INT:
+        case T_SHORT:
+        case T_INT:
         case T_ENUM:
-           return CF_INT;
+            return CF_INT;
 
-       case T_USHORT:
-       case T_UINT:
-       case T_PTR:
-       case T_ARRAY:
-           return CF_INT | CF_UNSIGNED;
+        case T_USHORT:
+        case T_UINT:
+        case T_PTR:
+        case T_ARRAY:
+            return CF_INT | CF_UNSIGNED;
 
         case T_LONG:
-           return CF_LONG;
+            return CF_LONG;
 
-               case T_ULONG:
-                   return CF_LONG | CF_UNSIGNED;
+        case T_ULONG:
+            return CF_LONG | CF_UNSIGNED;
 
         case T_FLOAT:
         case T_DOUBLE:
@@ -513,16 +531,16 @@ unsigned TypeOf (const Type* T)
             return CF_FLOAT;
 
         case T_FUNC:
-           return (((FuncDesc*) T->A.P)->Flags & FD_VARIADIC)? 0 : CF_FIXARGC;
+            return (((FuncDesc*) T->A.P)->Flags & FD_VARIADIC)? 0 : CF_FIXARGC;
 
         case T_STRUCT:
         case T_UNION:
-                   /* Address of ... */
-                   return CF_INT | CF_UNSIGNED;
+            /* Address of ... */
+            return CF_INT | CF_UNSIGNED;
 
-               default:
-                   Error ("Illegal type %04lX", T->C);
-                   return CF_INT;
+        default:
+            Error ("Illegal type %04lX", T->C);
+            return CF_INT;
     }
 }
 
@@ -530,8 +548,8 @@ unsigned TypeOf (const Type* T)
 
 Type* Indirect (Type* T)
 /* Do one indirection for the given type, that is, return the type where the
- * given type points to.
- */
+** given type points to.
+*/
 {
     /* We are expecting a pointer expression */
     CHECK (IsClassPtr (T));
@@ -542,47 +560,19 @@ Type* Indirect (Type* T)
 
 
 
-Type* ArrayToPtr (const Type* T)
+Type* ArrayToPtr (Type* T)
 /* Convert an array to a pointer to it's first element */
 {
-    /* Function must only be called for an array */
-    CHECK (IsTypeArray (T));
-
     /* Return pointer to first element */
-    return PointerTo (T + 1);
-}
-
-
-
-TypeCode GetQualifier (const Type* T)
-/* Get the qualifier from the given type string */
-{
-    /* If this is an array, look at the element type, otherwise look at the
-     * type itself.
-     */
-    if (IsTypeArray (T)) {
-       ++T;
-    }
-    return (T->C & T_MASK_QUAL);
-}
-
-
-
-int IsFastCallFunc (const Type* T)
-/* Return true if this is a function type or pointer to function with
- * __fastcall__ calling conventions
- */
-{
-    FuncDesc* F        = GetFuncDesc (T);
-    return (F->Flags & FD_FASTCALL) != 0;
+    return PointerTo (GetElementType (T));
 }
 
 
 
 int IsVariadicFunc (const Type* T)
 /* Return true if this is a function type or pointer to function type with
- * variable parameter list
- */
+** variable parameter list
+*/
 {
     FuncDesc* F = GetFuncDesc (T);
     return (F->Flags & FD_VARIADIC) != 0;
@@ -594,8 +584,8 @@ FuncDesc* GetFuncDesc (const Type* T)
 /* Get the FuncDesc pointer from a function or pointer-to-function type */
 {
     if (UnqualifiedType (T->C) == T_PTR) {
-       /* Pointer to function */
-       ++T;
+        /* Pointer to function */
+        ++T;
     }
 
     /* Be sure it's a function type */
@@ -611,8 +601,8 @@ void SetFuncDesc (Type* T, FuncDesc* F)
 /* Set the FuncDesc pointer in a function or pointer-to-function type */
 {
     if (UnqualifiedType (T->C) == T_PTR) {
-       /* Pointer to function */
-       ++T;
+        /* Pointer to function */
+        ++T;
     }
 
     /* Be sure it's a function type */
@@ -628,8 +618,8 @@ Type* GetFuncReturn (Type* T)
 /* Return a pointer to the return type of a function or pointer-to-function type */
 {
     if (UnqualifiedType (T->C) == T_PTR) {
-       /* Pointer to function */
-       ++T;
+        /* Pointer to function */
+        ++T;
     }
 
     /* Be sure it's a function type */
@@ -643,8 +633,8 @@ Type* GetFuncReturn (Type* T)
 
 long GetElementCount (const Type* T)
 /* Get the element count of the array specified in T (which must be of
- * array type).
- */
+** array type).
+*/
 {
     CHECK (IsTypeArray (T));
     return T->A.L;
@@ -654,8 +644,8 @@ long GetElementCount (const Type* T)
 
 void SetElementCount (Type* T, long Count)
 /* Set the element count of the array specified in T (which must be of
- * array type).
- */
+** array type).
+*/
 {
     CHECK (IsTypeArray (T));
     T->A.L = Count;
@@ -672,6 +662,20 @@ Type* GetElementType (Type* T)
 
 
 
+Type* GetBaseElementType (Type* T)
+/* Return the base element type of a given type. If T is not an array, this
+** will return. Otherwise it will return the base element type, which means
+** the element type that is not an array.
+*/
+{
+    while (IsTypeArray (T)) {
+        ++T;
+    }
+    return T;
+}
+
+
+
 SymEntry* GetSymEntry (const Type* T)
 /* Return a SymEntry pointer from a type */
 {
@@ -698,15 +702,15 @@ void SetSymEntry (Type* T, SymEntry* S)
 
 Type* IntPromotion (Type* T)
 /* Apply the integer promotions to T and return the result. The returned type
- * string may be T if there is no need to change it.
- */
+** string may be T if there is no need to change it.
+*/
 {
     /* We must have an int to apply int promotions */
     PRECONDITION (IsClassInt (T));
 
     /* An integer can represent all values from either signed or unsigned char,
-     * so convert chars to int and leave all other types alone.
-     */
+    ** so convert chars to int and leave all other types alone.
+    */
     if (IsTypeChar (T)) {
         return type_int;
     } else {
@@ -718,12 +722,12 @@ Type* IntPromotion (Type* T)
 
 Type* PtrConversion (Type* T)
 /* If the type is a function, convert it to pointer to function. If the
- * expression is an array, convert it to pointer to first element. Otherwise
- * return T.
- */
+** expression is an array, convert it to pointer to first element. Otherwise
+** return T.
+*/
 {
     if (IsTypeFunc (T)) {
-               return PointerTo (T);
+        return PointerTo (T);
     } else if (IsTypeArray (T)) {
         return ArrayToPtr (T);
     } else {
@@ -733,4 +737,20 @@ Type* PtrConversion (Type* T)
 
 
 
+TypeCode AddrSizeQualifier (unsigned AddrSize)
+/* Return T_QUAL_NEAR or T_QUAL_FAR depending on the address size */
+{
+    switch (AddrSize) {
 
+        case ADDR_SIZE_ABS:
+            return T_QUAL_NEAR;
+
+        case ADDR_SIZE_FAR:
+            return T_QUAL_FAR;
+
+        default:
+            Error ("Invalid address size");
+            return T_QUAL_NEAR;
+
+    }
+}