/* */
/* */
/* */
-/* (C) 1998-2009, Ullrich von Bassewitz */
+/* (C) 1998-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#include "exprdefs.h"
#include "print.h"
#include "shift.h"
+#include "segdefs.h"
#include "strbuf.h"
#include "tgttrans.h"
#include "version.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
ExprNode* N;
/* Do we have some nodes in the list already? */
- if (FreeExprNodes) {
+ if (FreeNodeCount) {
/* Use first node from list */
N = FreeExprNodes;
FreeExprNodes = N->Left;
+ --FreeNodeCount;
} else {
/* Allocate fresh memory */
N = xmalloc (sizeof (ExprNode));
/* Remember this node for later */
E->Left = FreeExprNodes;
FreeExprNodes = E;
+ ++FreeNodeCount;
} else {
/* Free the memory */
xfree (E);
-static int IsEasyConst (const ExprNode* E, long* Val)
+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.
+static ExprNode* Bank (ExprNode* Operand)
+/* Return the bank of the given segmented expression */
+{
+ /* Generate the bank expression */
+ ExprNode* Expr = NewExprNode (EXPR_BANKRAW);
+ Expr->Left = Operand;
+
+ /* Return the result */
+ return Expr;
+}
+
+
+
static ExprNode* BankByte (ExprNode* Operand)
/* Return the bank byte of the given expression */
{
+ExprNode* FuncBank (void)
+/* Handle the .BANK builtin function */
+{
+ return Bank (Expression ());
+}
+
+
+
ExprNode* FuncBankByte (void)
/* Handle the .BANKBYTE builtin function */
{
/* We have a list of tokens that ends with the closing paren. Skip
* the tokens, and count them. Allow optionally curly braces.
*/
- Token Term = GetTokListTerm (TOK_RPAREN);
+ token_t Term = GetTokListTerm (TOK_RPAREN);
unsigned Count = 0;
- while (Tok != Term) {
+ 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 (Tok)) {
+ if (TokIsSep (CurTok.Tok)) {
break;
}
}
/* If the list was enclosed in curly braces, skip the closing brace */
- if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
+ if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
NextTok ();
}
/* Handle the .DEFINED builtin function */
{
/* Parse the symbol name and search for the symbol */
- SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
+ SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
/* Check if the symbol is defined */
return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
* single linked list of tokens including attributes. The list is
* either enclosed in curly braces, or terminated by a comma.
*/
- Token Term = GetTokListTerm (TOK_COMMA);
- while (Tok != Term) {
+ token_t Term = GetTokListTerm (TOK_COMMA);
+ while (CurTok.Tok != Term) {
/* We may not end-of-line of end-of-file here */
- if (TokIsSep (Tok)) {
+ if (TokIsSep (CurTok.Tok)) {
Error ("Unexpected end of line");
return GenLiteral0 ();
- }
+ }
/* Get a node with this token */
Node = NewTokNode ();
Term = GetTokListTerm (TOK_RPAREN);
Result = 1;
Node = Root;
- while (Tok != Term) {
+ while (CurTok.Tok != Term) {
/* We may not end-of-line of end-of-file here */
- if (TokIsSep (Tok)) {
+ if (TokIsSep (CurTok.Tok)) {
Error ("Unexpected end of line");
return GenLiteral0 ();
}
+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 */
{
/* Parse the symbol name and search for the symbol */
- SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
+ SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
/* Check if the symbol is referenced */
return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
SizeSym = 0;
/* Check for a cheap local which needs special handling */
- if (Tok == TOK_LOCAL_IDENT) {
+ if (CurTok.Tok == TOK_LOCAL_IDENT) {
/* Cheap local symbol */
- Sym = SymFindLocal (SymLast, &SVal, SYM_FIND_EXISTING);
+ Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
if (Sym == 0) {
- Error ("Unknown symbol or scope: `%m%p'", &SVal);
+ 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, &SVal);
+ SB_Copy (&Name, &CurTok.SVal);
NextTok ();
SB_Terminate (&ScopeName);
unsigned char C = 0;
/* String constant expected */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
Error ("String constant expected");
NextTok ();
goto ExitPoint;
}
/* Remember the string and skip it */
- SB_Copy (&Str, &SVal);
+ SB_Copy (&Str, &CurTok.SVal);
NextTok ();
/* Comma must follow */
int Len;
/* String constant expected */
- if (Tok != TOK_STRCON) {
+ if (CurTok.Tok != TOK_STRCON) {
Error ("String constant expected");
/* Smart error recovery */
- if (Tok != TOK_RPAREN) {
+ if (CurTok.Tok != TOK_RPAREN) {
NextTok ();
}
Len = 0;
} else {
/* Get the length of the string */
- Len = SB_GetLen (&SVal);
+ Len = SB_GetLen (&CurTok.SVal);
/* Skip the string */
NextTok ();
/* We have a list of tokens that ends with the closing paren. Skip
* the tokens, and count them. Allow optionally curly braces.
*/
- Token Term = GetTokListTerm (TOK_RPAREN);
+ token_t Term = GetTokListTerm (TOK_RPAREN);
int Count = 0;
- while (Tok != Term) {
+ 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 (Tok)) {
+ if (TokIsSep (CurTok.Tok)) {
break;
}
}
/* If the list was enclosed in curly braces, skip the closing brace */
- if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
+ if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
NextTok ();
}
NextTok ();
/* Expression must be enclosed in braces */
- if (Tok != TOK_LPAREN) {
+ if (CurTok.Tok != TOK_LPAREN) {
Error ("'(' expected");
SkipUntilSep ();
return GenLiteral0 ();
ExprNode* N;
long Val;
- switch (Tok) {
+ switch (CurTok.Tok) {
case TOK_INTCON:
- N = GenLiteralExpr (IVal);
+ N = GenLiteralExpr (CurTok.IVal);
NextTok ();
break;
case TOK_CHARCON:
- N = GenLiteralExpr (TgtTranslateChar (IVal));
+ N = GenLiteralExpr (TgtTranslateChar (CurTok.IVal));
NextTok ();
break;
case TOK_NAMESPACE:
case TOK_IDENT:
- N = Symbol (ParseScopedSymName (SYM_ALLOC_NEW));
- break;
-
case TOK_LOCAL_IDENT:
- N = Symbol (SymFindLocal (SymLast, &SVal, SYM_ALLOC_NEW));
- NextTok ();
- break;
+ N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
+ break;
case TOK_ULABEL:
- N = ULabRef (IVal);
+ N = ULabRef (CurTok.IVal);
NextTok ();
break;
N = HiByte (Factor ());
break;
- case TOK_BANK:
+ case TOK_XOR:
+ /* ^ means the bank byte of an expression */
NextTok ();
N = BankByte (Factor ());
break;
ConsumeRParen ();
break;
+ case TOK_BANK:
+ N = Function (FuncBank);
+ break;
+
case TOK_BANKBYTE:
N = Function (FuncBankByte);
break;
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;
break;
default:
- if (LooseCharTerm && Tok == TOK_STRCON && SB_GetLen (&SVal) == 1) {
+ if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
+ SB_GetLen (&CurTok.SVal) == 1) {
/* A character constant */
- N = GenLiteralExpr (TgtTranslateChar (SB_At (&SVal, 0)));
+ N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
} else {
N = GenLiteral0 (); /* Dummy */
Error ("Syntax error");
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) {
+ 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) {
long LVal, RVal, Val;
ExprNode* Left;
ExprNode* Right;
/* Remember the token and skip it */
- Token T = Tok;
+ token_t T = CurTok.Tok;
NextTok ();
/* Move root to left side and read the right side */
ExprNode* Root = Term ();
/* Handle additive operations */
- while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
+ while (CurTok.Tok == TOK_PLUS ||
+ CurTok.Tok == TOK_MINUS ||
+ CurTok.Tok == TOK_OR) {
long LVal, RVal, Val;
ExprNode* Left;
ExprNode* Right;
/* Remember the token and skip it */
- Token T = Tok;
+ token_t T = CurTok.Tok;
NextTok ();
/* Move root to left side and read the right 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) {
+ 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 = Tok;
+ token_t T = CurTok.Tok;
NextTok ();
/* Move root to left side and read the right side */
ExprNode* Root = BoolExpr ();
/* Handle booleans */
- while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
+ while (CurTok.Tok == TOK_BOOLAND || CurTok.Tok == TOK_BOOLXOR) {
long LVal, RVal, Val;
ExprNode* Left;
ExprNode* Right;
/* Remember the token and skip it */
- Token T = Tok;
+ token_t T = CurTok.Tok;
NextTok ();
/* Move root to left side and read the right side */
ExprNode* Root = Expr2 ();
/* Handle booleans */
- while (Tok == TOK_BOOLOR) {
+ while (CurTok.Tok == TOK_BOOLOR) {
long LVal, RVal, Val;
ExprNode* Left;
ExprNode* Right;
/* Remember the token and skip it */
- Token T = Tok;
+ token_t T = CurTok.Tok;
NextTok ();
/* Move root to left side and read the right side */
ExprNode* Root;
/* Handle booleans */
- if (Tok == TOK_BOOLNOT) {
+ if (CurTok.Tok == TOK_BOOLNOT) {
long Val;
ExprNode* Left;
{
if (Root) {
FreeExpr (Root->Left);
- FreeExpr (Root->Right);
- FreeExprNode (Root);
+ FreeExpr (Root->Right);
+ FreeExprNode (Root);
}
}
-static ExprNode* GenSectionExpr (unsigned SegNum)
+static ExprNode* GenSectionExpr (unsigned SecNum)
/* Return an expression node for the given section */
{
ExprNode* Expr = NewExprNode (EXPR_SECTION);
- Expr->V.SegNum = SegNum;
+ Expr->V.SecNum = SecNum;
+ return Expr;
+}
+
+
+
+static ExprNode* GenBankExpr (unsigned SecNum)
+/* Return an expression node for the given bank */
+{
+ ExprNode* Expr = NewExprNode (EXPR_BANK);
+ Expr->V.SecNum = SecNum;
return Expr;
}
break;
case EXPR_SECTION:
- Clone = GenSectionExpr (Expr->V.SegNum);
+ Clone = GenSectionExpr (Expr->V.SecNum);
break;
+ case EXPR_BANK:
+ Clone = GenBankExpr (Expr->V.SecNum);
+ break;
+
default:
/* Generate a new node */
Clone = NewExprNode (Expr->Op);
+ExprNode* FinalizeExpr (ExprNode* Expr, const Collection* LineInfos)
+/* Finalize an expression tree before it is written to the file. This will
+ * replace EXPR_BANKRAW nodes by EXPR_BANK nodes, and replace constant
+ * expressions by their result. The LineInfos are used when diagnosing errors.
+ * Beware: The expression tree may get replaced in future versions, so don't
+ * use Expr after calling this function.
+ */
+{
+ ExprDesc ED;
+
+ /* Check the type code */
+ switch (EXPR_NODETYPE (Expr->Op)) {
+
+ case EXPR_LEAFNODE:
+ /* Nothing to do for leaf nodes */
+ break;
+
+ case EXPR_BINARYNODE:
+ Expr->Left = FinalizeExpr (Expr->Left, LineInfos);
+ Expr->Right = FinalizeExpr (Expr->Right, LineInfos);
+ /* FALLTHROUGH */
+
+ case EXPR_UNARYNODE:
+ Expr->Left = FinalizeExpr (Expr->Left, LineInfos);
+
+ /* Special handling for BANKRAW */
+ if (Expr->Op == EXPR_BANKRAW) {
+
+ /* Study the expression */
+ ED_Init (&ED);
+ StudyExpr (Expr->Left, &ED);
+
+ /* The expression must be ok and must have exactly one segment
+ * reference.
+ */
+ if (ED.Flags & ED_TOO_COMPLEX) {
+ LIError (LineInfos,
+ "Cannot evaluate expression");
+ } else if (ED.SecCount == 0) {
+ LIError (LineInfos,
+ ".BANK expects a segment reference");
+ } else if (ED.SecCount > 1 || ED.SecRef[0].Count > 1) {
+ LIError (LineInfos,
+ "Too many segment references in argument to .BANK");
+ } else {
+ Segment* S;
+
+ FreeExpr (Expr->Left);
+ Expr->Op = EXPR_BANK;
+ Expr->Left = 0;
+ Expr->V.SecNum = ED.SecRef[0].Ref;
+
+ /* Mark the segment */
+ S = CollAt (&SegmentList, Expr->V.SecNum);
+ S->Flags |= SEG_FLAG_BANKREF;
+ }
+
+ /* Cleanup */
+ ED_Done (&ED);
+
+ }
+ break;
+ }
+
+ /* Return the (partial) tree */
+ return Expr;
+}
+
+
+
void WriteExpr (ExprNode* Expr)
/* Write the given expression to the object file */
{
case EXPR_SYMBOL:
if (SymIsImport (Expr->V.Sym)) {
ObjWrite8 (EXPR_SYMBOL);
- ObjWriteVar (GetSymIndex (Expr->V.Sym));
+ ObjWriteVar (GetSymImportId (Expr->V.Sym));
} else {
WriteExpr (GetSymExpr (Expr->V.Sym));
}
case EXPR_SECTION:
ObjWrite8 (EXPR_SECTION);
- ObjWrite8 (Expr->V.SegNum);
+ ObjWriteVar (Expr->V.SecNum);
break;
case EXPR_ULABEL:
WriteExpr (ULabResolve (Expr->V.IVal));
break;
+ case EXPR_BANK:
+ ObjWrite8 (EXPR_BANK);
+ ObjWriteVar (Expr->V.SecNum);
+ break;
+
default:
/* Not a leaf node */
ObjWrite8 (Expr->Op);
}
/* Check the type code */
- switch (Expr->Op & EXPR_TYPEMASK) {
+ switch (EXPR_NODETYPE (Expr->Op)) {
case EXPR_LEAFNODE:
if (Expr->Op == EXPR_SYMBOL) {