/* */
/* */
/* */
-/* (C) 2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
+/* (C) 2003-2007 Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
static void ED_UpdateAddrSize (ExprDesc* ED, unsigned char AddrSize)
/* Update the address size of the expression */
{
- if (ED->AddrSize == ADDR_SIZE_DEFAULT || AddrSize > ED->AddrSize) {
- ED->AddrSize = AddrSize;
+ if (ED_IsValid (ED)) {
+ /* ADDR_SIZE_DEFAULT may get overridden */
+ if (ED->AddrSize == ADDR_SIZE_DEFAULT || AddrSize > ED->AddrSize) {
+ ED->AddrSize = AddrSize;
+ }
+ } else {
+ /* ADDR_SIZE_DEFAULT takes precedence */
+ if (ED->AddrSize != ADDR_SIZE_DEFAULT) {
+ if (AddrSize == ADDR_SIZE_DEFAULT || AddrSize > ED->AddrSize) {
+ ED->AddrSize = AddrSize;
+ }
+ }
+ }
+}
+
+
+
+static void ED_MergeAddrSize (ExprDesc* ED, const ExprDesc* Right)
+/* Merge the address sizes of two expressions into ED */
+{
+ if (ED->AddrSize == ADDR_SIZE_DEFAULT) {
+ /* If ED is valid, ADDR_SIZE_DEFAULT gets always overridden, otherwise
+ * it takes precedence over anything else.
+ */
+ if (ED_IsValid (ED)) {
+ ED->AddrSize = Right->AddrSize;
+ }
+ } else if (Right->AddrSize == ADDR_SIZE_DEFAULT) {
+ /* If Right is valid, ADDR_SIZE_DEFAULT gets always overridden,
+ * otherwise it takes precedence over anything else.
+ */
+ if (!ED_IsValid (Right)) {
+ ED->AddrSize = Right->AddrSize;
+ }
+ } else {
+ /* Neither ED nor Right has a default address size, use the larger of
+ * the two.
+ */
+ if (Right->AddrSize > ED->AddrSize) {
+ ED->AddrSize = Right->AddrSize;
+ }
}
}
SymRef = ED->SymRef + ED->SymCount++;
/* Initialize the new struct and return it */
- SymRef->Count = 1;
+ SymRef->Count = 0;
SymRef->Ref = Sym;
return SymRef;
}
+static void ED_NegRefs (ExprDesc* D)
+/* Negate the references in ED */
+{
+ unsigned I;
+ for (I = 0; I < D->SymCount; ++I) {
+ D->SymRef[I].Count = -D->SymRef[I].Count;
+ }
+ for (I = 0; I < D->SecCount; ++I) {
+ D->SecRef[I].Count = -D->SecRef[I].Count;
+ }
+}
+
+
+
static void ED_Add (ExprDesc* ED, const ExprDesc* Right)
/* Calculate ED = ED + Right, update address size in ED */
{
ED->Val += Right->Val;
ED_MergeRefs (ED, Right);
- ED_UpdateAddrSize (ED, Right->AddrSize);
+ ED_MergeAddrSize (ED, Right);
+}
+
+
+
+static void ED_Sub (ExprDesc* ED, const ExprDesc* Right)
+/* Calculate ED = ED - Right, update address size in ED */
+{
+ ExprDesc D = *Right; /* Temporary */
+ ED_NegRefs (&D);
+
+ ED->Val -= Right->Val;
+ ED_MergeRefs (ED, &D); /* Merge negatives */
+ ED_MergeAddrSize (ED, Right);
}
for (I = 0; I < ED->SecCount; ++I) {
ED->SecRef[I].Count *= Right->Val;
}
- ED_UpdateAddrSize (ED, Right->AddrSize);
+ ED_MergeAddrSize (ED, Right);
}
static void ED_Neg (ExprDesc* D)
/* Negate an expression */
{
- unsigned I;
-
D->Val = -D->Val;
- for (I = 0; I < D->SymCount; ++I) {
- D->SymRef[I].Count = -D->SymRef[I].Count;
- }
- for (I = 0; I < D->SecCount; ++I) {
- D->SecRef[I].Count = -D->SecRef[I].Count;
- }
+ ED_NegRefs (D);
}
+static unsigned char GetConstAddrSize (long Val)
+/* Get the address size of a constant */
+{
+ if ((Val & ~0xFFL) == 0) {
+ return ADDR_SIZE_ZP;
+ } else if ((Val & ~0xFFFFL) == 0) {
+ return ADDR_SIZE_ABS;
+ } else if ((Val & ~0xFFFFFFL) == 0) {
+ return ADDR_SIZE_FAR;
+ } else {
+ return ADDR_SIZE_LONG;
+ }
+}
+
+
+
static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
/* Study a binary expression subtree. This is a helper function for StudyExpr
* used for operations that succeed when both operands are known and constant.
/* Merge references and update address size */
ED_MergeRefs (D, &Right);
- ED_UpdateAddrSize (D, Right.AddrSize);
+ ED_MergeAddrSize (D, &Right);
}
/* Study a literal expression node */
{
/* This one is easy */
- D->Val = Expr->V.Val;
+ D->Val = Expr->V.IVal;
+ D->AddrSize = GetConstAddrSize (D->Val);
}
* a circular reference.
*/
if (SymHasExpr (Sym)) {
+
if (SymHasUserMark (Sym)) {
if (Verbosity > 0) {
DumpExpr (Expr, SymResolve);
}
PError (GetSymPos (Sym),
- "Circular reference in definition of symbol `%s'",
+ "Circular reference in definition of symbol `%m%p'",
GetSymName (Sym));
ED_Invalidate (D);
} else {
+
+ unsigned char AddrSize;
+
+ /* Mark the symbol and study its associated expression */
SymMarkUser (Sym);
StudyExprInternal (GetSymExpr (Sym), D);
SymUnmarkUser (Sym);
+
+ /* If the symbol has an explicit address size, use it. This may
+ * lead to range errors later (maybe even in the linker stage), if
+ * the user lied about the address size, but for now we trust him.
+ */
+ AddrSize = GetSymAddrSize (Sym);
+ if (AddrSize != ADDR_SIZE_DEFAULT) {
+ D->AddrSize = AddrSize;
+ }
}
- } else {
- /* The symbol is either undefined or an import. In both cases, track
- * the symbols used and update the address size, but in case of an
- * undefined symbol also set the "too complex" flag, since we cannot
- * evaluate the final result.
+
+ } else if (SymIsImport (Sym)) {
+
+ /* The symbol is an import. Track the symbols used and update the
+ * address size.
*/
ED_SymRef* SymRef = ED_GetSymRef (D, Sym);
++SymRef->Count;
ED_UpdateAddrSize (D, GetSymAddrSize (Sym));
- if (!SymIsImport (Sym)) {
- /* Cannot handle */
- ED_Invalidate (D);
+
+ } else {
+
+ unsigned char AddrSize;
+ SymTable* Parent;
+
+ /* The symbol is undefined. Track symbol usage but set the "too
+ * complex" flag, since we cannot evaluate the final result.
+ */
+ ED_SymRef* SymRef = ED_GetSymRef (D, Sym);
+ ++SymRef->Count;
+ ED_Invalidate (D);
+
+ /* Since the symbol may be a forward, and we may need a statement
+ * about the address size, check higher lexical levels for a symbol
+ * with the same name and use its address size if we find such a
+ * symbol which is defined.
+ */
+ AddrSize = GetSymAddrSize (Sym);
+ Parent = GetSymParentScope (Sym);
+ if (AddrSize == ADDR_SIZE_DEFAULT && Parent != 0) {
+ SymEntry* H = SymFindAny (Parent, GetSymName (Sym));
+ if (H) {
+ AddrSize = GetSymAddrSize (H);
+ if (AddrSize != ADDR_SIZE_DEFAULT) {
+ D->AddrSize = AddrSize;
+ }
+ }
+ } else {
+ D->AddrSize = AddrSize;
}
}
}
/* Study a section expression node */
{
/* Get the section reference */
- ED_SecRef* SecRef = ED_GetSecRef (D, Expr->V.SegNum);
+ ED_SecRef* SecRef = ED_GetSecRef (D, Expr->V.SecNum);
/* Update the data and the address size */
++SecRef->Count;
*/
if (ULabCanResolve ()) {
/* We can resolve the label */
- StudyExprInternal (ULabResolve (Expr->V.Val), D);
+ StudyExprInternal (ULabResolve (Expr->V.IVal), D);
} else {
ED_Invalidate (D);
}
StudyExprInternal (Expr->Right, &Right);
/* Check if we can handle the operation */
- if (ED_IsValid (D) || ED_IsValid (&Right)) {
+ if (ED_IsValid (D) && ED_IsValid (&Right)) {
/* Add both */
ED_Add (D, &Right);
/* Merge references and update address size */
ED_MergeRefs (D, &Right);
- ED_UpdateAddrSize (D, Right.AddrSize);
+ ED_MergeAddrSize (D, &Right);
}
StudyExprInternal (Expr->Right, &Right);
/* Check if we can handle the operation */
- if (ED_IsValid (D) || ED_IsValid (&Right)) {
+ if (ED_IsValid (D) && ED_IsValid (&Right)) {
/* Subtract both */
- ED_Neg (&Right);
- ED_Add (D, &Right);
+ ED_Sub (D, &Right);
} else {
/* Merge references and update address size */
ED_MergeRefs (D, &Right);
- ED_UpdateAddrSize (D, Right.AddrSize);
+ ED_MergeAddrSize (D, &Right);
}
/* If we could not handle the op, merge references and update address size */
if (!ED_IsValid (D)) {
ED_MergeRefs (D, &Right);
- ED_UpdateAddrSize (D, Right.AddrSize);
+ ED_MergeAddrSize (D, &Right);
}
/* Done */
+static void StudyMax (ExprNode* Expr, ExprDesc* D)
+/* Study an MAX binary expression node */
+{
+ /* Use helper function */
+ StudyBinaryExpr (Expr, D);
+
+ /* If the result is valid, apply the operation */
+ if (ED_IsValid (D)) {
+ D->Val = (D->Val > D->Right)? D->Val : D->Right;
+ }
+}
+
+
+
+static void StudyMin (ExprNode* Expr, ExprDesc* D)
+/* Study an MIN binary expression node */
+{
+ /* Use helper function */
+ StudyBinaryExpr (Expr, D);
+
+ /* If the result is valid, apply the operation */
+ if (ED_IsValid (D)) {
+ D->Val = (D->Val < D->Right)? D->Val : D->Right;
+ }
+}
+
+
+
static void StudyUnaryMinus (ExprNode* Expr, ExprDesc* D)
/* Study an EXPR_UNARY_MINUS expression node */
{
StudyBoolXor (Expr, D);
break;
+ case EXPR_MAX:
+ StudyMax (Expr, D);
+ break;
+
+ case EXPR_MIN:
+ StudyMin (Expr, D);
+ break;
+
case EXPR_UNARY_MINUS:
StudyUnaryMinus (Expr, D);
break;
void StudyExpr (ExprNode* Expr, ExprDesc* D)
/* Study an expression tree and place the contents into D */
{
- unsigned I;
+ unsigned I, J;
/* Call the internal function */
StudyExprInternal (Expr, D);
/* Remove symbol references with count zero */
- I = 0;
+ I = J = 0;
while (I < D->SymCount) {
if (D->SymRef[I].Count == 0) {
/* Delete the entry */
}
}
- /* If we don't have an address size, assign one of the expression is a
+ /* If we don't have an address size, assign one if the expression is a
* constant.
*/
- if (D->AddrSize == ADDR_SIZE_DEFAULT) {
- if (ED_IsConst (D)) {
- if ((D->Val & ~0xFFL) == 0) {
- D->AddrSize = ADDR_SIZE_ZP;
- } else if ((D->Val & ~0xFFFFL) == 0) {
- D->AddrSize = ADDR_SIZE_ABS;
- } else if ((D->Val & 0xFFFFFFL) == 0) {
- D->AddrSize = ADDR_SIZE_FAR;
- } else {
- D->AddrSize = ADDR_SIZE_LONG;
+ if (D->AddrSize == ADDR_SIZE_DEFAULT && ED_IsConst (D)) {
+ D->AddrSize = GetConstAddrSize (D->Val);
+ }
+
+ /* If the expression is valid, throw away the address size and recalculate
+ * it using the data we have. This is more exact than the on-the-fly
+ * calculation done when evaluating the tree, because symbols may have
+ * been removed from the expression, and the final numeric value is now
+ * known.
+ */
+ if (ED_IsValid (D)) {
+ unsigned char AddrSize;
+
+ /* If there are symbols or sections, use the largest one. If the
+ * expression resolves to a const, use the address size of the value.
+ */
+ if (D->SymCount > 0 || D->SecCount > 0) {
+
+ D->AddrSize = ADDR_SIZE_DEFAULT;
+
+ for (I = 0; I < D->SymCount; ++I) {
+ const SymEntry* Sym = D->SymRef[I].Ref;
+ AddrSize = GetSymAddrSize (Sym);
+ if (AddrSize > D->AddrSize) {
+ D->AddrSize = AddrSize;
+ }
+ }
+
+ for (I = 0; I < D->SecCount; ++I) {
+ unsigned SegNum = D->SecRef[0].Ref;
+ AddrSize = GetSegAddrSize (SegNum);
+ if (AddrSize > D->AddrSize) {
+ D->AddrSize = AddrSize;
+ }
+ }
+
+ } else {
+ AddrSize = GetConstAddrSize (D->Val);
+ if (AddrSize > D->AddrSize) {
+ D->AddrSize = AddrSize;
}
}
}
#if 0
+ /* Debug code */
printf ("StudyExpr: "); DumpExpr (Expr, SymResolve);
+ printf ("Value: %08lX\n", D->Val);
if (!ED_IsValid (D)) {
printf ("Invalid: %s\n", AddrSizeToStr (D->AddrSize));
} else {
printf ("Valid: %s\n", AddrSizeToStr (D->AddrSize));
- printf ("%u symbols:\n", D->SymCount);
- printf ("%u sections:\n", D->SecCount);
}
+ printf ("%u symbols:\n", D->SymCount);
+ printf ("%u sections:\n", D->SecCount);
#endif
}