/* */
/* */
/* */
-/* (C) 2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@cc65.org */
+/* (C) 2002-2010, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
+/* common */
+#include "check.h"
+#include "strbuf.h"
+
/* cc65 */
+#include "asmlabel.h"
#include "datatype.h"
+#include "error.h"
+#include "exprdesc.h"
+#include "stackptr.h"
#include "symentry.h"
#include "exprdesc.h"
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-void MakeConstIntExpr (ExprDesc* Expr, long Value)
+ExprDesc* ED_Init (ExprDesc* Expr)
+/* Initialize an ExprDesc */
+{
+ Expr->Sym = 0;
+ Expr->Type = 0;
+ Expr->Flags = 0;
+ Expr->Name = 0;
+ Expr->IVal = 0;
+ Expr->FVal = FP_D_Make (0.0);
+ Expr->LVal = 0;
+ Expr->BitOffs = 0;
+ Expr->BitWidth = 0;
+ return Expr;
+}
+
+
+
+void ED_MakeBitField (ExprDesc* Expr, unsigned BitOffs, unsigned BitWidth)
+/* Make this expression a bit field expression */
+{
+ Expr->Flags |= E_BITFIELD;
+ Expr->BitOffs = BitOffs;
+ Expr->BitWidth = BitWidth;
+}
+
+
+
+void ED_SetCodeRange (ExprDesc* Expr, const CodeMark* Start, const CodeMark* End)
+/* Set the code range for this expression */
+{
+ Expr->Flags |= E_HAVE_MARKS;
+ Expr->Start = *Start;
+ Expr->End = *End;
+}
+
+
+
+int ED_CodeRangeIsEmpty (const ExprDesc* Expr)
+/* Return true if no code was output for this expression */
+{
+ /* We must have code marks */
+ PRECONDITION (Expr->Flags & E_HAVE_MARKS);
+
+ return CodeRangeIsEmpty (&Expr->Start, &Expr->End);
+}
+
+
+
+const char* ED_GetLabelName (const ExprDesc* Expr, long Offs)
+/* Return the assembler label name of the given expression. Beware: This
+ * function may use a static buffer, so the name may get "lost" on the second
+ * call to the function.
+ */
+{
+ static StrBuf Buf = STATIC_STRBUF_INITIALIZER;
+
+ /* Expr may have it's own offset, adjust Offs accordingly */
+ Offs += Expr->IVal;
+
+ /* Generate a label depending on the location */
+ switch (ED_GetLoc (Expr)) {
+
+ case E_LOC_ABS:
+ /* Absolute: numeric address or const */
+ SB_Printf (&Buf, "$%04X", (int)(Offs & 0xFFFF));
+ break;
+
+ case E_LOC_GLOBAL:
+ case E_LOC_STATIC:
+ /* Global or static variable */
+ if (Offs) {
+ SB_Printf (&Buf, "%s%+ld", SymGetAsmName (Expr->Sym), Offs);
+ } else {
+ SB_Printf (&Buf, "%s", SymGetAsmName (Expr->Sym));
+ }
+ break;
+
+ case E_LOC_REGISTER:
+ /* Register variable */
+ SB_Printf (&Buf, "regbank+%u", (unsigned)((Offs + Expr->Name) & 0xFFFFU));
+ break;
+
+ case E_LOC_LITERAL:
+ /* Literal in the literal pool */
+ if (Offs) {
+ SB_Printf (&Buf, "%s%+ld", LocalLabelName (Expr->Name), Offs);
+ } else {
+ SB_Printf (&Buf, "%s", LocalLabelName (Expr->Name));
+ }
+ break;
+
+ default:
+ Internal ("Invalid location in ED_GetLabelName: 0x%04X", ED_GetLoc (Expr));
+ }
+
+ /* Return a pointer to the static buffer */
+ return SB_GetConstBuf (&Buf);
+}
+
+
+
+int ED_GetStackOffs (const ExprDesc* Expr, int Offs)
+/* Get the stack offset of an address on the stack in Expr taking into account
+ * an additional offset in Offs.
+ */
+{
+ PRECONDITION (ED_IsLocStack (Expr));
+ Offs += ((int) Expr->IVal) - StackPtr;
+ CHECK (Offs >= 0); /* Cannot handle negative stack offsets */
+ return Offs;
+}
+
+
+
+ExprDesc* ED_MakeConstAbs (ExprDesc* Expr, long Value, Type* Type)
+/* Make Expr an absolute const with the given value and type. */
+{
+ Expr->Sym = 0;
+ Expr->Type = Type;
+ Expr->Flags = E_LOC_ABS | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS);
+ Expr->Name = 0;
+ Expr->IVal = Value;
+ Expr->FVal = FP_D_Make (0.0);
+ return Expr;
+}
+
+
+
+ExprDesc* ED_MakeConstAbsInt (ExprDesc* Expr, long Value)
/* Make Expr a constant integer expression with the given value */
{
- Expr->Flags = E_MCONST;
- Expr->Type = type_int;
- Expr->ConstVal = Value;
+ Expr->Sym = 0;
+ Expr->Type = type_int;
+ Expr->Flags = E_LOC_ABS | E_RTYPE_RVAL | (Expr->Flags & E_HAVE_MARKS);
+ Expr->Name = 0;
+ Expr->IVal = Value;
+ Expr->FVal = FP_D_Make (0.0);
+ return Expr;
+}
+
+
+
+ExprDesc* ED_MakeRValExpr (ExprDesc* Expr)
+/* Convert Expr into a rvalue which is in the primary register without an
+ * offset.
+ */
+{
+ Expr->Sym = 0;
+ Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET);
+ Expr->Flags |= (E_LOC_EXPR | E_RTYPE_RVAL);
+ Expr->Name = 0;
+ Expr->IVal = 0; /* No offset */
+ Expr->FVal = FP_D_Make (0.0);
+ return Expr;
+}
+
+
+
+ExprDesc* ED_MakeLValExpr (ExprDesc* Expr)
+/* Convert Expr into a lvalue which is in the primary register without an
+ * offset.
+ */
+{
+ Expr->Sym = 0;
+ Expr->Flags &= ~(E_MASK_LOC | E_MASK_RTYPE | E_BITFIELD | E_NEED_TEST | E_CC_SET);
+ Expr->Flags |= (E_LOC_EXPR | E_RTYPE_LVAL);
+ Expr->Name = 0;
+ Expr->IVal = 0; /* No offset */
+ Expr->FVal = FP_D_Make (0.0);
+ return Expr;
+}
+
+
+
+int ED_IsConst (const ExprDesc* Expr)
+/* Return true if the expression denotes a constant of some sort. This can be a
+ * numeric constant, the address of a global variable (maybe with offset) or
+ * similar.
+ */
+{
+ return ED_IsRVal (Expr) && (Expr->Flags & E_LOC_CONST) != 0;
+}
+
+
+
+int ED_IsConstAbsInt (const ExprDesc* Expr)
+/* Return true if the expression is a constant (numeric) integer. */
+{
+ return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE)) == (E_LOC_ABS|E_RTYPE_RVAL) &&
+ IsClassInt (Expr->Type);
+}
+
+
+
+int ED_IsNullPtr (const ExprDesc* Expr)
+/* Return true if the given expression is a NULL pointer constant */
+{
+ return (Expr->Flags & (E_MASK_LOC|E_MASK_RTYPE|E_BITFIELD)) ==
+ (E_LOC_ABS|E_RTYPE_RVAL) &&
+ Expr->IVal == 0 &&
+ IsClassInt (Expr->Type);
+}
+
+
+
+int ED_IsBool (const ExprDesc* Expr)
+/* Return true of the expression can be treated as a boolean, that is, it can
+ * be an operand to a compare operation.
+ */
+{
+ /* Either ints, floats, or pointers can be used in a boolean context */
+ return IsClassInt (Expr->Type) ||
+ IsClassFloat (Expr->Type) ||
+ IsClassPtr (Expr->Type);
}
void PrintExprDesc (FILE* F, ExprDesc* E)
/* Print an ExprDesc */
{
- fprintf (F, "Symbol: %s\n", E->Sym? E->Sym->Name : "(none)");
- fprintf (F, "Type: ");
+ unsigned Flags;
+ char Sep;
+
+ fprintf (F, "Symbol: %s\n", E->Sym? E->Sym->Name : "(none)");
if (E->Type) {
+ fprintf (F, "Type: ");
PrintType (F, E->Type);
+ fprintf (F, "\nRaw type: ");
+ PrintRawType (F, E->Type);
} else {
- fprintf (F, "(unknown)");
+ fprintf (F, "Type: (unknown)\n"
+ "Raw type: (unknown)\n");
}
- fprintf (F, "\n");
- fprintf (F, "Value: 0x%08lX\n", E->ConstVal);
- fprintf (F, "Flags: ");
- switch (E->Flags & E_MCTYPE) {
- case E_TCONST: fprintf (F, "E_TCONST "); break;
- case E_TGLAB: fprintf (F, "E_TGLAB "); break;
- case E_TLIT: fprintf (F, "E_TLIT "); break;
- case E_TLOFFS: fprintf (F, "E_TLOFFS "); break;
- case E_TLLAB: fprintf (F, "E_TLLAB "); break;
- case E_TREGISTER: fprintf (F, "E_TREGISTER "); break;
- default: fprintf (F, "0x%02X ", E->Flags & E_MCTYPE); break;
+ fprintf (F, "IVal: 0x%08lX\n", E->IVal);
+ fprintf (F, "FVal: %f\n", FP_D_ToFloat (E->FVal));
+
+ Flags = E->Flags;
+ Sep = '(';
+ fprintf (F, "Flags: 0x%04X ", Flags);
+ if (Flags & E_LOC_ABS) {
+ fprintf (F, "%cE_LOC_ABS", Sep);
+ Flags &= ~E_LOC_ABS;
+ Sep = ',';
}
- if ((E->Flags & E_MREG) == E_MREG) {
- fprintf (F, "E_MREG ");
- } else if ((E->Flags & E_MEOFFS) == E_MEOFFS) {
- fprintf (F, "E_MEOFFS ");
- } else if ((E->Flags & E_MEXPR) == E_MEXPR) {
- fprintf (F, "E_MEXPR ");
+ if (Flags & E_LOC_GLOBAL) {
+ fprintf (F, "%cE_LOC_GLOBAL", Sep);
+ Flags &= ~E_LOC_GLOBAL;
+ Sep = ',';
}
- if ((E->Flags & E_MGLOBAL) == E_MGLOBAL) {
- fprintf (F, "E_MGLOBAL ");
+ if (Flags & E_LOC_STATIC) {
+ fprintf (F, "%cE_LOC_STATIC", Sep);
+ Flags &= ~E_LOC_STATIC;
+ Sep = ',';
}
- if ((E->Flags & E_MLOCAL) == E_MLOCAL) {
- fprintf (F, "E_MLOCAL ");
+ if (Flags & E_LOC_REGISTER) {
+ fprintf (F, "%cE_LOC_REGISTER", Sep);
+ Flags &= ~E_LOC_REGISTER;
+ Sep = ',';
}
- if ((E->Flags & E_MCONST) == E_MCONST) {
- fprintf (F, "E_MCONST ");
+ if (Flags & E_LOC_STACK) {
+ fprintf (F, "%cE_LOC_STACK", Sep);
+ Flags &= ~E_LOC_STACK;
+ Sep = ',';
}
- fprintf (F, "\n");
-
- fprintf (F, "Test: ");
- if (E->Test & E_CC) {
- fprintf (F, "E_CC ");
+ if (Flags & E_LOC_PRIMARY) {
+ fprintf (F, "%cE_LOC_PRIMARY", Sep);
+ Flags &= ~E_LOC_PRIMARY;
+ Sep = ',';
}
- if (E->Test & E_FORCETEST) {
- fprintf (F, "E_FORCETEST ");
+ if (Flags & E_LOC_EXPR) {
+ fprintf (F, "%cE_LOC_EXPR", Sep);
+ Flags &= ~E_LOC_EXPR;
+ Sep = ',';
}
- fprintf (F, "\n");
-
- fprintf (F, "Name: 0x%08lX\n", E->Name);
+ if (Flags & E_LOC_LITERAL) {
+ fprintf (F, "%cE_LOC_LITERAL", Sep);
+ Flags &= ~E_LOC_LITERAL;
+ Sep = ',';
+ }
+ if (Flags & E_RTYPE_LVAL) {
+ fprintf (F, "%cE_RTYPE_LVAL", Sep);
+ Flags &= ~E_RTYPE_LVAL;
+ Sep = ',';
+ }
+ if (Flags & E_BITFIELD) {
+ fprintf (F, "%cE_BITFIELD", Sep);
+ Flags &= ~E_BITFIELD;
+ Sep = ',';
+ }
+ if (Flags & E_NEED_TEST) {
+ fprintf (F, "%cE_NEED_TEST", Sep);
+ Flags &= ~E_NEED_TEST;
+ Sep = ',';
+ }
+ if (Flags & E_CC_SET) {
+ fprintf (F, "%cE_CC_SET", Sep);
+ Flags &= ~E_CC_SET;
+ Sep = ',';
+ }
+ if (Flags) {
+ fprintf (F, "%c,0x%04X", Sep, Flags);
+ Sep = ',';
+ }
+ if (Sep != '(') {
+ fputc (')', F);
+ }
+ fprintf (F, "\nName: 0x%08lX\n", E->Name);
}
-type* ReplaceType (ExprDesc* Expr, const type* NewType)
+Type* ReplaceType (ExprDesc* Expr, const Type* NewType)
/* Replace the type of Expr by a copy of Newtype and return the old type string */
{
- type* OldType = Expr->Type;
+ Type* OldType = Expr->Type;
Expr->Type = TypeDup (NewType);
return OldType;
}
-
-
-