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;
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 /* If the symbol is a variable, return just its value, otherwise
309 * return a reference to the symbol.
312 return CloneExpr (GetSymExpr (S));
314 /* Create symbol node */
315 return GenSymExpr (S);
322 ExprNode* FuncBankByte (void)
323 /* Handle the .BANKBYTE builtin function */
325 return BankByte (Expression ());
330 static ExprNode* FuncBlank (void)
331 /* Handle the .BLANK builtin function */
333 /* We have a list of tokens that ends with the closing paren. Skip
334 * the tokens, and count them. Allow optionally curly braces.
336 token_t Term = GetTokListTerm (TOK_RPAREN);
338 while (CurTok.Tok != Term) {
340 /* Check for end of line or end of input. Since the calling function
341 * will check for the closing paren, we don't need to print an error
342 * here, just bail out.
344 if (TokIsSep (CurTok.Tok)) {
355 /* If the list was enclosed in curly braces, skip the closing brace */
356 if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
360 /* Return true if the list was empty */
361 return GenLiteralExpr (Count == 0);
366 static ExprNode* FuncConst (void)
367 /* Handle the .CONST builtin function */
369 /* Read an expression */
370 ExprNode* Expr = Expression ();
372 /* Check the constness of the expression */
373 ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
375 /* Free the expression */
384 static ExprNode* FuncDefined (void)
385 /* Handle the .DEFINED builtin function */
387 /* Parse the symbol name and search for the symbol */
388 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
390 /* Check if the symbol is defined */
391 return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
396 ExprNode* FuncHiByte (void)
397 /* Handle the .HIBYTE builtin function */
399 return HiByte (Expression ());
404 static ExprNode* FuncHiWord (void)
405 /* Handle the .HIWORD builtin function */
407 return HiWord (Expression ());
412 ExprNode* FuncLoByte (void)
413 /* Handle the .LOBYTE builtin function */
415 return LoByte (Expression ());
420 static ExprNode* FuncLoWord (void)
421 /* Handle the .LOWORD builtin function */
423 return LoWord (Expression ());
428 static ExprNode* DoMatch (enum TC EqualityLevel)
429 /* Handle the .MATCH and .XMATCH builtin functions */
436 /* A list of tokens follows. Read this list and remember it building a
437 * single linked list of tokens including attributes. The list is
438 * either enclosed in curly braces, or terminated by a comma.
440 token_t Term = GetTokListTerm (TOK_COMMA);
441 while (CurTok.Tok != Term) {
443 /* We may not end-of-line of end-of-file here */
444 if (TokIsSep (CurTok.Tok)) {
445 Error ("Unexpected end of line");
446 return GenLiteral0 ();
449 /* Get a node with this token */
450 Node = NewTokNode ();
452 /* Insert the node into the list */
464 /* Skip the terminator token*/
467 /* If the token list was enclosed in curly braces, we expect a comma */
468 if (Term == TOK_RCURLY) {
472 /* Read the second list which is optionally enclosed in curly braces and
473 * terminated by the right parenthesis. Compare each token against the
474 * one in the first list.
476 Term = GetTokListTerm (TOK_RPAREN);
479 while (CurTok.Tok != Term) {
481 /* We may not end-of-line of end-of-file here */
482 if (TokIsSep (CurTok.Tok)) {
483 Error ("Unexpected end of line");
484 return GenLiteral0 ();
487 /* Compare the tokens if the result is not already known */
490 /* The second list is larger than the first one */
492 } else if (TokCmp (Node) < EqualityLevel) {
493 /* Tokens do not match */
498 /* Next token in first list */
503 /* Next token in current list */
507 /* If the token list was enclosed in curly braces, eat the closing brace */
508 if (Term == TOK_RCURLY) {
512 /* Check if there are remaining tokens in the first list */
517 /* Free the token list */
524 /* Done, return the result */
525 return GenLiteralExpr (Result);
530 static ExprNode* FuncMatch (void)
531 /* Handle the .MATCH function */
533 return DoMatch (tcSameToken);
538 static ExprNode* FuncMax (void)
539 /* Handle the .MAX function */
544 long LeftVal, RightVal;
546 /* Two arguments to the pseudo function */
547 Left = Expression ();
549 Right = Expression ();
551 /* Check if we can evaluate the value immediately */
552 if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
555 Expr = GenLiteralExpr ((LeftVal > RightVal)? LeftVal : RightVal);
557 /* Make an expression node */
558 Expr = NewExprNode (EXPR_MAX);
567 static ExprNode* FuncMin (void)
568 /* Handle the .MIN function */
573 long LeftVal, RightVal;
575 /* Two arguments to the pseudo function */
576 Left = Expression ();
578 Right = Expression ();
580 /* Check if we can evaluate the value immediately */
581 if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
584 Expr = GenLiteralExpr ((LeftVal < RightVal)? LeftVal : RightVal);
586 /* Make an expression node */
587 Expr = NewExprNode (EXPR_MIN);
596 static ExprNode* FuncReferenced (void)
597 /* Handle the .REFERENCED builtin function */
599 /* Parse the symbol name and search for the symbol */
600 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
602 /* Check if the symbol is referenced */
603 return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
608 static ExprNode* FuncSizeOf (void)
609 /* Handle the .SIZEOF function */
611 StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
612 StrBuf Name = STATIC_STRBUF_INITIALIZER;
620 /* Assume an error */
623 /* Check for a cheap local which needs special handling */
624 if (CurTok.Tok == TOK_LOCAL_IDENT) {
626 /* Cheap local symbol */
627 Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
629 Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
631 SizeSym = GetSizeOfSymbol (Sym);
634 /* Remember and skip SVal, terminate ScopeName so it is empty */
635 SB_Copy (&Name, &CurTok.SVal);
637 SB_Terminate (&ScopeName);
641 /* Parse the scope and the name */
642 SymTable* ParentScope = ParseScopedIdent (&Name, &ScopeName);
644 /* Check if the parent scope is valid */
645 if (ParentScope == 0) {
647 SB_Done (&ScopeName);
649 return GenLiteral0 ();
652 /* If ScopeName is empty, no explicit scope was specified. We have to
653 * search upper scope levels in this case.
655 NoScope = SB_IsEmpty (&ScopeName);
657 /* First search for a scope with the given name */
659 Scope = SymFindAnyScope (ParentScope, &Name);
661 Scope = SymFindScope (ParentScope, &Name, SYM_FIND_EXISTING);
664 /* If we did find a scope with the name, read the symbol defining the
665 * size, otherwise search for a symbol entry with the name and scope.
668 /* Yep, it's a scope */
669 SizeSym = GetSizeOfScope (Scope);
672 Sym = SymFindAny (ParentScope, &Name);
674 Sym = SymFind (ParentScope, &Name, SYM_FIND_EXISTING);
677 /* If we found the symbol retrieve the size, otherwise complain */
679 SizeSym = GetSizeOfSymbol (Sym);
681 Error ("Unknown symbol or scope: `%m%p%m%p'",
687 /* Check if we have a size */
688 if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
689 Error ("Size of `%m%p%m%p' is unknown", &ScopeName, &Name);
693 /* Free the string buffers */
694 SB_Done (&ScopeName);
697 /* Return the size */
698 return GenLiteralExpr (Size);
703 static ExprNode* FuncStrAt (void)
704 /* Handle the .STRAT function */
706 StrBuf Str = STATIC_STRBUF_INITIALIZER;
710 /* String constant expected */
711 if (CurTok.Tok != TOK_STRCON) {
712 Error ("String constant expected");
717 /* Remember the string and skip it */
718 SB_Copy (&Str, &CurTok.SVal);
721 /* Comma must follow */
724 /* Expression expected */
725 Index = ConstExpression ();
727 /* Must be a valid index */
728 if (Index >= (long) SB_GetLen (&Str)) {
729 Error ("Range error");
733 /* Get the char, handle as unsigned. Be sure to translate it into
734 * the target character set.
736 C = TgtTranslateChar (SB_At (&Str, (unsigned)Index));
739 /* Free string buffer memory */
742 /* Return the char expression */
743 return GenLiteralExpr (C);
748 static ExprNode* FuncStrLen (void)
749 /* Handle the .STRLEN function */
753 /* String constant expected */
754 if (CurTok.Tok != TOK_STRCON) {
756 Error ("String constant expected");
757 /* Smart error recovery */
758 if (CurTok.Tok != TOK_RPAREN) {
765 /* Get the length of the string */
766 Len = SB_GetLen (&CurTok.SVal);
768 /* Skip the string */
772 /* Return the length */
773 return GenLiteralExpr (Len);
778 static ExprNode* FuncTCount (void)
779 /* Handle the .TCOUNT function */
781 /* We have a list of tokens that ends with the closing paren. Skip
782 * the tokens, and count them. Allow optionally curly braces.
784 token_t Term = GetTokListTerm (TOK_RPAREN);
786 while (CurTok.Tok != Term) {
788 /* Check for end of line or end of input. Since the calling function
789 * will check for the closing paren, we don't need to print an error
790 * here, just bail out.
792 if (TokIsSep (CurTok.Tok)) {
803 /* If the list was enclosed in curly braces, skip the closing brace */
804 if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
808 /* Return the number of tokens */
809 return GenLiteralExpr (Count);
814 static ExprNode* FuncXMatch (void)
815 /* Handle the .XMATCH function */
817 return DoMatch (tcIdentical);
822 static ExprNode* Function (ExprNode* (*F) (void))
823 /* Handle builtin functions */
827 /* Skip the keyword */
830 /* Expression must be enclosed in braces */
831 if (CurTok.Tok != TOK_LPAREN) {
832 Error ("'(' expected");
834 return GenLiteral0 ();
838 /* Call the function itself */
841 /* Closing brace must follow */
844 /* Return the result of the actual function */
850 static ExprNode* Factor (void)
856 switch (CurTok.Tok) {
859 N = GenLiteralExpr (CurTok.IVal);
864 N = GenLiteralExpr (TgtTranslateChar (CurTok.IVal));
870 case TOK_LOCAL_IDENT:
871 N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
875 N = ULabRef (CurTok.IVal);
887 if (IsEasyConst (L, &Val)) {
889 N = GenLiteralExpr (-Val);
891 N = NewExprNode (EXPR_UNARY_MINUS);
899 if (IsEasyConst (L, &Val)) {
901 N = GenLiteralExpr (~Val);
903 N = NewExprNode (EXPR_NOT);
916 N = LoByte (Factor ());
921 N = HiByte (Factor ());
926 N = BankByte (Factor ());
936 N = Function (FuncBankByte);
940 N = Function (FuncBlank);
944 N = Function (FuncConst);
948 N = GenLiteralExpr (CPUIsets[CPU]);
953 N = Function (FuncDefined);
957 N = Function (FuncHiByte);
961 N = Function (FuncHiWord);
965 N = Function (FuncLoByte);
969 N = Function (FuncLoWord);
973 N = Function (FuncMatch);
977 N = Function (FuncMax);
981 N = Function (FuncMin);
985 N = Function (FuncReferenced);
989 N = Function (FuncSizeOf);
993 N = Function (FuncStrAt);
997 N = Function (FuncStrLen);
1001 N = Function (FuncTCount);
1005 N = GenLiteralExpr (time (0));
1010 N = GenLiteralExpr (GetVersionAsNumber ());
1015 N = Function (FuncXMatch);
1019 if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
1020 SB_GetLen (&CurTok.SVal) == 1) {
1021 /* A character constant */
1022 N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
1024 N = GenLiteral0 (); /* Dummy */
1025 Error ("Syntax error");
1035 static ExprNode* Term (void)
1037 /* Read left hand side */
1038 ExprNode* Root = Factor ();
1040 /* Handle multiplicative operations */
1041 while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV ||
1042 CurTok.Tok == TOK_MOD || CurTok.Tok == TOK_AND ||
1043 CurTok.Tok == TOK_XOR || CurTok.Tok == TOK_SHL ||
1044 CurTok.Tok == TOK_SHR) {
1046 long LVal, RVal, Val;
1050 /* Remember the token and skip it */
1051 token_t T = CurTok.Tok;
1054 /* Move root to left side and read the right side */
1058 /* If both expressions are constant, we can evaluate the term */
1059 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1068 Error ("Division by zero");
1077 Error ("Modulo operation with zero");
1093 Val = shl_l (LVal, RVal);
1097 Val = shr_l (LVal, RVal);
1101 Internal ("Invalid token");
1104 /* Generate a literal expression and delete the old left and
1109 Root = GenLiteralExpr (Val);
1113 /* Generate an expression tree */
1116 case TOK_MUL: Op = EXPR_MUL; break;
1117 case TOK_DIV: Op = EXPR_DIV; break;
1118 case TOK_MOD: Op = EXPR_MOD; break;
1119 case TOK_AND: Op = EXPR_AND; break;
1120 case TOK_XOR: Op = EXPR_XOR; break;
1121 case TOK_SHL: Op = EXPR_SHL; break;
1122 case TOK_SHR: Op = EXPR_SHR; break;
1123 default: Internal ("Invalid token");
1125 Root = NewExprNode (Op);
1127 Root->Right = Right;
1133 /* Return the expression tree we've created */
1139 static ExprNode* SimpleExpr (void)
1141 /* Read left hand side */
1142 ExprNode* Root = Term ();
1144 /* Handle additive operations */
1145 while (CurTok.Tok == TOK_PLUS ||
1146 CurTok.Tok == TOK_MINUS ||
1147 CurTok.Tok == TOK_OR) {
1149 long LVal, RVal, Val;
1153 /* Remember the token and skip it */
1154 token_t T = CurTok.Tok;
1157 /* Move root to left side and read the right side */
1161 /* If both expressions are constant, we can evaluate the term */
1162 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1165 case TOK_PLUS: Val = LVal + RVal; break;
1166 case TOK_MINUS: Val = LVal - RVal; break;
1167 case TOK_OR: Val = LVal | RVal; break;
1168 default: Internal ("Invalid token");
1171 /* Generate a literal expression and delete the old left and
1176 Root = GenLiteralExpr (Val);
1180 /* Generate an expression tree */
1183 case TOK_PLUS: Op = EXPR_PLUS; break;
1184 case TOK_MINUS: Op = EXPR_MINUS; break;
1185 case TOK_OR: Op = EXPR_OR; break;
1186 default: Internal ("Invalid token");
1188 Root = NewExprNode (Op);
1190 Root->Right = Right;
1195 /* Return the expression tree we've created */
1201 static ExprNode* BoolExpr (void)
1202 /* Evaluate a boolean expression */
1204 /* Read left hand side */
1205 ExprNode* Root = SimpleExpr ();
1207 /* Handle booleans */
1208 while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE ||
1209 CurTok.Tok == TOK_LT || CurTok.Tok == TOK_GT ||
1210 CurTok.Tok == TOK_LE || CurTok.Tok == TOK_GE) {
1212 long LVal, RVal, Val;
1216 /* Remember the token and skip it */
1217 token_t T = CurTok.Tok;
1220 /* Move root to left side and read the right side */
1222 Right = SimpleExpr ();
1224 /* If both expressions are constant, we can evaluate the term */
1225 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1228 case TOK_EQ: Val = (LVal == RVal); break;
1229 case TOK_NE: Val = (LVal != RVal); break;
1230 case TOK_LT: Val = (LVal < RVal); break;
1231 case TOK_GT: Val = (LVal > RVal); break;
1232 case TOK_LE: Val = (LVal <= RVal); break;
1233 case TOK_GE: Val = (LVal >= RVal); break;
1234 default: Internal ("Invalid token");
1237 /* Generate a literal expression and delete the old left and
1242 Root = GenLiteralExpr (Val);
1246 /* Generate an expression tree */
1249 case TOK_EQ: Op = EXPR_EQ; break;
1250 case TOK_NE: Op = EXPR_NE; break;
1251 case TOK_LT: Op = EXPR_LT; break;
1252 case TOK_GT: Op = EXPR_GT; break;
1253 case TOK_LE: Op = EXPR_LE; break;
1254 case TOK_GE: Op = EXPR_GE; break;
1255 default: Internal ("Invalid token");
1257 Root = NewExprNode (Op);
1259 Root->Right = Right;
1264 /* Return the expression tree we've created */
1270 static ExprNode* Expr2 (void)
1271 /* Boolean operators: AND and XOR */
1273 /* Read left hand side */
1274 ExprNode* Root = BoolExpr ();
1276 /* Handle booleans */
1277 while (CurTok.Tok == TOK_BOOLAND || CurTok.Tok == TOK_BOOLXOR) {
1279 long LVal, RVal, Val;
1283 /* Remember the token and skip it */
1284 token_t T = CurTok.Tok;
1287 /* Move root to left side and read the right side */
1289 Right = BoolExpr ();
1291 /* If both expressions are constant, we can evaluate the term */
1292 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1295 case TOK_BOOLAND: Val = ((LVal != 0) && (RVal != 0)); break;
1296 case TOK_BOOLXOR: Val = ((LVal != 0) ^ (RVal != 0)); break;
1297 default: Internal ("Invalid token");
1300 /* Generate a literal expression and delete the old left and
1305 Root = GenLiteralExpr (Val);
1309 /* Generate an expression tree */
1312 case TOK_BOOLAND: Op = EXPR_BOOLAND; break;
1313 case TOK_BOOLXOR: Op = EXPR_BOOLXOR; break;
1314 default: Internal ("Invalid token");
1316 Root = NewExprNode (Op);
1318 Root->Right = Right;
1323 /* Return the expression tree we've created */
1329 static ExprNode* Expr1 (void)
1330 /* Boolean operators: OR */
1332 /* Read left hand side */
1333 ExprNode* Root = Expr2 ();
1335 /* Handle booleans */
1336 while (CurTok.Tok == TOK_BOOLOR) {
1338 long LVal, RVal, Val;
1342 /* Remember the token and skip it */
1343 token_t T = CurTok.Tok;
1346 /* Move root to left side and read the right side */
1350 /* If both expressions are constant, we can evaluate the term */
1351 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1354 case TOK_BOOLOR: Val = ((LVal != 0) || (RVal != 0)); break;
1355 default: Internal ("Invalid token");
1358 /* Generate a literal expression and delete the old left and
1363 Root = GenLiteralExpr (Val);
1367 /* Generate an expression tree */
1370 case TOK_BOOLOR: Op = EXPR_BOOLOR; break;
1371 default: Internal ("Invalid token");
1373 Root = NewExprNode (Op);
1375 Root->Right = Right;
1380 /* Return the expression tree we've created */
1386 static ExprNode* Expr0 (void)
1387 /* Boolean operators: NOT */
1391 /* Handle booleans */
1392 if (CurTok.Tok == TOK_BOOLNOT) {
1397 /* Skip the operator token */
1400 /* Read the argument */
1403 /* If the argument is const, evaluate it directly */
1404 if (IsEasyConst (Left, &Val)) {
1406 Root = GenLiteralExpr (!Val);
1408 Root = NewExprNode (EXPR_BOOLNOT);
1414 /* Read left hand side */
1419 /* Return the expression tree we've created */
1425 ExprNode* Expression (void)
1426 /* Evaluate an expression, build the expression tree on the heap and return
1427 * a pointer to the root of the tree.
1435 long ConstExpression (void)
1436 /* Parse an expression. Check if the expression is const, and print an error
1437 * message if not. Return the value of the expression, or a dummy, if it is
1443 /* Read the expression */
1444 ExprNode* Expr = Expression ();
1446 /* Study the expression */
1449 StudyExpr (Expr, &D);
1451 /* Check if the expression is constant */
1452 if (ED_IsConst (&D)) {
1455 Error ("Constant expression expected");
1459 /* Free the expression tree and allocated memory for D */
1463 /* Return the value */
1469 void FreeExpr (ExprNode* Root)
1470 /* Free the expression, Root is pointing to. */
1473 FreeExpr (Root->Left);
1474 FreeExpr (Root->Right);
1475 FreeExprNode (Root);
1481 ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
1482 /* Try to simplify the given expression tree */
1484 if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
1485 /* No external references */
1487 Expr = GenLiteralExpr (D->Val);
1494 ExprNode* GenLiteralExpr (long Val)
1495 /* Return an expression tree that encodes the given literal value */
1497 ExprNode* Expr = NewExprNode (EXPR_LITERAL);
1504 ExprNode* GenLiteral0 (void)
1505 /* Return an expression tree that encodes the the number zero */
1507 return GenLiteralExpr (0);
1512 ExprNode* GenSymExpr (SymEntry* Sym)
1513 /* Return an expression node that encodes the given symbol */
1515 ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
1517 SymAddExprRef (Sym, Expr);
1523 static ExprNode* GenSectionExpr (unsigned SecNum)
1524 /* Return an expression node for the given section */
1526 ExprNode* Expr = NewExprNode (EXPR_SECTION);
1527 Expr->V.SecNum = SecNum;
1533 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
1534 /* Generate an addition from the two operands */
1537 if (IsEasyConst (Left, &Val) && Val == 0) {
1540 } else if (IsEasyConst (Right, &Val) && Val == 0) {
1544 ExprNode* Root = NewExprNode (EXPR_PLUS);
1546 Root->Right = Right;
1553 ExprNode* GenCurrentPC (void)
1554 /* Return the current program counter as expression */
1558 if (GetRelocMode ()) {
1559 /* Create SegmentBase + Offset */
1560 Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
1561 GenLiteralExpr (GetPC ()));
1563 /* Absolute mode, just return PC value */
1564 Root = GenLiteralExpr (GetPC ());
1572 ExprNode* GenSwapExpr (ExprNode* Expr)
1573 /* Return an extended expression with lo and hi bytes swapped */
1575 ExprNode* N = NewExprNode (EXPR_SWAP);
1582 ExprNode* GenBranchExpr (unsigned Offs)
1583 /* Return an expression that encodes the difference between current PC plus
1584 * offset and the target expression (that is, Expression() - (*+Offs) ).
1591 /* Read Expression() */
1594 /* If the expression is a cheap constant, generate a simpler tree */
1595 if (IsEasyConst (N, &Val)) {
1597 /* Free the constant expression tree */
1600 /* Generate the final expression:
1602 * Val - ((Seg + PC) + Offs)
1603 * Val - Seg - PC - Offs
1604 * (Val - PC - Offs) - Seg
1606 Root = GenLiteralExpr (Val - GetPC () - Offs);
1607 if (GetRelocMode ()) {
1609 Root = NewExprNode (EXPR_MINUS);
1611 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1616 /* Generate the expression:
1618 * N - ((Seg + PC) + Offs)
1619 * N - Seg - PC - Offs
1620 * N - (PC + Offs) - Seg
1622 Root = NewExprNode (EXPR_MINUS);
1624 Root->Right = GenLiteralExpr (GetPC () + Offs);
1625 if (GetRelocMode ()) {
1627 Root = NewExprNode (EXPR_MINUS);
1629 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1633 /* Return the result */
1639 ExprNode* GenULabelExpr (unsigned Num)
1640 /* Return an expression for an unnamed label with the given index */
1642 ExprNode* Node = NewExprNode (EXPR_ULABEL);
1645 /* Return the new node */
1651 ExprNode* GenByteExpr (ExprNode* Expr)
1652 /* Force the given expression into a byte and return the result */
1654 /* Use the low byte operator to force the expression into byte size */
1655 return LoByte (Expr);
1660 ExprNode* GenWordExpr (ExprNode* Expr)
1661 /* Force the given expression into a word and return the result. */
1663 /* Use the low byte operator to force the expression into word size */
1664 return LoWord (Expr);
1669 ExprNode* GenNE (ExprNode* Expr, long Val)
1670 /* Generate an expression that compares Expr and Val for inequality */
1672 /* Generate a compare node */
1673 ExprNode* Root = NewExprNode (EXPR_NE);
1675 Root->Right = GenLiteralExpr (Val);
1677 /* Return the result */
1683 int IsConstExpr (ExprNode* Expr, long* Val)
1684 /* Return true if the given expression is a constant expression, that is, one
1685 * with no references to external symbols. If Val is not NULL and the
1686 * expression is constant, the constant value is stored here.
1691 /* Study the expression */
1694 StudyExpr (Expr, &D);
1696 /* Check if the expression is constant */
1697 IsConst = ED_IsConst (&D);
1698 if (IsConst && Val != 0) {
1702 /* Delete allocated memory and return the result */
1709 ExprNode* CloneExpr (ExprNode* Expr)
1710 /* Clone the given expression tree. The function will simply clone symbol
1711 * nodes, it will not resolve them.
1716 /* Accept NULL pointers */
1721 /* Clone the node */
1725 Clone = GenLiteralExpr (Expr->V.IVal);
1729 Clone = GenULabelExpr (Expr->V.IVal);
1733 Clone = GenSymExpr (Expr->V.Sym);
1737 Clone = GenSectionExpr (Expr->V.SecNum);
1741 /* Generate a new node */
1742 Clone = NewExprNode (Expr->Op);
1743 /* Clone the tree nodes */
1744 Clone->Left = CloneExpr (Expr->Left);
1745 Clone->Right = CloneExpr (Expr->Right);
1755 void WriteExpr (ExprNode* Expr)
1756 /* Write the given expression to the object file */
1758 /* Null expressions are encoded by a type byte of zero */
1760 ObjWrite8 (EXPR_NULL);
1764 /* If the is a leafnode, write the expression attribute, otherwise
1765 * write the expression operands.
1770 ObjWrite8 (EXPR_LITERAL);
1771 ObjWrite32 (Expr->V.IVal);
1775 if (SymIsImport (Expr->V.Sym)) {
1776 ObjWrite8 (EXPR_SYMBOL);
1777 ObjWriteVar (GetSymImportId (Expr->V.Sym));
1779 WriteExpr (GetSymExpr (Expr->V.Sym));
1784 ObjWrite8 (EXPR_SECTION);
1785 ObjWrite8 (Expr->V.SecNum);
1789 WriteExpr (ULabResolve (Expr->V.IVal));
1793 /* Not a leaf node */
1794 ObjWrite8 (Expr->Op);
1795 WriteExpr (Expr->Left);
1796 WriteExpr (Expr->Right);
1804 void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
1805 /* Mark the address size of the given expression tree as guessed. The address
1806 * size passed as argument is the one NOT used, because the actual address
1807 * size wasn't known. Example: Zero page addressing was not used because symbol
1808 * is undefined, and absolute addressing was available.
1809 * This function will actually parse the expression tree for undefined symbols,
1810 * and mark these symbols accordingly.
1813 /* Accept NULL expressions */
1818 /* Check the type code */
1819 switch (Expr->Op & EXPR_TYPEMASK) {
1822 if (Expr->Op == EXPR_SYMBOL) {
1823 if (!SymIsDef (Expr->V.Sym)) {
1824 /* Symbol is undefined, mark it */
1825 SymGuessedAddrSize (Expr->V.Sym, AddrSize);
1830 case EXPR_BINARYNODE:
1831 ExprGuessedAddrSize (Expr->Right, AddrSize);
1834 case EXPR_UNARYNODE:
1835 ExprGuessedAddrSize (Expr->Left, AddrSize);