cc65/src/ca65/studyexpr.c

1566 lines
37 KiB
C

/*****************************************************************************/
/* */
/* 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 <string.h>
/* common */
#include "check.h"
#include "debugflag.h"
#include "shift.h"
#include "xmalloc.h"
/* ca65 */
#include "error.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 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);
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
}