1 /*****************************************************************************/
5 /* Expression evaluation for the ca65 macroassembler */
9 /* (C) 1998-2004 Ullrich von Bassewitz */
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;
102 /* Allocate fresh memory */
103 N = xmalloc (sizeof (ExprNode));
106 N->Left = N->Right = 0;
114 static void FreeExprNode (ExprNode* E)
118 if (E->Op == EXPR_SYMBOL) {
119 /* Remove the symbol reference */
120 SymDelExprRef (E->V.Sym, E);
122 /* Place the symbol into the free nodes list if possible */
123 if (FreeNodeCount < MAX_FREE_NODES) {
124 /* Remember this node for later */
125 E->Left = FreeExprNodes;
128 /* Free the memory */
136 /*****************************************************************************/
138 /*****************************************************************************/
142 static ExprNode* Expr0 (void);
146 int IsByteRange (long Val)
147 /* Return true if this is a byte value */
149 return (Val & ~0xFFL) == 0;
154 int IsWordRange (long Val)
155 /* Return true if this is a word value */
157 return (Val & ~0xFFFFL) == 0;
162 int IsFarRange (long Val)
163 /* Return true if this is a far (24 bit) value */
165 return (Val & ~0xFFFFFFL) == 0;
170 static int IsEasyConst (const ExprNode* E, long* Val)
171 /* Do some light checking if the given node is a constant. Don't care if E is
172 * a complex expression. If E is a constant, return true and place its value
173 * into Val, provided that Val is not NULL.
176 /* Resolve symbols, follow symbol chains */
177 while (E->Op == EXPR_SYMBOL) {
178 E = SymResolve (E->V.Sym);
180 /* Could not resolve */
185 /* Symbols resolved, check for a literal */
186 if (E->Op == EXPR_LITERAL) {
193 /* Not found to be a const according to our tests */
199 static ExprNode* LoByte (ExprNode* Operand)
200 /* Return the low byte of the given expression */
205 /* Special handling for const expressions */
206 if (IsEasyConst (Operand, &Val)) {
208 Expr = GenLiteralExpr (Val & 0xFF);
210 /* Extract byte #0 */
211 Expr = NewExprNode (EXPR_BYTE0);
212 Expr->Left = Operand;
219 static ExprNode* HiByte (ExprNode* Operand)
220 /* Return the high byte of the given expression */
225 /* Special handling for const expressions */
226 if (IsEasyConst (Operand, &Val)) {
228 Expr = GenLiteralExpr ((Val >> 8) & 0xFF);
230 /* Extract byte #1 */
231 Expr = NewExprNode (EXPR_BYTE1);
232 Expr->Left = Operand;
239 static ExprNode* BankByte (ExprNode* Operand)
240 /* Return the bank byte of the given expression */
245 /* Special handling for const expressions */
246 if (IsEasyConst (Operand, &Val)) {
248 Expr = GenLiteralExpr ((Val >> 16) & 0xFF);
250 /* Extract byte #2 */
251 Expr = NewExprNode (EXPR_BYTE2);
252 Expr->Left = Operand;
259 static ExprNode* LoWord (ExprNode* Operand)
260 /* Return the low word of the given expression */
265 /* Special handling for const expressions */
266 if (IsEasyConst (Operand, &Val)) {
268 Expr = GenLiteralExpr (Val & 0xFFFF);
270 /* Extract word #0 */
271 Expr = NewExprNode (EXPR_WORD0);
272 Expr->Left = Operand;
279 static ExprNode* HiWord (ExprNode* Operand)
280 /* Return the high word of the given expression */
285 /* Special handling for const expressions */
286 if (IsEasyConst (Operand, &Val)) {
288 Expr = GenLiteralExpr ((Val >> 16) & 0xFFFF);
290 /* Extract word #1 */
291 Expr = NewExprNode (EXPR_WORD1);
292 Expr->Left = Operand;
299 static ExprNode* Symbol (SymEntry* S)
300 /* Reference a symbol and return an expression for it */
303 /* Some weird error happened before */
304 return GenLiteralExpr (0);
306 /* Mark the symbol as referenced */
308 /* Create symbol node */
309 return GenSymExpr (S);
315 static ExprNode* FuncBankByte (void)
316 /* Handle the .BANKBYTE builtin function */
318 return BankByte (Expression ());
323 static ExprNode* FuncBlank (void)
324 /* Handle the .BLANK builtin function */
326 /* We have a list of tokens that ends with the closing paren. Skip
327 * the tokens, and count them. Allow optionally curly braces.
329 enum Token Term = GetTokListTerm (TOK_RPAREN);
331 while (Tok != Term) {
333 /* Check for end of line or end of input. Since the calling function
334 * will check for the closing paren, we don't need to print an error
335 * here, just bail out.
337 if (TokIsSep (Tok)) {
348 /* If the list was enclosed in curly braces, skip the closing brace */
349 if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
353 /* Return true if the list was empty */
354 return GenLiteralExpr (Count == 0);
359 static ExprNode* FuncConst (void)
360 /* Handle the .CONST builtin function */
362 /* Read an expression */
363 ExprNode* Expr = Expression ();
365 /* Check the constness of the expression */
366 ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
368 /* Free the expression */
377 static ExprNode* FuncDefined (void)
378 /* Handle the .DEFINED builtin function */
380 /* Parse the symbol name and search for the symbol */
381 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
383 /* Check if the symbol is defined */
384 return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
389 static ExprNode* FuncHiByte (void)
390 /* Handle the .HIBYTE builtin function */
392 return HiByte (Expression ());
397 static ExprNode* FuncHiWord (void)
398 /* Handle the .HIWORD builtin function */
400 return HiWord (Expression ());
405 static ExprNode* FuncLoByte (void)
406 /* Handle the .LOBYTE builtin function */
408 return LoByte (Expression ());
413 static ExprNode* FuncLoWord (void)
414 /* Handle the .LOWORD builtin function */
416 return LoWord (Expression ());
421 static ExprNode* DoMatch (enum TC EqualityLevel)
422 /* Handle the .MATCH and .XMATCH builtin functions */
429 /* A list of tokens follows. Read this list and remember it building a
430 * single linked list of tokens including attributes. The list is
431 * either enclosed in curly braces, or terminated by a comma.
433 enum Token Term = GetTokListTerm (TOK_COMMA);
434 while (Tok != Term) {
436 /* We may not end-of-line of end-of-file here */
437 if (TokIsSep (Tok)) {
438 Error ("Unexpected end of line");
439 return GenLiteralExpr (0);
442 /* Get a node with this token */
443 Node = NewTokNode ();
445 /* Insert the node into the list */
457 /* Skip the terminator token*/
460 /* If the token list was enclosed in curly braces, we expect a comma */
461 if (Term == TOK_RCURLY) {
465 /* Read the second list which is optionally enclosed in curly braces and
466 * terminated by the right parenthesis. Compare each token against the
467 * one in the first list.
469 Term = GetTokListTerm (TOK_RPAREN);
472 while (Tok != Term) {
474 /* We may not end-of-line of end-of-file here */
475 if (TokIsSep (Tok)) {
476 Error ("Unexpected end of line");
477 return GenLiteralExpr (0);
480 /* Compare the tokens if the result is not already known */
483 /* The second list is larger than the first one */
485 } else if (TokCmp (Node) < EqualityLevel) {
486 /* Tokens do not match */
491 /* Next token in first list */
496 /* Next token in current list */
500 /* If the token list was enclosed in curly braces, eat the closing brace */
501 if (Term == TOK_RCURLY) {
505 /* Check if there are remaining tokens in the first list */
510 /* Free the token list */
517 /* Done, return the result */
518 return GenLiteralExpr (Result);
523 static ExprNode* FuncMatch (void)
524 /* Handle the .MATCH function */
526 return DoMatch (tcSameToken);
531 static ExprNode* FuncReferenced (void)
532 /* Handle the .REFERENCED builtin function */
534 /* Parse the symbol name and search for the symbol */
535 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
537 /* Check if the symbol is referenced */
538 return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
543 static ExprNode* FuncSizeOf (void)
544 /* Handle the .SIZEOF function */
546 StrBuf ScopeName = AUTO_STRBUF_INITIALIZER;
547 char Name[sizeof (SVal)];
555 /* Assume an error */
558 /* Check for a cheap local which needs special handling */
559 if (Tok == TOK_LOCAL_IDENT) {
561 /* Cheap local symbol */
562 Sym = SymFindLocal (SymLast, SVal, SYM_FIND_EXISTING);
564 Error ("Unknown symbol or scope: `%s'", SVal);
566 SizeSym = GetSizeOfSymbol (Sym);
569 /* Remember and skip SVal, terminate ScopeName so it is empty */
572 SB_Terminate (&ScopeName);
576 /* Parse the scope and the name */
577 SymTable* ParentScope = ParseScopedIdent (Name, &ScopeName);
579 /* Check if the parent scope is valid */
580 if (ParentScope == 0) {
582 DoneStrBuf (&ScopeName);
583 return GenLiteralExpr (0);
586 /* If ScopeName is empty, no explicit scope was specified. We have to
587 * search upper scope levels in this case.
589 NoScope = SB_IsEmpty (&ScopeName);
591 /* First search for a scope with the given name */
593 Scope = SymFindAnyScope (ParentScope, Name);
595 Scope = SymFindScope (ParentScope, Name, SYM_FIND_EXISTING);
598 /* If we did find a scope with the name, read the symbol defining the
599 * size, otherwise search for a symbol entry with the name and scope.
602 /* Yep, it's a scope */
603 SizeSym = GetSizeOfScope (Scope);
606 Sym = SymFindAny (ParentScope, Name);
608 Sym = SymFind (ParentScope, Name, SYM_FIND_EXISTING);
611 /* If we found the symbol retrieve the size, otherwise complain */
613 SizeSym = GetSizeOfSymbol (Sym);
615 Error ("Unknown symbol or scope: `%s%s'",
616 SB_GetConstBuf (&ScopeName), Name);
621 /* Check if we have a size */
622 if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
623 Error ("Size of `%s%s' is unknown", SB_GetConstBuf (&ScopeName), Name);
627 /* Free the scope name */
628 DoneStrBuf (&ScopeName);
630 /* Return the size */
631 return GenLiteralExpr (Size);
636 static ExprNode* FuncStrAt (void)
637 /* Handle the .STRAT function */
639 char Str [sizeof(SVal)];
643 /* String constant expected */
644 if (Tok != TOK_STRCON) {
645 Error ("String constant expected");
651 /* Remember the string and skip it */
655 /* Comma must follow */
658 /* Expression expected */
659 Index = ConstExpression ();
661 /* Must be a valid index */
662 if (Index >= (long) strlen (Str)) {
663 Error ("Range error");
664 return GenLiteralExpr (0);
667 /* Get the char, handle as unsigned. Be sure to translate it into
668 * the target character set.
670 C = TgtTranslateChar (Str [(size_t)Index]);
672 /* Return the char expression */
673 return GenLiteralExpr (C);
678 static ExprNode* FuncStrLen (void)
679 /* Handle the .STRLEN function */
683 /* String constant expected */
684 if (Tok != TOK_STRCON) {
686 Error ("String constant expected");
687 /* Smart error recovery */
688 if (Tok != TOK_RPAREN) {
695 /* Get the length of the string */
698 /* Skip the string */
702 /* Return the length */
703 return GenLiteralExpr (Len);
708 static ExprNode* FuncTCount (void)
709 /* Handle the .TCOUNT function */
711 /* We have a list of tokens that ends with the closing paren. Skip
712 * the tokens, and count them. Allow optionally curly braces.
714 enum Token Term = GetTokListTerm (TOK_RPAREN);
716 while (Tok != Term) {
718 /* Check for end of line or end of input. Since the calling function
719 * will check for the closing paren, we don't need to print an error
720 * here, just bail out.
722 if (TokIsSep (Tok)) {
733 /* If the list was enclosed in curly braces, skip the closing brace */
734 if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
738 /* Return the number of tokens */
739 return GenLiteralExpr (Count);
744 static ExprNode* FuncXMatch (void)
745 /* Handle the .XMATCH function */
747 return DoMatch (tcIdentical);
752 static ExprNode* Function (ExprNode* (*F) (void))
753 /* Handle builtin functions */
757 /* Skip the keyword */
760 /* Expression must be enclosed in braces */
761 if (Tok != TOK_LPAREN) {
762 Error ("'(' expected");
764 return GenLiteralExpr (0);
768 /* Call the function itself */
771 /* Closing brace must follow */
774 /* Return the result of the actual function */
780 static ExprNode* Factor (void)
789 N = GenLiteralExpr (IVal);
794 N = GenLiteralExpr (TgtTranslateChar (IVal));
800 N = Symbol (ParseScopedSymName (SYM_ALLOC_NEW));
803 case TOK_LOCAL_IDENT:
804 N = Symbol (SymFindLocal (SymLast, SVal, SYM_ALLOC_NEW));
821 if (IsEasyConst (L, &Val)) {
823 N = GenLiteralExpr (-Val);
825 N = NewExprNode (EXPR_UNARY_MINUS);
833 if (IsEasyConst (L, &Val)) {
835 N = GenLiteralExpr (~Val);
837 N = NewExprNode (EXPR_NOT);
850 N = LoByte (Factor ());
855 N = HiByte (Factor ());
860 N = BankByte (Factor ());
870 N = Function (FuncBankByte);
874 N = Function (FuncBlank);
878 N = Function (FuncConst);
882 N = GenLiteralExpr (CPUIsets[CPU]);
887 N = Function (FuncDefined);
891 N = Function (FuncHiByte);
895 N = Function (FuncHiWord);
899 N = Function (FuncLoByte);
903 N = Function (FuncLoWord);
907 N = Function (FuncMatch);
911 N = Function (FuncReferenced);
915 N = Function (FuncSizeOf);
919 N = Function (FuncStrAt);
923 N = Function (FuncStrLen);
927 N = Function (FuncTCount);
931 N = GenLiteralExpr (time (0));
936 N = GenLiteralExpr (VERSION);
941 N = Function (FuncXMatch);
945 if (LooseCharTerm && Tok == TOK_STRCON && strlen(SVal) == 1) {
946 /* A character constant */
947 N = GenLiteralExpr (TgtTranslateChar (SVal[0]));
949 N = GenLiteralExpr (0); /* Dummy */
950 Error ("Syntax error");
960 static ExprNode* Term (void)
962 /* Read left hand side */
963 ExprNode* Root = Factor ();
965 /* Handle multiplicative operations */
966 while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
967 Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
970 long LVal, RVal, Val;
974 /* Remember the token and skip it */
978 /* Move root to left side and read the right side */
982 /* If both expressions are constant, we can evaluate the term */
983 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
992 Error ("Division by zero");
1001 Error ("Modulo operation with zero");
1017 Val = shl_l (LVal, RVal);
1021 Val = shr_l (LVal, RVal);
1025 Internal ("Invalid token");
1028 /* Generate a literal expression and delete the old left and
1033 Root = GenLiteralExpr (Val);
1037 /* Generate an expression tree */
1040 case TOK_MUL: Op = EXPR_MUL; break;
1041 case TOK_DIV: Op = EXPR_DIV; break;
1042 case TOK_MOD: Op = EXPR_MOD; break;
1043 case TOK_AND: Op = EXPR_AND; break;
1044 case TOK_XOR: Op = EXPR_XOR; break;
1045 case TOK_SHL: Op = EXPR_SHL; break;
1046 case TOK_SHR: Op = EXPR_SHR; break;
1047 default: Internal ("Invalid token");
1049 Root = NewExprNode (Op);
1051 Root->Right = Right;
1057 /* Return the expression tree we've created */
1063 static ExprNode* SimpleExpr (void)
1065 /* Read left hand side */
1066 ExprNode* Root = Term ();
1068 /* Handle additive operations */
1069 while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
1071 long LVal, RVal, Val;
1075 /* Remember the token and skip it */
1079 /* Move root to left side and read the right side */
1083 /* If both expressions are constant, we can evaluate the term */
1084 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1087 case TOK_PLUS: Val = LVal + RVal; break;
1088 case TOK_MINUS: Val = LVal - RVal; break;
1089 case TOK_OR: Val = LVal | RVal; break;
1090 default: Internal ("Invalid token");
1093 /* Generate a literal expression and delete the old left and
1098 Root = GenLiteralExpr (Val);
1102 /* Generate an expression tree */
1105 case TOK_PLUS: Op = EXPR_PLUS; break;
1106 case TOK_MINUS: Op = EXPR_MINUS; break;
1107 case TOK_OR: Op = EXPR_OR; break;
1108 default: Internal ("Invalid token");
1110 Root = NewExprNode (Op);
1112 Root->Right = Right;
1117 /* Return the expression tree we've created */
1123 static ExprNode* BoolExpr (void)
1124 /* Evaluate a boolean expression */
1126 /* Read left hand side */
1127 ExprNode* Root = SimpleExpr ();
1129 /* Handle booleans */
1130 while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
1131 Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
1133 long LVal, RVal, Val;
1137 /* Remember the token and skip it */
1141 /* Move root to left side and read the right side */
1143 Right = SimpleExpr ();
1145 /* If both expressions are constant, we can evaluate the term */
1146 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1149 case TOK_EQ: Val = (LVal == RVal); break;
1150 case TOK_NE: Val = (LVal != RVal); break;
1151 case TOK_LT: Val = (LVal < RVal); break;
1152 case TOK_GT: Val = (LVal > RVal); break;
1153 case TOK_LE: Val = (LVal <= RVal); break;
1154 case TOK_GE: Val = (LVal >= RVal); break;
1155 default: Internal ("Invalid token");
1158 /* Generate a literal expression and delete the old left and
1163 Root = GenLiteralExpr (Val);
1167 /* Generate an expression tree */
1170 case TOK_EQ: Op = EXPR_EQ; break;
1171 case TOK_NE: Op = EXPR_NE; break;
1172 case TOK_LT: Op = EXPR_LT; break;
1173 case TOK_GT: Op = EXPR_GT; break;
1174 case TOK_LE: Op = EXPR_LE; break;
1175 case TOK_GE: Op = EXPR_GE; break;
1176 default: Internal ("Invalid token");
1178 Root = NewExprNode (Op);
1180 Root->Right = Right;
1185 /* Return the expression tree we've created */
1191 static ExprNode* Expr2 (void)
1192 /* Boolean operators: AND and XOR */
1194 /* Read left hand side */
1195 ExprNode* Root = BoolExpr ();
1197 /* Handle booleans */
1198 while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
1200 long LVal, RVal, Val;
1204 /* Remember the token and skip it */
1208 /* Move root to left side and read the right side */
1210 Right = BoolExpr ();
1212 /* If both expressions are constant, we can evaluate the term */
1213 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1216 case TOK_BOOLAND: Val = ((LVal != 0) && (RVal != 0)); break;
1217 case TOK_BOOLXOR: Val = ((LVal != 0) ^ (RVal != 0)); break;
1218 default: Internal ("Invalid token");
1221 /* Generate a literal expression and delete the old left and
1226 Root = GenLiteralExpr (Val);
1230 /* Generate an expression tree */
1233 case TOK_BOOLAND: Op = EXPR_BOOLAND; break;
1234 case TOK_BOOLXOR: Op = EXPR_BOOLXOR; break;
1235 default: Internal ("Invalid token");
1237 Root = NewExprNode (Op);
1239 Root->Right = Right;
1244 /* Return the expression tree we've created */
1250 static ExprNode* Expr1 (void)
1251 /* Boolean operators: OR */
1253 /* Read left hand side */
1254 ExprNode* Root = Expr2 ();
1256 /* Handle booleans */
1257 while (Tok == TOK_BOOLOR) {
1259 long LVal, RVal, Val;
1263 /* Remember the token and skip it */
1267 /* Move root to left side and read the right side */
1271 /* If both expressions are constant, we can evaluate the term */
1272 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1275 case TOK_BOOLOR: Val = ((LVal != 0) || (RVal != 0)); break;
1276 default: Internal ("Invalid token");
1279 /* Generate a literal expression and delete the old left and
1284 Root = GenLiteralExpr (Val);
1288 /* Generate an expression tree */
1291 case TOK_BOOLOR: Op = EXPR_BOOLOR; break;
1292 default: Internal ("Invalid token");
1294 Root = NewExprNode (Op);
1296 Root->Right = Right;
1301 /* Return the expression tree we've created */
1307 static ExprNode* Expr0 (void)
1308 /* Boolean operators: NOT */
1312 /* Handle booleans */
1313 if (Tok == TOK_BOOLNOT) {
1318 /* Skip the operator token */
1321 /* Read the argument */
1324 /* If the argument is const, evaluate it directly */
1325 if (IsEasyConst (Left, &Val)) {
1327 Root = GenLiteralExpr (!Val);
1329 Root = NewExprNode (EXPR_BOOLNOT);
1335 /* Read left hand side */
1340 /* Return the expression tree we've created */
1346 ExprNode* Expression (void)
1347 /* Evaluate an expression, build the expression tree on the heap and return
1348 * a pointer to the root of the tree.
1356 long ConstExpression (void)
1357 /* Parse an expression. Check if the expression is const, and print an error
1358 * message if not. Return the value of the expression, or a dummy, if it is
1364 /* Read the expression */
1365 ExprNode* Expr = Expression ();
1367 /* Study the expression */
1370 StudyExpr (Expr, &D);
1372 /* Check if the expression is constant */
1373 if (ED_IsConst (&D)) {
1376 Error ("Constant expression expected");
1380 /* Free the expression tree and allocated memory for D */
1384 /* Return the value */
1390 void FreeExpr (ExprNode* Root)
1391 /* Free the expression, Root is pointing to. */
1394 FreeExpr (Root->Left);
1395 FreeExpr (Root->Right);
1396 FreeExprNode (Root);
1402 ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
1403 /* Try to simplify the given expression tree */
1405 if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
1406 /* No external references */
1408 Expr = GenLiteralExpr (D->Val);
1415 ExprNode* GenLiteralExpr (long Val)
1416 /* Return an expression tree that encodes the given literal value */
1418 ExprNode* Expr = NewExprNode (EXPR_LITERAL);
1425 ExprNode* GenSymExpr (SymEntry* Sym)
1426 /* Return an expression node that encodes the given symbol */
1428 ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
1430 SymAddExprRef (Sym, Expr);
1436 static ExprNode* GenSectionExpr (unsigned SegNum)
1437 /* Return an expression node for the given section */
1439 ExprNode* Expr = NewExprNode (EXPR_SECTION);
1440 Expr->V.SegNum = SegNum;
1446 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
1447 /* Generate an addition from the two operands */
1450 if (IsEasyConst (Left, &Val) && Val == 0) {
1453 } else if (IsEasyConst (Right, &Val) && Val == 0) {
1457 ExprNode* Root = NewExprNode (EXPR_PLUS);
1459 Root->Right = Right;
1466 ExprNode* GenCurrentPC (void)
1467 /* Return the current program counter as expression */
1472 /* Create SegmentBase + Offset */
1473 Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
1474 GenLiteralExpr (GetPC ()));
1476 /* Absolute mode, just return PC value */
1477 Root = GenLiteralExpr (GetPC ());
1485 ExprNode* GenSwapExpr (ExprNode* Expr)
1486 /* Return an extended expression with lo and hi bytes swapped */
1488 ExprNode* N = NewExprNode (EXPR_SWAP);
1495 ExprNode* GenBranchExpr (unsigned Offs)
1496 /* Return an expression that encodes the difference between current PC plus
1497 * offset and the target expression (that is, Expression() - (*+Offs) ).
1504 /* Read Expression() */
1507 /* If the expression is a cheap constant, generate a simpler tree */
1508 if (IsEasyConst (N, &Val)) {
1510 /* Free the constant expression tree */
1513 /* Generate the final expression:
1515 * Val - ((Seg + PC) + Offs)
1516 * Val - Seg - PC - Offs
1517 * (Val - PC - Offs) - Seg
1519 Root = GenLiteralExpr (Val - GetPC () - Offs);
1522 Root = NewExprNode (EXPR_MINUS);
1524 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1529 /* Generate the expression:
1531 * N - ((Seg + PC) + Offs)
1532 * N - Seg - PC - Offs
1533 * N - (PC + Offs) - Seg
1535 Root = NewExprNode (EXPR_MINUS);
1537 Root->Right = GenLiteralExpr (GetPC () + Offs);
1540 Root = NewExprNode (EXPR_MINUS);
1542 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1546 /* Return the result */
1552 ExprNode* GenULabelExpr (unsigned Num)
1553 /* Return an expression for an unnamed label with the given index */
1555 ExprNode* Node = NewExprNode (EXPR_ULABEL);
1558 /* Return the new node */
1564 ExprNode* GenByteExpr (ExprNode* Expr)
1565 /* Force the given expression into a byte and return the result */
1567 /* Use the low byte operator to force the expression into byte size */
1568 return LoByte (Expr);
1573 ExprNode* GenWordExpr (ExprNode* Expr)
1574 /* Force the given expression into a word and return the result. */
1576 /* Use the low byte operator to force the expression into word size */
1577 return LoWord (Expr);
1582 ExprNode* GenNE (ExprNode* Expr, long Val)
1583 /* Generate an expression that compares Expr and Val for inequality */
1585 /* Generate a compare node */
1586 ExprNode* Root = NewExprNode (EXPR_NE);
1588 Root->Right = GenLiteralExpr (Val);
1590 /* Return the result */
1596 int IsConstExpr (ExprNode* Expr, long* Val)
1597 /* Return true if the given expression is a constant expression, that is, one
1598 * with no references to external symbols. If Val is not NULL and the
1599 * expression is constant, the constant value is stored here.
1604 /* Study the expression */
1607 StudyExpr (Expr, &D);
1609 /* Check if the expression is constant */
1610 IsConst = ED_IsConst (&D);
1611 if (IsConst && Val != 0) {
1615 /* Delete allocated memory and return the result */
1622 ExprNode* CloneExpr (ExprNode* Expr)
1623 /* Clone the given expression tree. The function will simply clone symbol
1624 * nodes, it will not resolve them.
1629 /* Accept NULL pointers */
1634 /* Clone the node */
1638 Clone = GenLiteralExpr (Expr->V.Val);
1642 Clone = GenULabelExpr (Expr->V.Val);
1646 Clone = GenSymExpr (Expr->V.Sym);
1650 Clone = GenSectionExpr (Expr->V.SegNum);
1654 /* Generate a new node */
1655 Clone = NewExprNode (Expr->Op);
1656 /* Clone the tree nodes */
1657 Clone->Left = CloneExpr (Expr->Left);
1658 Clone->Right = CloneExpr (Expr->Right);
1668 void WriteExpr (ExprNode* Expr)
1669 /* Write the given expression to the object file */
1671 /* Null expressions are encoded by a type byte of zero */
1673 ObjWrite8 (EXPR_NULL);
1677 /* If the is a leafnode, write the expression attribute, otherwise
1678 * write the expression operands.
1683 ObjWrite8 (EXPR_LITERAL);
1684 ObjWrite32 (Expr->V.Val);
1688 if (SymIsImport (Expr->V.Sym)) {
1689 ObjWrite8 (EXPR_SYMBOL);
1690 ObjWriteVar (GetSymIndex (Expr->V.Sym));
1692 WriteExpr (GetSymExpr (Expr->V.Sym));
1697 ObjWrite8 (EXPR_SECTION);
1698 ObjWrite8 (Expr->V.SegNum);
1702 WriteExpr (ULabResolve (Expr->V.Val));
1706 /* Not a leaf node */
1707 ObjWrite8 (Expr->Op);
1708 WriteExpr (Expr->Left);
1709 WriteExpr (Expr->Right);