/*****************************************************************************/ /* */ /* studyexpr.c */ /* */ /* Study an expression tree */ /* */ /* */ /* */ /* (C) 2003-2012, Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ /* warranty. In no event will the authors be held liable for any damages */ /* arising from the use of this software. */ /* */ /* Permission is granted to anyone to use this software for any purpose, */ /* including commercial applications, and to alter it and redistribute it */ /* freely, subject to the following restrictions: */ /* */ /* 1. The origin of this software must not be misrepresented; you must not */ /* claim that you wrote the original software. If you use this software */ /* in a product, an acknowledgment in the product documentation would be */ /* appreciated but is not required. */ /* 2. Altered source versions must be plainly marked as such, and must not */ /* be misrepresented as being the original software. */ /* 3. This notice may not be removed or altered from any source */ /* distribution. */ /* */ /*****************************************************************************/ #include /* common */ #include "check.h" #include "debugflag.h" #include "shift.h" #include "xmalloc.h" /* ca65 */ #include "error.h" #include "expr.h" #include "segment.h" #include "studyexpr.h" #include "symtab.h" #include "ulabel.h" /*****************************************************************************/ /* struct ExprDesc */ /*****************************************************************************/ ExprDesc* ED_Init (ExprDesc* ED) /* Initialize an ExprDesc structure for use with StudyExpr */ { ED->Flags = ED_OK; ED->AddrSize = ADDR_SIZE_DEFAULT; ED->Val = 0; ED->SymCount = 0; ED->SymLimit = 0; ED->SymRef = 0; ED->SecCount = 0; ED->SecLimit = 0; ED->SecRef = 0; return ED; } void ED_Done (ExprDesc* ED) /* Delete allocated memory for an ExprDesc. */ { xfree (ED->SymRef); xfree (ED->SecRef); } int ED_IsConst (const ExprDesc* D) /* Return true if the expression is constant */ { unsigned I; if (D->Flags & ED_TOO_COMPLEX) { return 0; } for (I = 0; I < D->SymCount; ++I) { if (D->SymRef[I].Count != 0) { return 0; } } for (I = 0; I < D->SecCount; ++I) { if (D->SecRef[I].Count != 0) { return 0; } } return 1; } static int ED_IsValid (const ExprDesc* D) /* Return true if the expression is valid, that is, neither the ERROR nor the ** TOO_COMPLEX flags are set. */ { return ((D->Flags & (ED_ERROR | ED_TOO_COMPLEX)) == 0); } static int ED_HasError (const ExprDesc* D) /* Return true if the expression has an error. */ { return ((D->Flags & ED_ERROR) != 0); } static void ED_Invalidate (ExprDesc* D) /* Set the TOO_COMPLEX flag for D */ { D->Flags |= ED_TOO_COMPLEX; } static void ED_SetError (ExprDesc* D) /* Set the TOO_COMPLEX and ERROR flags for D */ { D->Flags |= (ED_ERROR | ED_TOO_COMPLEX); } static void ED_UpdateAddrSize (ExprDesc* ED, unsigned char AddrSize) /* Update the address size of the expression */ { 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; } } } static void ED_MergeAddrSizeAND (ExprNode* Expr, ExprDesc* ED, const ExprDesc* Right) /* Merge the address sizes of two expressions into ED, special case for AND operator */ { int ConstL, ConstR; int Size, ConstSize; long Val, ValR; 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 smaller of ** the two. */ if (Right->AddrSize < ED->AddrSize) { ED->AddrSize = Right->AddrSize; } } /* Check if either side of the expression is constant */ ConstL = IsConstExpr (Expr->Left, &Val); ConstR = IsConstExpr (Expr->Right, &ValR); if (!ConstL && !ConstR) { /* If neither part of the expression is constant, the above is all we can do */ return; } /* We start assuming the left side is constant, left value is in Val, right size in Size */ Size = Right->AddrSize; /* Now check if the right side is constant, and if so put the right value into Val and the Left size into Size. */ if (ConstR) { Val = ValR; Size = ED->AddrSize; } /* Figure out the size of the constant value */ if (IsByteRange (Val)) { ConstSize = ADDR_SIZE_ZP; } else if (IsWordRange (Val)) { ConstSize = ADDR_SIZE_ABS; } else if (IsFarRange (Val)) { ConstSize = ADDR_SIZE_FAR; } else { ConstSize = ADDR_SIZE_LONG; } if (Size == ADDR_SIZE_DEFAULT) { ED->AddrSize = ConstSize; } else { /* use the smaller of the two sizes */ ED->AddrSize = (ConstSize < Size) ? ConstSize : Size; } } static ED_SymRef* ED_FindSymRef (ExprDesc* ED, SymEntry* Sym) /* Find a symbol reference and return it. Return NULL if the reference does ** not exist. */ { unsigned I; ED_SymRef* SymRef; for (I = 0, SymRef = ED->SymRef; I < ED->SymCount; ++I, ++SymRef) { if (SymRef->Ref == Sym) { return SymRef; } } return 0; } static ED_SecRef* ED_FindSecRef (ExprDesc* ED, unsigned Sec) /* Find a section reference and return it. Return NULL if the reference does ** not exist. */ { unsigned I; ED_SecRef* SecRef; for (I = 0, SecRef = ED->SecRef; I < ED->SecCount; ++I, ++SecRef) { if (SecRef->Ref == Sec) { return SecRef; } } return 0; } static ED_SymRef* ED_AllocSymRef (ExprDesc* ED, SymEntry* Sym) /* Allocate a new symbol reference and return it. The count of the new ** reference will be set to zero, and the reference itself to Sym. */ { ED_SymRef* SymRef; /* Make sure we have enough SymRef slots */ if (ED->SymCount >= ED->SymLimit) { ED->SymLimit *= 2; if (ED->SymLimit == 0) { ED->SymLimit = 2; } ED->SymRef = xrealloc (ED->SymRef, ED->SymLimit * sizeof (ED->SymRef[0])); } /* Allocate a new slot */ SymRef = ED->SymRef + ED->SymCount++; /* Initialize the new struct and return it */ SymRef->Count = 0; SymRef->Ref = Sym; return SymRef; } static ED_SecRef* ED_AllocSecRef (ExprDesc* ED, unsigned Sec) /* Allocate a new section reference and return it. The count of the new ** reference will be set to zero, and the reference itself to Sec. */ { ED_SecRef* SecRef; /* Make sure we have enough SecRef slots */ if (ED->SecCount >= ED->SecLimit) { ED->SecLimit *= 2; if (ED->SecLimit == 0) { ED->SecLimit = 2; } ED->SecRef = xrealloc (ED->SecRef, ED->SecLimit * sizeof (ED->SecRef[0])); } /* Allocate a new slot */ SecRef = ED->SecRef + ED->SecCount++; /* Initialize the new struct and return it */ SecRef->Count = 0; SecRef->Ref = Sec; return SecRef; } static ED_SymRef* ED_GetSymRef (ExprDesc* ED, SymEntry* Sym) /* Get a symbol reference and return it. If the symbol reference does not ** exist, a new one is created and returned. */ { ED_SymRef* SymRef = ED_FindSymRef (ED, Sym); if (SymRef == 0) { SymRef = ED_AllocSymRef (ED, Sym); } return SymRef; } static ED_SecRef* ED_GetSecRef (ExprDesc* ED, unsigned Sec) /* Get a section reference and return it. If the section reference does not ** exist, a new one is created and returned. */ { ED_SecRef* SecRef = ED_FindSecRef (ED, Sec); if (SecRef == 0) { SecRef = ED_AllocSecRef (ED, Sec); } return SecRef; } static void ED_MergeSymRefs (ExprDesc* ED, const ExprDesc* New) /* Merge the symbol references from New into ED */ { unsigned I; for (I = 0; I < New->SymCount; ++I) { /* Get a pointer to the SymRef entry */ const ED_SymRef* NewRef = New->SymRef + I; /* Get the corresponding entry in ED */ ED_SymRef* SymRef = ED_GetSymRef (ED, NewRef->Ref); /* Sum up the references */ SymRef->Count += NewRef->Count; } } static void ED_MergeSecRefs (ExprDesc* ED, const ExprDesc* New) /* Merge the section references from New into ED */ { unsigned I; for (I = 0; I < New->SecCount; ++I) { /* Get a pointer to the SymRef entry */ const ED_SecRef* NewRef = New->SecRef + I; /* Get the corresponding entry in ED */ ED_SecRef* SecRef = ED_GetSecRef (ED, NewRef->Ref); /* Sum up the references */ SecRef->Count += NewRef->Count; } } static void ED_MergeRefs (ExprDesc* ED, const ExprDesc* New) /* Merge all references from New into ED */ { ED_MergeSymRefs (ED, New); ED_MergeSecRefs (ED, New); } 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_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); } static void ED_Mul (ExprDesc* ED, const ExprDesc* Right) /* Calculate ED = ED * Right, update address size in ED */ { unsigned I; ED->Val *= Right->Val; for (I = 0; I < ED->SymCount; ++I) { ED->SymRef[I].Count *= Right->Val; } for (I = 0; I < ED->SecCount; ++I) { ED->SecRef[I].Count *= Right->Val; } ED_MergeAddrSize (ED, Right); } static void ED_Neg (ExprDesc* D) /* Negate an expression */ { D->Val = -D->Val; ED_NegRefs (D); } static void ED_Move (ExprDesc* From, ExprDesc* To) /* Move the data from one ExprDesc to another. Old data is freed, and From ** is prepared to that ED_Done may be called safely. */ { /* Delete old data */ ED_Done (To); /* Move the data */ *To = *From; /* Cleanup From */ ED_Init (From); } /*****************************************************************************/ /* Code */ /*****************************************************************************/ static void StudyExprInternal (ExprNode* Expr, ExprDesc* D); /* Study an expression tree and place the contents into 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. ** It evaluates the two subtrees and checks if they are constant. If they ** aren't constant, it will set the TOO_COMPLEX flag, and merge references. ** Otherwise the first value is returned in D->Val, the second one in D->Right, ** so the actual operation can be done by the caller. */ { ExprDesc Right; /* Study the left side of the expression */ StudyExprInternal (Expr->Left, D); /* Study the right side of the expression */ ED_Init (&Right); StudyExprInternal (Expr->Right, &Right); /* Check if we can handle the operation */ if (ED_IsConst (D) && ED_IsConst (&Right)) { /* Remember the constant value from Right */ D->Right = Right.Val; } else { /* Cannot evaluate */ ED_Invalidate (D); /* Merge references and update address size */ ED_MergeRefs (D, &Right); if (Expr->Op == EXPR_AND) { ED_MergeAddrSizeAND (Expr, D, &Right); } else { ED_MergeAddrSize (D, &Right); } } /* Cleanup Right */ ED_Done (&Right); } static void StudyLiteral (ExprNode* Expr, ExprDesc* D) /* Study a literal expression node */ { /* This one is easy */ D->Val = Expr->V.IVal; D->AddrSize = GetConstAddrSize (D->Val); } static void StudySymbol (ExprNode* Expr, ExprDesc* D) /* Study a symbol expression node */ { /* Get the symbol from the expression */ SymEntry* Sym = Expr->V.Sym; /* If the symbol is defined somewhere, it has an expression associated. ** In this case, just study the expression associated with the symbol, ** but mark the symbol so if we encounter it twice, we know that we have ** a circular reference. */ if (SymHasExpr (Sym)) { if (SymHasUserMark (Sym)) { LIError (&Sym->DefLines, "Circular reference in definition of symbol '%m%p'", GetSymName (Sym)); ED_SetError (D); } else { unsigned char AddrSize; /* Mark the symbol and study its associated expression */ SymMarkUser (Sym); StudyExprInternal (GetSymExpr (Sym), D); SymUnmarkUser (Sym); /* If requested and if the expression is valid, dump it */ if (Debug > 0 && !ED_HasError (D)) { DumpExpr (Expr, SymResolve); } /* 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 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)); } 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; } } } static void StudySection (ExprNode* Expr, ExprDesc* D) /* Study a section expression node */ { /* Get the section reference */ ED_SecRef* SecRef = ED_GetSecRef (D, Expr->V.SecNum); /* Update the data and the address size */ ++SecRef->Count; ED_UpdateAddrSize (D, GetSegAddrSize (SecRef->Ref)); } static void StudyULabel (ExprNode* Expr, ExprDesc* D) /* Study an unnamed label expression node */ { /* If we can resolve the label, study the expression associated with it, ** otherwise mark the expression as too complex to evaluate. */ if (ULabCanResolve ()) { /* We can resolve the label */ StudyExprInternal (ULabResolve (Expr->V.IVal), D); } else { ED_Invalidate (D); } } static void StudyPlus (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_PLUS binary expression node */ { ExprDesc Right; /* Study the left side of the expression */ StudyExprInternal (Expr->Left, D); /* Study the right side of the expression */ ED_Init (&Right); StudyExprInternal (Expr->Right, &Right); /* Check if we can handle the operation */ if (ED_IsValid (D) && ED_IsValid (&Right)) { /* Add both */ ED_Add (D, &Right); } else { /* Cannot evaluate */ ED_Invalidate (D); /* Merge references and update address size */ ED_MergeRefs (D, &Right); ED_MergeAddrSize (D, &Right); } /* Done */ ED_Done (&Right); } static void StudyMinus (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_MINUS binary expression node */ { ExprDesc Right; /* Study the left side of the expression */ StudyExprInternal (Expr->Left, D); /* Study the right side of the expression */ ED_Init (&Right); StudyExprInternal (Expr->Right, &Right); /* Check if we can handle the operation */ if (ED_IsValid (D) && ED_IsValid (&Right)) { /* Subtract both */ ED_Sub (D, &Right); } else { /* Cannot evaluate */ ED_Invalidate (D); /* Merge references and update address size */ ED_MergeRefs (D, &Right); ED_MergeAddrSize (D, &Right); } /* Done */ ED_Done (&Right); } static void StudyMul (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_MUL binary expression node */ { ExprDesc Right; /* Study the left side of the expression */ StudyExprInternal (Expr->Left, D); /* Study the right side of the expression */ ED_Init (&Right); StudyExprInternal (Expr->Right, &Right); /* We can handle the operation if at least one of both operands is const ** and the other one is valid. */ if (ED_IsConst (D) && ED_IsValid (&Right)) { /* Multiply both, result goes into Right */ ED_Mul (&Right, D); /* Move result into D */ ED_Move (&Right, D); } else if (ED_IsConst (&Right) && ED_IsValid (D)) { /* Multiply both */ ED_Mul (D, &Right); } else { /* Cannot handle this operation */ ED_Invalidate (D); } /* If we could not handle the op, merge references and update address size */ if (!ED_IsValid (D)) { ED_MergeRefs (D, &Right); ED_MergeAddrSize (D, &Right); } /* Done */ ED_Done (&Right); } static void StudyDiv (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_DIV binary expression node */ { /* Use helper function */ StudyBinaryExpr (Expr, D); /* If the result is valid, apply the operation */ if (ED_IsValid (D)) { if (D->Right == 0) { Error ("Division by zero"); ED_SetError (D); } else { D->Val /= D->Right; } } } static void StudyMod (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_MOD binary expression node */ { /* Use helper function */ StudyBinaryExpr (Expr, D); /* If the result is valid, apply the operation */ if (ED_IsValid (D)) { if (D->Right == 0) { Error ("Modulo operation with zero"); ED_SetError (D); } else { D->Val %= D->Right; } } } static void StudyOr (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_OR binary expression node */ { /* Use helper function */ StudyBinaryExpr (Expr, D); /* If the result is valid, apply the operation */ if (ED_IsValid (D)) { D->Val |= D->Right; } } static void StudyXor (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_XOR binary expression node */ { /* Use helper function */ StudyBinaryExpr (Expr, D); /* If the result is valid, apply the operation */ if (ED_IsValid (D)) { D->Val ^= D->Right; } } static void StudyAnd (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_AND binary expression node */ { /* Use helper function */ StudyBinaryExpr (Expr, D); /* If the result is valid, apply the operation */ if (ED_IsValid (D)) { D->Val &= D->Right; } } static void StudyShl (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_SHL binary expression node */ { /* Use helper function */ StudyBinaryExpr (Expr, D); /* If the result is valid, apply the operation */ if (ED_IsValid (D)) { D->Val = shl_l (D->Val, D->Right); } } static void StudyShr (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_SHR binary expression node */ { /* Use helper function */ StudyBinaryExpr (Expr, D); /* If the result is valid, apply the operation */ if (ED_IsValid (D)) { D->Val = shr_l (D->Val, D->Right); } } static void StudyEQ (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_EQ 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); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyNE (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_NE 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); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyLT (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_LT 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); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyGT (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_GT 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); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyLE (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_LE 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); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyGE (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_GE 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); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyBoolAnd (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BOOLAND binary expression node */ { StudyExprInternal (Expr->Left, D); if (ED_IsConst (D)) { if (D->Val != 0) { /* Shortcut op */ ED_Done (D); ED_Init (D); StudyExprInternal (Expr->Right, D); if (ED_IsConst (D)) { D->Val = (D->Val != 0); } else { ED_Invalidate (D); } } } else { ED_Invalidate (D); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyBoolOr (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BOOLOR binary expression node */ { StudyExprInternal (Expr->Left, D); if (ED_IsConst (D)) { if (D->Val == 0) { /* Shortcut op */ ED_Done (D); ED_Init (D); StudyExprInternal (Expr->Right, D); if (ED_IsConst (D)) { D->Val = (D->Val != 0); } else { ED_Invalidate (D); } } else { D->Val = 1; } } else { ED_Invalidate (D); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyBoolXor (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BOOLXOR 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 != 0) ^ (D->Right != 0); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } 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 */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* If it is valid, negate it */ if (ED_IsValid (D)) { ED_Neg (D); } } static void StudyNot (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_NOT expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = ~D->Val; } else { ED_Invalidate (D); } } static void StudySwap (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_SWAP expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = (D->Val & ~0xFFFFUL) | ((D->Val >> 8) & 0xFF) | ((D->Val << 8) & 0xFF00); } else { ED_Invalidate (D); } } static void StudyBoolNot (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BOOLNOT expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = (D->Val == 0); } else { ED_Invalidate (D); } /* In any case, the result is 0 or 1 */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyBank (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BANK expression node */ { /* Study the expression extracting section references */ StudyExprInternal (Expr->Left, D); /* The expression is always linker evaluated, so invalidate it */ ED_Invalidate (D); } static void StudyByte0 (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BYTE0 expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = (D->Val & 0xFF); } else { ED_Invalidate (D); } /* In any case, the result is a zero page expression */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyByte1 (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BYTE1 expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = (D->Val >> 8) & 0xFF; } else { ED_Invalidate (D); } /* In any case, the result is a zero page expression */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyByte2 (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BYTE2 expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = (D->Val >> 16) & 0xFF; } else { ED_Invalidate (D); } /* In any case, the result is a zero page expression */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyByte3 (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_BYTE3 expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = (D->Val >> 24) & 0xFF; } else { ED_Invalidate (D); } /* In any case, the result is a zero page expression */ D->AddrSize = ADDR_SIZE_ZP; } static void StudyWord0 (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_WORD0 expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val &= 0xFFFFL; } else { ED_Invalidate (D); } /* In any case, the result is an absolute expression */ D->AddrSize = ADDR_SIZE_ABS; } static void StudyWord1 (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_WORD1 expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val = (D->Val >> 16) & 0xFFFFL; } else { ED_Invalidate (D); } /* In any case, the result is an absolute expression */ D->AddrSize = ADDR_SIZE_ABS; } static void StudyFarAddr (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_FARADDR expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val &= 0xFFFFFFL; } else { ED_Invalidate (D); } /* In any case, the result is a far address */ D->AddrSize = ADDR_SIZE_FAR; } static void StudyDWord (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_DWORD expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (ED_IsConst (D)) { D->Val &= 0xFFFFFFFFL; } else { ED_Invalidate (D); } /* In any case, the result is a long expression */ D->AddrSize = ADDR_SIZE_LONG; } static void StudyNearAddr (ExprNode* Expr, ExprDesc* D) /* Study an EXPR_NEARADDR expression node */ { /* Study the expression */ StudyExprInternal (Expr->Left, D); /* We can handle only const expressions */ if (!ED_IsConst (D)) { ED_Invalidate (D); } /* Promote to absolute if smaller. */ if (D->AddrSize < ADDR_SIZE_ABS) { D->AddrSize = ADDR_SIZE_ABS; } } static void StudyExprInternal (ExprNode* Expr, ExprDesc* D) /* Study an expression tree and place the contents into D */ { /* Study this expression node */ switch (Expr->Op) { case EXPR_LITERAL: StudyLiteral (Expr, D); break; case EXPR_SYMBOL: StudySymbol (Expr, D); break; case EXPR_SECTION: StudySection (Expr, D); break; case EXPR_ULABEL: StudyULabel (Expr, D); break; case EXPR_PLUS: StudyPlus (Expr, D); break; case EXPR_MINUS: StudyMinus (Expr, D); break; case EXPR_MUL: StudyMul (Expr, D); break; case EXPR_DIV: StudyDiv (Expr, D); break; case EXPR_MOD: StudyMod (Expr, D); break; case EXPR_OR: StudyOr (Expr, D); break; case EXPR_XOR: StudyXor (Expr, D); break; case EXPR_AND: StudyAnd (Expr, D); break; case EXPR_SHL: StudyShl (Expr, D); break; case EXPR_SHR: StudyShr (Expr, D); break; case EXPR_EQ: StudyEQ (Expr, D); break; case EXPR_NE: StudyNE (Expr, D); break; case EXPR_LT: StudyLT (Expr, D); break; case EXPR_GT: StudyGT (Expr, D); break; case EXPR_LE: StudyLE (Expr, D); break; case EXPR_GE: StudyGE (Expr, D); break; case EXPR_BOOLAND: StudyBoolAnd (Expr, D); break; case EXPR_BOOLOR: StudyBoolOr (Expr, D); break; case EXPR_BOOLXOR: 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; case EXPR_NOT: StudyNot (Expr, D); break; case EXPR_SWAP: StudySwap (Expr, D); break; case EXPR_BOOLNOT: StudyBoolNot (Expr, D); break; case EXPR_BANK: StudyBank (Expr, D); break; case EXPR_BYTE0: StudyByte0 (Expr, D); break; case EXPR_BYTE1: StudyByte1 (Expr, D); break; case EXPR_BYTE2: StudyByte2 (Expr, D); break; case EXPR_BYTE3: StudyByte3 (Expr, D); break; case EXPR_WORD0: StudyWord0 (Expr, D); break; case EXPR_WORD1: StudyWord1 (Expr, D); break; case EXPR_FARADDR: StudyFarAddr (Expr, D); break; case EXPR_DWORD: StudyDWord (Expr, D); break; case EXPR_NEARADDR: StudyNearAddr (Expr, D); break; default: Internal ("Unknown Op type: %u", Expr->Op); break; } } void StudyExpr (ExprNode* Expr, ExprDesc* D) /* Study an expression tree and place the contents into D */ { unsigned I, J; /* Call the internal function */ StudyExprInternal (Expr, D); /* Remove symbol references with count zero */ I = J = 0; while (I < D->SymCount) { if (D->SymRef[I].Count == 0) { /* Delete the entry */ --D->SymCount; memmove (D->SymRef + I, D->SymRef + I + 1, (D->SymCount - I) * sizeof (D->SymRef[0])); } else { /* Next entry */ ++I; } } /* Remove section references with count zero */ I = 0; while (I < D->SecCount) { if (D->SecRef[I].Count == 0) { /* Delete the entry */ --D->SecCount; memmove (D->SecRef + I, D->SecRef + I + 1, (D->SecCount - I) * sizeof (D->SecRef[0])); } else { /* Next entry */ ++I; } } /* If we don't have an address size, assign one if the expression is a ** constant. */ 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); #endif }