/* expr.c
**
-** Ullrich von Bassewitz, 21.06.1998
+** 1998-06-21, Ullrich von Bassewitz
+** 2017-12-05, Greg King
*/
/* Generator attributes */
#define GEN_NOPUSH 0x01 /* Don't push lhs */
#define GEN_COMM 0x02 /* Operator is commutative */
+#define GEN_NOFUNC 0x04 /* Not allowed for function pointers */
/* Map a generator function and its attributes to a token */
typedef struct {
/* Handle function pointers transparently */
IsFuncPtr = IsTypeFuncPtr (Expr->Type);
if (IsFuncPtr) {
-
- /* Check wether it's a fastcall function that has parameters */
- IsFastcall = IsQualFastcall (Expr->Type + 1) && (Func->ParamCount > 0);
+ /* Check whether it's a fastcall function that has parameters */
+ IsFastcall = (Func->Flags & FD_VARIADIC) == 0 && Func->ParamCount > 0 &&
+ (AutoCDecl ?
+ IsQualFastcall (Expr->Type + 1) :
+ !IsQualCDecl (Expr->Type + 1));
/* Things may be difficult, depending on where the function pointer
** resides. If the function pointer is an expression of some sort
}
/* If we didn't inline the function, get fastcall info */
- IsFastcall = IsQualFastcall (Expr->Type);
+ IsFastcall = (Func->Flags & FD_VARIADIC) == 0 &&
+ (AutoCDecl ?
+ IsQualFastcall (Expr->Type) :
+ !IsQualCDecl (Expr->Type));
}
/* Parse the parameter list */
/* Special handling for function pointers */
if (IsFuncPtr) {
+ if (Func->WrappedCall) {
+ Warning ("Calling a wrapped function via a pointer, wrapped-call will not be used");
+ }
+
/* If the function is not a fastcall function, load the pointer to
** the function into the primary.
*/
} else {
/* Normal function */
- g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
+ if (Func->WrappedCall) {
+ char tmp[64];
+ StrBuf S = AUTO_STRBUF_INITIALIZER;
+
+ /* Store the WrappedCall data in tmp4 */
+ sprintf(tmp, "ldy #%u", Func->WrappedCallData);
+ SB_AppendStr (&S, tmp);
+ g_asmcode (&S);
+ SB_Clear(&S);
+
+ SB_AppendStr (&S, "sty tmp4");
+ g_asmcode (&S);
+ SB_Clear(&S);
+
+ /* Store the original function address in ptr4 */
+ SB_AppendStr (&S, "ldy #<(_");
+ SB_AppendStr (&S, (const char*) Expr->Name);
+ SB_AppendChar (&S, ')');
+ g_asmcode (&S);
+ SB_Clear(&S);
+
+ SB_AppendStr (&S, "sty ptr4");
+ g_asmcode (&S);
+ SB_Clear(&S);
+
+ SB_AppendStr (&S, "ldy #>(_");
+ SB_AppendStr (&S, (const char*) Expr->Name);
+ SB_AppendChar (&S, ')');
+ g_asmcode (&S);
+ SB_Clear(&S);
+
+ SB_AppendStr (&S, "sty ptr4+1");
+ g_asmcode (&S);
+ SB_Clear(&S);
+
+ SB_Done (&S);
+
+ g_call (TypeOf (Expr->Type), Func->WrappedCall->Name, ParamSize);
+ } else {
+ g_call (TypeOf (Expr->Type), (const char*) Expr->Name, ParamSize);
+ }
}
switch (CurTok.Tok) {
+ case TOK_BOOL_AND:
+ /* A computed goto label address */
+ if (IS_Get (&Standard) >= STD_CC65) {
+ SymEntry* Entry;
+ NextToken ();
+ Entry = AddLabelSym (CurTok.Ident, SC_REF | SC_GOTO_IND);
+ /* output its label */
+ E->Flags = E_RTYPE_RVAL | E_LOC_STATIC;
+ E->Name = Entry->V.L.Label;
+ E->Type = PointerTo (type_void);
+ NextToken ();
+ } else {
+ Error ("Computed gotos are a C extension, not supported with this --standard");
+ ED_MakeConstAbsInt (E, 1);
+ }
+ break;
+
case TOK_IDENT:
/* Identifier. Get a pointer to the symbol table entry */
Sym = E->Sym = FindSym (CurTok.Ident);
} else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
/* Function */
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
- E->Name = (unsigned long) Sym->Name;
+ E->Name = (uintptr_t) Sym->Name;
} else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
/* Local variable. If this is a parameter for a variadic
** function, we have to add some address calculations, and the
/* Static variable */
if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) {
E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL;
- E->Name = (unsigned long) Sym->Name;
+ E->Name = (uintptr_t) Sym->Name;
} else {
E->Flags = E_LOC_STATIC | E_RTYPE_LVAL;
- E->Name = Sym->V.Label;
+ E->Name = Sym->V.L.Label;
}
} else {
/* Local static variable */
** list and returning int.
*/
if (IS_Get (&Standard) >= STD_C99) {
- Error ("Call to undefined function `%s'", Ident);
+ Error ("Call to undefined function '%s'", Ident);
} else {
- Warning ("Call to undefined function `%s'", Ident);
+ Warning ("Call to undefined function '%s'", Ident);
}
Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF | SC_FUNC);
E->Type = Sym->Type;
E->Flags = E_LOC_GLOBAL | E_RTYPE_RVAL;
- E->Name = (unsigned long) Sym->Name;
+ E->Name = (uintptr_t) Sym->Name;
} else {
/* Undeclared Variable */
Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
E->Flags = E_LOC_STACK | E_RTYPE_LVAL;
E->Type = type_int;
- Error ("Undefined symbol: `%s'", Ident);
+ Error ("Undefined symbol: '%s'", Ident);
}
}
NextToken ();
Field = FindStructField (Expr->Type, Ident);
if (Field == 0) {
- Error ("Struct/union has no field named `%s'", Ident);
+ Error ("Struct/union has no field named '%s'", Ident);
/* Make the expression an integer at address zero */
ED_MakeConstAbs (Expr, 0, type_int);
return;
** Since we don't have a name, invent one.
*/
ED_MakeConstAbs (Expr, 0, GetImplicitFuncType ());
- Expr->Name = (long) IllegalFunc;
+ Expr->Name = (uintptr_t) IllegalFunc;
}
/* Call the function */
FunctionCall (Expr);
/* Get the data type */
Flags = TypeOf (Expr->Type);
- /* Push the address if needed */
- PushAddr (Expr);
+ /* Emit smaller code if a char variable is at a constant location */
+ if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst(Expr)) {
- /* Fetch the value and save it (since it's the result of the expression) */
- LoadExpr (CF_NONE, Expr);
- g_save (Flags | CF_FORCECHAR);
+ LoadExpr (CF_NONE, Expr);
+ AddCodeLine ("inc %s", ED_GetLabelName(Expr, 0));
- /* If we have a pointer expression, increment by the size of the type */
- if (IsTypePtr (Expr->Type)) {
- g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
} else {
- g_inc (Flags | CF_CONST | CF_FORCECHAR, 1);
- }
- /* Store the result back */
- Store (Expr, 0);
+ /* Push the address if needed */
+ PushAddr (Expr);
- /* Restore the original value in the primary register */
- g_restore (Flags | CF_FORCECHAR);
+ /* Fetch the value and save it (since it's the result of the expression) */
+ LoadExpr (CF_NONE, Expr);
+ g_save (Flags | CF_FORCECHAR);
+
+ /* If we have a pointer expression, increment by the size of the type */
+ if (IsTypePtr (Expr->Type)) {
+ g_inc (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
+ } else {
+ g_inc (Flags | CF_CONST | CF_FORCECHAR, 1);
+ }
+
+ /* Store the result back */
+ Store (Expr, 0);
+
+ /* Restore the original value in the primary register */
+ g_restore (Flags | CF_FORCECHAR);
+ }
/* The result is always an expression, no reference */
ED_MakeRValExpr (Expr);
/* Get the data type */
Flags = TypeOf (Expr->Type);
- /* Push the address if needed */
- PushAddr (Expr);
+ /* Emit smaller code if a char variable is at a constant location */
+ if ((Flags & CF_CHAR) == CF_CHAR && ED_IsLocConst(Expr)) {
- /* Fetch the value and save it (since it's the result of the expression) */
- LoadExpr (CF_NONE, Expr);
- g_save (Flags | CF_FORCECHAR);
+ LoadExpr (CF_NONE, Expr);
+ AddCodeLine ("dec %s", ED_GetLabelName(Expr, 0));
- /* If we have a pointer expression, increment by the size of the type */
- if (IsTypePtr (Expr->Type)) {
- g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
} else {
- g_dec (Flags | CF_CONST | CF_FORCECHAR, 1);
- }
- /* Store the result back */
- Store (Expr, 0);
+ /* Push the address if needed */
+ PushAddr (Expr);
+
+ /* Fetch the value and save it (since it's the result of the expression) */
+ LoadExpr (CF_NONE, Expr);
+ g_save (Flags | CF_FORCECHAR);
+
+ /* If we have a pointer expression, increment by the size of the type */
+ if (IsTypePtr (Expr->Type)) {
+ g_dec (Flags | CF_CONST | CF_FORCECHAR, CheckedSizeOf (Expr->Type + 1));
+ } else {
+ g_dec (Flags | CF_CONST | CF_FORCECHAR, 1);
+ }
- /* Restore the original value in the primary register */
- g_restore (Flags | CF_FORCECHAR);
+ /* Store the result back */
+ Store (Expr, 0);
+
+ /* Restore the original value in the primary register */
+ g_restore (Flags | CF_FORCECHAR);
+ }
/* The result is always an expression, no reference */
ED_MakeRValExpr (Expr);
} else {
Error ("Illegal indirection");
}
- /* The * operator yields an lvalue */
- ED_MakeLVal (Expr);
+ /* If the expression points to an array, then don't convert the
+ ** address -- it already is the location of the first element.
+ */
+ if (!IsTypeArray (Expr->Type)) {
+ /* The * operator yields an lvalue */
+ ED_MakeLVal (Expr);
+ }
}
break;
Tok = CurTok.Tok;
NextToken ();
+ /* If lhs is a function, convert it to pointer to function */
+ if (IsTypeFunc (Expr->Type)) {
+ Expr->Type = PointerTo (Expr->Type);
+ }
+
/* Get the lhs on stack */
GetCodePos (&Mark1);
ltype = TypeOf (Expr->Type);
/* Get the right hand side */
MarkedExprWithCheck (hienext, &Expr2);
+ /* If rhs is a function, convert it to pointer to function */
+ if (IsTypeFunc (Expr2.Type)) {
+ Expr2.Type = PointerTo (Expr2.Type);
+ }
+
/* Check for a constant expression */
rconst = (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2));
if (!rconst) {
LoadExpr (CF_NONE, &Expr2);
}
+ /* Some operations aren't allowed on function pointers */
+ if ((Gen->Flags & GEN_NOFUNC) != 0) {
+ /* Output only one message even if both sides are wrong */
+ if (IsTypeFuncPtr (Expr->Type)) {
+ Error ("Invalid left operand for relational operator");
+ /* Avoid further errors */
+ ED_MakeConstAbsInt (Expr, 0);
+ ED_MakeConstAbsInt (&Expr2, 0);
+ } else if (IsTypeFuncPtr (Expr2.Type)) {
+ Error ("Invalid right operand for relational operator");
+ /* Avoid further errors */
+ ED_MakeConstAbsInt (Expr, 0);
+ ED_MakeConstAbsInt (&Expr2, 0);
+ }
+ }
+
/* Make sure, the types are compatible */
if (IsClassInt (Expr->Type)) {
if (!IsClassInt (Expr2.Type) && !(IsClassPtr(Expr2.Type) && ED_IsNullPtr(Expr))) {
*/
Type* left = Indirect (Expr->Type);
Type* right = Indirect (Expr2.Type);
- if (TypeCmp (left, right) < TC_EQUAL && left->C != T_VOID && right->C != T_VOID) {
- /* Incomatible pointers */
+ if (TypeCmp (left, right) < TC_QUAL_DIFF && left->C != T_VOID && right->C != T_VOID) {
+ /* Incompatible pointers */
Error ("Incompatible types");
}
} else if (!ED_IsNullPtr (&Expr2)) {
Type* lhst; /* Type of left hand side */
Type* rhst; /* Type of right hand side */
-
/* Skip the PLUS token */
NextToken ();
typeadjust (Expr, &Expr2, 1);
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `+'");
+ Error ("Invalid operands for binary operator '+'");
}
} else {
}
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `+'");
+ Error ("Invalid operands for binary operator '+'");
flags = CF_INT;
}
flags = typeadjust (Expr, &Expr2, 1);
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `+'");
+ Error ("Invalid operands for binary operator '+'");
flags = CF_INT;
}
flags = CF_PTR;
} else if (IsClassInt (lhst) && IsClassPtr (rhst)) {
/* Left is int, right is pointer, must scale lhs */
- g_tosint (TypeOf (rhst)); /* Make sure, TOS is int */
+ g_tosint (TypeOf (lhst)); /* Make sure TOS is int */
g_swap (CF_INT); /* Swap TOS and primary */
g_scale (CF_INT, CheckedPSizeOf (rhst));
/* Operate on pointers, result type is a pointer */
flags = typeadjust (Expr, &Expr2, 0) & ~CF_CONST;
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `+'");
+ Error ("Invalid operands for binary operator '+'");
flags = CF_INT;
}
/* Condition codes not set */
ED_MarkAsUntested (Expr);
-
}
int rscale; /* Scale factor for the result */
+ /* lhs cannot be function or pointer to function */
+ if (IsTypeFunc (Expr->Type) || IsTypeFuncPtr (Expr->Type)) {
+ Error ("Invalid left operand for binary operator '-'");
+ /* Make it pointer to char to avoid further errors */
+ Expr->Type = type_uchar;
+ }
+
/* Skip the MINUS token */
NextToken ();
/* Parse the right hand side */
MarkedExprWithCheck (hie9, &Expr2);
+ /* rhs cannot be function or pointer to function */
+ if (IsTypeFunc (Expr2.Type) || IsTypeFuncPtr (Expr2.Type)) {
+ Error ("Invalid right operand for binary operator '-'");
+ /* Make it pointer to char to avoid further errors */
+ Expr2.Type = type_uchar;
+ }
+
/* Check for a constant rhs expression */
if (ED_IsConstAbs (&Expr2) && ED_CodeRangeIsEmpty (&Expr2)) {
Expr->IVal -= Expr2.IVal;
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `-'");
+ Error ("Invalid operands for binary operator '-'");
}
/* Result is constant, condition codes not set */
flags = typeadjust (Expr, &Expr2, 1);
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `-'");
+ Error ("Invalid operands for binary operator '-'");
flags = CF_INT;
}
flags = typeadjust (Expr, &Expr2, 0);
} else {
/* OOPS */
- Error ("Invalid operands for binary operator `-'");
+ Error ("Invalid operands for binary operator '-'");
flags = CF_INT;
}
/* Handle greater-than type comparators */
{
static const GenDesc hie6_ops [] = {
- { TOK_LT, GEN_NOPUSH, g_lt },
- { TOK_LE, GEN_NOPUSH, g_le },
- { TOK_GE, GEN_NOPUSH, g_ge },
- { TOK_GT, GEN_NOPUSH, g_gt },
- { TOK_INVALID, 0, 0 }
+ { TOK_LT, GEN_NOPUSH | GEN_NOFUNC, g_lt },
+ { TOK_LE, GEN_NOPUSH | GEN_NOFUNC, g_le },
+ { TOK_GE, GEN_NOPUSH | GEN_NOFUNC, g_ge },
+ { TOK_GT, GEN_NOPUSH | GEN_NOFUNC, g_gt },
+ { TOK_INVALID, 0, 0 }
};
hie_compare (hie6_ops, Expr, ShiftExpr);
}
/* The rhs must be an integer (or a float, but we don't support that yet */
if (!IsClassInt (Expr2.Type)) {
- Error ("Invalid right operand for binary operator `%s'", Op);
+ Error ("Invalid right operand for binary operator '%s'", Op);
/* Continue. Wrong code will be generated, but the compiler won't
** break, so this is the best error recovery.
*/
*/
hie1 (&Expr2);
if (!IsClassInt (Expr2.Type)) {
- Error ("Invalid right operand for binary operator `%s'", Op);
+ Error ("Invalid right operand for binary operator '%s'", Op);
/* Continue. Wrong code will be generated, but the compiler won't
** break, so this is the best error recovery.
*/