]> git.sur5r.net Git - cc65/blobdiff - src/cc65/declare.c
Optimization for __bzero.
[cc65] / src / cc65 / declare.c
index 049e4b6161f96d24013d7ecfc9dd73f021f9a5aa..9f0a94a27d9f267b4fadc266d0fdd5222e44a5b8 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"
 
 
 
@@ -421,7 +424,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;
 
@@ -459,7 +462,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 +504,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 +821,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 +845,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 +861,114 @@ 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;
                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 ();
+
+       /* 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:
@@ -944,7 +1048,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 */
@@ -1066,28 +1169,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, 0, 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, 0, T);
 
     /* Output the data */
     DefineData (&ED);
@@ -1096,7 +1222,7 @@ static unsigned ParseSimpleInit (type* T)
     ClosingCurlyBraces (BraceCount);
 
     /* Done */
-    return Size;
+    return SIZEOF_PTR;
 }
 
 
@@ -1114,28 +1240,34 @@ static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers)
     /* Special handling for a character array initialized by a literal */
     if (IsTypeChar (ElementType) && CurTok.Tok == TOK_SCONST) {
 
-        /* Optional curly braces */
-        unsigned BraceCount = OpeningCurlyBraces (0);
-
         /* Char array initialized by string constant */
         const char* 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 ();
 
-        /* Closing curly braces (if we had any opening ones) */
-        ClosingCurlyBraces (BraceCount);
-
     } else {
 
-        /* Optional curly braces */
-        unsigned BraceCount = OpeningCurlyBraces (1);
+        /* Curly brace */
+        ConsumeLCurly ();
 
         /* Initialize the array members */
         Count = 0;
@@ -1151,8 +1283,8 @@ static unsigned ParseArrayInit (type* T, int AllowFlexibleMembers)
             NextToken ();
         }
 
-        /* Closing curly braces (if we had any opening ones) */
-        ClosingCurlyBraces (BraceCount);
+        /* Closing curly braces */
+        ConsumeRCurly ();
     }
 
 
@@ -1185,7 +1317,7 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers)
 
 
     /* Consume the opening curly brace */
-    unsigned BraceCount = OpeningCurlyBraces (1);
+    ConsumeLCurly ();
 
     /* Get a pointer to the struct entry from the type */
     Entry = DecodePtr (Type + 1);
@@ -1200,7 +1332,7 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers)
     if (Tab == 0) {
        Error ("Cannot initialize variables with incomplete type");
         /* Try error recovery */
-        SkipInitializer (BraceCount);
+        SkipInitializer (1);
        /* Nothing initialized */
        return 0;
     }
@@ -1213,7 +1345,7 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers)
     while (CurTok.Tok != TOK_RCURLY) {
        if (Entry == 0) {
            Error ("Too many initializers");
-            SkipInitializer (BraceCount);
+            SkipInitializer (1);
            return Size;
        }
         /* Parse initialization of one field. Flexible array members may
@@ -1228,7 +1360,7 @@ static unsigned ParseStructInit (type* Type, int AllowFlexibleMembers)
     }
 
     /* Consume the closing curly brace */
-    ClosingCurlyBraces (BraceCount);
+    ConsumeRCurly ();
 
     /* If there are struct fields left, reserve additional storage */
     if (Size < StructSize) {
@@ -1254,7 +1386,7 @@ static unsigned ParseVoidInit (void)
     unsigned Size;
 
     /* Opening brace */
-    unsigned BraceCount = OpeningCurlyBraces (1);
+    ConsumeLCurly ();
 
     /* Allow an arbitrary list of values */
     Size = 0;
@@ -1306,7 +1438,7 @@ static unsigned ParseVoidInit (void)
     } while (CurTok.Tok != TOK_RCURLY);
 
     /* Closing brace */
-    ClosingCurlyBraces (BraceCount);
+    ConsumeRCurly ();
 
     /* Return the number of bytes initialized */
     return Size;
@@ -1325,10 +1457,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);
@@ -1356,7 +1490,19 @@ 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;
 }