]> git.sur5r.net Git - cc65/blobdiff - src/cc65/stdfunc.c
Comment and indentation changes
[cc65] / src / cc65 / stdfunc.c
index f1fef71aa2a32efbb8599e9913560be7e539f6d3..9fa237c6e39ac6153858878bb92e2114c5bb8e38 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
+/* (C) 1998-2004 Ullrich von Bassewitz                                       */
 /*               Römerstrasse 52                                             */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
@@ -41,6 +41,7 @@
 #include "check.h"
 
 /* cc65 */
+#include "asmlabel.h"
 #include "codegen.h"
 #include "error.h"
 #include "funcdesc.h"
 #include "litpool.h"
 #include "scanner.h"
 #include "stdfunc.h"
+#include "stdnames.h"
 #include "typeconv.h"
 
 
 
 /*****************************************************************************/
-/*                            Function forwards                             */
+/*                            Function forwards                             */
 /*****************************************************************************/
 
 
@@ -64,7 +66,7 @@ static void StdFunc_strlen (FuncDesc*, ExprDesc*);
 
 
 /*****************************************************************************/
-/*                                  Data                                    */
+/*                                  Data                                    */
 /*****************************************************************************/
 
 
@@ -74,13 +76,14 @@ static void StdFunc_strlen (FuncDesc*, ExprDesc*);
  */
 static struct StdFuncDesc {
     const char*                Name;
-    void               (*Handler) (FuncDesc*, ExprDesc*);
-} StdFuncs [] = {
+    void               (*Handler) (FuncDesc*, ExprDesc*);
+} StdFuncs[] = {
     {          "memset",       StdFunc_memset          },
     {          "strlen",       StdFunc_strlen          },
 
 };
-#define FUNC_COUNT     (sizeof (StdFuncs) / sizeof (StdFuncs [0]))
+#define FUNC_COUNT     (sizeof (StdFuncs) / sizeof (StdFuncs[0]))
+
 
 
 /*****************************************************************************/
@@ -97,16 +100,6 @@ static int CmpFunc (const void* Key, const void* Elem)
 
 
 
-static struct StdFuncDesc* FindFunc (const char* Name)
-/* Find a function with the given name. Return a pointer to the descriptor if
- * found, return NULL otherwise.
- */
-{
-    return bsearch (Name, StdFuncs, FUNC_COUNT, sizeof (StdFuncs [0]), CmpFunc);
-}
-
-
-
 static unsigned ParseArg (type* Type, ExprDesc* Arg)
 /* Parse one argument but do not push it onto the stack. Return the code
  * generator flags needed to do the actual push.
@@ -116,23 +109,21 @@ static unsigned ParseArg (type* Type, ExprDesc* Arg)
     unsigned Flags = CF_FORCECHAR;
 
     /* Read the expression we're going to pass to the function */
-    int k = hie1 (InitExprDesc (Arg));
+    hie1 (Arg);
 
     /* Convert this expression to the expected type */
-    k = TypeConversion (Arg, k, Type);
-
-    /* If the value is not a constant, load it into the primary */
-    if (k != 0 || Arg->Flags != E_MCONST) {
-
-        /* Load into the primary */
-        ExprLoad (CF_NONE, k, Arg);
-        k = 0;
-
-    } else {
+    TypeConversion (Arg, Type);
 
+    /* If the value is a constant, set the flag, otherwise load it into the
+     * primary register.
+     */
+    if (ED_IsConstAbsInt (Arg)) {
         /* Remember that we have a constant value */
         Flags |= CF_CONST;
-
+    } else {
+        /* Load into the primary */
+        ExprLoad (CF_NONE, Arg);
+        ED_MakeRVal (Arg);
     }
 
     /* Use the type of the argument for the push */
@@ -147,8 +138,7 @@ static unsigned ParseArg (type* Type, ExprDesc* Arg)
 
 
 
-static void StdFunc_memset (FuncDesc* F attribute ((unused)),
-                            ExprDesc* lval attribute ((unused)))
+static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
 /* Handle the memset function */
 {
     /* Argument types */
@@ -163,7 +153,7 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)),
 
     /* Argument #1 */
     Flags = ParseArg (Arg1Type, &Arg);
-    g_push (Flags, Arg.ConstVal);
+    g_push (Flags, Arg.Val);
     ParamSize += SizeOf (Arg1Type);
     ConsumeComma ();
 
@@ -171,12 +161,12 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)),
      * function if it is a constant zero.
      */
     Flags = ParseArg (Arg2Type, &Arg);
-    if ((Flags & CF_CONST) != 0 && Arg.ConstVal == 0) {
+    if ((Flags & CF_CONST) != 0 && Arg.Val == 0) {
         /* Don't call memset, call bzero instead */
         MemSet = 0;
     } else {
         /* Push the argument */
-        g_push (Flags, Arg.ConstVal);
+        g_push (Flags, Arg.Val);
         ParamSize += SizeOf (Arg2Type);
     }
     ConsumeComma ();
@@ -188,99 +178,134 @@ static void StdFunc_memset (FuncDesc* F attribute ((unused)),
      */
     Flags = ParseArg (Arg3Type, &Arg);
     if (Flags & CF_CONST) {
-        ExprLoad (CF_FORCECHAR, 0, &Arg);
+       if (Arg.Val == 0) {
+           Warning ("Call to memset has no effect");
+       }
+        ExprLoad (CF_FORCECHAR, &Arg);
     }
 
     /* Emit the actual function call */
-    g_call (CF_NONE, MemSet? "memset" : "_bzero", ParamSize);
+    g_call (CF_NONE, MemSet? Func_memset : Func__bzero, ParamSize);
 
     /* We expect the closing brace */
     ConsumeRParen ();
+
+    /* The function result is an rvalue in the primary register */
+    ED_MakeRValExpr (Expr);
+    Expr->Type = GetFuncReturn (Expr->Type);
 }
 
 
 
-static void StdFunc_strlen (FuncDesc* F attribute ((unused)),
-                            ExprDesc* lval attribute ((unused)))
+static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
 /* Handle the strlen function */
 {
-    static type   ParamType[] = { T_PTR, T_SCHAR, T_END };
-    int           k;
-    ExprDesc      Param;
-    unsigned      CodeFlags;
-    unsigned long ParamName;
+    static type ArgType[] = { T_PTR, T_SCHAR, T_END };
+    ExprDesc    Arg;
+    unsigned    L;
+
 
     /* Setup the argument type string */
-    ParamType[1] = GetDefaultChar () | T_QUAL_CONST;
+    ArgType[1] = GetDefaultChar () | T_QUAL_CONST;
 
-    /* Fetch the parameter and convert it to the type needed */
-    k = TypeConversion (&Param, hie1 (InitExprDesc (&Param)), ParamType);
+    /* Evaluate the parameter */
+    hie1 (&Arg);
+
+    /* We can generate special code for several locations */
+    if (ED_IsLocConst (&Arg) && IsTypeArray (Arg.Type)) {
+
+        /* Do type conversion */
+        TypeConversion (&Arg, ArgType);
+
+        /* If the expression is a literal, and if string literals are read
+         * only, we can calculate the length of the string and remove it
+         * from the literal pool. Otherwise we have to calculate the length
+         * at runtime.
+         */
+        if (ED_IsLocLiteral (&Arg) && IS_Get (&WritableStrings)) {
+
+            /* Constant string literal */
+            ED_MakeConstAbs (Expr, strlen (GetLiteral (Arg.Val)), type_size_t);
+            ResetLiteralPoolOffs (Arg.Val);
+
+        } else {
+
+            /* Generate the strlen code */
+            L = GetLocalLabel ();
+            AddCodeLine ("ldy #$FF");
+            g_defcodelabel (L);
+            AddCodeLine ("iny");
+            AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg, 0));
+            AddCodeLine ("bne %s", LocalLabelName (L));
+            AddCodeLine ("tax");
+            AddCodeLine ("tya");
+
+            /* The function result is an rvalue in the primary register */
+            ED_MakeRValExpr (Expr);
+            Expr->Type = type_size_t;
 
-    /* Check if the parameter is a constant array of some type, or a numeric
-     * address cast to a pointer.
-     */
-    CodeFlags = 0;
-    ParamName = Param.Name;
-    if ((IsTypeArray (Param.Type) && (Param.Flags & E_MCONST) != 0) ||
-        (IsTypePtr (Param.Type) && Param.Flags == (E_MCONST | E_TCONST))) {
-
-        /* Check which type of constant it is */
-        switch (Param.Flags & E_MCTYPE) {
-
-            case E_TCONST:
-                /* Numerical address */
-                CodeFlags |= CF_CONST | CF_ABSOLUTE;
-                break;
-
-            case E_TREGISTER:
-                /* Register variable */
-                CodeFlags |= CF_CONST | CF_REGVAR;
-                break;
-
-            case E_TGLAB:
-                /* Global label */
-                CodeFlags |= CF_CONST | CF_EXTERNAL;
-                break;
-
-            case E_TLLAB:
-                /* Local symbol */
-                CodeFlags |= CF_CONST | CF_STATIC;
-                break;
-
-            case E_TLIT:
-                /* A literal of some kind. If string literals are read only,
-                 * we can calculate the length of the string and remove it
-                 * from the literal pool. Otherwise we have to calculate the
-                 * length at runtime.
-                 */
-                if (!WriteableStrings) {
-                    /* String literals are const */
-                    ExprDesc Length;
-                    MakeConstIntExpr (&Length, strlen (GetLiteral (Param.ConstVal)));
-                    ResetLiteralPoolOffs (Param.ConstVal);
-                    ExprLoad (CF_NONE, 0, &Length);
-                    goto ExitPoint;
-                } else {
-                    CodeFlags |= CF_CONST | CF_STATIC;
-                    ParamName = LiteralPoolLabel;
-                }
-                break;
-
-            default:
-                Internal ("Unknown constant type: %04X", Param.Flags);
         }
 
+    } else if (ED_IsLocStack (&Arg) && StackPtr >= -255 && IsTypeArray (Arg.Type)) {
+
+        /* Calculate the true stack offset */
+        unsigned Offs = (unsigned) (Arg.Val - StackPtr);
+
+        /* Do type conversion */
+        TypeConversion (&Arg, ArgType);
+
+        /* Generate the strlen code */
+        L = GetLocalLabel ();
+        AddCodeLine ("ldx #$FF");
+        AddCodeLine ("ldy #$%02X", (unsigned char) (Offs-1));
+        g_defcodelabel (L);
+        AddCodeLine ("inx");
+        AddCodeLine ("iny");
+        AddCodeLine ("lda (sp),y");
+        AddCodeLine ("bne %s", LocalLabelName (L));
+        AddCodeLine ("txa");
+        AddCodeLine ("ldx #$00");
+
+        /* The function result is an rvalue in the primary register */
+        ED_MakeRValExpr (Expr);
+        Expr->Type = type_size_t;
+
+    } else if (ED_IsLocRegister (&Arg) && ED_IsLVal (&Arg) && IsTypePtr (Arg.Type)) {
+
+        /* Do type conversion */
+        TypeConversion (&Arg, ArgType);
+
+        /* Generate the strlen code */
+        L = GetLocalLabel ();
+        AddCodeLine ("ldy #$FF");
+        g_defcodelabel (L);
+        AddCodeLine ("iny");
+        AddCodeLine ("lda (%s),y", ED_GetLabelName (&Arg, 0));
+        AddCodeLine ("bne %s", LocalLabelName (L));
+        AddCodeLine ("tax");
+        AddCodeLine ("tya");
+
+        /* The function result is an rvalue in the primary register */
+        ED_MakeRValExpr (Expr);
+        Expr->Type = type_size_t;
+
     } else {
 
-       /* Not an array with a constant address. Load parameter into primary */
-       ExprLoad (CF_NONE, k, &Param);
+        /* Do type conversion */
+        TypeConversion (&Arg, ArgType);
 
-    }
+        /* Load the expression into the primary */
+        ExprLoad (CF_NONE, &Arg);
+
+        /* Call the strlen function */
+        AddCodeLine ("jsr _%s", Func_strlen);
 
-    /* Generate the strlen code */
-    g_strlen (CodeFlags, ParamName, Param.ConstVal);
+        /* The function result is an rvalue in the primary register */
+        ED_MakeRValExpr (Expr);
+        Expr->Type = type_size_t;
+
+    }
 
-ExitPoint:
     /* We expect the closing brace */
     ConsumeRParen ();
 }
@@ -293,23 +318,33 @@ ExitPoint:
 
 
 
-int IsStdFunc (const char* Name)
+int FindStdFunc (const char* Name)
 /* Determine if the given function is a known standard function that may be
- * called in a special way.
+ * called in a special way. If so, return the index, otherwise return -1.
  */
 {
     /* Look into the table for known names */
-    return FindFunc (Name) != 0;
+    struct StdFuncDesc* D =
+        bsearch (Name, StdFuncs, FUNC_COUNT, sizeof (StdFuncs[0]), CmpFunc);
+
+    /* Return the function index or -1 */
+    if (D == 0) {
+        return -1;
+    } else {
+        return D - StdFuncs;
+    }
 }
 
 
 
-void HandleStdFunc (FuncDesc* F, ExprDesc* lval)
+void HandleStdFunc (int Index, FuncDesc* F, ExprDesc* lval)
 /* Generate code for a known standard function. */
 {
+    struct StdFuncDesc* D;
+
     /* Get a pointer to the table entry */
-    struct StdFuncDesc* D = FindFunc ((const char*) lval->Name);
-    CHECK (D != 0);
+    CHECK (Index >= 0 && Index < (int)FUNC_COUNT);
+    D = StdFuncs + Index;
 
     /* Call the handler function */
     D->Handler (F, lval);