From: cuz Date: Sun, 23 Nov 2003 21:39:30 +0000 (+0000) Subject: Much extended StudyExpr X-Git-Tag: V2.12.0~1119 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=49f72c6d245153a9de6e859fa73279ef7d83b5bd;p=cc65 Much extended StudyExpr git-svn-id: svn://svn.cc65.org/cc65/trunk@2681 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/ca65/expr.c b/src/ca65/expr.c index 09e3dc3b9..dcb2f681e 100644 --- a/src/ca65/expr.c +++ b/src/ca65/expr.c @@ -1132,6 +1132,8 @@ long ConstExpression (void) * not constant. */ { + long Val; + #if 1 /* Read the expression */ ExprNode* Expr = Expr0 (); @@ -1142,18 +1144,23 @@ long ConstExpression (void) /* Study the expression */ ExprDesc D; - InitExprDesc (&D); - StudyExpr (Expr, &D, 1); + ED_Init (&D); + StudyExpr (Expr, &D); /* Check if the expression is constant */ - if (!ExprDescIsConst (&D)) { + if (ED_IsConst (&D)) { + Val = D.Val; + } else { Error ("Constant expression expected"); - D.Val = 0; + Val = 0; } - /* Free the expression tree and return the value */ + /* Free the expression tree and allocated memory for D */ FreeExpr (Expr); - return D.Val; + ED_Done (&D); + + /* Return the value */ + return Val; } @@ -1177,17 +1184,20 @@ ExprNode* SimplifyExpr (ExprNode* Expr) /* Create an expression description and initialize it */ ExprDesc D; - InitExprDesc (&D); + ED_Init (&D); /* Study the expression */ - StudyExpr (Expr, &D, 1); + StudyExpr (Expr, &D); /* Now check if we can generate a literal value */ - if (ExprDescIsConst (&D)) { + if (ED_IsConst (&D)) { /* No external references */ FreeExpr (Expr); Expr = GenLiteralExpr (D.Val); } + + /* Free allocated memory */ + ED_Done (&D); } return Expr; } @@ -1381,20 +1391,22 @@ int IsConstExpr (ExprNode* Expr, long* Val) * expression is constant, the constant value is stored here. */ { + int IsConst; + /* Study the expression */ ExprDesc D; - InitExprDesc (&D); - StudyExpr (Expr, &D, 1); + ED_Init (&D); + StudyExpr (Expr, &D); /* Check if the expression is constant */ - if (ExprDescIsConst (&D)) { - if (Val) { - *Val = D.Val; - } - return 1; - } else { - return 0; + IsConst = ED_IsConst (&D); + if (IsConst && Val != 0) { + *Val = D.Val; } + + /* Delete allocated memory and return the result */ + ED_Done (&D); + return IsConst; } @@ -1452,16 +1464,10 @@ static void CheckAddrSize (const ExprNode* N, unsigned char* AddrSize) case EXPR_WORD0: case EXPR_WORD1: - case EXPR_FORCEWORD: /* No need to look at the expression */ *AddrSize = ADDR_SIZE_ABS; break; - case EXPR_FORCEFAR: - /* No need to look at the expression */ - *AddrSize = ADDR_SIZE_FAR; - break; - default: CheckAddrSize (N->Left, AddrSize); break; diff --git a/src/ca65/studyexpr.c b/src/ca65/studyexpr.c index e125dec99..2421b3565 100644 --- a/src/ca65/studyexpr.c +++ b/src/ca65/studyexpr.c @@ -33,449 +33,1174 @@ +#include + /* common */ #include "check.h" #include "print.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, the TOO_COMPLEX flag is + * not set + */ +{ + return ((D->Flags & ED_TOO_COMPLEX) == 0); +} + + + +static void ED_Invalidate (ExprDesc* D) +/* Set the TOO_COMPLEX flag for D */ +{ + D->Flags |= ED_TOO_COMPLEX; +} + + + +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; + } +} + + + +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 = 1; + 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_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); +} + + + +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_UpdateAddrSize (ED, Right->AddrSize); +} + + + +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; + } +} + + + +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 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_UpdateAddrSize (D, Right.AddrSize); + + } + + /* 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.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)) { + if (Verbosity > 0) { + DumpExpr (Expr, SymResolve); + } + PError (GetSymPos (Sym), + "Circular reference in definition of symbol `%s'", + GetSymName (Sym)); + ED_Invalidate (D); + } else { + SymMarkUser (Sym); + StudyExprInternal (GetSymExpr (Sym), D); + SymUnmarkUser (Sym); + } + } 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. + */ + ED_SymRef* SymRef = ED_GetSymRef (D, Sym); + ++SymRef->Count; + ED_UpdateAddrSize (D, GetSymAddrSize (Sym)); + if (!SymIsImport (Sym)) { + /* Cannot handle */ + ED_Invalidate (D); + } + } +} + + + +static void StudySection (ExprNode* Expr, ExprDesc* D) +/* Study a section expression node */ +{ + /* Get the section reference */ + ED_SecRef* SecRef = ED_GetSecRef (D, Expr->V.SegNum); + + /* 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.Val), 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_UpdateAddrSize (D, Right.AddrSize); + + } + + /* 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_Neg (&Right); + ED_Add (D, &Right); + + } else { + + /* Cannot evaluate */ + ED_Invalidate (D); + + /* Merge references and update address size */ + ED_MergeRefs (D, &Right); + ED_UpdateAddrSize (D, Right.AddrSize); + + } + + /* 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)) { + + /* Multiplicate 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)) { + + /* Multiplicate 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_UpdateAddrSize (D, Right.AddrSize); + } + + /* 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_Invalidate (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_Invalidate (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; + } +} + + -/* ca65 */ -#include "error.h" -#include "segment.h" -#include "studyexpr.h" -#include "symtab.h" -#include "ulabel.h" +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; + } +} -/*****************************************************************************/ -/* Code */ -/*****************************************************************************/ +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); + } +} -ExprDesc* InitExprDesc (ExprDesc* ED) -/* Initialize an ExprDesc structure for use with StudyExpr */ + +static void StudyShr (ExprNode* Expr, ExprDesc* D) +/* Study an EXPR_SHR binary expression node */ { - ED->Val = 0; - ED->TooComplex = 0; - ED->SymCount = 0; - ED->SecCount = 0; - return ED; + /* 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); + } } -int ExprDescIsConst (const ExprDesc* ED) -/* Return true if the expression is constant */ +static void StudyEQ (ExprNode* Expr, ExprDesc* D) +/* Study an EXPR_EQ binary expression node */ { - return (ED->TooComplex == 0 && ED->SymCount == 0 && ED->SecCount == 0); + /* 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 StudyBinaryExpr (ExprNode* Expr, ExprDesc* D) -/* Study a binary expression subtree. Helper function for StudyExpr. */ -{ - StudyExpr (Expr->Left, D, 1); - if (ExprDescIsConst (D)) { - D->Left = D->Val; - D->Val = 0; - StudyExpr (Expr->Right, D, 1); - if (!ExprDescIsConst (D)) { - D->TooComplex = 1; +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 { - D->TooComplex = 1; + ED_Invalidate (D); } + + /* In any case, the result is 0 or 1 */ + D->AddrSize = ADDR_SIZE_ZP; } -void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign) -/* Study an expression tree and place the contents into D */ +static void StudyBoolOr (ExprNode* Expr, ExprDesc* D) +/* Study an EXPR_BOOLOR binary expression node */ { - SymEntry* Sym; - unsigned Sec; - ExprDesc SD; - ExprDesc SD1; + 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 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 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; +} + - /* Initialize SD. This is not needed in all cases, but it's rather cheap - * and simplifies the code below. - */ - InitExprDesc (&SD); +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 = (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 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: - D->Val += (Sign * Expr->V.Val); + StudyLiteral (Expr, D); break; case EXPR_SYMBOL: - Sym = Expr->V.Sym; - if (SymIsImport (Sym)) { - if (D->SymCount == 0) { - D->SymCount += Sign; - D->SymRef = Sym; - } else if (D->SymRef == Sym) { - /* Same symbol */ - D->SymCount += Sign; - } else { - /* More than one import */ - D->TooComplex = 1; - } - } else if (SymHasExpr (Sym)) { - if (SymHasUserMark (Sym)) { - if (Verbosity > 0) { - DumpExpr (Expr, SymResolve); - } - PError (GetSymPos (Sym), - "Circular reference in definition of symbol `%s'", - GetSymName (Sym)); - D->TooComplex = 1; - } else { - SymMarkUser (Sym); - StudyExpr (GetSymExpr (Sym), D, Sign); - SymUnmarkUser (Sym); - } - } else { - D->TooComplex = 1; - } + StudySymbol (Expr, D); break; case EXPR_SECTION: - Sec = Expr->V.SegNum; - if (D->SecCount == 0) { - D->SecCount += Sign; - D->SecRef = Sec; - } else if (D->SecRef == Sec) { - /* Same section */ - D->SecCount += Sign; - } else { - /* More than one section */ - D->TooComplex = 1; - } + StudySection (Expr, D); break; case EXPR_ULABEL: - if (ULabCanResolve ()) { - /* We can resolve the label */ - StudyExpr (ULabResolve (Expr->V.Val), D, Sign); - } else { - D->TooComplex = 1; - } + StudyULabel (Expr, D); break; case EXPR_PLUS: - StudyExpr (Expr->Left, D, Sign); - StudyExpr (Expr->Right, D, Sign); + StudyPlus (Expr, D); break; case EXPR_MINUS: - StudyExpr (Expr->Left, D, Sign); - StudyExpr (Expr->Right, D, -Sign); + StudyMinus (Expr, D); break; case EXPR_MUL: - InitExprDesc (&SD1); - StudyExpr (Expr->Left, &SD, 1); - StudyExpr (Expr->Right, &SD1, 1); - if (SD.TooComplex == 0 && SD1.TooComplex == 0) { - /* First calculate SD = SD*SD1 if possible */ - if (ExprDescIsConst (&SD)) { - /* Left is a constant */ - SD1.Val *= SD.Val; - SD1.SymCount *= SD.Val; - SD1.SecCount *= SD.Val; - SD = SD1; - } else if (ExprDescIsConst (&SD1)) { - /* Right is constant */ - SD.Val *= SD1.Val; - SD.SymCount *= SD1.Val; - SD.SecCount *= SD1.Val; - } else { - D->TooComplex = 1; - } - /* Now calculate D * Sign * SD */ - if (!D->TooComplex) { - if ((D->SymCount == 0 || SD.SymCount == 0 || D->SymRef == SD.SymRef) && - (D->SecCount == 0 || SD.SecCount == 0 || D->SecRef == SD.SecRef)) { - D->Val += (Sign * SD.Val); - if (D->SymCount == 0) { - D->SymRef = SD.SymRef; - } - D->SymCount += (Sign * SD.SymCount); - if (D->SecCount == 0) { - D->SecRef = SD.SecRef; - } - D->SecCount += (Sign * SD.SecCount); - } - } else { - D->TooComplex = 1; - } - } else { - D->TooComplex = 1; - } + StudyMul (Expr, D); break; case EXPR_DIV: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - if (SD.Val == 0) { - Error ("Division by zero"); - D->TooComplex = 1; - } else { - D->Val += Sign * (SD.Left / SD.Val); - } - } else { - D->TooComplex = 1; - } + StudyDiv (Expr, D); break; case EXPR_MOD: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - if (SD.Val == 0) { - Error ("Modulo operation with zero"); - D->TooComplex = 1; - } else { - D->Val += Sign * (SD.Left % SD.Val); - } - } else { - D->TooComplex = 1; - } + StudyMod (Expr, D); break; case EXPR_OR: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left | SD.Val); - } else { - D->TooComplex = 1; - } + StudyOr (Expr, D); break; case EXPR_XOR: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left ^ SD.Val); - } else { - D->TooComplex = 1; - } + StudyXor (Expr, D); break; case EXPR_AND: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left & SD.Val); - } else { - D->TooComplex = 1; - } + StudyAnd (Expr, D); break; case EXPR_SHL: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += (Sign * shl_l (SD.Left, (unsigned) SD.Val)); - } else { - D->TooComplex = 1; - } + StudyShl (Expr, D); break; case EXPR_SHR: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += (Sign * shr_l (SD.Left, (unsigned) SD.Val)); - } else { - D->TooComplex = 1; - } + StudyShr (Expr, D); break; case EXPR_EQ: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left == SD.Val); - } else { - D->TooComplex = 1; - } + StudyEQ (Expr, D); break; case EXPR_NE: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left != SD.Val); - } else { - D->TooComplex = 1; - } + StudyNE (Expr, D); break; case EXPR_LT: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left < SD.Val); - } else { - D->TooComplex = 1; - } + StudyLT (Expr, D); break; case EXPR_GT: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left > SD.Val); - } else { - D->TooComplex = 1; - } + StudyGT (Expr, D); break; case EXPR_LE: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left <= SD.Val); - } else { - D->TooComplex = 1; - } + StudyLE (Expr, D); break; case EXPR_GE: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * (SD.Left >= SD.Val); - } else { - D->TooComplex = 1; - } + StudyGE (Expr, D); break; case EXPR_BOOLAND: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - if (SD.Val != 0) { /* Shortcut op */ - SD.Val = 0; - StudyExpr (Expr->Right, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * (SD.Val != 0); - } else { - D->TooComplex = 1; - } - } - } else { - D->TooComplex = 1; - } + StudyBoolAnd (Expr, D); break; case EXPR_BOOLOR: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - if (SD.Val == 0) { /* Shortcut op */ - StudyExpr (Expr->Right, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * (SD.Val != 0); - } else { - D->TooComplex = 1; - } - } else { - D->Val += Sign; - } - } else { - D->TooComplex = 1; - } + StudyBoolOr (Expr, D); break; case EXPR_BOOLXOR: - StudyBinaryExpr (Expr, &SD); - if (!SD.TooComplex) { - D->Val += Sign * ((SD.Left != 0) ^ (SD.Val != 0)); - } + StudyBoolXor (Expr, D); break; case EXPR_UNARY_MINUS: - StudyExpr (Expr->Left, D, -Sign); + StudyUnaryMinus (Expr, D); break; case EXPR_NOT: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += (Sign * ~SD.Val); - } else { - D->TooComplex = 1; - } + StudyNot (Expr, D); break; case EXPR_SWAP: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * (((SD.Val >> 8) & 0x00FF) | ((SD.Val << 8) & 0xFF00)); - } else { - D->TooComplex = 1; - } + StudySwap (Expr, D); break; case EXPR_BOOLNOT: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * (SD.Val != 0); - } else { - D->TooComplex = 1; - } - break; - - case EXPR_FORCEWORD: - case EXPR_FORCEFAR: - /* Ignore */ - StudyExpr (Expr->Left, D, Sign); + StudyBoolNot (Expr, D); break; case EXPR_BYTE0: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * (SD.Val & 0xFF); - } else { - D->TooComplex = 1; - } + StudyByte0 (Expr, D); break; case EXPR_BYTE1: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * ((SD.Val >> 8) & 0xFF); - } else { - D->TooComplex = 1; - } + StudyByte1 (Expr, D); break; case EXPR_BYTE2: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * ((SD.Val >> 16) & 0xFF); - } else { - D->TooComplex = 1; - } + StudyByte2 (Expr, D); break; case EXPR_BYTE3: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * ((SD.Val >> 24) & 0xFF); - } else { - D->TooComplex = 1; - } + StudyByte3 (Expr, D); break; case EXPR_WORD0: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * (SD.Val & 0xFFFF); - } else { - D->TooComplex = 1; - } + StudyWord0 (Expr, D); break; case EXPR_WORD1: - StudyExpr (Expr->Left, &SD, 1); - if (ExprDescIsConst (&SD)) { - D->Val += Sign * ((SD.Val >> 16) & 0xFFFF); - } else { - D->TooComplex = 1; - } + StudyWord1 (Expr, D); break; default: @@ -486,3 +1211,70 @@ void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign) +void StudyExpr (ExprNode* Expr, ExprDesc* D) +/* Study an expression tree and place the contents into D */ +{ + unsigned I; + + /* Call the internal function */ + StudyExprInternal (Expr, D); + + /* Remove symbol references with count zero */ + I = 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 of 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 0 + printf ("StudyExpr: "); DumpExpr (Expr, SymResolve); + 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 +} + + + diff --git a/src/ca65/studyexpr.h b/src/ca65/studyexpr.h index 8921733b4..6bac754f5 100644 --- a/src/ca65/studyexpr.h +++ b/src/ca65/studyexpr.h @@ -49,34 +49,69 @@ +/* Flags */ +#define ED_OK 0x00 /* Nothing special */ +#define ED_TOO_COMPLEX 0x01 /* Expression is too complex */ + +/* Symbol reference */ +typedef struct ED_SymRef ED_SymRef; +struct ED_SymRef { + long Count; /* Number of references */ + struct SymEntry* Ref; /* Actual reference */ +}; + +/* Section reference */ +typedef struct ED_SecRef ED_SecRef; +struct ED_SecRef { + long Count; /* Number of references */ + unsigned Ref; /* Actual reference */ +}; + /* Structure for parsing expression trees */ typedef struct ExprDesc ExprDesc; struct ExprDesc { + unsigned short Flags; /* See ED_xxx */ + unsigned char AddrSize; /* Address size of the expression */ long Val; /* The offset value */ - long Left; /* Left value for StudyBinaryExpr */ - int TooComplex; /* Expression is too complex to evaluate */ - long SymCount; /* Symbol reference count */ - long SecCount; /* Section reference count */ - struct SymEntry* SymRef; /* Symbol reference if any */ - unsigned SecRef; /* Section reference if any */ -}; + long Right; /* Right value for StudyBinaryExpr */ + /* Symbol reference management */ + unsigned SymCount; /* Number of symbols referenced */ + unsigned SymLimit; /* Memory allocated */ + ED_SymRef* SymRef; /* Symbol references */ + + /* Section reference management */ + unsigned SecCount; /* Number of sections referenced */ + unsigned SecLimit; /* Memory allocated */ + ED_SecRef* SecRef; /* Section references */ +}; /*****************************************************************************/ -/* Code */ +/* struct ExprDesc */ /*****************************************************************************/ -ExprDesc* InitExprDesc (ExprDesc* ED); +ExprDesc* ED_Init (ExprDesc* ED); /* Initialize an ExprDesc structure for use with StudyExpr */ -int ExprDescIsConst (const ExprDesc* ED); +void ED_Done (ExprDesc* ED); +/* Delete allocated memory for an ExprDesc. */ + +int ED_IsConst (const ExprDesc* ED); /* Return true if the expression is constant */ -void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign); + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +void StudyExpr (ExprNode* Expr, ExprDesc* D); /* Study an expression tree and place the contents into D */