2000-05-28 13:40:48 +00:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* */
|
|
|
|
|
/* expr.c */
|
|
|
|
|
/* */
|
|
|
|
|
/* Expression evaluation for the ca65 macroassembler */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* */
|
2003-01-19 12:04:33 +00:00
|
|
|
|
/* (C) 1998-2003 Ullrich von Bassewitz */
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* R<>merstra<72>e 52 */
|
2003-06-06 20:47:59 +00:00
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
|
/* EMail: uz@cc65.org */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* */
|
|
|
|
|
/* */
|
|
|
|
|
/* 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. */
|
|
|
|
|
/* */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-11-20 15:22:57 +00:00
|
|
|
|
#include <string.h>
|
2002-11-26 13:44:35 +00:00
|
|
|
|
#include <time.h>
|
2000-11-20 15:22:57 +00:00
|
|
|
|
|
2000-07-29 15:53:33 +00:00
|
|
|
|
/* common */
|
2000-08-01 15:17:43 +00:00
|
|
|
|
#include "check.h"
|
2003-10-10 17:38:06 +00:00
|
|
|
|
#include "cpu.h"
|
2000-07-29 15:53:33 +00:00
|
|
|
|
#include "exprdefs.h"
|
2001-03-10 10:21:03 +00:00
|
|
|
|
#include "print.h"
|
2003-11-11 13:57:30 +00:00
|
|
|
|
#include "shift.h"
|
2000-08-23 07:01:18 +00:00
|
|
|
|
#include "tgttrans.h"
|
2003-08-12 15:11:55 +00:00
|
|
|
|
#include "version.h"
|
2000-07-29 15:53:33 +00:00
|
|
|
|
#include "xmalloc.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2000-07-29 15:53:33 +00:00
|
|
|
|
/* ca65 */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "error.h"
|
2003-10-21 20:34:56 +00:00
|
|
|
|
#include "expr.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "global.h"
|
|
|
|
|
#include "instr.h"
|
2000-06-03 11:15:11 +00:00
|
|
|
|
#include "nexttok.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "objfile.h"
|
2003-10-21 20:34:56 +00:00
|
|
|
|
#include "segment.h"
|
2003-11-06 11:22:31 +00:00
|
|
|
|
#include "symbol.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "symtab.h"
|
2000-06-03 11:15:11 +00:00
|
|
|
|
#include "toklist.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
|
#include "ulabel.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Data */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Since all expressions are first packed into expression trees, and each
|
|
|
|
|
* expression tree node is allocated on the heap, we add some type of special
|
|
|
|
|
* purpose memory allocation here: Instead of freeing the nodes, we save some
|
|
|
|
|
* number of freed nodes for later and remember them in a single linked list
|
|
|
|
|
* using the Left link.
|
|
|
|
|
*/
|
|
|
|
|
#define MAX_FREE_NODES 64
|
2003-11-11 13:57:30 +00:00
|
|
|
|
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 */
|
|
|
|
|
};
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Helpers */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
static ExprNode* NewExprNode (unsigned Op)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Create a new expression node */
|
|
|
|
|
{
|
|
|
|
|
ExprNode* N;
|
|
|
|
|
|
|
|
|
|
/* Do we have some nodes in the list already? */
|
|
|
|
|
if (FreeExprNodes) {
|
|
|
|
|
/* Use first node from list */
|
|
|
|
|
N = FreeExprNodes;
|
|
|
|
|
FreeExprNodes = N->Left;
|
|
|
|
|
} else {
|
|
|
|
|
/* Allocate fresh memory */
|
2000-06-14 09:32:22 +00:00
|
|
|
|
N = xmalloc (sizeof (ExprNode));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
2003-10-31 20:21:48 +00:00
|
|
|
|
N->Op = Op;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
N->Left = N->Right = 0;
|
|
|
|
|
N->Obj = 0;
|
|
|
|
|
|
|
|
|
|
return N;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void FreeExprNode (ExprNode* E)
|
|
|
|
|
/* Free a node */
|
|
|
|
|
{
|
|
|
|
|
if (E) {
|
2003-11-04 19:02:11 +00:00
|
|
|
|
if (E->Op == EXPR_SYMBOL) {
|
|
|
|
|
/* Remove the symbol reference */
|
2003-11-06 11:22:31 +00:00
|
|
|
|
SymDelExprRef (E->V.Sym, E);
|
2003-11-04 19:02:11 +00:00
|
|
|
|
}
|
|
|
|
|
/* Place the symbol into the free nodes list if possible */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
if (FreeNodeCount < MAX_FREE_NODES) {
|
|
|
|
|
/* Remember this node for later */
|
|
|
|
|
E->Left = FreeExprNodes;
|
|
|
|
|
FreeExprNodes = E;
|
|
|
|
|
} else {
|
|
|
|
|
/* Free the memory */
|
2000-06-14 09:32:22 +00:00
|
|
|
|
xfree (E);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/* Code */
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* Expr0 (void);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int IsByteRange (long Val)
|
|
|
|
|
/* Return true if this is a byte value */
|
|
|
|
|
{
|
|
|
|
|
return (Val & ~0xFFL) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int IsWordRange (long Val)
|
|
|
|
|
/* Return true if this is a word value */
|
|
|
|
|
{
|
|
|
|
|
return (Val & ~0xFFFF) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-12 16:40:26 +00:00
|
|
|
|
static int IsEasyConst (const ExprNode* E, long* Val)
|
|
|
|
|
/* Do some light checking if the given node is a constant. Don't care if E is
|
|
|
|
|
* a complex expression. If E is a constant, return true and place its value
|
|
|
|
|
* into Val, provided that Val is not NULL.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
/* Resolve symbols, follow symbol chains */
|
|
|
|
|
while (E->Op == EXPR_SYMBOL) {
|
|
|
|
|
E = SymResolve (E->V.Sym);
|
|
|
|
|
if (E == 0) {
|
|
|
|
|
/* Could not resolve */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Symbols resolved, check for a literal */
|
|
|
|
|
if (E->Op == EXPR_LITERAL) {
|
|
|
|
|
if (Val) {
|
|
|
|
|
*Val = E->V.Val;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Not found to be a const according to our tests */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static int FuncBlank (void)
|
|
|
|
|
/* Handle the .BLANK builtin function */
|
|
|
|
|
{
|
|
|
|
|
/* Assume no tokens if the closing brace follows (this is not correct in
|
|
|
|
|
* all cases, since the token may be the closing brace, but this will
|
|
|
|
|
* give a syntax error anyway and may not be handled by .BLANK.
|
|
|
|
|
*/
|
|
|
|
|
if (Tok == TOK_RPAREN) {
|
|
|
|
|
/* No tokens */
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
/* Skip any tokens */
|
|
|
|
|
int Braces = 0;
|
2003-01-19 12:04:33 +00:00
|
|
|
|
while (!TokIsSep (Tok)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
if (Tok == TOK_LPAREN) {
|
|
|
|
|
++Braces;
|
|
|
|
|
} else if (Tok == TOK_RPAREN) {
|
|
|
|
|
if (Braces == 0) {
|
|
|
|
|
/* Done */
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
--Braces;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int FuncConst (void)
|
|
|
|
|
/* Handle the .CONST builtin function */
|
|
|
|
|
{
|
|
|
|
|
/* Read an expression */
|
|
|
|
|
ExprNode* Expr = Expression ();
|
|
|
|
|
|
|
|
|
|
/* Check the constness of the expression */
|
2003-11-11 13:57:30 +00:00
|
|
|
|
int Result = IsConstExpr (Expr, 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Free the expression */
|
|
|
|
|
FreeExpr (Expr);
|
|
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int FuncDefined (void)
|
|
|
|
|
/* Handle the .DEFINED builtin function */
|
|
|
|
|
{
|
2003-11-06 11:22:31 +00:00
|
|
|
|
/* Parse the symbol name and search for the symbol */
|
|
|
|
|
SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
|
2002-11-22 01:45:00 +00:00
|
|
|
|
|
2003-11-06 11:22:31 +00:00
|
|
|
|
/* Check if the symbol is defined */
|
|
|
|
|
return (Sym != 0 && SymIsDef (Sym));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int DoMatch (enum TC EqualityLevel)
|
|
|
|
|
/* Handle the .MATCH and .XMATCH builtin functions */
|
|
|
|
|
{
|
|
|
|
|
int Result;
|
|
|
|
|
TokNode* Root = 0;
|
|
|
|
|
TokNode* Last = 0;
|
|
|
|
|
TokNode* Node = 0;
|
|
|
|
|
|
|
|
|
|
/* A list of tokens follows. Read this list and remember it building a
|
|
|
|
|
* single linked list of tokens including attributes. The list is
|
|
|
|
|
* terminated by a comma.
|
|
|
|
|
*/
|
|
|
|
|
while (Tok != TOK_COMMA) {
|
|
|
|
|
|
|
|
|
|
/* We may not end-of-line of end-of-file here */
|
2003-01-19 12:04:33 +00:00
|
|
|
|
if (TokIsSep (Tok)) {
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("Unexpected end of line");
|
2000-05-28 13:40:48 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get a node with this token */
|
|
|
|
|
Node = NewTokNode ();
|
|
|
|
|
|
|
|
|
|
/* Insert the node into the list */
|
|
|
|
|
if (Last == 0) {
|
|
|
|
|
Root = Node;
|
|
|
|
|
} else {
|
|
|
|
|
Last->Next = Node;
|
|
|
|
|
}
|
|
|
|
|
Last = Node;
|
|
|
|
|
|
|
|
|
|
/* Skip the token */
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip the comma */
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Read the second list which is terminated by the right parenthesis and
|
|
|
|
|
* compare each token against the one in the first list.
|
|
|
|
|
*/
|
|
|
|
|
Result = 1;
|
|
|
|
|
Node = Root;
|
|
|
|
|
while (Tok != TOK_RPAREN) {
|
|
|
|
|
|
|
|
|
|
/* We may not end-of-line of end-of-file here */
|
2003-01-19 12:04:33 +00:00
|
|
|
|
if (TokIsSep (Tok)) {
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("Unexpected end of line");
|
2000-05-28 13:40:48 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compare the tokens if the result is not already known */
|
|
|
|
|
if (Result != 0) {
|
|
|
|
|
if (Node == 0) {
|
|
|
|
|
/* The second list is larger than the first one */
|
|
|
|
|
Result = 0;
|
|
|
|
|
} else if (TokCmp (Node) < EqualityLevel) {
|
|
|
|
|
/* Tokens do not match */
|
|
|
|
|
Result = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Next token in first list */
|
|
|
|
|
if (Node) {
|
|
|
|
|
Node = Node->Next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Next token in current list */
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if there are remaining tokens in the first list */
|
|
|
|
|
if (Node != 0) {
|
|
|
|
|
Result = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free the token list */
|
|
|
|
|
while (Root) {
|
|
|
|
|
Node = Root;
|
|
|
|
|
Root = Root->Next;
|
|
|
|
|
FreeTokNode (Node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Done, return the result */
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int FuncMatch (void)
|
|
|
|
|
/* Handle the .MATCH function */
|
|
|
|
|
{
|
|
|
|
|
return DoMatch (tcSameToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int FuncReferenced (void)
|
|
|
|
|
/* Handle the .REFERENCED builtin function */
|
|
|
|
|
{
|
2003-11-06 11:22:31 +00:00
|
|
|
|
/* Parse the symbol name and search for the symbol */
|
|
|
|
|
SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-06 11:22:31 +00:00
|
|
|
|
/* Check if the symbol is referenced */
|
|
|
|
|
return (Sym != 0 && SymIsRef (Sym));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-25 21:32:11 +00:00
|
|
|
|
static int FuncStrAt (void)
|
|
|
|
|
/* Handle the .STRAT function */
|
|
|
|
|
{
|
|
|
|
|
char Str [sizeof(SVal)];
|
|
|
|
|
long Index;
|
|
|
|
|
|
|
|
|
|
/* String constant expected */
|
|
|
|
|
if (Tok != TOK_STRCON) {
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("String constant expected");
|
2000-07-25 21:32:11 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remember the string and skip it */
|
|
|
|
|
strcpy (Str, SVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Comma must follow */
|
|
|
|
|
ConsumeComma ();
|
|
|
|
|
|
|
|
|
|
/* Expression expected */
|
|
|
|
|
Index = ConstExpression ();
|
|
|
|
|
|
|
|
|
|
/* Must be a valid index */
|
2001-09-15 11:51:08 +00:00
|
|
|
|
if (Index >= (long) strlen (Str)) {
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("Range error");
|
2000-07-25 21:32:11 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-12-01 10:37:41 +00:00
|
|
|
|
/* Return the char, handle as unsigned. Be sure to translate it into
|
|
|
|
|
* the target character set.
|
|
|
|
|
*/
|
|
|
|
|
return (unsigned char) TgtTranslateChar (Str [(size_t)Index]);
|
2000-07-25 21:32:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int FuncStrLen (void)
|
|
|
|
|
/* Handle the .STRLEN function */
|
|
|
|
|
{
|
|
|
|
|
/* String constant expected */
|
|
|
|
|
if (Tok != TOK_STRCON) {
|
|
|
|
|
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("String constant expected");
|
2000-07-25 21:32:11 +00:00
|
|
|
|
/* Smart error recovery */
|
|
|
|
|
if (Tok != TOK_RPAREN) {
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Get the length of the string */
|
|
|
|
|
int Len = strlen (SVal);
|
|
|
|
|
|
|
|
|
|
/* Skip the string */
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Return the length */
|
|
|
|
|
return Len;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-07-15 10:33:32 +00:00
|
|
|
|
static int FuncTCount (void)
|
|
|
|
|
/* Handle the .TCOUNT function */
|
|
|
|
|
{
|
|
|
|
|
/* We have a list of tokens that ends with the closing paren. Skip
|
|
|
|
|
* the tokens, handling nested braces and count them.
|
|
|
|
|
*/
|
|
|
|
|
int Count = 0;
|
|
|
|
|
unsigned Parens = 0;
|
|
|
|
|
while (Parens != 0 || Tok != TOK_RPAREN) {
|
|
|
|
|
|
|
|
|
|
/* Check for end of line or end of input. Since the calling function
|
|
|
|
|
* will check for the closing paren, we don't need to print an error
|
|
|
|
|
* here, just bail out.
|
|
|
|
|
*/
|
2003-01-19 12:04:33 +00:00
|
|
|
|
if (TokIsSep (Tok)) {
|
2000-07-15 10:33:32 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* One more token */
|
|
|
|
|
++Count;
|
|
|
|
|
|
|
|
|
|
/* Keep track of the nesting level */
|
|
|
|
|
switch (Tok) {
|
|
|
|
|
case TOK_LPAREN: ++Parens; break;
|
|
|
|
|
case TOK_RPAREN: --Parens; break;
|
2000-07-25 21:32:11 +00:00
|
|
|
|
default: break;
|
2000-07-15 10:33:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Skip the token */
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the number of tokens */
|
|
|
|
|
return Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
static int FuncXMatch (void)
|
|
|
|
|
/* Handle the .XMATCH function */
|
|
|
|
|
{
|
|
|
|
|
return DoMatch (tcIdentical);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* Function (int (*F) (void))
|
|
|
|
|
/* Handle builtin functions */
|
|
|
|
|
{
|
|
|
|
|
long Result;
|
|
|
|
|
|
|
|
|
|
/* Skip the keyword */
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Expression must be enclosed in braces */
|
|
|
|
|
if (Tok != TOK_LPAREN) {
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("'(' expected");
|
2000-05-28 13:40:48 +00:00
|
|
|
|
SkipUntilSep ();
|
2003-06-06 21:09:36 +00:00
|
|
|
|
return GenLiteralExpr (0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Call the function itself */
|
2000-07-15 10:33:32 +00:00
|
|
|
|
Result = F ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Closing brace must follow */
|
|
|
|
|
ConsumeRParen ();
|
|
|
|
|
|
|
|
|
|
/* Return an expression node with the boolean code */
|
2003-06-06 21:09:36 +00:00
|
|
|
|
return GenLiteralExpr (Result);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* Factor (void)
|
|
|
|
|
{
|
2003-11-12 16:40:26 +00:00
|
|
|
|
ExprNode* L;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ExprNode* N;
|
|
|
|
|
SymEntry* S;
|
2003-11-12 16:40:26 +00:00
|
|
|
|
long Val;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
switch (Tok) {
|
2000-07-25 21:32:11 +00:00
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
case TOK_INTCON:
|
2003-06-06 21:09:36 +00:00
|
|
|
|
N = GenLiteralExpr (IVal);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
|
2000-08-21 21:20:40 +00:00
|
|
|
|
case TOK_CHARCON:
|
2003-06-06 21:09:36 +00:00
|
|
|
|
N = GenLiteralExpr (TgtTranslateChar (IVal));
|
2000-08-21 21:20:40 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
|
2003-11-06 11:22:31 +00:00
|
|
|
|
case TOK_NAMESPACE:
|
|
|
|
|
case TOK_IDENT:
|
|
|
|
|
/* Search for the symbol */
|
|
|
|
|
S = ParseScopedSymName (SYM_ALLOC_NEW);
|
|
|
|
|
if (S == 0) {
|
|
|
|
|
/* Some weird error happened before */
|
|
|
|
|
N = GenLiteralExpr (0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
} else {
|
2003-11-06 11:22:31 +00:00
|
|
|
|
/* Mark the symbol as referenced */
|
|
|
|
|
SymRef (S);
|
|
|
|
|
/* Create symbol node */
|
|
|
|
|
N = GenSymExpr (S);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_ULABEL:
|
|
|
|
|
N = ULabRef (IVal);
|
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_MINUS:
|
|
|
|
|
NextTok ();
|
2003-11-12 16:40:26 +00:00
|
|
|
|
L = Factor ();
|
|
|
|
|
if (IsEasyConst (L, &Val)) {
|
|
|
|
|
FreeExpr (L);
|
|
|
|
|
N = GenLiteralExpr (-Val);
|
|
|
|
|
} else {
|
|
|
|
|
N = NewExprNode (EXPR_UNARY_MINUS);
|
|
|
|
|
N->Left = L;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_NOT:
|
|
|
|
|
NextTok ();
|
2003-11-12 16:40:26 +00:00
|
|
|
|
L = Factor ();
|
|
|
|
|
if (IsEasyConst (L, &Val)) {
|
|
|
|
|
FreeExpr (L);
|
|
|
|
|
N = GenLiteralExpr (~Val);
|
|
|
|
|
} else {
|
|
|
|
|
N = NewExprNode (EXPR_NOT);
|
|
|
|
|
N->Left = L;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_STAR:
|
|
|
|
|
case TOK_PC:
|
|
|
|
|
NextTok ();
|
2003-06-06 21:09:36 +00:00
|
|
|
|
N = GenCurrentPC ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_LT:
|
|
|
|
|
NextTok ();
|
2003-11-12 16:40:26 +00:00
|
|
|
|
L = Factor ();
|
|
|
|
|
if (IsEasyConst (L, &Val)) {
|
|
|
|
|
FreeExpr (L);
|
|
|
|
|
N = GenLiteralExpr (Val & 0xFF);
|
|
|
|
|
} else {
|
|
|
|
|
N = NewExprNode (EXPR_BYTE0);
|
|
|
|
|
N->Left = L;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_GT:
|
|
|
|
|
NextTok ();
|
2003-11-12 16:40:26 +00:00
|
|
|
|
L = Factor ();
|
|
|
|
|
if (IsEasyConst (L, &Val)) {
|
|
|
|
|
FreeExpr (L);
|
|
|
|
|
N = GenLiteralExpr ((Val >> 8) & 0xFF);
|
|
|
|
|
} else {
|
|
|
|
|
N = NewExprNode (EXPR_BYTE1);
|
|
|
|
|
N->Left = L;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
case TOK_BANK:
|
|
|
|
|
NextTok ();
|
2003-11-12 16:40:26 +00:00
|
|
|
|
L = Factor ();
|
|
|
|
|
if (IsEasyConst (L, &Val)) {
|
|
|
|
|
FreeExpr (L);
|
|
|
|
|
N = GenLiteralExpr ((Val >> 16) & 0xFF);
|
|
|
|
|
} else {
|
|
|
|
|
N = NewExprNode (EXPR_BYTE2);
|
|
|
|
|
N->Left = L;
|
|
|
|
|
}
|
2003-11-11 13:57:30 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
case TOK_LPAREN:
|
|
|
|
|
NextTok ();
|
|
|
|
|
N = Expr0 ();
|
|
|
|
|
ConsumeRParen ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_BLANK:
|
|
|
|
|
N = Function (FuncBlank);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_CONST:
|
|
|
|
|
N = Function (FuncConst);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_CPU:
|
2003-10-10 17:38:06 +00:00
|
|
|
|
N = GenLiteralExpr (CPUIsets[CPU]);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_DEFINED:
|
|
|
|
|
N = Function (FuncDefined);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_MATCH:
|
|
|
|
|
N = Function (FuncMatch);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_REFERENCED:
|
|
|
|
|
N = Function (FuncReferenced);
|
|
|
|
|
break;
|
|
|
|
|
|
2000-07-25 21:32:11 +00:00
|
|
|
|
case TOK_STRAT:
|
|
|
|
|
N = Function (FuncStrAt);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_STRLEN:
|
|
|
|
|
N = Function (FuncStrLen);
|
|
|
|
|
break;
|
|
|
|
|
|
2000-07-15 10:33:32 +00:00
|
|
|
|
case TOK_TCOUNT:
|
|
|
|
|
N = Function (FuncTCount);
|
|
|
|
|
break;
|
|
|
|
|
|
2002-11-26 13:44:35 +00:00
|
|
|
|
case TOK_TIME:
|
2003-06-06 21:09:36 +00:00
|
|
|
|
N = GenLiteralExpr (time (0));
|
2002-11-26 13:44:35 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
|
2003-08-12 15:11:55 +00:00
|
|
|
|
case TOK_VERSION:
|
|
|
|
|
N = GenLiteralExpr (VERSION);
|
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
case TOK_XMATCH:
|
|
|
|
|
N = Function (FuncXMatch);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2000-09-02 12:01:40 +00:00
|
|
|
|
if (LooseCharTerm && Tok == TOK_STRCON && strlen(SVal) == 1) {
|
|
|
|
|
/* A character constant */
|
2003-06-06 21:09:36 +00:00
|
|
|
|
N = GenLiteralExpr (TgtTranslateChar (SVal[0]));
|
2000-09-02 12:01:40 +00:00
|
|
|
|
} else {
|
2003-06-06 21:09:36 +00:00
|
|
|
|
N = GenLiteralExpr (0); /* Dummy */
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("Syntax error");
|
2000-09-02 12:01:40 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return N;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* Term (void)
|
|
|
|
|
{
|
|
|
|
|
/* Read left hand side */
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* Root = Factor ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Handle multiplicative operations */
|
|
|
|
|
while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
|
|
|
|
|
Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
|
|
|
|
|
Tok == TOK_SHR) {
|
|
|
|
|
|
2003-11-12 16:40:26 +00:00
|
|
|
|
long LVal, RVal, Val;
|
|
|
|
|
ExprNode* Left;
|
|
|
|
|
ExprNode* Right;
|
|
|
|
|
|
|
|
|
|
/* Remember the token and skip it */
|
|
|
|
|
enum Token T = Tok;
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Move root to left side and read the right side */
|
|
|
|
|
Left = Root;
|
|
|
|
|
Right = Factor ();
|
|
|
|
|
|
|
|
|
|
/* If both expressions are constant, we can evaluate the term */
|
|
|
|
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
|
|
|
|
|
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_MUL:
|
|
|
|
|
Val = LVal * RVal;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_DIV:
|
|
|
|
|
if (RVal == 0) {
|
|
|
|
|
Error ("Division by zero");
|
|
|
|
|
Val = 1;
|
|
|
|
|
} else {
|
|
|
|
|
Val = LVal / RVal;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_MOD:
|
|
|
|
|
if (RVal == 0) {
|
|
|
|
|
Error ("Modulo operation with zero");
|
|
|
|
|
Val = 1;
|
|
|
|
|
} else {
|
|
|
|
|
Val = LVal % RVal;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_AND:
|
|
|
|
|
Val = LVal & RVal;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_XOR:
|
|
|
|
|
Val = LVal ^ RVal;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_SHL:
|
|
|
|
|
Val = shl_l (LVal, RVal);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TOK_SHR:
|
|
|
|
|
Val = shr_l (LVal, RVal);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Internal ("Invalid token");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate a literal expression and delete the old left and
|
|
|
|
|
* right sides.
|
|
|
|
|
*/
|
|
|
|
|
FreeExpr (Left);
|
|
|
|
|
FreeExpr (Right);
|
|
|
|
|
Root = GenLiteralExpr (Val);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Generate an expression tree */
|
|
|
|
|
unsigned char Op;
|
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_MUL: Op = EXPR_MUL; break;
|
|
|
|
|
case TOK_DIV: Op = EXPR_DIV; break;
|
|
|
|
|
case TOK_MOD: Op = EXPR_MOD; break;
|
|
|
|
|
case TOK_AND: Op = EXPR_AND; break;
|
|
|
|
|
case TOK_XOR: Op = EXPR_XOR; break;
|
|
|
|
|
case TOK_SHL: Op = EXPR_SHL; break;
|
|
|
|
|
case TOK_SHR: Op = EXPR_SHR; break;
|
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
|
|
|
|
Root = NewExprNode (Op);
|
|
|
|
|
Root->Left = Left;
|
|
|
|
|
Root->Right = Right;
|
2003-10-31 20:21:48 +00:00
|
|
|
|
|
2003-11-12 16:40:26 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the expression tree we've created */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* SimpleExpr (void)
|
|
|
|
|
{
|
|
|
|
|
/* Read left hand side */
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* Root = Term ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Handle additive operations */
|
|
|
|
|
while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
|
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
/* Create the new node */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ExprNode* Left = Root;
|
|
|
|
|
switch (Tok) {
|
2003-10-31 20:21:48 +00:00
|
|
|
|
case TOK_PLUS: Root = NewExprNode (EXPR_PLUS); break;
|
|
|
|
|
case TOK_MINUS: Root = NewExprNode (EXPR_MINUS); break;
|
|
|
|
|
case TOK_OR: Root = NewExprNode (EXPR_OR); break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Root->Left = Left;
|
|
|
|
|
|
|
|
|
|
/* Skip the operator token */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Parse the right hand side */
|
|
|
|
|
Root->Right = Term ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the expression tree we've created */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* BoolExpr (void)
|
|
|
|
|
/* Evaluate a boolean expression */
|
|
|
|
|
{
|
|
|
|
|
/* Read left hand side */
|
|
|
|
|
ExprNode* Root = SimpleExpr ();
|
|
|
|
|
|
|
|
|
|
/* Handle booleans */
|
|
|
|
|
while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
|
|
|
|
|
Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
|
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
/* Create the new node */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ExprNode* Left = Root;
|
|
|
|
|
switch (Tok) {
|
2003-10-31 20:21:48 +00:00
|
|
|
|
case TOK_EQ: Root = NewExprNode (EXPR_EQ); break;
|
|
|
|
|
case TOK_NE: Root = NewExprNode (EXPR_NE); break;
|
|
|
|
|
case TOK_LT: Root = NewExprNode (EXPR_LT); break;
|
|
|
|
|
case TOK_GT: Root = NewExprNode (EXPR_GT); break;
|
|
|
|
|
case TOK_LE: Root = NewExprNode (EXPR_LE); break;
|
|
|
|
|
case TOK_GE: Root = NewExprNode (EXPR_GE); break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Root->Left = Left;
|
|
|
|
|
|
|
|
|
|
/* Skip the operator token */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Parse the right hand side */
|
|
|
|
|
Root->Right = SimpleExpr ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the expression tree we've created */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* Expr2 (void)
|
|
|
|
|
/* Boolean operators: AND and XOR */
|
|
|
|
|
{
|
|
|
|
|
/* Read left hand side */
|
|
|
|
|
ExprNode* Root = BoolExpr ();
|
|
|
|
|
|
|
|
|
|
/* Handle booleans */
|
2003-11-11 13:57:30 +00:00
|
|
|
|
while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
/* Create the new node */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ExprNode* Left = Root;
|
|
|
|
|
switch (Tok) {
|
2003-11-11 13:57:30 +00:00
|
|
|
|
case TOK_BOOLAND: Root = NewExprNode (EXPR_BOOLAND); break;
|
|
|
|
|
case TOK_BOOLXOR: Root = NewExprNode (EXPR_BOOLXOR); break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Root->Left = Left;
|
|
|
|
|
|
|
|
|
|
/* Skip the operator token */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Parse the right hand side */
|
|
|
|
|
Root->Right = BoolExpr ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the expression tree we've created */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* Expr1 (void)
|
|
|
|
|
/* Boolean operators: OR */
|
|
|
|
|
{
|
|
|
|
|
/* Read left hand side */
|
|
|
|
|
ExprNode* Root = Expr2 ();
|
|
|
|
|
|
|
|
|
|
/* Handle booleans */
|
2003-11-11 13:57:30 +00:00
|
|
|
|
while (Tok == TOK_BOOLOR) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
/* Create the new node */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ExprNode* Left = Root;
|
|
|
|
|
switch (Tok) {
|
2003-11-11 13:57:30 +00:00
|
|
|
|
case TOK_BOOLOR: Root = NewExprNode (EXPR_BOOLOR); break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Root->Left = Left;
|
|
|
|
|
|
|
|
|
|
/* Skip the operator token */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Parse the right hand side */
|
|
|
|
|
Root->Right = Expr2 ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the expression tree we've created */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* Expr0 (void)
|
|
|
|
|
/* Boolean operators: NOT */
|
|
|
|
|
{
|
|
|
|
|
ExprNode* Root;
|
|
|
|
|
|
|
|
|
|
/* Handle booleans */
|
2003-11-11 13:57:30 +00:00
|
|
|
|
if (Tok == TOK_BOOLNOT) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
/* Create the new node */
|
2003-11-11 13:57:30 +00:00
|
|
|
|
Root = NewExprNode (EXPR_BOOLNOT);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
/* Skip the operator token */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Parse the left hand side, allow more BNOTs */
|
|
|
|
|
Root->Left = Expr0 ();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Read left hand side */
|
|
|
|
|
Root = Expr1 ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the expression tree we've created */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
static void StudyExpr (ExprNode* Expr, ExprDesc* D, int Sign);
|
|
|
|
|
static void StudyBinaryExpr (ExprNode* Expr, ExprDesc* D)
|
|
|
|
|
/* Study a binary expression subtree */
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* SimplifyExpr (ExprNode* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Try to simplify the given expression tree */
|
|
|
|
|
{
|
2003-11-11 13:57:30 +00:00
|
|
|
|
if (Expr && Expr->Op != EXPR_LITERAL) {
|
|
|
|
|
|
|
|
|
|
/* Create an expression description and initialize it */
|
|
|
|
|
ExprDesc D;
|
|
|
|
|
InitExprDesc (&D);
|
|
|
|
|
|
|
|
|
|
/* Study the expression */
|
|
|
|
|
StudyExpr (Expr, &D, 1);
|
|
|
|
|
|
|
|
|
|
/* Now check if we can generate a literal value */
|
|
|
|
|
if (ExprDescIsConst (&D)) {
|
|
|
|
|
/* No external references */
|
|
|
|
|
FreeExpr (Expr);
|
|
|
|
|
Expr = GenLiteralExpr (D.Val);
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
2003-11-11 13:57:30 +00:00
|
|
|
|
return Expr;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExprNode* Expression (void)
|
|
|
|
|
/* Evaluate an expression, build the expression tree on the heap and return
|
|
|
|
|
* a pointer to the root of the tree.
|
|
|
|
|
*/
|
|
|
|
|
{
|
2003-11-11 13:57:30 +00:00
|
|
|
|
#if 1
|
2000-05-28 13:40:48 +00:00
|
|
|
|
return SimplifyExpr (Expr0 ());
|
2003-11-11 13:57:30 +00:00
|
|
|
|
#else
|
|
|
|
|
/* Test code */
|
|
|
|
|
ExprNode* Expr = Expr0 ();
|
|
|
|
|
printf ("Before: "); DumpExpr (Expr, SymResolve);
|
|
|
|
|
Expr = SimplifyExpr (Expr);
|
|
|
|
|
printf ("After: "); DumpExpr (Expr, SymResolve);
|
|
|
|
|
return Expr;
|
|
|
|
|
#endif
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long ConstExpression (void)
|
|
|
|
|
/* Parse an expression. Check if the expression is const, and print an error
|
|
|
|
|
* message if not. Return the value of the expression, or a dummy, if it is
|
|
|
|
|
* not constant.
|
|
|
|
|
*/
|
|
|
|
|
{
|
2003-11-11 13:57:30 +00:00
|
|
|
|
#if 1
|
|
|
|
|
/* Read the expression */
|
|
|
|
|
ExprNode* Expr = Expr0 ();
|
|
|
|
|
#else
|
|
|
|
|
/* Test code */
|
|
|
|
|
ExprNode* Expr = Expression ();
|
|
|
|
|
#endif
|
2003-10-31 20:56:40 +00:00
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* Study the expression */
|
|
|
|
|
ExprDesc D;
|
|
|
|
|
InitExprDesc (&D);
|
|
|
|
|
StudyExpr (Expr, &D, 1);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* Check if the expression is constant */
|
|
|
|
|
if (!ExprDescIsConst (&D)) {
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("Constant expression expected");
|
2003-11-11 13:57:30 +00:00
|
|
|
|
D.Val = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
2003-10-31 20:56:40 +00:00
|
|
|
|
|
|
|
|
|
/* Free the expression tree and return the value */
|
|
|
|
|
FreeExpr (Expr);
|
2003-11-11 13:57:30 +00:00
|
|
|
|
return D.Val;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 20:47:59 +00:00
|
|
|
|
void FreeExpr (ExprNode* Root)
|
|
|
|
|
/* Free the expression, Root is pointing to. */
|
|
|
|
|
{
|
|
|
|
|
if (Root) {
|
|
|
|
|
FreeExpr (Root->Left);
|
|
|
|
|
FreeExpr (Root->Right);
|
|
|
|
|
FreeExprNode (Root);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenLiteralExpr (long Val)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Return an expression tree that encodes the given literal value */
|
|
|
|
|
{
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* Expr = NewExprNode (EXPR_LITERAL);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
Expr->V.Val = Val;
|
|
|
|
|
return Expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* GenSymExpr (SymEntry* Sym)
|
|
|
|
|
/* Return an expression node that encodes the given symbol */
|
|
|
|
|
{
|
|
|
|
|
ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
|
|
|
|
|
Expr->V.Sym = Sym;
|
2003-11-06 11:22:31 +00:00
|
|
|
|
SymAddExprRef (Sym, Expr);
|
2003-10-31 20:21:48 +00:00
|
|
|
|
return Expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* GenSectionExpr (unsigned SegNum)
|
|
|
|
|
/* Return an expression node for the given section */
|
|
|
|
|
{
|
|
|
|
|
ExprNode* Expr = NewExprNode (EXPR_SECTION);
|
|
|
|
|
Expr->V.SegNum = SegNum;
|
|
|
|
|
return Expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenCurrentPC (void)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Return the current program counter as expression */
|
|
|
|
|
{
|
|
|
|
|
ExprNode* Root;
|
|
|
|
|
|
|
|
|
|
if (RelocMode) {
|
|
|
|
|
/* Create SegmentBase + Offset */
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Root = NewExprNode (EXPR_PLUS);
|
2003-11-07 19:28:37 +00:00
|
|
|
|
Root->Left = GenSectionExpr (GetCurrentSegNum ());
|
2003-06-06 21:09:36 +00:00
|
|
|
|
Root->Right = GenLiteralExpr (GetPC ());
|
2000-05-28 13:40:48 +00:00
|
|
|
|
} else {
|
2003-06-06 21:09:36 +00:00
|
|
|
|
/* Absolute mode, just return PC value */
|
|
|
|
|
Root = GenLiteralExpr (GetPC ());
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenSwapExpr (ExprNode* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Return an extended expression with lo and hi bytes swapped */
|
|
|
|
|
{
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* N = NewExprNode (EXPR_SWAP);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
N->Left = Expr;
|
|
|
|
|
return N;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenBranchExpr (unsigned Offs)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Return an expression that encodes the difference between current PC plus
|
|
|
|
|
* offset and the target expression (that is, Expression() - (*+Offs) ).
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
ExprNode* N;
|
|
|
|
|
ExprNode* Root;
|
|
|
|
|
|
|
|
|
|
/* Create *+Offs */
|
|
|
|
|
if (RelocMode) {
|
2003-10-31 20:21:48 +00:00
|
|
|
|
N = NewExprNode (EXPR_PLUS);
|
2003-11-07 19:28:37 +00:00
|
|
|
|
N->Left = GenSectionExpr (GetCurrentSegNum ());
|
2003-11-11 13:57:30 +00:00
|
|
|
|
N->Right = GenLiteralExpr (GetPC () + Offs);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
} else {
|
2003-06-06 21:09:36 +00:00
|
|
|
|
N = GenLiteralExpr (GetPC () + Offs);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create the root node */
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Root = NewExprNode (EXPR_MINUS);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
Root->Left = Expression ();
|
|
|
|
|
Root->Right = N;
|
|
|
|
|
|
|
|
|
|
/* Return the result */
|
|
|
|
|
return SimplifyExpr (Root);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenULabelExpr (unsigned Num)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Return an expression for an unnamed label with the given index */
|
|
|
|
|
{
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* Node = NewExprNode (EXPR_ULABEL);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
Node->V.Val = Num;
|
|
|
|
|
|
|
|
|
|
/* Return the new node */
|
|
|
|
|
return Node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenByteExpr (ExprNode* Expr)
|
2003-06-06 20:47:59 +00:00
|
|
|
|
/* Force the given expression into a byte and return the result */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
{
|
2003-06-06 20:47:59 +00:00
|
|
|
|
/* Use the low byte operator to force the expression into byte size */
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* Root = NewExprNode (EXPR_BYTE0);
|
2003-06-06 20:47:59 +00:00
|
|
|
|
Root->Left = Expr;
|
|
|
|
|
|
|
|
|
|
/* Return the result */
|
|
|
|
|
return Root;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenWordExpr (ExprNode* Expr)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Force the given expression into a word and return the result. */
|
|
|
|
|
{
|
2003-06-06 20:47:59 +00:00
|
|
|
|
/* AND the expression by $FFFF to force it into word size */
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* Root = NewExprNode (EXPR_AND);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
Root->Left = Expr;
|
2003-06-06 21:09:36 +00:00
|
|
|
|
Root->Right = GenLiteralExpr (0xFFFF);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Return the result */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-06-06 21:09:36 +00:00
|
|
|
|
ExprNode* GenNE (ExprNode* Expr, long Val)
|
|
|
|
|
/* Generate an expression that compares Expr and Val for inequality */
|
2003-06-06 20:47:59 +00:00
|
|
|
|
{
|
|
|
|
|
/* Generate a compare node */
|
2003-10-31 20:21:48 +00:00
|
|
|
|
ExprNode* Root = NewExprNode (EXPR_NE);
|
2003-06-06 20:47:59 +00:00
|
|
|
|
Root->Left = Expr;
|
2003-06-06 21:09:36 +00:00
|
|
|
|
Root->Right = GenLiteralExpr (Val);
|
2003-06-06 20:47:59 +00:00
|
|
|
|
|
|
|
|
|
/* Return the result */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
int IsConstExpr (ExprNode* Expr, long* Val)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Return true if the given expression is a constant expression, that is, one
|
2003-11-11 13:57:30 +00:00
|
|
|
|
* with no references to external symbols. If Val is not NULL and the
|
|
|
|
|
* expression is constant, the constant value is stored here.
|
2000-05-28 13:40:48 +00:00
|
|
|
|
*/
|
|
|
|
|
{
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* Study the expression */
|
|
|
|
|
ExprDesc D;
|
|
|
|
|
InitExprDesc (&D);
|
|
|
|
|
StudyExpr (Expr, &D, 1);
|
|
|
|
|
|
|
|
|
|
/* Check if the expression is constant */
|
|
|
|
|
if (ExprDescIsConst (&D)) {
|
|
|
|
|
if (Val) {
|
|
|
|
|
*Val = D.Val;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
} else {
|
2003-11-11 13:57:30 +00:00
|
|
|
|
return 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void CheckByteExpr (const ExprNode* N, int* IsByte)
|
|
|
|
|
/* Internal routine that is recursively called to check if there is a zeropage
|
|
|
|
|
* symbol in the expression tree.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
if (N) {
|
2003-11-11 13:57:30 +00:00
|
|
|
|
switch (N->Op & EXPR_TYPEMASK) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
case EXPR_LEAFNODE:
|
2003-11-11 22:16:47 +00:00
|
|
|
|
switch (N->Op) {
|
|
|
|
|
|
|
|
|
|
case EXPR_SYMBOL:
|
|
|
|
|
if (SymIsZP (N->V.Sym)) {
|
|
|
|
|
*IsByte = 1;
|
|
|
|
|
} else if (SymHasExpr (N->V.Sym)) {
|
|
|
|
|
/* Check if this expression is a byte expression */
|
|
|
|
|
CheckByteExpr (GetSymExpr (N->V.Sym), IsByte);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EXPR_SECTION:
|
|
|
|
|
if (GetSegAddrSize (N->V.SegNum) == ADDR_SIZE_ZP) {
|
|
|
|
|
*IsByte = 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
case EXPR_UNARYNODE:
|
2003-11-11 22:16:47 +00:00
|
|
|
|
CheckByteExpr (N->Left, IsByte);
|
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
case EXPR_BINARYNODE:
|
2003-11-11 22:16:47 +00:00
|
|
|
|
CheckByteExpr (N->Left, IsByte);
|
|
|
|
|
CheckByteExpr (N->Right, IsByte);
|
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
default:
|
2003-11-11 22:16:47 +00:00
|
|
|
|
Internal ("Unknown expression op: %02X", N->Op);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int IsByteExpr (ExprNode* Root)
|
|
|
|
|
/* Return true if this is a byte expression */
|
|
|
|
|
{
|
|
|
|
|
int IsByte;
|
2003-11-11 13:57:30 +00:00
|
|
|
|
long Val;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
if (IsConstExpr (Root, &Val)) {
|
|
|
|
|
IsByte = IsByteRange (Val);
|
2000-07-29 15:53:33 +00:00
|
|
|
|
} else if (Root->Op == EXPR_BYTE0 || Root->Op == EXPR_BYTE1 ||
|
|
|
|
|
Root->Op == EXPR_BYTE2 || Root->Op == EXPR_BYTE3) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Symbol forced to have byte range */
|
|
|
|
|
IsByte = 1;
|
|
|
|
|
} else {
|
|
|
|
|
/* We have undefined symbols in the expression. Assume that the
|
|
|
|
|
* expression is a byte expression if there is at least one symbol
|
|
|
|
|
* declared as zeropage in it. Being wrong here is not a very big
|
|
|
|
|
* problem since the linker knows about all symbols and detects
|
|
|
|
|
* error like mixing absolute and zeropage labels.
|
|
|
|
|
*/
|
|
|
|
|
IsByte = 0;
|
|
|
|
|
CheckByteExpr (Root, &IsByte);
|
|
|
|
|
}
|
|
|
|
|
return IsByte;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExprNode* CloneExpr (ExprNode* Expr)
|
|
|
|
|
/* Clone the given expression tree. The function will simply clone symbol
|
|
|
|
|
* nodes, it will not resolve them.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
ExprNode* Clone;
|
|
|
|
|
|
|
|
|
|
/* Accept NULL pointers */
|
|
|
|
|
if (Expr == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
/* Clone the node */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
switch (Expr->Op) {
|
|
|
|
|
|
|
|
|
|
case EXPR_LITERAL:
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Clone = GenLiteralExpr (Expr->V.Val);
|
|
|
|
|
break;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
case EXPR_ULABEL:
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Clone = GenULabelExpr (Expr->V.Val);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EXPR_SYMBOL:
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Clone = GenSymExpr (Expr->V.Sym);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2002-12-14 22:57:00 +00:00
|
|
|
|
case EXPR_SECTION:
|
2003-10-31 20:21:48 +00:00
|
|
|
|
Clone = GenSectionExpr (Expr->V.SegNum);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
|
default:
|
|
|
|
|
/* Generate a new node */
|
|
|
|
|
Clone = NewExprNode (Expr->Op);
|
|
|
|
|
/* Clone the tree nodes */
|
|
|
|
|
Clone->Left = CloneExpr (Expr->Left);
|
|
|
|
|
Clone->Right = CloneExpr (Expr->Right);
|
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
|
return Clone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteExpr (ExprNode* Expr)
|
|
|
|
|
/* Write the given expression to the object file */
|
|
|
|
|
{
|
|
|
|
|
/* Null expressions are encoded by a type byte of zero */
|
|
|
|
|
if (Expr == 0) {
|
2003-11-11 13:57:30 +00:00
|
|
|
|
ObjWrite8 (EXPR_NULL);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the is a leafnode, write the expression attribute, otherwise
|
|
|
|
|
* write the expression operands.
|
|
|
|
|
*/
|
|
|
|
|
switch (Expr->Op) {
|
|
|
|
|
|
|
|
|
|
case EXPR_LITERAL:
|
2003-11-11 13:57:30 +00:00
|
|
|
|
ObjWrite8 (EXPR_LITERAL);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ObjWrite32 (Expr->V.Val);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EXPR_SYMBOL:
|
2003-11-11 13:57:30 +00:00
|
|
|
|
if (SymIsImport (Expr->V.Sym)) {
|
|
|
|
|
ObjWrite8 (EXPR_SYMBOL);
|
|
|
|
|
ObjWriteVar (GetSymIndex (Expr->V.Sym));
|
|
|
|
|
} else {
|
|
|
|
|
WriteExpr (GetSymExpr (Expr->V.Sym));
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2002-12-14 22:57:00 +00:00
|
|
|
|
case EXPR_SECTION:
|
2003-11-11 13:57:30 +00:00
|
|
|
|
ObjWrite8 (EXPR_SECTION);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
ObjWrite8 (Expr->V.SegNum);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EXPR_ULABEL:
|
2003-11-11 13:57:30 +00:00
|
|
|
|
WriteExpr (ULabResolve (Expr->V.Val));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* Not a leaf node */
|
2003-11-11 13:57:30 +00:00
|
|
|
|
ObjWrite8 (Expr->Op);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
WriteExpr (Expr->Left);
|
|
|
|
|
WriteExpr (Expr->Right);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-31 20:56:40 +00:00
|
|
|
|
|