mirror of
https://github.com/cc65/cc65.git
synced 2025-01-27 09:33:42 +00:00
Moved StudyExpr + helpers into its own module
git-svn-id: svn://svn.cc65.org/cc65/trunk@2675 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
cd918a387c
commit
7e44224dd0
462
src/ca65/expr.c
462
src/ca65/expr.c
@ -55,6 +55,7 @@
|
||||
#include "objfile.h"
|
||||
#include "segment.h"
|
||||
#include "struct.h"
|
||||
#include "studyexpr.h"
|
||||
#include "symbol.h"
|
||||
#include "symtab.h"
|
||||
#include "toklist.h"
|
||||
@ -76,60 +77,16 @@
|
||||
*/
|
||||
#define MAX_FREE_NODES 64
|
||||
static ExprNode* FreeExprNodes = 0;
|
||||
static unsigned FreeNodeCount = 0;
|
||||
|
||||
/* Structure for parsing expression trees */
|
||||
typedef struct ExprDesc ExprDesc;
|
||||
struct ExprDesc {
|
||||
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 */
|
||||
SymEntry* SymRef; /* Symbol reference if any */
|
||||
unsigned SecRef; /* Section reference if any */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Forwards */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign);
|
||||
/* Study an expression tree and place the contents into D */
|
||||
static unsigned FreeNodeCount = 0;
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Helpers */
|
||||
/* Helpers */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static ExprDesc* InitExprDesc (ExprDesc* ED)
|
||||
/* Initialize an ExprDesc structure for use with StudyExpr */
|
||||
{
|
||||
ED->Val = 0;
|
||||
ED->TooComplex = 0;
|
||||
ED->SymCount = 0;
|
||||
ED->SecCount = 0;
|
||||
return ED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ExprDescIsConst (const ExprDesc* ED)
|
||||
/* Return true if the expression is constant */
|
||||
{
|
||||
return (ED->TooComplex == 0 && ED->SymCount == 0 && ED->SecCount == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static ExprNode* NewExprNode (unsigned Op)
|
||||
/* Create a new expression node */
|
||||
{
|
||||
@ -1150,419 +1107,6 @@ static ExprNode* Expr0 (void)
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign)
|
||||
/* Study an expression tree and place the contents into D */
|
||||
{
|
||||
SymEntry* Sym;
|
||||
unsigned Sec;
|
||||
ExprDesc SD;
|
||||
ExprDesc SD1;
|
||||
|
||||
/* Initialize SD. This is not needed in all cases, but it's rather cheap
|
||||
* and simplifies the code below.
|
||||
*/
|
||||
InitExprDesc (&SD);
|
||||
|
||||
/* Study this expression node */
|
||||
switch (Expr->Op) {
|
||||
|
||||
case EXPR_LITERAL:
|
||||
D->Val += (Sign * Expr->V.Val);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_ULABEL:
|
||||
if (ULabCanResolve ()) {
|
||||
/* We can resolve the label */
|
||||
StudyExpr (ULabResolve (Expr->V.Val), D, Sign);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_PLUS:
|
||||
StudyExpr (Expr->Left, D, Sign);
|
||||
StudyExpr (Expr->Right, D, Sign);
|
||||
break;
|
||||
|
||||
case EXPR_MINUS:
|
||||
StudyExpr (Expr->Left, D, Sign);
|
||||
StudyExpr (Expr->Right, D, -Sign);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_OR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left | SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_XOR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left ^ SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_AND:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left & SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_SHL:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += (Sign * shl_l (SD.Left, (unsigned) SD.Val));
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_SHR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += (Sign * shr_l (SD.Left, (unsigned) SD.Val));
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_EQ:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left == SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_NE:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left != SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_LT:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left < SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_GT:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left > SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_LE:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left <= SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_GE:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left >= SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BOOLXOR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * ((SD.Left != 0) ^ (SD.Val != 0));
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_UNARY_MINUS:
|
||||
StudyExpr (Expr->Left, D, -Sign);
|
||||
break;
|
||||
|
||||
case EXPR_NOT:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += (Sign * ~SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
|
||||
case EXPR_BYTE0:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * (SD.Val & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BYTE1:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 8) & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BYTE2:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 16) & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BYTE3:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 24) & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_WORD0:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * (SD.Val & 0xFFFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_WORD1:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 16) & 0xFFFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Unknown Op type: %u", Expr->Op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ExprNode* Expression (void)
|
||||
/* Evaluate an expression, build the expression tree on the heap and return
|
||||
* a pointer to the root of the tree.
|
||||
|
@ -40,6 +40,7 @@ OBJS = anonname.o \
|
||||
segment.o \
|
||||
spool.o \
|
||||
struct.o \
|
||||
studyexpr.o \
|
||||
symentry.o \
|
||||
symbol.o \
|
||||
symtab.o \
|
||||
|
@ -89,6 +89,7 @@ OBJS = anonname.obj \
|
||||
segment.obj \
|
||||
spool.obj \
|
||||
struct.obj \
|
||||
studyexpr.obj \
|
||||
symbol.obj \
|
||||
symentry.obj \
|
||||
symtab.obj \
|
||||
|
488
src/ca65/studyexpr.c
Normal file
488
src/ca65/studyexpr.c
Normal file
@ -0,0 +1,488 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* studyexpr.c */
|
||||
/* */
|
||||
/* Study an expression tree */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2003 Ullrich von Bassewitz */
|
||||
/* Römerstraße 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "check.h"
|
||||
#include "print.h"
|
||||
#include "shift.h"
|
||||
|
||||
/* ca65 */
|
||||
#include "error.h"
|
||||
#include "segment.h"
|
||||
#include "studyexpr.h"
|
||||
#include "symtab.h"
|
||||
#include "ulabel.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ExprDesc* InitExprDesc (ExprDesc* ED)
|
||||
/* Initialize an ExprDesc structure for use with StudyExpr */
|
||||
{
|
||||
ED->Val = 0;
|
||||
ED->TooComplex = 0;
|
||||
ED->SymCount = 0;
|
||||
ED->SecCount = 0;
|
||||
return ED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ExprDescIsConst (const ExprDesc* ED)
|
||||
/* Return true if the expression is constant */
|
||||
{
|
||||
return (ED->TooComplex == 0 && ED->SymCount == 0 && ED->SecCount == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign)
|
||||
/* Study an expression tree and place the contents into D */
|
||||
{
|
||||
SymEntry* Sym;
|
||||
unsigned Sec;
|
||||
ExprDesc SD;
|
||||
ExprDesc SD1;
|
||||
|
||||
/* Initialize SD. This is not needed in all cases, but it's rather cheap
|
||||
* and simplifies the code below.
|
||||
*/
|
||||
InitExprDesc (&SD);
|
||||
|
||||
/* Study this expression node */
|
||||
switch (Expr->Op) {
|
||||
|
||||
case EXPR_LITERAL:
|
||||
D->Val += (Sign * Expr->V.Val);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_ULABEL:
|
||||
if (ULabCanResolve ()) {
|
||||
/* We can resolve the label */
|
||||
StudyExpr (ULabResolve (Expr->V.Val), D, Sign);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_PLUS:
|
||||
StudyExpr (Expr->Left, D, Sign);
|
||||
StudyExpr (Expr->Right, D, Sign);
|
||||
break;
|
||||
|
||||
case EXPR_MINUS:
|
||||
StudyExpr (Expr->Left, D, Sign);
|
||||
StudyExpr (Expr->Right, D, -Sign);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_OR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left | SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_XOR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left ^ SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_AND:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left & SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_SHL:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += (Sign * shl_l (SD.Left, (unsigned) SD.Val));
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_SHR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += (Sign * shr_l (SD.Left, (unsigned) SD.Val));
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_EQ:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left == SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_NE:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left != SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_LT:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left < SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_GT:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left > SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_LE:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left <= SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_GE:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * (SD.Left >= SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BOOLXOR:
|
||||
StudyBinaryExpr (Expr, &SD);
|
||||
if (!SD.TooComplex) {
|
||||
D->Val += Sign * ((SD.Left != 0) ^ (SD.Val != 0));
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_UNARY_MINUS:
|
||||
StudyExpr (Expr->Left, D, -Sign);
|
||||
break;
|
||||
|
||||
case EXPR_NOT:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += (Sign * ~SD.Val);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
break;
|
||||
|
||||
case EXPR_BYTE0:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * (SD.Val & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BYTE1:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 8) & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BYTE2:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 16) & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_BYTE3:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 24) & 0xFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_WORD0:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * (SD.Val & 0xFFFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXPR_WORD1:
|
||||
StudyExpr (Expr->Left, &SD, 1);
|
||||
if (ExprDescIsConst (&SD)) {
|
||||
D->Val += Sign * ((SD.Val >> 16) & 0xFFFF);
|
||||
} else {
|
||||
D->TooComplex = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal ("Unknown Op type: %u", Expr->Op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
88
src/ca65/studyexpr.h
Normal file
88
src/ca65/studyexpr.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* studyexpr.h */
|
||||
/* */
|
||||
/* Study an expression tree */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2003 Ullrich von Bassewitz */
|
||||
/* Römerstraße 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef STUDYEXPR_H
|
||||
#define STUDYEXPR_H
|
||||
|
||||
|
||||
|
||||
/* common */
|
||||
#include "exprdefs.h"
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Data */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Structure for parsing expression trees */
|
||||
typedef struct ExprDesc ExprDesc;
|
||||
struct ExprDesc {
|
||||
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 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
ExprDesc* InitExprDesc (ExprDesc* ED);
|
||||
/* Initialize an ExprDesc structure for use with StudyExpr */
|
||||
|
||||
int ExprDescIsConst (const ExprDesc* ED);
|
||||
/* Return true if the expression is constant */
|
||||
|
||||
void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign);
|
||||
/* Study an expression tree and place the contents into D */
|
||||
|
||||
|
||||
|
||||
/* End of studyexpr.h */
|
||||
#endif
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user