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"
|
2003-12-02 22:09:45 +00:00
|
|
|
|
#include "strbuf.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-30 18:41:32 +00:00
|
|
|
|
#include "sizeof.h"
|
2003-11-19 22:54:30 +00:00
|
|
|
|
#include "studyexpr.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;
|
2003-11-19 22:54:30 +00:00
|
|
|
|
static unsigned FreeNodeCount = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/*****************************************************************************/
|
2003-11-19 22:54:30 +00:00
|
|
|
|
/* Helpers */
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 */
|
|
|
|
|
{
|
2003-11-18 20:50:55 +00:00
|
|
|
|
return (Val & ~0xFFFFL) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int IsFarRange (long Val)
|
|
|
|
|
/* Return true if this is a far (24 bit) value */
|
|
|
|
|
{
|
|
|
|
|
return (Val & ~0xFFFFFFL) == 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-30 18:41:32 +00:00
|
|
|
|
static ExprNode* Symbol (SymEntry* S)
|
|
|
|
|
/* Reference a symbol and return an expression for it */
|
|
|
|
|
{
|
|
|
|
|
if (S == 0) {
|
|
|
|
|
/* Some weird error happened before */
|
|
|
|
|
return GenLiteralExpr (0);
|
|
|
|
|
} else {
|
|
|
|
|
/* Mark the symbol as referenced */
|
|
|
|
|
SymRef (S);
|
2003-11-30 21:47:40 +00:00
|
|
|
|
/* Create symbol node */
|
|
|
|
|
return GenSymExpr (S);
|
2003-11-30 18:41:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncBlank (void)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Handle the .BLANK builtin function */
|
|
|
|
|
{
|
2003-11-17 17:59:30 +00:00
|
|
|
|
int Result = 1;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
2003-11-17 17:59:30 +00:00
|
|
|
|
if (Tok != TOK_RPAREN) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
}
|
2003-11-17 17:59:30 +00:00
|
|
|
|
return GenLiteralExpr (Result);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncConst (void)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Handle the .CONST builtin function */
|
|
|
|
|
{
|
|
|
|
|
/* Read an expression */
|
|
|
|
|
ExprNode* Expr = Expression ();
|
|
|
|
|
|
|
|
|
|
/* Check the constness of the expression */
|
2003-11-17 17:59:30 +00:00
|
|
|
|
ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Free the expression */
|
|
|
|
|
FreeExpr (Expr);
|
|
|
|
|
|
|
|
|
|
/* Done */
|
|
|
|
|
return Result;
|
2003-11-18 20:50:55 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncDefined (void)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* 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 */
|
2003-11-17 17:59:30 +00:00
|
|
|
|
return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* DoMatch (enum TC EqualityLevel)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
/* Compare the tokens if the result is not already known */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
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 */
|
2003-11-17 17:59:30 +00:00
|
|
|
|
return GenLiteralExpr (Result);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncMatch (void)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Handle the .MATCH function */
|
|
|
|
|
{
|
|
|
|
|
return DoMatch (tcSameToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncReferenced (void)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* 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 */
|
2003-11-17 17:59:30 +00:00
|
|
|
|
return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static ExprNode* FuncSizeOf (void)
|
|
|
|
|
/* Handle the .SIZEOF function */
|
2003-11-18 20:50:55 +00:00
|
|
|
|
{
|
2003-12-02 22:09:45 +00:00
|
|
|
|
StrBuf FullName = AUTO_STRBUF_INITIALIZER;
|
|
|
|
|
char Name[sizeof (SVal)];
|
|
|
|
|
SymTable* Scope;
|
|
|
|
|
SymEntry* Sym;
|
|
|
|
|
SymEntry* SizeSym;
|
|
|
|
|
long Size;
|
2003-11-17 17:59:30 +00:00
|
|
|
|
|
2003-12-02 22:09:45 +00:00
|
|
|
|
|
|
|
|
|
/* Parse the scope and the name */
|
|
|
|
|
SymTable* ParentScope = ParseScopedIdent (Name, &FullName);
|
|
|
|
|
|
|
|
|
|
/* Check if the parent scope is valid */
|
|
|
|
|
if (ParentScope == 0) {
|
|
|
|
|
/* No such scope */
|
|
|
|
|
DoneStrBuf (&FullName);
|
2003-11-30 18:41:32 +00:00
|
|
|
|
return GenLiteralExpr (0);
|
2003-12-02 22:09:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The scope is valid, search first for a child scope, then for a symbol */
|
|
|
|
|
if ((Scope = SymFindScope (ParentScope, Name, SYM_FIND_EXISTING)) != 0) {
|
|
|
|
|
/* Yep, it's a scope */
|
|
|
|
|
SizeSym = GetSizeOfScope (Scope);
|
|
|
|
|
} else if ((Sym = SymFind (ParentScope, Name, SYM_FIND_EXISTING)) != 0) {
|
|
|
|
|
SizeSym = GetSizeOfSymbol (Sym);
|
2003-11-17 17:59:30 +00:00
|
|
|
|
} else {
|
2003-12-02 22:09:45 +00:00
|
|
|
|
Error ("Unknown symbol or scope: `%s'", SB_GetConstBuf (&FullName));
|
|
|
|
|
return GenLiteralExpr (0);
|
2003-11-17 17:59:30 +00:00
|
|
|
|
}
|
2003-12-02 22:09:45 +00:00
|
|
|
|
|
|
|
|
|
/* Check if we have a size */
|
|
|
|
|
if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
|
|
|
|
|
Error ("Size of `%s' is unknown", SB_GetConstBuf (&FullName));
|
|
|
|
|
return GenLiteralExpr (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the size */
|
|
|
|
|
return GenLiteralExpr (Size);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncStrAt (void)
|
2000-07-25 21:32:11 +00:00
|
|
|
|
/* Handle the .STRAT function */
|
|
|
|
|
{
|
|
|
|
|
char Str [sizeof(SVal)];
|
|
|
|
|
long Index;
|
2003-11-17 17:59:30 +00:00
|
|
|
|
unsigned char C;
|
2000-07-25 21:32:11 +00:00
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
/* Get the char, handle as unsigned. Be sure to translate it into
|
2000-12-01 10:37:41 +00:00
|
|
|
|
* the target character set.
|
|
|
|
|
*/
|
2003-11-17 17:59:30 +00:00
|
|
|
|
C = TgtTranslateChar (Str [(size_t)Index]);
|
|
|
|
|
|
|
|
|
|
/* Return the char expression */
|
|
|
|
|
return GenLiteralExpr (C);
|
2000-07-25 21:32:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncStrLen (void)
|
2000-07-25 21:32:11 +00:00
|
|
|
|
/* Handle the .STRLEN function */
|
|
|
|
|
{
|
2003-11-17 17:59:30 +00:00
|
|
|
|
int Len;
|
|
|
|
|
|
2000-07-25 21:32:11 +00:00
|
|
|
|
/* 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 ();
|
|
|
|
|
}
|
2003-11-17 17:59:30 +00:00
|
|
|
|
Len = 0;
|
2000-07-25 21:32:11 +00:00
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Get the length of the string */
|
2003-11-17 17:59:30 +00:00
|
|
|
|
Len = strlen (SVal);
|
2000-07-25 21:32:11 +00:00
|
|
|
|
|
|
|
|
|
/* Skip the string */
|
|
|
|
|
NextTok ();
|
|
|
|
|
}
|
2003-11-17 17:59:30 +00:00
|
|
|
|
|
|
|
|
|
/* Return the length */
|
|
|
|
|
return GenLiteralExpr (Len);
|
2000-07-25 21:32:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncTCount (void)
|
2000-07-15 10:33:32 +00:00
|
|
|
|
/* 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 */
|
2003-11-17 17:59:30 +00:00
|
|
|
|
return GenLiteralExpr (Count);
|
2000-07-15 10:33:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* FuncXMatch (void)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Handle the .XMATCH function */
|
|
|
|
|
{
|
|
|
|
|
return DoMatch (tcIdentical);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
static ExprNode* Function (ExprNode* (*F) (void))
|
2000-05-28 13:40:48 +00:00
|
|
|
|
/* Handle builtin functions */
|
|
|
|
|
{
|
2003-11-17 17:59:30 +00:00
|
|
|
|
ExprNode* E;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* 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 */
|
2003-11-17 17:59:30 +00:00
|
|
|
|
E = F ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Closing brace must follow */
|
|
|
|
|
ConsumeRParen ();
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
/* Return the result of the actual function */
|
|
|
|
|
return E;
|
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;
|
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:
|
2003-11-29 07:53:26 +00:00
|
|
|
|
N = Symbol (ParseScopedSymName (SYM_ALLOC_NEW));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
|
case TOK_LOCAL_IDENT:
|
2003-11-30 18:41:32 +00:00
|
|
|
|
N = Symbol (SymFindLocal (SymLast, SVal, SYM_ALLOC_NEW));
|
2003-11-29 07:53:26 +00:00
|
|
|
|
NextTok ();
|
|
|
|
|
break;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2003-11-17 17:59:30 +00:00
|
|
|
|
case TOK_SIZEOF:
|
|
|
|
|
N = Function (FuncSizeOf);
|
|
|
|
|
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;
|
2003-11-13 00:21:31 +00:00
|
|
|
|
switch (T) {
|
2003-11-12 16:40:26 +00:00
|
|
|
|
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-11-13 00:21:31 +00:00
|
|
|
|
long LVal, RVal, Val;
|
|
|
|
|
ExprNode* Left;
|
|
|
|
|
ExprNode* Right;
|
2003-10-31 20:21:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Remember the token and skip it */
|
|
|
|
|
enum Token T = Tok;
|
|
|
|
|
NextTok ();
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Move root to left side and read the right side */
|
|
|
|
|
Left = Root;
|
|
|
|
|
Right = Term ();
|
|
|
|
|
|
|
|
|
|
/* If both expressions are constant, we can evaluate the term */
|
|
|
|
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_PLUS: Val = LVal + RVal; break;
|
|
|
|
|
case TOK_MINUS: Val = LVal - RVal; break;
|
|
|
|
|
case TOK_OR: Val = 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_PLUS: Op = EXPR_PLUS; break;
|
|
|
|
|
case TOK_MINUS: Op = EXPR_MINUS; break;
|
|
|
|
|
case TOK_OR: Op = EXPR_OR; break;
|
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
|
|
|
|
Root = NewExprNode (Op);
|
|
|
|
|
Root->Left = Left;
|
|
|
|
|
Root->Right = Right;
|
|
|
|
|
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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-11-13 00:21:31 +00:00
|
|
|
|
long LVal, RVal, Val;
|
|
|
|
|
ExprNode* Left;
|
|
|
|
|
ExprNode* Right;
|
2003-10-31 20:21:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Remember the token and skip it */
|
|
|
|
|
enum Token T = Tok;
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Move root to left side and read the right side */
|
|
|
|
|
Left = Root;
|
|
|
|
|
Right = SimpleExpr ();
|
|
|
|
|
|
|
|
|
|
/* If both expressions are constant, we can evaluate the term */
|
|
|
|
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_EQ: Val = (LVal == RVal); break;
|
|
|
|
|
case TOK_NE: Val = (LVal != RVal); break;
|
|
|
|
|
case TOK_LT: Val = (LVal < RVal); break;
|
|
|
|
|
case TOK_GT: Val = (LVal > RVal); break;
|
|
|
|
|
case TOK_LE: Val = (LVal <= RVal); break;
|
|
|
|
|
case TOK_GE: Val = (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 {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Generate an expression tree */
|
|
|
|
|
unsigned char Op;
|
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_EQ: Op = EXPR_EQ; break;
|
|
|
|
|
case TOK_NE: Op = EXPR_NE; break;
|
|
|
|
|
case TOK_LT: Op = EXPR_LT; break;
|
|
|
|
|
case TOK_GT: Op = EXPR_GT; break;
|
|
|
|
|
case TOK_LE: Op = EXPR_LE; break;
|
|
|
|
|
case TOK_GE: Op = EXPR_GE; break;
|
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
|
|
|
|
Root = NewExprNode (Op);
|
|
|
|
|
Root->Left = Left;
|
|
|
|
|
Root->Right = Right;
|
|
|
|
|
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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-11-13 00:21:31 +00:00
|
|
|
|
long LVal, RVal, Val;
|
|
|
|
|
ExprNode* Left;
|
|
|
|
|
ExprNode* Right;
|
2003-10-31 20:21:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Remember the token and skip it */
|
|
|
|
|
enum Token T = Tok;
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Move root to left side and read the right side */
|
|
|
|
|
Left = Root;
|
|
|
|
|
Right = BoolExpr ();
|
|
|
|
|
|
|
|
|
|
/* If both expressions are constant, we can evaluate the term */
|
|
|
|
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
|
|
|
|
|
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_BOOLAND: Val = ((LVal != 0) && (RVal != 0)); break;
|
|
|
|
|
case TOK_BOOLXOR: Val = ((LVal != 0) ^ (RVal != 0)); break;
|
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Generate a literal expression and delete the old left and
|
|
|
|
|
* right sides.
|
|
|
|
|
*/
|
|
|
|
|
FreeExpr (Left);
|
|
|
|
|
FreeExpr (Right);
|
|
|
|
|
Root = GenLiteralExpr (Val);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
} else {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Generate an expression tree */
|
|
|
|
|
unsigned char Op;
|
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_BOOLAND: Op = EXPR_BOOLAND; break;
|
|
|
|
|
case TOK_BOOLXOR: Op = EXPR_BOOLXOR; break;
|
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
|
|
|
|
Root = NewExprNode (Op);
|
|
|
|
|
Root->Left = Left;
|
|
|
|
|
Root->Right = Right;
|
|
|
|
|
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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-11-13 00:21:31 +00:00
|
|
|
|
long LVal, RVal, Val;
|
|
|
|
|
ExprNode* Left;
|
|
|
|
|
ExprNode* Right;
|
2003-10-31 20:21:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Remember the token and skip it */
|
|
|
|
|
enum Token T = Tok;
|
|
|
|
|
NextTok ();
|
|
|
|
|
|
|
|
|
|
/* Move root to left side and read the right side */
|
|
|
|
|
Left = Root;
|
|
|
|
|
Right = Expr2 ();
|
|
|
|
|
|
|
|
|
|
/* If both expressions are constant, we can evaluate the term */
|
|
|
|
|
if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
|
|
|
|
|
|
|
|
|
|
switch (T) {
|
|
|
|
|
case TOK_BOOLOR: Val = ((LVal != 0) || (RVal != 0)); break;
|
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* 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_BOOLOR: Op = EXPR_BOOLOR; break;
|
|
|
|
|
default: Internal ("Invalid token");
|
|
|
|
|
}
|
|
|
|
|
Root = NewExprNode (Op);
|
|
|
|
|
Root->Left = Left;
|
|
|
|
|
Root->Right = Right;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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-11-13 00:21:31 +00:00
|
|
|
|
long Val;
|
|
|
|
|
ExprNode* Left;
|
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 ();
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Read the argument */
|
|
|
|
|
Left = Expr0 ();
|
|
|
|
|
|
|
|
|
|
/* If the argument is const, evaluate it directly */
|
|
|
|
|
if (IsEasyConst (Left, &Val)) {
|
|
|
|
|
FreeExpr (Left);
|
|
|
|
|
Root = GenLiteralExpr (!Val);
|
|
|
|
|
} else {
|
|
|
|
|
Root = NewExprNode (EXPR_BOOLNOT);
|
|
|
|
|
Root->Left = Left;
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* Read left hand side */
|
|
|
|
|
Root = Expr1 ();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the expression tree we've created */
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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-30 21:47:40 +00:00
|
|
|
|
return Expr0 ();
|
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-23 21:39:30 +00:00
|
|
|
|
long Val;
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* Read the expression */
|
|
|
|
|
ExprNode* Expr = Expression ();
|
2003-10-31 20:56:40 +00:00
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* Study the expression */
|
|
|
|
|
ExprDesc D;
|
2003-11-23 21:39:30 +00:00
|
|
|
|
ED_Init (&D);
|
|
|
|
|
StudyExpr (Expr, &D);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* Check if the expression is constant */
|
2003-11-23 21:39:30 +00:00
|
|
|
|
if (ED_IsConst (&D)) {
|
|
|
|
|
Val = D.Val;
|
|
|
|
|
} else {
|
2003-11-08 17:20:21 +00:00
|
|
|
|
Error ("Constant expression expected");
|
2003-11-23 21:39:30 +00:00
|
|
|
|
Val = 0;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
2003-10-31 20:56:40 +00:00
|
|
|
|
|
2003-11-23 21:39:30 +00:00
|
|
|
|
/* Free the expression tree and allocated memory for D */
|
2003-10-31 20:56:40 +00:00
|
|
|
|
FreeExpr (Expr);
|
2003-11-23 21:39:30 +00:00
|
|
|
|
ED_Done (&D);
|
|
|
|
|
|
|
|
|
|
/* Return the value */
|
|
|
|
|
return 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-11-30 21:47:40 +00:00
|
|
|
|
ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
|
2003-11-14 09:03:32 +00:00
|
|
|
|
/* Try to simplify the given expression tree */
|
|
|
|
|
{
|
2003-11-30 21:47:40 +00:00
|
|
|
|
if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
|
|
|
|
|
/* No external references */
|
|
|
|
|
FreeExpr (Expr);
|
|
|
|
|
Expr = GenLiteralExpr (D->Val);
|
2003-11-14 09:03:32 +00:00
|
|
|
|
}
|
|
|
|
|
return Expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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-11-14 08:44:12 +00:00
|
|
|
|
ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
|
|
|
|
|
/* Generate an addition from the two operands */
|
|
|
|
|
{
|
2003-11-30 21:47:40 +00:00
|
|
|
|
long Val;
|
|
|
|
|
if (IsEasyConst (Left, &Val) && Val == 0) {
|
|
|
|
|
FreeExpr (Left);
|
|
|
|
|
return Right;
|
|
|
|
|
} else if (IsEasyConst (Right, &Val) && Val == 0) {
|
|
|
|
|
FreeExpr (Right);
|
|
|
|
|
return Left;
|
|
|
|
|
} else {
|
|
|
|
|
ExprNode* Root = NewExprNode (EXPR_PLUS);
|
|
|
|
|
Root->Left = Left;
|
|
|
|
|
Root->Right = Right;
|
|
|
|
|
return Root;
|
|
|
|
|
}
|
2003-11-14 08:44:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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-11-14 08:44:12 +00:00
|
|
|
|
Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
|
|
|
|
|
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;
|
2003-11-13 00:21:31 +00:00
|
|
|
|
long Val;
|
|
|
|
|
|
|
|
|
|
/* Read Expression() */
|
|
|
|
|
N = Expression ();
|
|
|
|
|
|
|
|
|
|
/* If the expression is a cheap constant, generate a simpler tree */
|
|
|
|
|
if (IsEasyConst (N, &Val)) {
|
|
|
|
|
|
|
|
|
|
/* Free the constant expression tree */
|
|
|
|
|
FreeExpr (N);
|
|
|
|
|
|
|
|
|
|
/* Generate the final expression:
|
|
|
|
|
* Val - (* + Offs)
|
|
|
|
|
* Val - ((Seg + PC) + Offs)
|
|
|
|
|
* Val - Seg - PC - Offs
|
|
|
|
|
* (Val - PC - Offs) - Seg
|
|
|
|
|
*/
|
|
|
|
|
Root = GenLiteralExpr (Val - GetPC () - Offs);
|
|
|
|
|
if (RelocMode) {
|
|
|
|
|
N = Root;
|
|
|
|
|
Root = NewExprNode (EXPR_MINUS);
|
|
|
|
|
Root->Left = N;
|
|
|
|
|
Root->Right = GenSectionExpr (GetCurrentSegNum ());
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
|
/* Generate the expression:
|
|
|
|
|
* N - (* + Offs)
|
|
|
|
|
* N - ((Seg + PC) + Offs)
|
|
|
|
|
* N - Seg - PC - Offs
|
|
|
|
|
* N - (PC + Offs) - Seg
|
|
|
|
|
*/
|
|
|
|
|
Root = NewExprNode (EXPR_MINUS);
|
|
|
|
|
Root->Left = N;
|
|
|
|
|
Root->Right = GenLiteralExpr (GetPC () + Offs);
|
|
|
|
|
if (RelocMode) {
|
|
|
|
|
N = Root;
|
|
|
|
|
Root = NewExprNode (EXPR_MINUS);
|
|
|
|
|
Root->Left = N;
|
|
|
|
|
Root->Right = GenSectionExpr (GetCurrentSegNum ());
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
/* Return the result */
|
2003-11-13 00:21:31 +00:00
|
|
|
|
return Root;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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-23 21:39:30 +00:00
|
|
|
|
int IsConst;
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
|
/* Study the expression */
|
|
|
|
|
ExprDesc D;
|
2003-11-23 21:39:30 +00:00
|
|
|
|
ED_Init (&D);
|
|
|
|
|
StudyExpr (Expr, &D);
|
2003-11-11 13:57:30 +00:00
|
|
|
|
|
|
|
|
|
/* Check if the expression is constant */
|
2003-11-23 21:39:30 +00:00
|
|
|
|
IsConst = ED_IsConst (&D);
|
|
|
|
|
if (IsConst && Val != 0) {
|
|
|
|
|
*Val = D.Val;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
2003-11-23 21:39:30 +00:00
|
|
|
|
|
|
|
|
|
/* Delete allocated memory and return the result */
|
|
|
|
|
ED_Done (&D);
|
|
|
|
|
return IsConst;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-17 12:56:44 +00:00
|
|
|
|
static void CheckAddrSize (const ExprNode* N, unsigned char* AddrSize)
|
|
|
|
|
/* Internal routine that is recursively called to check for the address size
|
|
|
|
|
* of the expression tree.
|
2000-05-28 13:40:48 +00:00
|
|
|
|
*/
|
|
|
|
|
{
|
2003-11-17 12:56:44 +00:00
|
|
|
|
unsigned char A;
|
|
|
|
|
unsigned char Left, Right;
|
|
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
|
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:
|
2003-11-17 12:56:44 +00:00
|
|
|
|
if (SymIsZP (N->V.Sym)) {
|
|
|
|
|
if (*AddrSize < ADDR_SIZE_ZP) {
|
|
|
|
|
*AddrSize = ADDR_SIZE_ZP;
|
|
|
|
|
}
|
2003-11-11 22:16:47 +00:00
|
|
|
|
} else if (SymHasExpr (N->V.Sym)) {
|
2003-11-17 12:56:44 +00:00
|
|
|
|
/* Check if this expression is a byte expression */
|
|
|
|
|
CheckAddrSize (GetSymExpr (N->V.Sym), AddrSize);
|
|
|
|
|
} else {
|
|
|
|
|
/* Undefined symbol, use absolute */
|
|
|
|
|
if (*AddrSize < ADDR_SIZE_ABS) {
|
|
|
|
|
*AddrSize = ADDR_SIZE_ABS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2003-11-11 22:16:47 +00:00
|
|
|
|
|
|
|
|
|
case EXPR_SECTION:
|
2003-11-17 12:56:44 +00:00
|
|
|
|
A = GetSegAddrSize (N->V.SegNum);
|
|
|
|
|
if (A > *AddrSize) {
|
|
|
|
|
*AddrSize = A;
|
|
|
|
|
}
|
2003-11-11 22:16:47 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
case EXPR_UNARYNODE:
|
2003-11-17 12:56:44 +00:00
|
|
|
|
switch (N->Op) {
|
|
|
|
|
|
|
|
|
|
case EXPR_BYTE0:
|
|
|
|
|
case EXPR_BYTE1:
|
|
|
|
|
case EXPR_BYTE2:
|
|
|
|
|
case EXPR_BYTE3:
|
|
|
|
|
/* No need to look at the expression */
|
|
|
|
|
*AddrSize = ADDR_SIZE_ZP;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EXPR_WORD0:
|
|
|
|
|
case EXPR_WORD1:
|
|
|
|
|
/* No need to look at the expression */
|
|
|
|
|
*AddrSize = ADDR_SIZE_ABS;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
CheckAddrSize (N->Left, AddrSize);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
case EXPR_BINARYNODE:
|
2003-11-17 12:56:44 +00:00
|
|
|
|
Left = Right = ADDR_SIZE_DEFAULT;
|
|
|
|
|
CheckAddrSize (N->Left, &Left);
|
|
|
|
|
CheckAddrSize (N->Right, &Right);
|
|
|
|
|
A = (Left > Right)? Left : Right;
|
|
|
|
|
if (A > *AddrSize) {
|
|
|
|
|
*AddrSize = A;
|
|
|
|
|
}
|
2003-11-11 22:16:47 +00:00
|
|
|
|
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 */
|
|
|
|
|
{
|
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)) {
|
2003-11-17 12:56:44 +00:00
|
|
|
|
return IsByteRange (Val);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
} else {
|
2003-11-17 12:56:44 +00:00
|
|
|
|
unsigned char AddrSize = ADDR_SIZE_DEFAULT;
|
|
|
|
|
CheckAddrSize (Root, &AddrSize);
|
|
|
|
|
return (AddrSize == ADDR_SIZE_ZP);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|