/* */
/* */
/* */
-/* (C) 1998-2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* common */
#include "check.h"
+#include "cpu.h"
#include "exprdefs.h"
#include "print.h"
+#include "shift.h"
+#include "strbuf.h"
#include "tgttrans.h"
+#include "version.h"
#include "xmalloc.h"
/* ca65 */
#include "error.h"
+#include "expr.h"
#include "global.h"
#include "instr.h"
#include "nexttok.h"
-#include "objcode.h"
#include "objfile.h"
+#include "segment.h"
+#include "sizeof.h"
+#include "studyexpr.h"
+#include "symbol.h"
#include "symtab.h"
#include "toklist.h"
#include "ulabel.h"
-#include "expr.h"
* using the Left link.
*/
#define MAX_FREE_NODES 64
-static ExprNode* FreeExprNodes = 0;
-static unsigned FreeNodeCount = 0;
+static ExprNode* FreeExprNodes = 0;
+static unsigned FreeNodeCount = 0;
/*****************************************************************************/
-/* Helpers */
+/* Helpers */
/*****************************************************************************/
-static ExprNode* NewExprNode (void)
+static ExprNode* NewExprNode (unsigned Op)
/* Create a new expression node */
{
ExprNode* N;
/* Allocate fresh memory */
N = xmalloc (sizeof (ExprNode));
}
- N->Op = EXPR_NULL;
+ N->Op = Op;
N->Left = N->Right = 0;
N->Obj = 0;
/* Free a node */
{
if (E) {
+ if (E->Op == EXPR_SYMBOL) {
+ /* Remove the symbol reference */
+ SymDelExprRef (E->V.Sym, E);
+ }
+ /* Place the symbol into the free nodes list if possible */
if (FreeNodeCount < MAX_FREE_NODES) {
/* Remember this node for later */
E->Left = FreeExprNodes;
int IsWordRange (long Val)
/* Return true if this is a word value */
{
- return (Val & ~0xFFFF) == 0;
+ return (Val & ~0xFFFFL) == 0;
+}
+
+
+
+int IsFarRange (long Val)
+/* Return true if this is a far (24 bit) value */
+{
+ return (Val & ~0xFFFFFFL) == 0;
+}
+
+
+
+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.IVal;
+ }
+ return 1;
+ }
+
+ /* Not found to be a const according to our tests */
+ return 0;
+}
+
+
+
+static ExprNode* LoByte (ExprNode* Operand)
+/* Return the low byte of the given expression */
+{
+ ExprNode* Expr;
+ long Val;
+
+ /* Special handling for const expressions */
+ if (IsEasyConst (Operand, &Val)) {
+ FreeExpr (Operand);
+ Expr = GenLiteralExpr (Val & 0xFF);
+ } else {
+ /* Extract byte #0 */
+ Expr = NewExprNode (EXPR_BYTE0);
+ Expr->Left = Operand;
+ }
+ return Expr;
+}
+
+
+
+static ExprNode* HiByte (ExprNode* Operand)
+/* Return the high byte of the given expression */
+{
+ ExprNode* Expr;
+ long Val;
+
+ /* Special handling for const expressions */
+ if (IsEasyConst (Operand, &Val)) {
+ FreeExpr (Operand);
+ Expr = GenLiteralExpr ((Val >> 8) & 0xFF);
+ } else {
+ /* Extract byte #1 */
+ Expr = NewExprNode (EXPR_BYTE1);
+ Expr->Left = Operand;
+ }
+ return Expr;
}
-static int FuncBlank (void)
+static ExprNode* BankByte (ExprNode* Operand)
+/* Return the bank byte of the given expression */
+{
+ ExprNode* Expr;
+ long Val;
+
+ /* Special handling for const expressions */
+ if (IsEasyConst (Operand, &Val)) {
+ FreeExpr (Operand);
+ Expr = GenLiteralExpr ((Val >> 16) & 0xFF);
+ } else {
+ /* Extract byte #2 */
+ Expr = NewExprNode (EXPR_BYTE2);
+ Expr->Left = Operand;
+ }
+ return Expr;
+}
+
+
+
+static ExprNode* LoWord (ExprNode* Operand)
+/* Return the low word of the given expression */
+{
+ ExprNode* Expr;
+ long Val;
+
+ /* Special handling for const expressions */
+ if (IsEasyConst (Operand, &Val)) {
+ FreeExpr (Operand);
+ Expr = GenLiteralExpr (Val & 0xFFFF);
+ } else {
+ /* Extract word #0 */
+ Expr = NewExprNode (EXPR_WORD0);
+ Expr->Left = Operand;
+ }
+ return Expr;
+}
+
+
+
+static ExprNode* HiWord (ExprNode* Operand)
+/* Return the high word of the given expression */
+{
+ ExprNode* Expr;
+ long Val;
+
+ /* Special handling for const expressions */
+ if (IsEasyConst (Operand, &Val)) {
+ FreeExpr (Operand);
+ Expr = GenLiteralExpr ((Val >> 16) & 0xFFFF);
+ } else {
+ /* Extract word #1 */
+ Expr = NewExprNode (EXPR_WORD1);
+ Expr->Left = Operand;
+ }
+ return Expr;
+}
+
+
+
+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);
+ /* If the symbol is a variable, return just its value, otherwise
+ * return a reference to the symbol.
+ */
+ if (SymIsVar (S)) {
+ return CloneExpr (GetSymExpr (S));
+ } else {
+ /* Create symbol node */
+ return GenSymExpr (S);
+ }
+ }
+}
+
+
+
+ExprNode* FuncBankByte (void)
+/* Handle the .BANKBYTE builtin function */
+{
+ return BankByte (Expression ());
+}
+
+
+
+static ExprNode* 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.
+ /* We have a list of tokens that ends with the closing paren. Skip
+ * the tokens, and count them. Allow optionally curly braces.
*/
- if (Tok == TOK_RPAREN) {
- /* No tokens */
- return 1;
- } else {
- /* Skip any tokens */
- int Braces = 0;
- while (Tok != TOK_SEP && Tok != TOK_EOF) {
- if (Tok == TOK_LPAREN) {
- ++Braces;
- } else if (Tok == TOK_RPAREN) {
- if (Braces == 0) {
- /* Done */
- break;
- } else {
- --Braces;
- }
- }
- NextTok ();
+ token_t Term = GetTokListTerm (TOK_RPAREN);
+ unsigned Count = 0;
+ while (CurTok.Tok != Term) {
+
+ /* 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.
+ */
+ if (TokIsSep (CurTok.Tok)) {
+ break;
}
- return 0;
+
+ /* One more token */
+ ++Count;
+
+ /* Skip the token */
+ NextTok ();
+ }
+
+ /* If the list was enclosed in curly braces, skip the closing brace */
+ if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
+ NextTok ();
}
+
+ /* Return true if the list was empty */
+ return GenLiteralExpr (Count == 0);
}
-static int FuncConst (void)
+static ExprNode* FuncConst (void)
/* Handle the .CONST builtin function */
{
/* Read an expression */
ExprNode* Expr = Expression ();
/* Check the constness of the expression */
- int Result = IsConstExpr (Expr);
+ ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
/* Free the expression */
FreeExpr (Expr);
-static int FuncDefined (void)
+static ExprNode* FuncDefined (void)
/* Handle the .DEFINED builtin function */
{
- static const char* Keys[] = {
- "ANY",
- "GLOBAL",
- "LOCAL",
- };
-
- char Name [sizeof (SVal)];
- int Result = 0;
- int Scope;
-
- /* First argument is a symbol name */
- if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
- if (Tok != TOK_RPAREN) {
- NextTok ();
- }
- return 0;
- }
+ /* Parse the symbol name and search for the symbol */
+ SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
- /* Remember the name, then skip it */
- strcpy (Name, SVal);
- NextTok ();
+ /* Check if the symbol is defined */
+ return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
+}
- /* Comma and scope spec may follow */
- if (Tok == TOK_COMMA) {
- /* Skip the comma */
- NextTok ();
- /* An identifier must follow */
- if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
- return 0;
- }
+ExprNode* FuncHiByte (void)
+/* Handle the .HIBYTE builtin function */
+{
+ return HiByte (Expression ());
+}
- /* Get the scope, then skip it */
- Scope = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
- NextTok ();
- /* Check if we got a valid keyword */
- if (Scope < 0) {
- Error (ERR_ILLEGAL_SCOPE);
- return 0;
- }
- /* Map the scope */
- switch (Scope) {
- case 0: Scope = SCOPE_ANY; break;
- case 1: Scope = SCOPE_GLOBAL; break;
- case 2: Scope = SCOPE_LOCAL; break;
- default: Internal ("Invalid scope: %d", Scope);
- }
+static ExprNode* FuncHiWord (void)
+/* Handle the .HIWORD builtin function */
+{
+ return HiWord (Expression ());
+}
- } else {
- /* Any scope */
- Scope = SCOPE_ANY;
- }
+ExprNode* FuncLoByte (void)
+/* Handle the .LOBYTE builtin function */
+{
+ return LoByte (Expression ());
+}
- /* Search for the symbol */
- Result = SymIsDef (SVal, Scope);
- /* Done */
- return Result;
+
+static ExprNode* FuncLoWord (void)
+/* Handle the .LOWORD builtin function */
+{
+ return LoWord (Expression ());
}
-static int DoMatch (enum TC EqualityLevel)
+static ExprNode* DoMatch (enum TC EqualityLevel)
/* Handle the .MATCH and .XMATCH builtin functions */
{
int Result;
TokNode* Root = 0;
TokNode* Last = 0;
- TokNode* Node = 0;
+ TokNode* Node;
/* 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.
+ * either enclosed in curly braces, or terminated by a comma.
*/
- while (Tok != TOK_COMMA) {
+ token_t Term = GetTokListTerm (TOK_COMMA);
+ while (CurTok.Tok != Term) {
/* We may not end-of-line of end-of-file here */
- if (Tok == TOK_SEP || Tok == TOK_EOF) {
- Error (ERR_UNEXPECTED_EOL);
- return 0;
+ if (TokIsSep (CurTok.Tok)) {
+ Error ("Unexpected end of line");
+ return GenLiteral0 ();
}
/* Get a node with this token */
NextTok ();
}
- /* Skip the comma */
+ /* Skip the terminator token*/
NextTok ();
- /* Read the second list which is terminated by the right parenthesis and
- * compare each token against the one in the first list.
+ /* If the token list was enclosed in curly braces, we expect a comma */
+ if (Term == TOK_RCURLY) {
+ ConsumeComma ();
+ }
+
+ /* Read the second list which is optionally enclosed in curly braces and
+ * terminated by the right parenthesis. Compare each token against the
+ * one in the first list.
*/
+ Term = GetTokListTerm (TOK_RPAREN);
Result = 1;
Node = Root;
- while (Tok != TOK_RPAREN) {
+ while (CurTok.Tok != Term) {
/* We may not end-of-line of end-of-file here */
- if (Tok == TOK_SEP || Tok == TOK_EOF) {
- Error (ERR_UNEXPECTED_EOL);
- return 0;
+ if (TokIsSep (CurTok.Tok)) {
+ Error ("Unexpected end of line");
+ return GenLiteral0 ();
}
- /* Compare the tokens if the result is not already known */
+ /* 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 */
NextTok ();
}
+ /* If the token list was enclosed in curly braces, eat the closing brace */
+ if (Term == TOK_RCURLY) {
+ NextTok ();
+ }
+
/* Check if there are remaining tokens in the first list */
if (Node != 0) {
Result = 0;
}
/* Done, return the result */
- return Result;
+ return GenLiteralExpr (Result);
}
-static int FuncMatch (void)
+static ExprNode* FuncMatch (void)
/* Handle the .MATCH function */
{
return DoMatch (tcSameToken);
-static int FuncReferenced (void)
+static ExprNode* FuncMax (void)
+/* Handle the .MAX function */
+{
+ ExprNode* Left;
+ ExprNode* Right;
+ ExprNode* Expr;
+ long LeftVal, RightVal;
+
+ /* Two arguments to the pseudo function */
+ Left = Expression ();
+ ConsumeComma ();
+ Right = Expression ();
+
+ /* Check if we can evaluate the value immediately */
+ if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
+ FreeExpr (Left);
+ FreeExpr (Right);
+ Expr = GenLiteralExpr ((LeftVal > RightVal)? LeftVal : RightVal);
+ } else {
+ /* Make an expression node */
+ Expr = NewExprNode (EXPR_MAX);
+ Expr->Left = Left;
+ Expr->Right = Right;
+ }
+ return Expr;
+}
+
+
+
+static ExprNode* FuncMin (void)
+/* Handle the .MIN function */
+{
+ ExprNode* Left;
+ ExprNode* Right;
+ ExprNode* Expr;
+ long LeftVal, RightVal;
+
+ /* Two arguments to the pseudo function */
+ Left = Expression ();
+ ConsumeComma ();
+ Right = Expression ();
+
+ /* Check if we can evaluate the value immediately */
+ if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
+ FreeExpr (Left);
+ FreeExpr (Right);
+ Expr = GenLiteralExpr ((LeftVal < RightVal)? LeftVal : RightVal);
+ } else {
+ /* Make an expression node */
+ Expr = NewExprNode (EXPR_MIN);
+ Expr->Left = Left;
+ Expr->Right = Right;
+ }
+ return Expr;
+}
+
+
+
+static ExprNode* FuncReferenced (void)
/* Handle the .REFERENCED builtin function */
{
- int Result = 0;
+ /* Parse the symbol name and search for the symbol */
+ SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
+
+ /* Check if the symbol is referenced */
+ return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
+}
+
+
+
+static ExprNode* FuncSizeOf (void)
+/* Handle the .SIZEOF function */
+{
+ StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
+ StrBuf Name = STATIC_STRBUF_INITIALIZER;
+ SymTable* Scope;
+ SymEntry* Sym;
+ SymEntry* SizeSym;
+ long Size;
+ int NoScope;
+
+
+ /* Assume an error */
+ SizeSym = 0;
+
+ /* Check for a cheap local which needs special handling */
+ if (CurTok.Tok == TOK_LOCAL_IDENT) {
+
+ /* Cheap local symbol */
+ Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
+ if (Sym == 0) {
+ Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
+ } else {
+ SizeSym = GetSizeOfSymbol (Sym);
+ }
+
+ /* Remember and skip SVal, terminate ScopeName so it is empty */
+ SB_Copy (&Name, &CurTok.SVal);
+ NextTok ();
+ SB_Terminate (&ScopeName);
- if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
- if (Tok != TOK_RPAREN) {
- NextTok ();
- }
} else {
- Result = SymIsRef (SVal, SCOPE_ANY);
- NextTok ();
+
+ /* Parse the scope and the name */
+ SymTable* ParentScope = ParseScopedIdent (&Name, &ScopeName);
+
+ /* Check if the parent scope is valid */
+ if (ParentScope == 0) {
+ /* No such scope */
+ SB_Done (&ScopeName);
+ SB_Done (&Name);
+ return GenLiteral0 ();
+ }
+
+ /* If ScopeName is empty, no explicit scope was specified. We have to
+ * search upper scope levels in this case.
+ */
+ NoScope = SB_IsEmpty (&ScopeName);
+
+ /* First search for a scope with the given name */
+ if (NoScope) {
+ Scope = SymFindAnyScope (ParentScope, &Name);
+ } else {
+ Scope = SymFindScope (ParentScope, &Name, SYM_FIND_EXISTING);
+ }
+
+ /* If we did find a scope with the name, read the symbol defining the
+ * size, otherwise search for a symbol entry with the name and scope.
+ */
+ if (Scope) {
+ /* Yep, it's a scope */
+ SizeSym = GetSizeOfScope (Scope);
+ } else {
+ if (NoScope) {
+ Sym = SymFindAny (ParentScope, &Name);
+ } else {
+ Sym = SymFind (ParentScope, &Name, SYM_FIND_EXISTING);
+ }
+
+ /* If we found the symbol retrieve the size, otherwise complain */
+ if (Sym) {
+ SizeSym = GetSizeOfSymbol (Sym);
+ } else {
+ Error ("Unknown symbol or scope: `%m%p%m%p'",
+ &ScopeName, &Name);
+ }
+ }
}
- /* Done */
- return Result;
+ /* Check if we have a size */
+ if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
+ Error ("Size of `%m%p%m%p' is unknown", &ScopeName, &Name);
+ Size = 0;
+ }
+
+ /* Free the string buffers */
+ SB_Done (&ScopeName);
+ SB_Done (&Name);
+
+ /* Return the size */
+ return GenLiteralExpr (Size);
}
-static int FuncStrAt (void)
+static ExprNode* FuncStrAt (void)
/* Handle the .STRAT function */
{
- char Str [sizeof(SVal)];
+ StrBuf Str = STATIC_STRBUF_INITIALIZER;
long Index;
+ unsigned char C = 0;
/* String constant expected */
- if (Tok != TOK_STRCON) {
- Error (ERR_STRCON_EXPECTED);
+ if (CurTok.Tok != TOK_STRCON) {
+ Error ("String constant expected");
NextTok ();
- return 0;
-
+ goto ExitPoint;
}
/* Remember the string and skip it */
- strcpy (Str, SVal);
+ SB_Copy (&Str, &CurTok.SVal);
NextTok ();
/* Comma must follow */
Index = ConstExpression ();
/* Must be a valid index */
- if (Index >= (long) strlen (Str)) {
- Error (ERR_RANGE);
- return 0;
+ if (Index >= (long) SB_GetLen (&Str)) {
+ Error ("Range error");
+ goto ExitPoint;
}
- /* Return the char, handle as unsigned. Be sure to translate it into
+ /* Get the char, handle as unsigned. Be sure to translate it into
* the target character set.
*/
- return (unsigned char) TgtTranslateChar (Str [(size_t)Index]);
+ C = TgtTranslateChar (SB_At (&Str, (unsigned)Index));
+
+ExitPoint:
+ /* Free string buffer memory */
+ SB_Done (&Str);
+
+ /* Return the char expression */
+ return GenLiteralExpr (C);
}
-static int FuncStrLen (void)
+static ExprNode* FuncStrLen (void)
/* Handle the .STRLEN function */
{
+ int Len;
+
/* String constant expected */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
- Error (ERR_STRCON_EXPECTED);
+ Error ("String constant expected");
/* Smart error recovery */
- if (Tok != TOK_RPAREN) {
+ if (CurTok.Tok != TOK_RPAREN) {
NextTok ();
}
- return 0;
+ Len = 0;
} else {
/* Get the length of the string */
- int Len = strlen (SVal);
+ Len = SB_GetLen (&CurTok.SVal);
/* Skip the string */
NextTok ();
-
- /* Return the length */
- return Len;
-
}
+
+ /* Return the length */
+ return GenLiteralExpr (Len);
}
-static int FuncTCount (void)
+static ExprNode* 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.
+ * the tokens, and count them. Allow optionally curly braces.
*/
- int Count = 0;
- unsigned Parens = 0;
- while (Parens != 0 || Tok != TOK_RPAREN) {
+ token_t Term = GetTokListTerm (TOK_RPAREN);
+ int Count = 0;
+ while (CurTok.Tok != Term) {
/* 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.
*/
- if (Tok == TOK_SEP || Tok == TOK_EOF) {
+ if (TokIsSep (CurTok.Tok)) {
break;
}
/* One more token */
++Count;
- /* Keep track of the nesting level */
- switch (Tok) {
- case TOK_LPAREN: ++Parens; break;
- case TOK_RPAREN: --Parens; break;
- default: break;
- }
-
/* Skip the token */
NextTok ();
}
+ /* If the list was enclosed in curly braces, skip the closing brace */
+ if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
+ NextTok ();
+ }
+
/* Return the number of tokens */
- return Count;
+ return GenLiteralExpr (Count);
}
-static int FuncXMatch (void)
+static ExprNode* FuncXMatch (void)
/* Handle the .XMATCH function */
{
return DoMatch (tcIdentical);
-static ExprNode* Function (int (*F) (void))
+static ExprNode* Function (ExprNode* (*F) (void))
/* Handle builtin functions */
{
- long Result;
+ ExprNode* E;
/* Skip the keyword */
NextTok ();
/* Expression must be enclosed in braces */
- if (Tok != TOK_LPAREN) {
- Error (ERR_LPAREN_EXPECTED);
+ if (CurTok.Tok != TOK_LPAREN) {
+ Error ("'(' expected");
SkipUntilSep ();
- return LiteralExpr (0);
+ return GenLiteral0 ();
}
NextTok ();
/* Call the function itself */
- Result = F ();
+ E = F ();
/* Closing brace must follow */
ConsumeRParen ();
- /* Return an expression node with the boolean code */
- return LiteralExpr (Result);
+ /* Return the result of the actual function */
+ return E;
}
static ExprNode* Factor (void)
{
+ ExprNode* L;
ExprNode* N;
- SymEntry* S;
+ long Val;
- switch (Tok) {
+ switch (CurTok.Tok) {
case TOK_INTCON:
- N = LiteralExpr (IVal);
+ N = GenLiteralExpr (CurTok.IVal);
NextTok ();
break;
case TOK_CHARCON:
- N = LiteralExpr (TgtTranslateChar (IVal));
+ N = GenLiteralExpr (TgtTranslateChar (CurTok.IVal));
NextTok ();
break;
- case TOK_NAMESPACE:
- NextTok ();
- if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
- N = LiteralExpr (0); /* Dummy */
- } else {
- S = SymRef (SVal, SCOPE_GLOBAL);
- if (SymIsConst (S)) {
- /* Use the literal value instead */
- N = LiteralExpr (GetSymVal (S));
- } else {
- /* Create symbol node */
- N = NewExprNode ();
- N->Op = EXPR_SYMBOL;
- N->V.Sym = S;
- }
- NextTok ();
- }
- break;
-
- case TOK_IDENT:
- S = SymRef (SVal, SCOPE_LOCAL);
- if (SymIsConst (S)) {
- /* Use the literal value instead */
- N = LiteralExpr (GetSymVal (S));
- } else {
- /* Create symbol node */
- N = NewExprNode ();
- N->Op = EXPR_SYMBOL;
- N->V.Sym = S;
- }
- NextTok ();
+ case TOK_NAMESPACE:
+ case TOK_IDENT:
+ case TOK_LOCAL_IDENT:
+ N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
break;
case TOK_ULABEL:
- N = ULabRef (IVal);
+ N = ULabRef (CurTok.IVal);
NextTok ();
break;
+ case TOK_PLUS:
+ NextTok ();
+ N = Factor ();
+ break;
+
case TOK_MINUS:
NextTok ();
- N = NewExprNode ();
- N->Left = Factor ();
- N->Op = EXPR_UNARY_MINUS;
+ L = Factor ();
+ if (IsEasyConst (L, &Val)) {
+ FreeExpr (L);
+ N = GenLiteralExpr (-Val);
+ } else {
+ N = NewExprNode (EXPR_UNARY_MINUS);
+ N->Left = L;
+ }
break;
case TOK_NOT:
NextTok ();
- N = NewExprNode ();
- N->Left = Factor ();
- N->Op = EXPR_NOT;
+ L = Factor ();
+ if (IsEasyConst (L, &Val)) {
+ FreeExpr (L);
+ N = GenLiteralExpr (~Val);
+ } else {
+ N = NewExprNode (EXPR_NOT);
+ N->Left = L;
+ }
break;
case TOK_STAR:
case TOK_PC:
NextTok ();
- N = CurrentPC ();
+ N = GenCurrentPC ();
break;
case TOK_LT:
NextTok ();
- N = NewExprNode ();
- N->Left = Factor ();
- N->Op = EXPR_BYTE0;
+ N = LoByte (Factor ());
break;
case TOK_GT:
NextTok ();
- N = NewExprNode ();
- N->Left = Factor ();
- N->Op = EXPR_BYTE1;
+ N = HiByte (Factor ());
break;
+ case TOK_BANK:
+ NextTok ();
+ N = BankByte (Factor ());
+ break;
+
case TOK_LPAREN:
NextTok ();
N = Expr0 ();
ConsumeRParen ();
break;
+ case TOK_BANKBYTE:
+ N = Function (FuncBankByte);
+ break;
+
case TOK_BLANK:
N = Function (FuncBlank);
break;
break;
case TOK_CPU:
- N = LiteralExpr (GetCPU());
+ N = GenLiteralExpr (CPUIsets[CPU]);
NextTok ();
break;
N = Function (FuncDefined);
break;
+ case TOK_HIBYTE:
+ N = Function (FuncHiByte);
+ break;
+
+ case TOK_HIWORD:
+ N = Function (FuncHiWord);
+ break;
+
+ case TOK_LOBYTE:
+ N = Function (FuncLoByte);
+ break;
+
+ case TOK_LOWORD:
+ N = Function (FuncLoWord);
+ break;
+
case TOK_MATCH:
N = Function (FuncMatch);
break;
+ case TOK_MAX:
+ N = Function (FuncMax);
+ break;
+
+ case TOK_MIN:
+ N = Function (FuncMin);
+ break;
+
case TOK_REFERENCED:
N = Function (FuncReferenced);
break;
+ case TOK_SIZEOF:
+ N = Function (FuncSizeOf);
+ break;
+
case TOK_STRAT:
N = Function (FuncStrAt);
break;
break;
case TOK_TIME:
- N = LiteralExpr (time (0));
+ N = GenLiteralExpr (time (0));
NextTok ();
break;
+ case TOK_VERSION:
+ N = GenLiteralExpr (GetVersionAsNumber ());
+ NextTok ();
+ break;
+
case TOK_XMATCH:
N = Function (FuncXMatch);
break;
default:
- if (LooseCharTerm && Tok == TOK_STRCON && strlen(SVal) == 1) {
+ if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
+ SB_GetLen (&CurTok.SVal) == 1) {
/* A character constant */
- N = LiteralExpr (TgtTranslateChar (SVal[0]));
+ N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
} else {
- N = LiteralExpr (0); /* Dummy */
- Error (ERR_SYNTAX);
+ N = GenLiteral0 (); /* Dummy */
+ Error ("Syntax error");
}
NextTok ();
break;
static ExprNode* Term (void)
{
- ExprNode* Root;
-
/* Read left hand side */
- Root = Factor ();
+ ExprNode* Root = Factor ();
/* 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) {
-
- /* Create a new node and insert the left expression */
- ExprNode* Left = Root;
- Root = NewExprNode ();
- Root->Left = Left;
-
- /* Determine the operator token */
- switch (Tok) {
- case TOK_MUL: Root->Op = EXPR_MUL; break;
- case TOK_DIV: Root->Op = EXPR_DIV; break;
- case TOK_MOD: Root->Op = EXPR_MOD; break;
- case TOK_AND: Root->Op = EXPR_AND; break;
- case TOK_XOR: Root->Op = EXPR_XOR; break;
- case TOK_SHL: Root->Op = EXPR_SHL; break;
- case TOK_SHR: Root->Op = EXPR_SHR; break;
- default: Internal ("Invalid token");
- }
- NextTok ();
+ while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV ||
+ CurTok.Tok == TOK_MOD || CurTok.Tok == TOK_AND ||
+ CurTok.Tok == TOK_XOR || CurTok.Tok == TOK_SHL ||
+ CurTok.Tok == TOK_SHR) {
- /* Parse the right hand side */
- Root->Right = Factor ();
+ long LVal, RVal, Val;
+ ExprNode* Left;
+ ExprNode* Right;
+
+ /* Remember the token and skip it */
+ token_t T = CurTok.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;
+
+ }
}
static ExprNode* SimpleExpr (void)
{
- ExprNode* Root;
-
/* Read left hand side */
- Root = Term ();
+ ExprNode* Root = Term ();
/* Handle additive operations */
- while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
-
- /* Create a new node and insert the left expression */
- ExprNode* Left = Root;
- Root = NewExprNode ();
- Root->Left = Left;
-
- /* Determine the operator token */
- switch (Tok) {
- case TOK_PLUS: Root->Op = EXPR_PLUS; break;
- case TOK_MINUS: Root->Op = EXPR_MINUS; break;
- case TOK_OR: Root->Op = EXPR_OR; break;
- default: Internal ("Invalid token");
- }
- NextTok ();
+ while (CurTok.Tok == TOK_PLUS ||
+ CurTok.Tok == TOK_MINUS ||
+ CurTok.Tok == TOK_OR) {
- /* Parse the right hand side */
- Root->Right = Term ();
+ long LVal, RVal, Val;
+ ExprNode* Left;
+ ExprNode* Right;
+ /* Remember the token and skip it */
+ token_t T = CurTok.Tok;
+ NextTok ();
+
+ /* 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)) {
+
+ 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;
+
+ }
}
/* Return the expression tree we've created */
ExprNode* Root = SimpleExpr ();
/* Handle booleans */
- while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
- Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
-
- /* Create a new node and insert the left expression */
- ExprNode* Left = Root;
- Root = NewExprNode ();
- Root->Left = Left;
-
- /* Determine the operator token */
- switch (Tok) {
- case TOK_EQ: Root->Op = EXPR_EQ; break;
- case TOK_NE: Root->Op = EXPR_NE; break;
- case TOK_LT: Root->Op = EXPR_LT; break;
- case TOK_GT: Root->Op = EXPR_GT; break;
- case TOK_LE: Root->Op = EXPR_LE; break;
- case TOK_GE: Root->Op = EXPR_GE; break;
- default: Internal ("Invalid token");
- }
- NextTok ();
+ while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE ||
+ CurTok.Tok == TOK_LT || CurTok.Tok == TOK_GT ||
+ CurTok.Tok == TOK_LE || CurTok.Tok == TOK_GE) {
+
+ long LVal, RVal, Val;
+ ExprNode* Left;
+ ExprNode* Right;
+
+ /* Remember the token and skip it */
+ token_t T = CurTok.Tok;
+ NextTok ();
- /* Parse the right hand side */
- Root->Right = SimpleExpr ();
+ /* 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)) {
+
+ 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 {
+
+ /* 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;
+ }
}
/* Return the expression tree we've created */
ExprNode* Root = BoolExpr ();
/* Handle booleans */
- while (Tok == TOK_BAND || Tok == TOK_BXOR) {
-
- /* Create a new node and insert the left expression */
- ExprNode* Left = Root;
- Root = NewExprNode ();
- Root->Left = Left;
-
- /* Determine the operator token */
- switch (Tok) {
- case TOK_BAND: Root->Op = EXPR_BAND; break;
- case TOK_BXOR: Root->Op = EXPR_BXOR; break;
- default: Internal ("Invalid token");
- }
- NextTok ();
+ while (CurTok.Tok == TOK_BOOLAND || CurTok.Tok == TOK_BOOLXOR) {
- /* Parse the right hand side */
- Root->Right = BoolExpr ();
+ long LVal, RVal, Val;
+ ExprNode* Left;
+ ExprNode* Right;
+
+ /* Remember the token and skip it */
+ token_t T = CurTok.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);
+
+ } else {
+
+ /* 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;
+
+ }
}
/* Return the expression tree we've created */
ExprNode* Root = Expr2 ();
/* Handle booleans */
- while (Tok == TOK_BOR) {
-
- /* Create a new node and insert the left expression */
- ExprNode* Left = Root;
- Root = NewExprNode ();
- Root->Left = Left;
-
- /* Determine the operator token */
- switch (Tok) {
- case TOK_BOR: Root->Op = EXPR_BOR; break;
- default: Internal ("Invalid token");
- }
- NextTok ();
+ while (CurTok.Tok == TOK_BOOLOR) {
- /* Parse the right hand side */
- Root->Right = Expr2 ();
+ long LVal, RVal, Val;
+ ExprNode* Left;
+ ExprNode* Right;
+ /* Remember the token and skip it */
+ token_t T = CurTok.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");
+ }
+
+ /* 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;
+
+ }
}
/* Return the expression tree we've created */
ExprNode* Root;
/* Handle booleans */
- if (Tok == TOK_BNOT) {
+ if (CurTok.Tok == TOK_BOOLNOT) {
- /* Create a new node */
- Root = NewExprNode ();
+ long Val;
+ ExprNode* Left;
- /* Determine the operator token */
- switch (Tok) {
- case TOK_BNOT: Root->Op = EXPR_BNOT; break;
- default: Internal ("Invalid token");
- }
+ /* Skip the operator token */
NextTok ();
- /* Parse the left hand side, allow more BNOTs */
- Root->Left = Expr0 ();
+ /* 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;
+ }
} else {
-static ExprNode* SimplifyExpr (ExprNode* Root)
-/* Try to simplify the given expression tree */
-{
- if (Root) {
- SimplifyExpr (Root->Left);
- SimplifyExpr (Root->Right);
- if (IsConstExpr (Root)) {
- /* The complete expression is constant */
- Root->V.Val = GetExprVal (Root);
- Root->Op = EXPR_LITERAL;
- FreeExpr (Root->Left);
- FreeExpr (Root->Right);
- Root->Left = Root->Right = 0;
- }
- }
- 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.
*/
{
- return SimplifyExpr (Expr0 ());
+ return Expr0 ();
}
* not constant.
*/
{
- /* Read the expression, and call finalize (exception here, since we
- * expect a const).
- */
- ExprNode* Expr = FinalizeExpr (Expression ());
-
- /* Return the value */
- if (IsConstExpr (Expr)) {
- return GetExprVal (Expr);
- } else {
- Error (ERR_CONSTEXPR_EXPECTED);
- return 0;
- }
-}
-
-
-
-ExprNode* LiteralExpr (long Val)
-/* Return an expression tree that encodes the given literal value */
-{
- ExprNode* Expr = NewExprNode ();
- Expr->Op = EXPR_LITERAL;
- Expr->V.Val = Val;
- return Expr;
-}
-
-
+ long Val;
-ExprNode* CurrentPC (void)
-/* Return the current program counter as expression */
-{
- ExprNode* Left;
- ExprNode* Root;
-
- if (RelocMode) {
- /* Create SegmentBase + Offset */
- Left = NewExprNode ();
- Left->Op = EXPR_SEGMENT;
- Left->V.SegNum = GetSegNum ();
-
- Root = NewExprNode ();
- Root->Left = Left;
- Root->Right = LiteralExpr (GetPC ());
- Root->Op = EXPR_PLUS;
- } else {
- /* Absolute mode, just return PC value */
- Root = LiteralExpr (GetPC ());
- }
-
- return Root;
-}
-
-
-
-ExprNode* SwapExpr (ExprNode* Expr)
-/* Return an extended expression with lo and hi bytes swapped */
-{
- ExprNode* N = NewExprNode ();
- N->Op = EXPR_SWAP;
- N->Left = Expr;
- return N;
-}
-
-
-
-ExprNode* BranchExpr (unsigned Offs)
-/* Return an expression that encodes the difference between current PC plus
- * offset and the target expression (that is, Expression() - (*+Offs) ).
- */
-{
- ExprNode* N;
- ExprNode* Root;
- ExprNode* Left;
+ /* Read the expression */
+ ExprNode* Expr = Expression ();
- /* Create *+Offs */
- if (RelocMode) {
- Left = NewExprNode ();
- Left->Op = EXPR_SEGMENT;
- Left->V.SegNum = GetSegNum ();
+ /* Study the expression */
+ ExprDesc D;
+ ED_Init (&D);
+ StudyExpr (Expr, &D);
- N = NewExprNode ();
- N->Left = Left;
- N->Right = LiteralExpr (GetPC () + Offs);
- N->Op = EXPR_PLUS;
+ /* Check if the expression is constant */
+ if (ED_IsConst (&D)) {
+ Val = D.Val;
} else {
- N = LiteralExpr (GetPC () + Offs);
+ Error ("Constant expression expected");
+ Val = 0;
}
- /* Create the root node */
- Root = NewExprNode ();
- Root->Left = Expression ();
- Root->Right = N;
- Root->Op = EXPR_MINUS;
-
- /* Return the result */
- return SimplifyExpr (Root);
-}
-
-
-
-ExprNode* ULabelExpr (unsigned Num)
-/* Return an expression for an unnamed label with the given index */
-{
- /* Get an expression node */
- ExprNode* Node = NewExprNode ();
-
- /* Set the values */
- Node->Op = EXPR_ULABEL;
- Node->V.Val = Num;
+ /* Free the expression tree and allocated memory for D */
+ FreeExpr (Expr);
+ ED_Done (&D);
- /* Return the new node */
- return Node;
+ /* Return the value */
+ return Val;
}
-ExprNode* ForceWordExpr (ExprNode* Expr)
-/* Force the given expression into a word and return the result. */
+ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
+/* Try to simplify the given expression tree */
{
- /* And the expression by $FFFF to force it into word size */
- ExprNode* Root = NewExprNode ();
- Root->Left = Expr;
- Root->Op = EXPR_AND;
- Root->Right = LiteralExpr (0xFFFF);
-
- /* Return the result */
- return Root;
+ if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
+ /* No external references */
+ FreeExpr (Expr);
+ Expr = GenLiteralExpr (D->Val);
+ }
+ return Expr;
}
-int IsConstExpr (ExprNode* Root)
-/* Return true if the given expression is a constant expression, that is, one
- * with no references to external symbols.
- */
+ExprNode* GenLiteralExpr (long Val)
+/* Return an expression tree that encodes the given literal value */
{
- int Const;
- SymEntry* Sym;
+ ExprNode* Expr = NewExprNode (EXPR_LITERAL);
+ Expr->V.IVal = Val;
+ return Expr;
+}
- if (EXPR_IS_LEAF (Root->Op)) {
- switch (Root->Op) {
-
- case EXPR_LITERAL:
- return 1;
-
- case EXPR_SYMBOL:
- Sym = Root->V.Sym;
- if (SymHasUserMark (Sym)) {
- if (Verbosity > 0) {
- DumpExpr (Root);
- }
- PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
- Const = 0;
- } else {
- SymMarkUser (Sym);
- Const = SymIsConst (Sym);
- SymUnmarkUser (Sym);
- }
- return Const;
-
- default:
- return 0;
- }
- } else if (EXPR_IS_UNARY (Root->Op)) {
- return IsConstExpr (Root->Left);
+ExprNode* GenLiteral0 (void)
+/* Return an expression tree that encodes the the number zero */
+{
+ return GenLiteralExpr (0);
+}
+
- } else {
- /* We must handle shortcut boolean expressions here */
- switch (Root->Op) {
-
- case EXPR_BAND:
- if (IsConstExpr (Root->Left)) {
- /* lhs is const, if it is zero, don't eval right */
- if (GetExprVal (Root->Left) == 0) {
- return 1;
- } else {
- return IsConstExpr (Root->Right);
- }
- } else {
- /* lhs not const --> tree not const */
- return 0;
- }
- break;
-
- case EXPR_BOR:
- if (IsConstExpr (Root->Left)) {
- /* lhs is const, if it is not zero, don't eval right */
- if (GetExprVal (Root->Left) != 0) {
- return 1;
- } else {
- return IsConstExpr (Root->Right);
- }
- } else {
- /* lhs not const --> tree not const */
- return 0;
- }
- break;
-
- default:
- /* All others are handled normal */
- return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
- }
- }
+ExprNode* GenSymExpr (SymEntry* Sym)
+/* Return an expression node that encodes the given symbol */
+{
+ ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
+ Expr->V.Sym = Sym;
+ SymAddExprRef (Sym, Expr);
+ return Expr;
}
-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.
- */
+static ExprNode* GenSectionExpr (unsigned SecNum)
+/* Return an expression node for the given section */
{
- if (N) {
- switch (N->Op & EXPR_TYPEMASK) {
-
- case EXPR_LEAFNODE:
- 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 */
- *IsByte = IsByteExpr (GetSymExpr (N->V.Sym));
- }
- break;
-
- case EXPR_SEGMENT:
- if (GetSegType (N->V.SegNum) == SEGTYPE_ZP) {
- *IsByte = 1;
- }
- break;
-
- }
- break;
-
- case EXPR_UNARYNODE:
- CheckByteExpr (N->Left, IsByte);
- break;
-
- case EXPR_BINARYNODE:
- CheckByteExpr (N->Left, IsByte);
- CheckByteExpr (N->Right, IsByte);
- break;
-
- default:
- Internal ("Unknown expression op: %02X", N->Op);
- }
- }
+ ExprNode* Expr = NewExprNode (EXPR_SECTION);
+ Expr->V.SecNum = SecNum;
+ return Expr;
}
-int IsByteExpr (ExprNode* Root)
-/* Return true if this is a byte expression */
+ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
+/* Generate an addition from the two operands */
{
- int IsByte;
-
- if (IsConstExpr (Root)) {
- if (Root->Op != EXPR_LITERAL) {
- SimplifyExpr (Root);
- }
- return IsByteRange (GetExprVal (Root));
- } else if (Root->Op == EXPR_BYTE0 || Root->Op == EXPR_BYTE1 ||
- Root->Op == EXPR_BYTE2 || Root->Op == EXPR_BYTE3) {
- /* Symbol forced to have byte range */
- IsByte = 1;
+ long Val;
+ if (IsEasyConst (Left, &Val) && Val == 0) {
+ FreeExpr (Left);
+ return Right;
+ } else if (IsEasyConst (Right, &Val) && Val == 0) {
+ FreeExpr (Right);
+ return Left;
} 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);
+ ExprNode* Root = NewExprNode (EXPR_PLUS);
+ Root->Left = Left;
+ Root->Right = Right;
+ return Root;
}
- return IsByte;
}
-long GetExprVal (ExprNode* Expr)
-/* Get the value of a constant expression */
+ExprNode* GenCurrentPC (void)
+/* Return the current program counter as expression */
{
- long Right, Left;
-
- switch (Expr->Op) {
-
- case EXPR_LITERAL:
- return Expr->V.Val;
-
- case EXPR_SYMBOL:
- return GetSymVal (Expr->V.Sym);
-
- case EXPR_PLUS:
- return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
-
- case EXPR_MINUS:
- return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
-
- case EXPR_MUL:
- return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
-
- case EXPR_DIV:
- Left = GetExprVal (Expr->Left);
- Right = GetExprVal (Expr->Right);
- if (Right == 0) {
- Error (ERR_DIV_BY_ZERO);
- return 0;
- }
- return Left / Right;
-
- case EXPR_MOD:
- Left = GetExprVal (Expr->Left);
- Right = GetExprVal (Expr->Right);
- if (Right == 0) {
- Error (ERR_MOD_BY_ZERO);
- return 0;
- }
- return Left % Right;
-
- case EXPR_OR:
- return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
-
- case EXPR_XOR:
- return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
-
- case EXPR_AND:
- return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
-
- case EXPR_SHL:
- return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
-
- case EXPR_SHR:
- return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
-
- case EXPR_EQ:
- return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
-
- case EXPR_NE:
- return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
-
- case EXPR_LT:
- return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
-
- case EXPR_GT:
- return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
-
- case EXPR_LE:
- return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
-
- case EXPR_GE:
- return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
-
- case EXPR_UNARY_MINUS:
- return -GetExprVal (Expr->Left);
-
- case EXPR_NOT:
- return ~GetExprVal (Expr->Left);
-
- case EXPR_BYTE0:
- return GetExprVal (Expr->Left) & 0xFF;
-
- case EXPR_BYTE1:
- return (GetExprVal (Expr->Left) >> 8) & 0xFF;
-
- case EXPR_BYTE2:
- return (GetExprVal (Expr->Left) >> 16) & 0xFF;
-
- case EXPR_BYTE3:
- return (GetExprVal (Expr->Left) >> 24) & 0xFF;
-
- case EXPR_SWAP:
- Left = GetExprVal (Expr->Left);
- return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
-
- case EXPR_BAND:
- return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
+ ExprNode* Root;
- case EXPR_BOR:
- return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
+ if (GetRelocMode ()) {
+ /* Create SegmentBase + Offset */
+ Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
+ GenLiteralExpr (GetPC ()));
+ } else {
+ /* Absolute mode, just return PC value */
+ Root = GenLiteralExpr (GetPC ());
+ }
- case EXPR_BXOR:
- return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
+ return Root;
+}
- case EXPR_BNOT:
- return !GetExprVal (Expr->Left);
- case EXPR_ULABEL:
- Internal ("GetExprVal called for EXPR_ULABEL");
- /* NOTREACHED */
- return 0;
- default:
- Internal ("Unknown Op type: %u", Expr->Op);
- /* NOTREACHED */
- return 0;
- }
+ExprNode* GenSwapExpr (ExprNode* Expr)
+/* Return an extended expression with lo and hi bytes swapped */
+{
+ ExprNode* N = NewExprNode (EXPR_SWAP);
+ N->Left = Expr;
+ return N;
}
-static ExprNode* RemoveSyms (ExprNode* Expr, int MustClone)
-/* Remove resolved symbols from the tree by cloning symbol expressions */
+ExprNode* GenBranchExpr (unsigned Offs)
+/* Return an expression that encodes the difference between current PC plus
+ * offset and the target expression (that is, Expression() - (*+Offs) ).
+ */
{
- /* Accept NULL pointers */
- if (Expr == 0) {
- return 0;
- }
-
- /* Special node handling */
- switch (Expr->Op) {
-
- case EXPR_SYMBOL:
- if (SymHasExpr (Expr->V.Sym)) {
- /* The symbol has an expression tree */
- SymEntry* Sym = Expr->V.Sym;
- if (SymHasUserMark (Sym)) {
- /* Circular definition */
- if (Verbosity) {
- DumpExpr (Expr);
- }
- PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
- return LiteralExpr (0); /* Return a dummy value */
- }
- SymMarkUser (Sym);
- Expr = RemoveSyms (GetSymExpr (Sym), 1);
- SymUnmarkUser (Sym);
- return Expr;
- } else if (SymIsConst (Expr->V.Sym)) {
- /* The symbol is a constant */
- return LiteralExpr (GetSymVal (Expr->V.Sym));
- }
- break;
+ ExprNode* N;
+ ExprNode* Root;
+ 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 (GetRelocMode ()) {
+ N = Root;
+ Root = NewExprNode (EXPR_MINUS);
+ Root->Left = N;
+ Root->Right = GenSectionExpr (GetCurrentSegNum ());
+ }
- case EXPR_ULABEL:
- if (ULabCanResolve ()) {
- ExprNode* NewExpr = ULabResolve (Expr->V.Val);
- FreeExpr (Expr);
- Expr = NewExpr;
- }
- break;
+ } else {
+ /* 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 (GetRelocMode ()) {
+ N = Root;
+ Root = NewExprNode (EXPR_MINUS);
+ Root->Left = N;
+ Root->Right = GenSectionExpr (GetCurrentSegNum ());
+ }
}
- /* Clone the current node if needed */
- if (MustClone) {
-
- /* Create a new node */
- ExprNode* Clone = NewExprNode ();
-
- /* Clone the operation */
- Clone->Op = Expr->Op;
-
- /* Clone the attribute if needed */
- switch (Expr->Op) {
+ /* Return the result */
+ return Root;
+}
- case EXPR_LITERAL:
- case EXPR_ULABEL:
- Clone->V.Val = Expr->V.Val;
- break;
- case EXPR_SYMBOL:
- Clone->V.Sym = Expr->V.Sym;
- break;
- case EXPR_SEGMENT:
- Clone->V.SegNum = Expr->V.SegNum;
- break;
+ExprNode* GenULabelExpr (unsigned Num)
+/* Return an expression for an unnamed label with the given index */
+{
+ ExprNode* Node = NewExprNode (EXPR_ULABEL);
+ Node->V.IVal = Num;
- }
+ /* Return the new node */
+ return Node;
+}
- /* Clone the tree nodes */
- Clone->Left = RemoveSyms (Expr->Left, MustClone);
- Clone->Right = RemoveSyms (Expr->Right, MustClone);
- /* Done */
- return Clone;
- } else {
+ExprNode* GenByteExpr (ExprNode* Expr)
+/* Force the given expression into a byte and return the result */
+{
+ /* Use the low byte operator to force the expression into byte size */
+ return LoByte (Expr);
+}
- /* Nothing to clone */
- Expr->Left = RemoveSyms (Expr->Left, MustClone);
- Expr->Right = RemoveSyms (Expr->Right, MustClone);
- /* Done */
- return Expr;
- }
+ExprNode* GenWordExpr (ExprNode* Expr)
+/* Force the given expression into a word and return the result. */
+{
+ /* Use the low byte operator to force the expression into word size */
+ return LoWord (Expr);
}
-static ExprNode* ConstExtract (ExprNode* Expr, long* Val, int Sign)
-/* Extract and evaluate all constant factors in an subtree that has only
- * additions and subtractions.
- */
+ExprNode* GenNE (ExprNode* Expr, long Val)
+/* Generate an expression that compares Expr and Val for inequality */
{
- if (Expr->Op == EXPR_LITERAL) {
- if (Sign < 0) {
- *Val -= Expr->V.Val;
- } else {
- *Val += Expr->V.Val;
- }
- FreeExprNode (Expr);
- return 0;
- }
-
- if (Expr->Op == EXPR_PLUS || Expr->Op == EXPR_MINUS) {
- ExprNode* Left;
- ExprNode* Right;
- Left = ConstExtract (Expr->Left, Val, Sign);
- if (Expr->Op == EXPR_MINUS) {
- Sign = -Sign;
- }
- Right = ConstExtract (Expr->Right, Val, Sign);
- if (Left == 0 && Right == 0) {
- FreeExprNode (Expr);
- return 0;
- } else if (Left == 0) {
- FreeExprNode (Expr);
- return Right;
- } else if (Right == 0) {
- FreeExprNode (Expr);
- return Left;
- } else {
- /* Check for SEG - SEG which is now possible */
- if (Left->Op == EXPR_SEGMENT && Right->Op == EXPR_SEGMENT &&
- Left->V.SegNum == Right->V.SegNum) {
- /* SEG - SEG, remove it completely */
- FreeExprNode (Left);
- FreeExprNode (Right);
- FreeExprNode (Expr);
- return 0;
- } else {
- Expr->Left = Left;
- Expr->Right = Right;
- return Expr;
- }
- }
- }
-
- /* Some other sort of node, finalize the terms */
- if (Expr->Left) {
- Expr->Left = FinalizeExpr (Expr->Left);
- }
- if (Expr->Right) {
- Expr->Right = FinalizeExpr (Expr->Right);
- }
+ /* Generate a compare node */
+ ExprNode* Root = NewExprNode (EXPR_NE);
+ Root->Left = Expr;
+ Root->Right = GenLiteralExpr (Val);
- return Expr;
+ /* Return the result */
+ return Root;
}
-ExprNode* FinalizeExpr (ExprNode* Expr)
-/* Resolve any symbols by cloning the symbol expression tree instead of the
- * symbol reference, then try to simplify the expression as much as possible.
- * This function must only be called if all symbols are resolved (no undefined
- * symbol errors).
+int IsConstExpr (ExprNode* Expr, long* Val)
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols. If Val is not NULL and the
+ * expression is constant, the constant value is stored here.
*/
{
- long Val = 0;
- ExprNode* N;
+ int IsConst;
- Expr = RemoveSyms (Expr, 0);
- Expr = ConstExtract (Expr, &Val, 1);
- if (Expr == 0) {
- /* Reduced to a literal value */
- Expr = LiteralExpr (Val);
- } else if (Val) {
- /* Extracted a value */
- N = NewExprNode ();
- N->Op = EXPR_PLUS;
- N->Left = Expr;
- N->Right = LiteralExpr (Val);
- Expr = N;
+ /* Study the expression */
+ ExprDesc D;
+ ED_Init (&D);
+ StudyExpr (Expr, &D);
+
+ /* Check if the expression is constant */
+ IsConst = ED_IsConst (&D);
+ if (IsConst && Val != 0) {
+ *Val = D.Val;
}
- return Expr;
+
+ /* Delete allocated memory and return the result */
+ ED_Done (&D);
+ return IsConst;
}
return 0;
}
- /* Get a new node */
- Clone = NewExprNode ();
-
- /* Clone the operation */
- Clone->Op = Expr->Op;
-
- /* Clone the attribute if needed */
+ /* Clone the node */
switch (Expr->Op) {
case EXPR_LITERAL:
+ Clone = GenLiteralExpr (Expr->V.IVal);
+ break;
+
case EXPR_ULABEL:
- Clone->V.Val = Expr->V.Val;
+ Clone = GenULabelExpr (Expr->V.IVal);
break;
case EXPR_SYMBOL:
- Clone->V.Sym = Expr->V.Sym;
+ Clone = GenSymExpr (Expr->V.Sym);
break;
- case EXPR_SEGMENT:
- Clone->V.SegNum = Expr->V.SegNum;
+ case EXPR_SECTION:
+ Clone = GenSectionExpr (Expr->V.SecNum);
break;
+ default:
+ /* Generate a new node */
+ Clone = NewExprNode (Expr->Op);
+ /* Clone the tree nodes */
+ Clone->Left = CloneExpr (Expr->Left);
+ Clone->Right = CloneExpr (Expr->Right);
+ break;
}
- /* Clone the tree nodes */
- Clone->Left = CloneExpr (Expr->Left);
- Clone->Right = CloneExpr (Expr->Right);
-
/* Done */
return Clone;
}
{
/* Null expressions are encoded by a type byte of zero */
if (Expr == 0) {
- ObjWrite8 (0);
+ ObjWrite8 (EXPR_NULL);
return;
}
- /* Write the expression code */
- ObjWrite8 (Expr->Op);
-
/* If the is a leafnode, write the expression attribute, otherwise
* write the expression operands.
*/
switch (Expr->Op) {
case EXPR_LITERAL:
- ObjWrite32 (Expr->V.Val);
- break;
+ ObjWrite8 (EXPR_LITERAL);
+ ObjWrite32 (Expr->V.IVal);
+ break;
case EXPR_SYMBOL:
- /* Maybe we should use a code here? */
- CHECK (SymIsImport (Expr->V.Sym)); /* Safety */
- ObjWrite16 (GetSymIndex (Expr->V.Sym));
+ if (SymIsImport (Expr->V.Sym)) {
+ ObjWrite8 (EXPR_SYMBOL);
+ ObjWriteVar (GetSymImportId (Expr->V.Sym));
+ } else {
+ WriteExpr (GetSymExpr (Expr->V.Sym));
+ }
break;
- case EXPR_SEGMENT:
- ObjWrite8 (Expr->V.SegNum);
+ case EXPR_SECTION:
+ ObjWrite8 (EXPR_SECTION);
+ ObjWrite8 (Expr->V.SecNum);
break;
case EXPR_ULABEL:
- Internal ("WriteExpr: Cannot write EXPR_ULABEL nodes");
+ WriteExpr (ULabResolve (Expr->V.IVal));
break;
default:
/* Not a leaf node */
+ ObjWrite8 (Expr->Op);
WriteExpr (Expr->Left);
WriteExpr (Expr->Right);
break;
+void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
+/* Mark the address size of the given expression tree as guessed. The address
+ * size passed as argument is the one NOT used, because the actual address
+ * size wasn't known. Example: Zero page addressing was not used because symbol
+ * is undefined, and absolute addressing was available.
+ * This function will actually parse the expression tree for undefined symbols,
+ * and mark these symbols accordingly.
+ */
+{
+ /* Accept NULL expressions */
+ if (Expr == 0) {
+ return;
+ }
+
+ /* Check the type code */
+ switch (Expr->Op & EXPR_TYPEMASK) {
+
+ case EXPR_LEAFNODE:
+ if (Expr->Op == EXPR_SYMBOL) {
+ if (!SymIsDef (Expr->V.Sym)) {
+ /* Symbol is undefined, mark it */
+ SymGuessedAddrSize (Expr->V.Sym, AddrSize);
+ }
+ }
+ return;
+
+ case EXPR_BINARYNODE:
+ ExprGuessedAddrSize (Expr->Right, AddrSize);
+ /* FALLTHROUGH */
+
+ case EXPR_UNARYNODE:
+ ExprGuessedAddrSize (Expr->Left, AddrSize);
+ break;
+ }
+}
+
+
+