/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
+/* (C) 1998-2007 Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
+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 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 */
{
} else {
/* Mark the symbol as referenced */
SymRef (S);
- /* Create symbol node */
- return GenSymExpr (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);
+ }
}
}
+static ExprNode* FuncBankByte (void)
+/* Handle the .BANKBYTE builtin function */
+{
+ return BankByte (Expression ());
+}
+
+
+
static ExprNode* FuncBlank (void)
/* Handle the .BLANK builtin function */
{
- int Result = 1;
-
- /* 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) {
- /* Skip any tokens */
- int Braces = 0;
- while (!TokIsSep (Tok)) {
- if (Tok == TOK_LPAREN) {
- ++Braces;
- } else if (Tok == TOK_RPAREN) {
- if (Braces == 0) {
- /* Done */
- break;
- } else {
- --Braces;
- }
- }
- NextTok ();
+ enum Token Term = GetTokListTerm (TOK_RPAREN);
+ unsigned Count = 0;
+ while (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)) {
+ break;
}
- return 0;
+
+ /* One more token */
+ ++Count;
+
+ /* Skip the token */
+ NextTok ();
}
- return GenLiteralExpr (Result);
+
+ /* If the list was enclosed in curly braces, skip the closing brace */
+ if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
+ NextTok ();
+ }
+
+ /* Return true if the list was empty */
+ return GenLiteralExpr (Count == 0);
}
+static ExprNode* FuncHiByte (void)
+/* Handle the .HIBYTE builtin function */
+{
+ return HiByte (Expression ());
+}
+
+
+
+static ExprNode* FuncHiWord (void)
+/* Handle the .HIWORD builtin function */
+{
+ return HiWord (Expression ());
+}
+
+
+
+static ExprNode* FuncLoByte (void)
+/* Handle the .LOBYTE builtin function */
+{
+ return LoByte (Expression ());
+}
+
+
+
+static ExprNode* FuncLoWord (void)
+/* Handle the .LOWORD builtin function */
+{
+ return LoWord (Expression ());
+}
+
+
+
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) {
+ enum Token Term = GetTokListTerm (TOK_COMMA);
+ while (Tok != Term) {
/* We may not end-of-line of end-of-file here */
if (TokIsSep (Tok)) {
Error ("Unexpected end of line");
- return 0;
+ 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 (Tok != Term) {
/* We may not end-of-line of end-of-file here */
if (TokIsSep (Tok)) {
Error ("Unexpected end of line");
- return 0;
+ return GenLiteral0 ();
}
/* Compare the tokens if the result is not already known */
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;
if (ParentScope == 0) {
/* No such scope */
DoneStrBuf (&ScopeName);
- return GenLiteralExpr (0);
+ return GenLiteral0 ();
}
/* If ScopeName is empty, no explicit scope was specified. We have to
if (Tok != TOK_STRCON) {
Error ("String constant expected");
NextTok ();
- return 0;
-
+ return GenLiteral0 ();
}
/* Remember the string and skip it */
/* Must be a valid index */
if (Index >= (long) strlen (Str)) {
Error ("Range error");
- return 0;
+ return GenLiteral0 ();
}
/* Get the char, handle as unsigned. Be sure to translate it into
/* 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) {
+ enum Token Term = GetTokListTerm (TOK_RPAREN);
+ int Count = 0;
+ while (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
/* 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 && Tok == TOK_RCURLY) {
+ NextTok ();
+ }
+
/* Return the number of tokens */
return GenLiteralExpr (Count);
}
if (Tok != TOK_LPAREN) {
Error ("'(' expected");
SkipUntilSep ();
- return GenLiteralExpr (0);
+ return GenLiteral0 ();
}
NextTok ();
NextTok ();
break;
+ case TOK_PLUS:
+ NextTok ();
+ N = Factor ();
+ break;
+
case TOK_MINUS:
NextTok ();
L = Factor ();
case TOK_LT:
NextTok ();
- L = Factor ();
- if (IsEasyConst (L, &Val)) {
- FreeExpr (L);
- N = GenLiteralExpr (Val & 0xFF);
- } else {
- N = NewExprNode (EXPR_BYTE0);
- N->Left = L;
- }
+ N = LoByte (Factor ());
break;
case TOK_GT:
NextTok ();
- L = Factor ();
- if (IsEasyConst (L, &Val)) {
- FreeExpr (L);
- N = GenLiteralExpr ((Val >> 8) & 0xFF);
- } else {
- N = NewExprNode (EXPR_BYTE1);
- N->Left = L;
- }
+ N = HiByte (Factor ());
break;
case TOK_BANK:
NextTok ();
- L = Factor ();
- if (IsEasyConst (L, &Val)) {
- FreeExpr (L);
- N = GenLiteralExpr ((Val >> 16) & 0xFF);
- } else {
- N = NewExprNode (EXPR_BYTE2);
- N->Left = L;
- }
+ N = BankByte (Factor ());
break;
case TOK_LPAREN:
ConsumeRParen ();
break;
+ case TOK_BANKBYTE:
+ N = Function (FuncBankByte);
+ break;
+
case TOK_BLANK:
N = Function (FuncBlank);
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;
/* A character constant */
N = GenLiteralExpr (TgtTranslateChar (SVal[0]));
} else {
- N = GenLiteralExpr (0); /* Dummy */
+ N = GenLiteral0 (); /* Dummy */
Error ("Syntax error");
}
NextTok ();
+ExprNode* GenLiteral0 (void)
+/* Return an expression tree that encodes the the number zero */
+{
+ return GenLiteralExpr (0);
+}
+
+
+
ExprNode* GenSymExpr (SymEntry* Sym)
/* Return an expression node that encodes the given symbol */
{
{
ExprNode* Root;
- if (RelocMode) {
+ if (GetRelocMode ()) {
/* Create SegmentBase + Offset */
Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
GenLiteralExpr (GetPC ()));
* (Val - PC - Offs) - Seg
*/
Root = GenLiteralExpr (Val - GetPC () - Offs);
- if (RelocMode) {
+ if (GetRelocMode ()) {
N = Root;
Root = NewExprNode (EXPR_MINUS);
Root->Left = N;
Root = NewExprNode (EXPR_MINUS);
Root->Left = N;
Root->Right = GenLiteralExpr (GetPC () + Offs);
- if (RelocMode) {
+ if (GetRelocMode ()) {
N = Root;
Root = NewExprNode (EXPR_MINUS);
Root->Left = N;
/* Force the given expression into a byte and return the result */
{
/* Use the low byte operator to force the expression into byte size */
- ExprNode* Root = NewExprNode (EXPR_BYTE0);
- Root->Left = Expr;
-
- /* Return the result */
- return Root;
+ return LoByte (Expr);
}
ExprNode* GenWordExpr (ExprNode* Expr)
/* Force the given expression into a word and return the result. */
{
- /* AND the expression by $FFFF to force it into word size */
- ExprNode* Root = NewExprNode (EXPR_AND);
- Root->Left = Expr;
- Root->Right = GenLiteralExpr (0xFFFF);
-
- /* Return the result */
- return Root;
+ /* Use the low byte operator to force the expression into word size */
+ return LoWord (Expr);
}
-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.
- */
-{
- unsigned char A;
- unsigned char Left, Right;
-
- if (N) {
- switch (N->Op & EXPR_TYPEMASK) {
-
- case EXPR_LEAFNODE:
- switch (N->Op) {
-
- case EXPR_SYMBOL:
- if (SymIsZP (N->V.Sym)) {
- if (*AddrSize < ADDR_SIZE_ZP) {
- *AddrSize = ADDR_SIZE_ZP;
- }
- } else if (SymHasExpr (N->V.Sym)) {
- /* 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;
-
- case EXPR_SECTION:
- A = GetSegAddrSize (N->V.SegNum);
- if (A > *AddrSize) {
- *AddrSize = A;
- }
- break;
-
- }
- break;
-
- case EXPR_UNARYNODE:
- 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;
-
- case EXPR_BINARYNODE:
- Left = Right = ADDR_SIZE_DEFAULT;
- CheckAddrSize (N->Left, &Left);
- CheckAddrSize (N->Right, &Right);
- A = (Left > Right)? Left : Right;
- if (A > *AddrSize) {
- *AddrSize = A;
- }
- break;
-
- default:
- Internal ("Unknown expression op: %02X", N->Op);
- }
- }
-}
-
-
-
-int IsByteExpr (ExprNode* Root)
-/* Return true if this is a byte expression */
-{
- long Val;
-
- if (IsConstExpr (Root, &Val)) {
- return IsByteRange (Val);
- } else {
- unsigned char AddrSize = ADDR_SIZE_DEFAULT;
- CheckAddrSize (Root, &AddrSize);
- return (AddrSize == ADDR_SIZE_ZP);
- }
-}
-
-
-
ExprNode* CloneExpr (ExprNode* Expr)
/* Clone the given expression tree. The function will simply clone symbol
* nodes, it will not resolve them.
case EXPR_LITERAL:
ObjWrite8 (EXPR_LITERAL);
- ObjWrite32 (Expr->V.Val);
- break;
+ ObjWrite32 (Expr->V.Val);
+ break;
case EXPR_SYMBOL:
- if (SymIsImport (Expr->V.Sym)) {
+ if (SymIsImport (Expr->V.Sym)) {
ObjWrite8 (EXPR_SYMBOL);
ObjWriteVar (GetSymIndex (Expr->V.Sym));
} else {
+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;
+ }
+}
+
+