1 /*****************************************************************************/
5 /* Expression evaluation for the ca65 macroassembler */
9 /* (C) 1998-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
59 #include "studyexpr.h"
67 /*****************************************************************************/
69 /*****************************************************************************/
73 /* Since all expressions are first packed into expression trees, and each
74 * expression tree node is allocated on the heap, we add some type of special
75 * purpose memory allocation here: Instead of freeing the nodes, we save some
76 * number of freed nodes for later and remember them in a single linked list
77 * using the Left link.
79 #define MAX_FREE_NODES 64
80 static ExprNode* FreeExprNodes = 0;
81 static unsigned FreeNodeCount = 0;
85 /*****************************************************************************/
87 /*****************************************************************************/
91 static ExprNode* NewExprNode (unsigned Op)
92 /* Create a new expression node */
96 /* Do we have some nodes in the list already? */
98 /* Use first node from list */
100 FreeExprNodes = N->Left;
103 /* Allocate fresh memory */
104 N = xmalloc (sizeof (ExprNode));
107 N->Left = N->Right = 0;
115 static void FreeExprNode (ExprNode* E)
119 if (E->Op == EXPR_SYMBOL) {
120 /* Remove the symbol reference */
121 SymDelExprRef (E->V.Sym, E);
123 /* Place the symbol into the free nodes list if possible */
124 if (FreeNodeCount < MAX_FREE_NODES) {
125 /* Remember this node for later */
126 E->Left = FreeExprNodes;
130 /* Free the memory */
138 /*****************************************************************************/
140 /*****************************************************************************/
144 static ExprNode* Expr0 (void);
148 int IsByteRange (long Val)
149 /* Return true if this is a byte value */
151 return (Val & ~0xFFL) == 0;
156 int IsWordRange (long Val)
157 /* Return true if this is a word value */
159 return (Val & ~0xFFFFL) == 0;
164 int IsFarRange (long Val)
165 /* Return true if this is a far (24 bit) value */
167 return (Val & ~0xFFFFFFL) == 0;
172 int IsEasyConst (const ExprNode* E, long* Val)
173 /* Do some light checking if the given node is a constant. Don't care if E is
174 * a complex expression. If E is a constant, return true and place its value
175 * into Val, provided that Val is not NULL.
178 /* Resolve symbols, follow symbol chains */
179 while (E->Op == EXPR_SYMBOL) {
180 E = SymResolve (E->V.Sym);
182 /* Could not resolve */
187 /* Symbols resolved, check for a literal */
188 if (E->Op == EXPR_LITERAL) {
195 /* Not found to be a const according to our tests */
201 static ExprNode* LoByte (ExprNode* Operand)
202 /* Return the low byte of the given expression */
207 /* Special handling for const expressions */
208 if (IsEasyConst (Operand, &Val)) {
210 Expr = GenLiteralExpr (Val & 0xFF);
212 /* Extract byte #0 */
213 Expr = NewExprNode (EXPR_BYTE0);
214 Expr->Left = Operand;
221 static ExprNode* HiByte (ExprNode* Operand)
222 /* Return the high byte of the given expression */
227 /* Special handling for const expressions */
228 if (IsEasyConst (Operand, &Val)) {
230 Expr = GenLiteralExpr ((Val >> 8) & 0xFF);
232 /* Extract byte #1 */
233 Expr = NewExprNode (EXPR_BYTE1);
234 Expr->Left = Operand;
241 static ExprNode* BankByte (ExprNode* Operand)
242 /* Return the bank byte of the given expression */
247 /* Special handling for const expressions */
248 if (IsEasyConst (Operand, &Val)) {
250 Expr = GenLiteralExpr ((Val >> 16) & 0xFF);
252 /* Extract byte #2 */
253 Expr = NewExprNode (EXPR_BYTE2);
254 Expr->Left = Operand;
261 static ExprNode* LoWord (ExprNode* Operand)
262 /* Return the low word of the given expression */
267 /* Special handling for const expressions */
268 if (IsEasyConst (Operand, &Val)) {
270 Expr = GenLiteralExpr (Val & 0xFFFF);
272 /* Extract word #0 */
273 Expr = NewExprNode (EXPR_WORD0);
274 Expr->Left = Operand;
281 static ExprNode* HiWord (ExprNode* Operand)
282 /* Return the high word of the given expression */
287 /* Special handling for const expressions */
288 if (IsEasyConst (Operand, &Val)) {
290 Expr = GenLiteralExpr ((Val >> 16) & 0xFFFF);
292 /* Extract word #1 */
293 Expr = NewExprNode (EXPR_WORD1);
294 Expr->Left = Operand;
301 static ExprNode* Symbol (SymEntry* S)
302 /* Reference a symbol and return an expression for it */
305 /* Some weird error happened before */
306 return GenLiteralExpr (0);
308 /* Mark the symbol as referenced */
310 /* If the symbol is a variable, return just its value, otherwise
311 * return a reference to the symbol.
314 return CloneExpr (GetSymExpr (S));
316 /* Create symbol node */
317 return GenSymExpr (S);
324 ExprNode* FuncBankByte (void)
325 /* Handle the .BANKBYTE builtin function */
327 return BankByte (Expression ());
332 static ExprNode* FuncBlank (void)
333 /* Handle the .BLANK builtin function */
335 /* We have a list of tokens that ends with the closing paren. Skip
336 * the tokens, and count them. Allow optionally curly braces.
338 token_t Term = GetTokListTerm (TOK_RPAREN);
340 while (CurTok.Tok != Term) {
342 /* Check for end of line or end of input. Since the calling function
343 * will check for the closing paren, we don't need to print an error
344 * here, just bail out.
346 if (TokIsSep (CurTok.Tok)) {
357 /* If the list was enclosed in curly braces, skip the closing brace */
358 if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
362 /* Return true if the list was empty */
363 return GenLiteralExpr (Count == 0);
368 static ExprNode* FuncConst (void)
369 /* Handle the .CONST builtin function */
371 /* Read an expression */
372 ExprNode* Expr = Expression ();
374 /* Check the constness of the expression */
375 ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
377 /* Free the expression */
386 static ExprNode* FuncDefined (void)
387 /* Handle the .DEFINED builtin function */
389 /* Parse the symbol name and search for the symbol */
390 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
392 /* Check if the symbol is defined */
393 return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
398 ExprNode* FuncHiByte (void)
399 /* Handle the .HIBYTE builtin function */
401 return HiByte (Expression ());
406 static ExprNode* FuncHiWord (void)
407 /* Handle the .HIWORD builtin function */
409 return HiWord (Expression ());
414 ExprNode* FuncLoByte (void)
415 /* Handle the .LOBYTE builtin function */
417 return LoByte (Expression ());
422 static ExprNode* FuncLoWord (void)
423 /* Handle the .LOWORD builtin function */
425 return LoWord (Expression ());
430 static ExprNode* DoMatch (enum TC EqualityLevel)
431 /* Handle the .MATCH and .XMATCH builtin functions */
438 /* A list of tokens follows. Read this list and remember it building a
439 * single linked list of tokens including attributes. The list is
440 * either enclosed in curly braces, or terminated by a comma.
442 token_t Term = GetTokListTerm (TOK_COMMA);
443 while (CurTok.Tok != Term) {
445 /* We may not end-of-line of end-of-file here */
446 if (TokIsSep (CurTok.Tok)) {
447 Error ("Unexpected end of line");
448 return GenLiteral0 ();
451 /* Get a node with this token */
452 Node = NewTokNode ();
454 /* Insert the node into the list */
466 /* Skip the terminator token*/
469 /* If the token list was enclosed in curly braces, we expect a comma */
470 if (Term == TOK_RCURLY) {
474 /* Read the second list which is optionally enclosed in curly braces and
475 * terminated by the right parenthesis. Compare each token against the
476 * one in the first list.
478 Term = GetTokListTerm (TOK_RPAREN);
481 while (CurTok.Tok != Term) {
483 /* We may not end-of-line of end-of-file here */
484 if (TokIsSep (CurTok.Tok)) {
485 Error ("Unexpected end of line");
486 return GenLiteral0 ();
489 /* Compare the tokens if the result is not already known */
492 /* The second list is larger than the first one */
494 } else if (TokCmp (Node) < EqualityLevel) {
495 /* Tokens do not match */
500 /* Next token in first list */
505 /* Next token in current list */
509 /* If the token list was enclosed in curly braces, eat the closing brace */
510 if (Term == TOK_RCURLY) {
514 /* Check if there are remaining tokens in the first list */
519 /* Free the token list */
526 /* Done, return the result */
527 return GenLiteralExpr (Result);
532 static ExprNode* FuncMatch (void)
533 /* Handle the .MATCH function */
535 return DoMatch (tcSameToken);
540 static ExprNode* FuncMax (void)
541 /* Handle the .MAX function */
546 long LeftVal, RightVal;
548 /* Two arguments to the pseudo function */
549 Left = Expression ();
551 Right = Expression ();
553 /* Check if we can evaluate the value immediately */
554 if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
557 Expr = GenLiteralExpr ((LeftVal > RightVal)? LeftVal : RightVal);
559 /* Make an expression node */
560 Expr = NewExprNode (EXPR_MAX);
569 static ExprNode* FuncMin (void)
570 /* Handle the .MIN function */
575 long LeftVal, RightVal;
577 /* Two arguments to the pseudo function */
578 Left = Expression ();
580 Right = Expression ();
582 /* Check if we can evaluate the value immediately */
583 if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
586 Expr = GenLiteralExpr ((LeftVal < RightVal)? LeftVal : RightVal);
588 /* Make an expression node */
589 Expr = NewExprNode (EXPR_MIN);
598 static ExprNode* FuncReferenced (void)
599 /* Handle the .REFERENCED builtin function */
601 /* Parse the symbol name and search for the symbol */
602 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
604 /* Check if the symbol is referenced */
605 return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
610 static ExprNode* FuncSizeOf (void)
611 /* Handle the .SIZEOF function */
613 StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
614 StrBuf Name = STATIC_STRBUF_INITIALIZER;
622 /* Assume an error */
625 /* Check for a cheap local which needs special handling */
626 if (CurTok.Tok == TOK_LOCAL_IDENT) {
628 /* Cheap local symbol */
629 Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
631 Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
633 SizeSym = GetSizeOfSymbol (Sym);
636 /* Remember and skip SVal, terminate ScopeName so it is empty */
637 SB_Copy (&Name, &CurTok.SVal);
639 SB_Terminate (&ScopeName);
643 /* Parse the scope and the name */
644 SymTable* ParentScope = ParseScopedIdent (&Name, &ScopeName);
646 /* Check if the parent scope is valid */
647 if (ParentScope == 0) {
649 SB_Done (&ScopeName);
651 return GenLiteral0 ();
654 /* If ScopeName is empty, no explicit scope was specified. We have to
655 * search upper scope levels in this case.
657 NoScope = SB_IsEmpty (&ScopeName);
659 /* First search for a scope with the given name */
661 Scope = SymFindAnyScope (ParentScope, &Name);
663 Scope = SymFindScope (ParentScope, &Name, SYM_FIND_EXISTING);
666 /* If we did find a scope with the name, read the symbol defining the
667 * size, otherwise search for a symbol entry with the name and scope.
670 /* Yep, it's a scope */
671 SizeSym = GetSizeOfScope (Scope);
674 Sym = SymFindAny (ParentScope, &Name);
676 Sym = SymFind (ParentScope, &Name, SYM_FIND_EXISTING);
679 /* If we found the symbol retrieve the size, otherwise complain */
681 SizeSym = GetSizeOfSymbol (Sym);
683 Error ("Unknown symbol or scope: `%m%p%m%p'",
689 /* Check if we have a size */
690 if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
691 Error ("Size of `%m%p%m%p' is unknown", &ScopeName, &Name);
695 /* Free the string buffers */
696 SB_Done (&ScopeName);
699 /* Return the size */
700 return GenLiteralExpr (Size);
705 static ExprNode* FuncStrAt (void)
706 /* Handle the .STRAT function */
708 StrBuf Str = STATIC_STRBUF_INITIALIZER;
712 /* String constant expected */
713 if (CurTok.Tok != TOK_STRCON) {
714 Error ("String constant expected");
719 /* Remember the string and skip it */
720 SB_Copy (&Str, &CurTok.SVal);
723 /* Comma must follow */
726 /* Expression expected */
727 Index = ConstExpression ();
729 /* Must be a valid index */
730 if (Index >= (long) SB_GetLen (&Str)) {
731 Error ("Range error");
735 /* Get the char, handle as unsigned. Be sure to translate it into
736 * the target character set.
738 C = TgtTranslateChar (SB_At (&Str, (unsigned)Index));
741 /* Free string buffer memory */
744 /* Return the char expression */
745 return GenLiteralExpr (C);
750 static ExprNode* FuncStrLen (void)
751 /* Handle the .STRLEN function */
755 /* String constant expected */
756 if (CurTok.Tok != TOK_STRCON) {
758 Error ("String constant expected");
759 /* Smart error recovery */
760 if (CurTok.Tok != TOK_RPAREN) {
767 /* Get the length of the string */
768 Len = SB_GetLen (&CurTok.SVal);
770 /* Skip the string */
774 /* Return the length */
775 return GenLiteralExpr (Len);
780 static ExprNode* FuncTCount (void)
781 /* Handle the .TCOUNT function */
783 /* We have a list of tokens that ends with the closing paren. Skip
784 * the tokens, and count them. Allow optionally curly braces.
786 token_t Term = GetTokListTerm (TOK_RPAREN);
788 while (CurTok.Tok != Term) {
790 /* Check for end of line or end of input. Since the calling function
791 * will check for the closing paren, we don't need to print an error
792 * here, just bail out.
794 if (TokIsSep (CurTok.Tok)) {
805 /* If the list was enclosed in curly braces, skip the closing brace */
806 if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
810 /* Return the number of tokens */
811 return GenLiteralExpr (Count);
816 static ExprNode* FuncXMatch (void)
817 /* Handle the .XMATCH function */
819 return DoMatch (tcIdentical);
824 static ExprNode* Function (ExprNode* (*F) (void))
825 /* Handle builtin functions */
829 /* Skip the keyword */
832 /* Expression must be enclosed in braces */
833 if (CurTok.Tok != TOK_LPAREN) {
834 Error ("'(' expected");
836 return GenLiteral0 ();
840 /* Call the function itself */
843 /* Closing brace must follow */
846 /* Return the result of the actual function */
852 static ExprNode* Factor (void)
858 switch (CurTok.Tok) {
861 N = GenLiteralExpr (CurTok.IVal);
866 N = GenLiteralExpr (TgtTranslateChar (CurTok.IVal));
872 case TOK_LOCAL_IDENT:
873 N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
877 N = ULabRef (CurTok.IVal);
889 if (IsEasyConst (L, &Val)) {
891 N = GenLiteralExpr (-Val);
893 N = NewExprNode (EXPR_UNARY_MINUS);
901 if (IsEasyConst (L, &Val)) {
903 N = GenLiteralExpr (~Val);
905 N = NewExprNode (EXPR_NOT);
918 N = LoByte (Factor ());
923 N = HiByte (Factor ());
928 N = BankByte (Factor ());
938 N = Function (FuncBankByte);
942 N = Function (FuncBlank);
946 N = Function (FuncConst);
950 N = GenLiteralExpr (CPUIsets[CPU]);
955 N = Function (FuncDefined);
959 N = Function (FuncHiByte);
963 N = Function (FuncHiWord);
967 N = Function (FuncLoByte);
971 N = Function (FuncLoWord);
975 N = Function (FuncMatch);
979 N = Function (FuncMax);
983 N = Function (FuncMin);
987 N = Function (FuncReferenced);
991 N = Function (FuncSizeOf);
995 N = Function (FuncStrAt);
999 N = Function (FuncStrLen);
1003 N = Function (FuncTCount);
1007 N = GenLiteralExpr (time (0));
1012 N = GenLiteralExpr (GetVersionAsNumber ());
1017 N = Function (FuncXMatch);
1021 if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
1022 SB_GetLen (&CurTok.SVal) == 1) {
1023 /* A character constant */
1024 N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
1026 N = GenLiteral0 (); /* Dummy */
1027 Error ("Syntax error");
1037 static ExprNode* Term (void)
1039 /* Read left hand side */
1040 ExprNode* Root = Factor ();
1042 /* Handle multiplicative operations */
1043 while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV ||
1044 CurTok.Tok == TOK_MOD || CurTok.Tok == TOK_AND ||
1045 CurTok.Tok == TOK_XOR || CurTok.Tok == TOK_SHL ||
1046 CurTok.Tok == TOK_SHR) {
1048 long LVal, RVal, Val;
1052 /* Remember the token and skip it */
1053 token_t T = CurTok.Tok;
1056 /* Move root to left side and read the right side */
1060 /* If both expressions are constant, we can evaluate the term */
1061 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1070 Error ("Division by zero");
1079 Error ("Modulo operation with zero");
1095 Val = shl_l (LVal, RVal);
1099 Val = shr_l (LVal, RVal);
1103 Internal ("Invalid token");
1106 /* Generate a literal expression and delete the old left and
1111 Root = GenLiteralExpr (Val);
1115 /* Generate an expression tree */
1118 case TOK_MUL: Op = EXPR_MUL; break;
1119 case TOK_DIV: Op = EXPR_DIV; break;
1120 case TOK_MOD: Op = EXPR_MOD; break;
1121 case TOK_AND: Op = EXPR_AND; break;
1122 case TOK_XOR: Op = EXPR_XOR; break;
1123 case TOK_SHL: Op = EXPR_SHL; break;
1124 case TOK_SHR: Op = EXPR_SHR; break;
1125 default: Internal ("Invalid token");
1127 Root = NewExprNode (Op);
1129 Root->Right = Right;
1135 /* Return the expression tree we've created */
1141 static ExprNode* SimpleExpr (void)
1143 /* Read left hand side */
1144 ExprNode* Root = Term ();
1146 /* Handle additive operations */
1147 while (CurTok.Tok == TOK_PLUS ||
1148 CurTok.Tok == TOK_MINUS ||
1149 CurTok.Tok == TOK_OR) {
1151 long LVal, RVal, Val;
1155 /* Remember the token and skip it */
1156 token_t T = CurTok.Tok;
1159 /* Move root to left side and read the right side */
1163 /* If both expressions are constant, we can evaluate the term */
1164 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1167 case TOK_PLUS: Val = LVal + RVal; break;
1168 case TOK_MINUS: Val = LVal - RVal; break;
1169 case TOK_OR: Val = LVal | RVal; break;
1170 default: Internal ("Invalid token");
1173 /* Generate a literal expression and delete the old left and
1178 Root = GenLiteralExpr (Val);
1182 /* Generate an expression tree */
1185 case TOK_PLUS: Op = EXPR_PLUS; break;
1186 case TOK_MINUS: Op = EXPR_MINUS; break;
1187 case TOK_OR: Op = EXPR_OR; break;
1188 default: Internal ("Invalid token");
1190 Root = NewExprNode (Op);
1192 Root->Right = Right;
1197 /* Return the expression tree we've created */
1203 static ExprNode* BoolExpr (void)
1204 /* Evaluate a boolean expression */
1206 /* Read left hand side */
1207 ExprNode* Root = SimpleExpr ();
1209 /* Handle booleans */
1210 while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE ||
1211 CurTok.Tok == TOK_LT || CurTok.Tok == TOK_GT ||
1212 CurTok.Tok == TOK_LE || CurTok.Tok == TOK_GE) {
1214 long LVal, RVal, Val;
1218 /* Remember the token and skip it */
1219 token_t T = CurTok.Tok;
1222 /* Move root to left side and read the right side */
1224 Right = SimpleExpr ();
1226 /* If both expressions are constant, we can evaluate the term */
1227 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1230 case TOK_EQ: Val = (LVal == RVal); break;
1231 case TOK_NE: Val = (LVal != RVal); break;
1232 case TOK_LT: Val = (LVal < RVal); break;
1233 case TOK_GT: Val = (LVal > RVal); break;
1234 case TOK_LE: Val = (LVal <= RVal); break;
1235 case TOK_GE: Val = (LVal >= RVal); break;
1236 default: Internal ("Invalid token");
1239 /* Generate a literal expression and delete the old left and
1244 Root = GenLiteralExpr (Val);
1248 /* Generate an expression tree */
1251 case TOK_EQ: Op = EXPR_EQ; break;
1252 case TOK_NE: Op = EXPR_NE; break;
1253 case TOK_LT: Op = EXPR_LT; break;
1254 case TOK_GT: Op = EXPR_GT; break;
1255 case TOK_LE: Op = EXPR_LE; break;
1256 case TOK_GE: Op = EXPR_GE; break;
1257 default: Internal ("Invalid token");
1259 Root = NewExprNode (Op);
1261 Root->Right = Right;
1266 /* Return the expression tree we've created */
1272 static ExprNode* Expr2 (void)
1273 /* Boolean operators: AND and XOR */
1275 /* Read left hand side */
1276 ExprNode* Root = BoolExpr ();
1278 /* Handle booleans */
1279 while (CurTok.Tok == TOK_BOOLAND || CurTok.Tok == TOK_BOOLXOR) {
1281 long LVal, RVal, Val;
1285 /* Remember the token and skip it */
1286 token_t T = CurTok.Tok;
1289 /* Move root to left side and read the right side */
1291 Right = BoolExpr ();
1293 /* If both expressions are constant, we can evaluate the term */
1294 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1297 case TOK_BOOLAND: Val = ((LVal != 0) && (RVal != 0)); break;
1298 case TOK_BOOLXOR: Val = ((LVal != 0) ^ (RVal != 0)); break;
1299 default: Internal ("Invalid token");
1302 /* Generate a literal expression and delete the old left and
1307 Root = GenLiteralExpr (Val);
1311 /* Generate an expression tree */
1314 case TOK_BOOLAND: Op = EXPR_BOOLAND; break;
1315 case TOK_BOOLXOR: Op = EXPR_BOOLXOR; break;
1316 default: Internal ("Invalid token");
1318 Root = NewExprNode (Op);
1320 Root->Right = Right;
1325 /* Return the expression tree we've created */
1331 static ExprNode* Expr1 (void)
1332 /* Boolean operators: OR */
1334 /* Read left hand side */
1335 ExprNode* Root = Expr2 ();
1337 /* Handle booleans */
1338 while (CurTok.Tok == TOK_BOOLOR) {
1340 long LVal, RVal, Val;
1344 /* Remember the token and skip it */
1345 token_t T = CurTok.Tok;
1348 /* Move root to left side and read the right side */
1352 /* If both expressions are constant, we can evaluate the term */
1353 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1356 case TOK_BOOLOR: Val = ((LVal != 0) || (RVal != 0)); break;
1357 default: Internal ("Invalid token");
1360 /* Generate a literal expression and delete the old left and
1365 Root = GenLiteralExpr (Val);
1369 /* Generate an expression tree */
1372 case TOK_BOOLOR: Op = EXPR_BOOLOR; break;
1373 default: Internal ("Invalid token");
1375 Root = NewExprNode (Op);
1377 Root->Right = Right;
1382 /* Return the expression tree we've created */
1388 static ExprNode* Expr0 (void)
1389 /* Boolean operators: NOT */
1393 /* Handle booleans */
1394 if (CurTok.Tok == TOK_BOOLNOT) {
1399 /* Skip the operator token */
1402 /* Read the argument */
1405 /* If the argument is const, evaluate it directly */
1406 if (IsEasyConst (Left, &Val)) {
1408 Root = GenLiteralExpr (!Val);
1410 Root = NewExprNode (EXPR_BOOLNOT);
1416 /* Read left hand side */
1421 /* Return the expression tree we've created */
1427 ExprNode* Expression (void)
1428 /* Evaluate an expression, build the expression tree on the heap and return
1429 * a pointer to the root of the tree.
1437 long ConstExpression (void)
1438 /* Parse an expression. Check if the expression is const, and print an error
1439 * message if not. Return the value of the expression, or a dummy, if it is
1445 /* Read the expression */
1446 ExprNode* Expr = Expression ();
1448 /* Study the expression */
1451 StudyExpr (Expr, &D);
1453 /* Check if the expression is constant */
1454 if (ED_IsConst (&D)) {
1457 Error ("Constant expression expected");
1461 /* Free the expression tree and allocated memory for D */
1465 /* Return the value */
1471 void FreeExpr (ExprNode* Root)
1472 /* Free the expression, Root is pointing to. */
1475 FreeExpr (Root->Left);
1476 FreeExpr (Root->Right);
1477 FreeExprNode (Root);
1483 ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
1484 /* Try to simplify the given expression tree */
1486 if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
1487 /* No external references */
1489 Expr = GenLiteralExpr (D->Val);
1496 ExprNode* GenLiteralExpr (long Val)
1497 /* Return an expression tree that encodes the given literal value */
1499 ExprNode* Expr = NewExprNode (EXPR_LITERAL);
1506 ExprNode* GenLiteral0 (void)
1507 /* Return an expression tree that encodes the the number zero */
1509 return GenLiteralExpr (0);
1514 ExprNode* GenSymExpr (SymEntry* Sym)
1515 /* Return an expression node that encodes the given symbol */
1517 ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
1519 SymAddExprRef (Sym, Expr);
1525 static ExprNode* GenSectionExpr (unsigned SecNum)
1526 /* Return an expression node for the given section */
1528 ExprNode* Expr = NewExprNode (EXPR_SECTION);
1529 Expr->V.SecNum = SecNum;
1535 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
1536 /* Generate an addition from the two operands */
1539 if (IsEasyConst (Left, &Val) && Val == 0) {
1542 } else if (IsEasyConst (Right, &Val) && Val == 0) {
1546 ExprNode* Root = NewExprNode (EXPR_PLUS);
1548 Root->Right = Right;
1555 ExprNode* GenCurrentPC (void)
1556 /* Return the current program counter as expression */
1560 if (GetRelocMode ()) {
1561 /* Create SegmentBase + Offset */
1562 Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
1563 GenLiteralExpr (GetPC ()));
1565 /* Absolute mode, just return PC value */
1566 Root = GenLiteralExpr (GetPC ());
1574 ExprNode* GenSwapExpr (ExprNode* Expr)
1575 /* Return an extended expression with lo and hi bytes swapped */
1577 ExprNode* N = NewExprNode (EXPR_SWAP);
1584 ExprNode* GenBranchExpr (unsigned Offs)
1585 /* Return an expression that encodes the difference between current PC plus
1586 * offset and the target expression (that is, Expression() - (*+Offs) ).
1593 /* Read Expression() */
1596 /* If the expression is a cheap constant, generate a simpler tree */
1597 if (IsEasyConst (N, &Val)) {
1599 /* Free the constant expression tree */
1602 /* Generate the final expression:
1604 * Val - ((Seg + PC) + Offs)
1605 * Val - Seg - PC - Offs
1606 * (Val - PC - Offs) - Seg
1608 Root = GenLiteralExpr (Val - GetPC () - Offs);
1609 if (GetRelocMode ()) {
1611 Root = NewExprNode (EXPR_MINUS);
1613 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1618 /* Generate the expression:
1620 * N - ((Seg + PC) + Offs)
1621 * N - Seg - PC - Offs
1622 * N - (PC + Offs) - Seg
1624 Root = NewExprNode (EXPR_MINUS);
1626 Root->Right = GenLiteralExpr (GetPC () + Offs);
1627 if (GetRelocMode ()) {
1629 Root = NewExprNode (EXPR_MINUS);
1631 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1635 /* Return the result */
1641 ExprNode* GenULabelExpr (unsigned Num)
1642 /* Return an expression for an unnamed label with the given index */
1644 ExprNode* Node = NewExprNode (EXPR_ULABEL);
1647 /* Return the new node */
1653 ExprNode* GenByteExpr (ExprNode* Expr)
1654 /* Force the given expression into a byte and return the result */
1656 /* Use the low byte operator to force the expression into byte size */
1657 return LoByte (Expr);
1662 ExprNode* GenWordExpr (ExprNode* Expr)
1663 /* Force the given expression into a word and return the result. */
1665 /* Use the low byte operator to force the expression into word size */
1666 return LoWord (Expr);
1671 ExprNode* GenNE (ExprNode* Expr, long Val)
1672 /* Generate an expression that compares Expr and Val for inequality */
1674 /* Generate a compare node */
1675 ExprNode* Root = NewExprNode (EXPR_NE);
1677 Root->Right = GenLiteralExpr (Val);
1679 /* Return the result */
1685 int IsConstExpr (ExprNode* Expr, long* Val)
1686 /* Return true if the given expression is a constant expression, that is, one
1687 * with no references to external symbols. If Val is not NULL and the
1688 * expression is constant, the constant value is stored here.
1693 /* Study the expression */
1696 StudyExpr (Expr, &D);
1698 /* Check if the expression is constant */
1699 IsConst = ED_IsConst (&D);
1700 if (IsConst && Val != 0) {
1704 /* Delete allocated memory and return the result */
1711 ExprNode* CloneExpr (ExprNode* Expr)
1712 /* Clone the given expression tree. The function will simply clone symbol
1713 * nodes, it will not resolve them.
1718 /* Accept NULL pointers */
1723 /* Clone the node */
1727 Clone = GenLiteralExpr (Expr->V.IVal);
1731 Clone = GenULabelExpr (Expr->V.IVal);
1735 Clone = GenSymExpr (Expr->V.Sym);
1739 Clone = GenSectionExpr (Expr->V.SecNum);
1743 /* Generate a new node */
1744 Clone = NewExprNode (Expr->Op);
1745 /* Clone the tree nodes */
1746 Clone->Left = CloneExpr (Expr->Left);
1747 Clone->Right = CloneExpr (Expr->Right);
1757 void WriteExpr (ExprNode* Expr)
1758 /* Write the given expression to the object file */
1760 /* Null expressions are encoded by a type byte of zero */
1762 ObjWrite8 (EXPR_NULL);
1766 /* If the is a leafnode, write the expression attribute, otherwise
1767 * write the expression operands.
1772 ObjWrite8 (EXPR_LITERAL);
1773 ObjWrite32 (Expr->V.IVal);
1777 if (SymIsImport (Expr->V.Sym)) {
1778 ObjWrite8 (EXPR_SYMBOL);
1779 ObjWriteVar (GetSymImportId (Expr->V.Sym));
1781 WriteExpr (GetSymExpr (Expr->V.Sym));
1786 ObjWrite8 (EXPR_SECTION);
1787 ObjWrite8 (Expr->V.SecNum);
1791 WriteExpr (ULabResolve (Expr->V.IVal));
1795 /* Not a leaf node */
1796 ObjWrite8 (Expr->Op);
1797 WriteExpr (Expr->Left);
1798 WriteExpr (Expr->Right);
1806 void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
1807 /* Mark the address size of the given expression tree as guessed. The address
1808 * size passed as argument is the one NOT used, because the actual address
1809 * size wasn't known. Example: Zero page addressing was not used because symbol
1810 * is undefined, and absolute addressing was available.
1811 * This function will actually parse the expression tree for undefined symbols,
1812 * and mark these symbols accordingly.
1815 /* Accept NULL expressions */
1820 /* Check the type code */
1821 switch (Expr->Op & EXPR_TYPEMASK) {
1824 if (Expr->Op == EXPR_SYMBOL) {
1825 if (!SymIsDef (Expr->V.Sym)) {
1826 /* Symbol is undefined, mark it */
1827 SymGuessedAddrSize (Expr->V.Sym, AddrSize);
1832 case EXPR_BINARYNODE:
1833 ExprGuessedAddrSize (Expr->Right, AddrSize);
1836 case EXPR_UNARYNODE:
1837 ExprGuessedAddrSize (Expr->Left, AddrSize);