mirror of
https://github.com/cc65/cc65.git
synced 2025-08-10 04:25:21 +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:
462
src/ca65/expr.c
462
src/ca65/expr.c
@@ -55,6 +55,7 @@
|
|||||||
#include "objfile.h"
|
#include "objfile.h"
|
||||||
#include "segment.h"
|
#include "segment.h"
|
||||||
#include "struct.h"
|
#include "struct.h"
|
||||||
|
#include "studyexpr.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "toklist.h"
|
#include "toklist.h"
|
||||||
@@ -76,60 +77,16 @@
|
|||||||
*/
|
*/
|
||||||
#define MAX_FREE_NODES 64
|
#define MAX_FREE_NODES 64
|
||||||
static ExprNode* FreeExprNodes = 0;
|
static ExprNode* FreeExprNodes = 0;
|
||||||
static unsigned FreeNodeCount = 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 */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* 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)
|
static ExprNode* NewExprNode (unsigned Op)
|
||||||
/* Create a new expression node */
|
/* 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)
|
ExprNode* Expression (void)
|
||||||
/* Evaluate an expression, build the expression tree on the heap and return
|
/* Evaluate an expression, build the expression tree on the heap and return
|
||||||
* a pointer to the root of the tree.
|
* a pointer to the root of the tree.
|
||||||
|
@@ -40,6 +40,7 @@ OBJS = anonname.o \
|
|||||||
segment.o \
|
segment.o \
|
||||||
spool.o \
|
spool.o \
|
||||||
struct.o \
|
struct.o \
|
||||||
|
studyexpr.o \
|
||||||
symentry.o \
|
symentry.o \
|
||||||
symbol.o \
|
symbol.o \
|
||||||
symtab.o \
|
symtab.o \
|
||||||
|
@@ -89,6 +89,7 @@ OBJS = anonname.obj \
|
|||||||
segment.obj \
|
segment.obj \
|
||||||
spool.obj \
|
spool.obj \
|
||||||
struct.obj \
|
struct.obj \
|
||||||
|
studyexpr.obj \
|
||||||
symbol.obj \
|
symbol.obj \
|
||||||
symentry.obj \
|
symentry.obj \
|
||||||
symtab.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<72>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<72>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
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user