/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
+/* (C) 1998-2004 Ullrich von Bassewitz */
/* Römerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#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 */
/*****************************************************************************/
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
*/
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]))
+
/*****************************************************************************/
-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.
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 */
-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 */
/* Argument #1 */
Flags = ParseArg (Arg1Type, &Arg);
- g_push (Flags, Arg.ConstVal);
+ g_push (Flags, Arg.Val);
ParamSize += SizeOf (Arg1Type);
ConsumeComma ();
* 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 ();
*/
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 ();
}
-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);