1 /*****************************************************************************/
5 /* Expression evaluation for the ca65 macroassembler */
9 /* (C) 1998-2012, 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 /*****************************************************************************/
60 #include "studyexpr.h"
68 /*****************************************************************************/
70 /*****************************************************************************/
74 /* Since all expressions are first packed into expression trees, and each
75 ** expression tree node is allocated on the heap, we add some type of special
76 ** purpose memory allocation here: Instead of freeing the nodes, we save some
77 ** number of freed nodes for later and remember them in a single linked list
78 ** using the Left link.
80 #define MAX_FREE_NODES 64
81 static ExprNode* FreeExprNodes = 0;
82 static unsigned FreeNodeCount = 0;
86 /*****************************************************************************/
88 /*****************************************************************************/
92 static ExprNode* NewExprNode (unsigned Op)
93 /* Create a new expression node */
97 /* Do we have some nodes in the list already? */
99 /* Use first node from list */
101 FreeExprNodes = N->Left;
104 /* Allocate fresh memory */
105 N = xmalloc (sizeof (ExprNode));
108 N->Left = N->Right = 0;
116 static void FreeExprNode (ExprNode* E)
120 if (E->Op == EXPR_SYMBOL) {
121 /* Remove the symbol reference */
122 SymDelExprRef (E->V.Sym, E);
124 /* Place the symbol into the free nodes list if possible */
125 if (FreeNodeCount < MAX_FREE_NODES) {
126 /* Remember this node for later */
127 E->Left = FreeExprNodes;
131 /* Free the memory */
139 /*****************************************************************************/
141 /*****************************************************************************/
145 static ExprNode* Expr0 (void);
149 int IsByteRange (long Val)
150 /* Return true if this is a byte value */
152 return (Val & ~0xFFL) == 0;
157 int IsWordRange (long Val)
158 /* Return true if this is a word value */
160 return (Val & ~0xFFFFL) == 0;
165 int IsFarRange (long Val)
166 /* Return true if this is a far (24 bit) value */
168 return (Val & ~0xFFFFFFL) == 0;
173 int IsEasyConst (const ExprNode* E, long* Val)
174 /* Do some light checking if the given node is a constant. Don't care if E is
175 ** a complex expression. If E is a constant, return true and place its value
176 ** into Val, provided that Val is not NULL.
179 /* Resolve symbols, follow symbol chains */
180 while (E->Op == EXPR_SYMBOL) {
181 E = SymResolve (E->V.Sym);
183 /* Could not resolve */
188 /* Symbols resolved, check for a literal */
189 if (E->Op == EXPR_LITERAL) {
196 /* Not found to be a const according to our tests */
202 static ExprNode* LoByte (ExprNode* Operand)
203 /* Return the low byte of the given expression */
208 /* Special handling for const expressions */
209 if (IsEasyConst (Operand, &Val)) {
211 Expr = GenLiteralExpr (Val & 0xFF);
213 /* Extract byte #0 */
214 Expr = NewExprNode (EXPR_BYTE0);
215 Expr->Left = Operand;
222 static ExprNode* HiByte (ExprNode* Operand)
223 /* Return the high byte of the given expression */
228 /* Special handling for const expressions */
229 if (IsEasyConst (Operand, &Val)) {
231 Expr = GenLiteralExpr ((Val >> 8) & 0xFF);
233 /* Extract byte #1 */
234 Expr = NewExprNode (EXPR_BYTE1);
235 Expr->Left = Operand;
242 static ExprNode* Bank (ExprNode* Operand)
243 /* Return the bank of the given segmented expression */
245 /* Generate the bank expression */
246 ExprNode* Expr = NewExprNode (EXPR_BANK);
247 Expr->Left = Operand;
249 /* Return the result */
255 static ExprNode* BankByte (ExprNode* Operand)
256 /* Return the bank byte of the given expression */
261 /* Special handling for const expressions */
262 if (IsEasyConst (Operand, &Val)) {
264 Expr = GenLiteralExpr ((Val >> 16) & 0xFF);
266 /* Extract byte #2 */
267 Expr = NewExprNode (EXPR_BYTE2);
268 Expr->Left = Operand;
275 static ExprNode* LoWord (ExprNode* Operand)
276 /* Return the low word of the given expression */
281 /* Special handling for const expressions */
282 if (IsEasyConst (Operand, &Val)) {
284 Expr = GenLiteralExpr (Val & 0xFFFF);
286 /* Extract word #0 */
287 Expr = NewExprNode (EXPR_WORD0);
288 Expr->Left = Operand;
295 static ExprNode* HiWord (ExprNode* Operand)
296 /* Return the high word of the given expression */
301 /* Special handling for const expressions */
302 if (IsEasyConst (Operand, &Val)) {
304 Expr = GenLiteralExpr ((Val >> 16) & 0xFFFF);
306 /* Extract word #1 */
307 Expr = NewExprNode (EXPR_WORD1);
308 Expr->Left = Operand;
315 static ExprNode* Symbol (SymEntry* S)
316 /* Reference a symbol and return an expression for it */
319 /* Some weird error happened before */
320 return GenLiteralExpr (0);
322 /* Mark the symbol as referenced */
324 /* If the symbol is a variable, return just its value, otherwise
325 ** return a reference to the symbol.
328 return CloneExpr (GetSymExpr (S));
330 /* Create symbol node */
331 return GenSymExpr (S);
338 ExprNode* FuncBank (void)
339 /* Handle the .BANK builtin function */
341 return Bank (Expression ());
346 ExprNode* FuncBankByte (void)
347 /* Handle the .BANKBYTE builtin function */
349 return BankByte (Expression ());
354 static ExprNode* FuncBlank (void)
355 /* Handle the .BLANK builtin function */
357 /* We have a list of tokens that ends with the closing paren. Skip
358 ** the tokens, and count them. Allow optionally curly braces.
360 token_t Term = GetTokListTerm (TOK_RPAREN);
362 while (CurTok.Tok != Term) {
364 /* Check for end of line or end of input. Since the calling function
365 ** will check for the closing paren, we don't need to print an error
366 ** here, just bail out.
368 if (TokIsSep (CurTok.Tok)) {
379 /* If the list was enclosed in curly braces, skip the closing brace */
380 if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
384 /* Return true if the list was empty */
385 return GenLiteralExpr (Count == 0);
390 static ExprNode* FuncConst (void)
391 /* Handle the .CONST builtin function */
393 /* Read an expression */
394 ExprNode* Expr = Expression ();
396 /* Check the constness of the expression */
397 ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
399 /* Free the expression */
408 static ExprNode* FuncDefined (void)
409 /* Handle the .DEFINED builtin function */
411 /* Parse the symbol name and search for the symbol */
412 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
414 /* Check if the symbol is defined */
415 return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
420 ExprNode* FuncHiByte (void)
421 /* Handle the .HIBYTE builtin function */
423 return HiByte (Expression ());
428 static ExprNode* FuncHiWord (void)
429 /* Handle the .HIWORD builtin function */
431 return HiWord (Expression ());
436 ExprNode* FuncLoByte (void)
437 /* Handle the .LOBYTE builtin function */
439 return LoByte (Expression ());
444 static ExprNode* FuncLoWord (void)
445 /* Handle the .LOWORD builtin function */
447 return LoWord (Expression ());
452 static ExprNode* DoMatch (enum TC EqualityLevel)
453 /* Handle the .MATCH and .XMATCH builtin functions */
460 /* A list of tokens follows. Read this list and remember it building a
461 ** single linked list of tokens including attributes. The list is
462 ** either enclosed in curly braces, or terminated by a comma.
464 token_t Term = GetTokListTerm (TOK_COMMA);
465 while (CurTok.Tok != Term) {
467 /* We may not end-of-line of end-of-file here */
468 if (TokIsSep (CurTok.Tok)) {
469 Error ("Unexpected end of line");
470 return GenLiteral0 ();
473 /* Get a node with this token */
474 Node = NewTokNode ();
476 /* Insert the node into the list */
488 /* Skip the terminator token*/
491 /* If the token list was enclosed in curly braces, we expect a comma */
492 if (Term == TOK_RCURLY) {
496 /* Read the second list which is optionally enclosed in curly braces and
497 ** terminated by the right parenthesis. Compare each token against the
498 ** one in the first list.
500 Term = GetTokListTerm (TOK_RPAREN);
503 while (CurTok.Tok != Term) {
505 /* We may not end-of-line of end-of-file here */
506 if (TokIsSep (CurTok.Tok)) {
507 Error ("Unexpected end of line");
508 return GenLiteral0 ();
511 /* Compare the tokens if the result is not already known */
514 /* The second list is larger than the first one */
516 } else if (TokCmp (Node) < EqualityLevel) {
517 /* Tokens do not match */
522 /* Next token in first list */
527 /* Next token in current list */
531 /* If the token list was enclosed in curly braces, eat the closing brace */
532 if (Term == TOK_RCURLY) {
536 /* Check if there are remaining tokens in the first list */
541 /* Free the token list */
548 /* Done, return the result */
549 return GenLiteralExpr (Result);
554 static ExprNode* FuncMatch (void)
555 /* Handle the .MATCH function */
557 return DoMatch (tcSameToken);
562 static ExprNode* FuncMax (void)
563 /* Handle the .MAX function */
568 long LeftVal, RightVal;
570 /* Two arguments to the pseudo function */
571 Left = Expression ();
573 Right = Expression ();
575 /* Check if we can evaluate the value immediately */
576 if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
579 Expr = GenLiteralExpr ((LeftVal > RightVal)? LeftVal : RightVal);
581 /* Make an expression node */
582 Expr = NewExprNode (EXPR_MAX);
591 static ExprNode* FuncMin (void)
592 /* Handle the .MIN function */
597 long LeftVal, RightVal;
599 /* Two arguments to the pseudo function */
600 Left = Expression ();
602 Right = Expression ();
604 /* Check if we can evaluate the value immediately */
605 if (IsEasyConst (Left, &LeftVal) && IsEasyConst (Right, &RightVal)) {
608 Expr = GenLiteralExpr ((LeftVal < RightVal)? LeftVal : RightVal);
610 /* Make an expression node */
611 Expr = NewExprNode (EXPR_MIN);
620 static ExprNode* FuncReferenced (void)
621 /* Handle the .REFERENCED builtin function */
623 /* Parse the symbol name and search for the symbol */
624 SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING);
626 /* Check if the symbol is referenced */
627 return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
632 static ExprNode* FuncAddrSize(void)
633 /* Handle the .ADDRSIZE function */
635 StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
636 StrBuf Name = STATIC_STRBUF_INITIALIZER;
642 /* Assume we don't know the size */
645 /* Check for a cheap local which needs special handling */
646 if (CurTok.Tok == TOK_LOCAL_IDENT) {
648 /* Cheap local symbol */
649 Sym = SymFindLocal(SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
651 Error("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
654 AddrSize = Sym->AddrSize;
657 /* Remember and skip SVal, terminate ScopeName so it is empty */
658 SB_Copy(&Name, &CurTok.SVal);
660 SB_Terminate(&ScopeName);
665 /* Parse the scope and the name */
666 SymTable* ParentScope = ParseScopedIdent(&Name, &ScopeName);
668 /* Check if the parent scope is valid */
669 if (ParentScope == 0) {
673 return GenLiteral0();
676 /* If ScopeName is empty, no explicit scope was specified. We have to
677 * search upper scope levels in this case.
679 NoScope = SB_IsEmpty(&ScopeName);
681 /* If we did find a scope with the name, read the symbol defining the
682 * size, otherwise search for a symbol entry with the name and scope.
685 Sym = SymFindAny(ParentScope, &Name);
688 Sym = SymFind(ParentScope, &Name, SYM_FIND_EXISTING);
690 /* If we found the symbol retrieve the size, otherwise complain */
692 AddrSize = Sym->AddrSize;
695 Error("Unknown symbol or scope: `%m%p%m%p'",
701 /* Check if we have a size */
702 /* if we don't know, return it anyway, zero can mean unknown, or uncomment this code for an error
703 if (AddrSize == 0 ) {
704 Error ("Address size of `%m%p%m%p' is unknown", &ScopeName, &Name);
708 /* Free the string buffers */
712 /* Return the size */
713 return GenLiteralExpr(AddrSize);
718 static ExprNode* FuncSizeOf (void)
719 /* Handle the .SIZEOF function */
721 StrBuf ScopeName = STATIC_STRBUF_INITIALIZER;
722 StrBuf Name = STATIC_STRBUF_INITIALIZER;
730 /* Assume an error */
733 /* Check for a cheap local which needs special handling */
734 if (CurTok.Tok == TOK_LOCAL_IDENT) {
736 /* Cheap local symbol */
737 Sym = SymFindLocal (SymLast, &CurTok.SVal, SYM_FIND_EXISTING);
739 Error ("Unknown symbol or scope: `%m%p'", &CurTok.SVal);
741 SizeSym = GetSizeOfSymbol (Sym);
744 /* Remember and skip SVal, terminate ScopeName so it is empty */
745 SB_Copy (&Name, &CurTok.SVal);
747 SB_Terminate (&ScopeName);
751 /* Parse the scope and the name */
752 SymTable* ParentScope = ParseScopedIdent (&Name, &ScopeName);
754 /* Check if the parent scope is valid */
755 if (ParentScope == 0) {
757 SB_Done (&ScopeName);
759 return GenLiteral0 ();
762 /* If ScopeName is empty, no explicit scope was specified. We have to
763 ** search upper scope levels in this case.
765 NoScope = SB_IsEmpty (&ScopeName);
767 /* First search for a scope with the given name */
769 Scope = SymFindAnyScope (ParentScope, &Name);
771 Scope = SymFindScope (ParentScope, &Name, SYM_FIND_EXISTING);
774 /* If we did find a scope with the name, read the symbol defining the
775 ** size, otherwise search for a symbol entry with the name and scope.
778 /* Yep, it's a scope */
779 SizeSym = GetSizeOfScope (Scope);
782 Sym = SymFindAny (ParentScope, &Name);
784 Sym = SymFind (ParentScope, &Name, SYM_FIND_EXISTING);
787 /* If we found the symbol retrieve the size, otherwise complain */
789 SizeSym = GetSizeOfSymbol (Sym);
791 Error ("Unknown symbol or scope: `%m%p%m%p'",
797 /* Check if we have a size */
798 if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
799 Error ("Size of `%m%p%m%p' is unknown", &ScopeName, &Name);
803 /* Free the string buffers */
804 SB_Done (&ScopeName);
807 /* Return the size */
808 return GenLiteralExpr (Size);
813 static ExprNode* FuncStrAt (void)
814 /* Handle the .STRAT function */
816 StrBuf Str = STATIC_STRBUF_INITIALIZER;
820 /* String constant expected */
821 if (CurTok.Tok != TOK_STRCON) {
822 Error ("String constant expected");
827 /* Remember the string and skip it */
828 SB_Copy (&Str, &CurTok.SVal);
831 /* Comma must follow */
834 /* Expression expected */
835 Index = ConstExpression ();
837 /* Must be a valid index */
838 if (Index >= (long) SB_GetLen (&Str)) {
839 Error ("Range error");
843 /* Get the char, handle as unsigned. Be sure to translate it into
844 ** the target character set.
846 C = TgtTranslateChar (SB_At (&Str, (unsigned)Index));
849 /* Free string buffer memory */
852 /* Return the char expression */
853 return GenLiteralExpr (C);
858 static ExprNode* FuncStrLen (void)
859 /* Handle the .STRLEN function */
863 /* String constant expected */
864 if (CurTok.Tok != TOK_STRCON) {
866 Error ("String constant expected");
867 /* Smart error recovery */
868 if (CurTok.Tok != TOK_RPAREN) {
875 /* Get the length of the string */
876 Len = SB_GetLen (&CurTok.SVal);
878 /* Skip the string */
882 /* Return the length */
883 return GenLiteralExpr (Len);
888 static ExprNode* FuncTCount (void)
889 /* Handle the .TCOUNT function */
891 /* We have a list of tokens that ends with the closing paren. Skip
892 ** the tokens, and count them. Allow optionally curly braces.
894 token_t Term = GetTokListTerm (TOK_RPAREN);
896 while (CurTok.Tok != Term) {
898 /* Check for end of line or end of input. Since the calling function
899 ** will check for the closing paren, we don't need to print an error
900 ** here, just bail out.
902 if (TokIsSep (CurTok.Tok)) {
913 /* If the list was enclosed in curly braces, skip the closing brace */
914 if (Term == TOK_RCURLY && CurTok.Tok == TOK_RCURLY) {
918 /* Return the number of tokens */
919 return GenLiteralExpr (Count);
924 static ExprNode* FuncXMatch (void)
925 /* Handle the .XMATCH function */
927 return DoMatch (tcIdentical);
932 static ExprNode* Function (ExprNode* (*F) (void))
933 /* Handle builtin functions */
937 /* Skip the keyword */
940 /* Expression must be enclosed in braces */
941 if (CurTok.Tok != TOK_LPAREN) {
942 Error ("'(' expected");
944 return GenLiteral0 ();
948 /* Call the function itself */
951 /* Closing brace must follow */
954 /* Return the result of the actual function */
960 static ExprNode* Factor (void)
966 switch (CurTok.Tok) {
969 N = GenLiteralExpr (CurTok.IVal);
974 N = GenLiteralExpr (TgtTranslateChar (CurTok.IVal));
980 case TOK_LOCAL_IDENT:
981 N = Symbol (ParseAnySymName (SYM_ALLOC_NEW));
985 N = ULabRef (CurTok.IVal);
997 if (IsEasyConst (L, &Val)) {
999 N = GenLiteralExpr (-Val);
1001 N = NewExprNode (EXPR_UNARY_MINUS);
1009 if (IsEasyConst (L, &Val)) {
1011 N = GenLiteralExpr (~Val);
1013 N = NewExprNode (EXPR_NOT);
1021 N = GenCurrentPC ();
1026 N = LoByte (Factor ());
1031 N = HiByte (Factor ());
1035 /* ^ means the bank byte of an expression */
1037 N = BankByte (Factor ());
1047 N = Function (FuncBank);
1051 N = Function (FuncBankByte);
1055 N = Function(FuncAddrSize);
1059 N = Function (FuncBlank);
1063 N = Function (FuncConst);
1067 N = GenLiteralExpr (CPUIsets[CPU]);
1072 N = Function (FuncDefined);
1076 N = Function (FuncHiByte);
1080 N = Function (FuncHiWord);
1084 N = Function (FuncLoByte);
1088 N = Function (FuncLoWord);
1092 N = Function (FuncMatch);
1096 N = Function (FuncMax);
1100 N = Function (FuncMin);
1103 case TOK_REFERENCED:
1104 N = Function (FuncReferenced);
1108 N = Function (FuncSizeOf);
1112 N = Function (FuncStrAt);
1116 N = Function (FuncStrLen);
1120 N = Function (FuncTCount);
1124 N = GenLiteralExpr ((long) time (0));
1129 N = GenLiteralExpr (GetVersionAsNumber ());
1134 N = Function (FuncXMatch);
1138 if (LooseCharTerm && CurTok.Tok == TOK_STRCON &&
1139 SB_GetLen (&CurTok.SVal) == 1) {
1140 /* A character constant */
1141 N = GenLiteralExpr (TgtTranslateChar (SB_At (&CurTok.SVal, 0)));
1143 N = GenLiteral0 (); /* Dummy */
1144 Error ("Syntax error");
1154 static ExprNode* Term (void)
1156 /* Read left hand side */
1157 ExprNode* Root = Factor ();
1159 /* Handle multiplicative operations */
1160 while (CurTok.Tok == TOK_MUL || CurTok.Tok == TOK_DIV ||
1161 CurTok.Tok == TOK_MOD || CurTok.Tok == TOK_AND ||
1162 CurTok.Tok == TOK_XOR || CurTok.Tok == TOK_SHL ||
1163 CurTok.Tok == TOK_SHR) {
1165 long LVal, RVal, Val;
1169 /* Remember the token and skip it */
1170 token_t T = CurTok.Tok;
1173 /* Move root to left side and read the right side */
1177 /* If both expressions are constant, we can evaluate the term */
1178 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1187 Error ("Division by zero");
1196 Error ("Modulo operation with zero");
1212 Val = shl_l (LVal, RVal);
1216 Val = shr_l (LVal, RVal);
1220 Internal ("Invalid token");
1223 /* Generate a literal expression and delete the old left and
1228 Root = GenLiteralExpr (Val);
1232 /* Generate an expression tree */
1235 case TOK_MUL: Op = EXPR_MUL; break;
1236 case TOK_DIV: Op = EXPR_DIV; break;
1237 case TOK_MOD: Op = EXPR_MOD; break;
1238 case TOK_AND: Op = EXPR_AND; break;
1239 case TOK_XOR: Op = EXPR_XOR; break;
1240 case TOK_SHL: Op = EXPR_SHL; break;
1241 case TOK_SHR: Op = EXPR_SHR; break;
1242 default: Internal ("Invalid token");
1244 Root = NewExprNode (Op);
1246 Root->Right = Right;
1252 /* Return the expression tree we've created */
1258 static ExprNode* SimpleExpr (void)
1260 /* Read left hand side */
1261 ExprNode* Root = Term ();
1263 /* Handle additive operations */
1264 while (CurTok.Tok == TOK_PLUS ||
1265 CurTok.Tok == TOK_MINUS ||
1266 CurTok.Tok == TOK_OR) {
1268 long LVal, RVal, Val;
1272 /* Remember the token and skip it */
1273 token_t T = CurTok.Tok;
1276 /* Move root to left side and read the right side */
1280 /* If both expressions are constant, we can evaluate the term */
1281 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1284 case TOK_PLUS: Val = LVal + RVal; break;
1285 case TOK_MINUS: Val = LVal - RVal; break;
1286 case TOK_OR: Val = LVal | RVal; break;
1287 default: Internal ("Invalid token");
1290 /* Generate a literal expression and delete the old left and
1295 Root = GenLiteralExpr (Val);
1299 /* Generate an expression tree */
1302 case TOK_PLUS: Op = EXPR_PLUS; break;
1303 case TOK_MINUS: Op = EXPR_MINUS; break;
1304 case TOK_OR: Op = EXPR_OR; break;
1305 default: Internal ("Invalid token");
1307 Root = NewExprNode (Op);
1309 Root->Right = Right;
1314 /* Return the expression tree we've created */
1320 static ExprNode* BoolExpr (void)
1321 /* Evaluate a boolean expression */
1323 /* Read left hand side */
1324 ExprNode* Root = SimpleExpr ();
1326 /* Handle booleans */
1327 while (CurTok.Tok == TOK_EQ || CurTok.Tok == TOK_NE ||
1328 CurTok.Tok == TOK_LT || CurTok.Tok == TOK_GT ||
1329 CurTok.Tok == TOK_LE || CurTok.Tok == TOK_GE) {
1331 long LVal, RVal, Val;
1335 /* Remember the token and skip it */
1336 token_t T = CurTok.Tok;
1339 /* Move root to left side and read the right side */
1341 Right = SimpleExpr ();
1343 /* If both expressions are constant, we can evaluate the term */
1344 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1347 case TOK_EQ: Val = (LVal == RVal); break;
1348 case TOK_NE: Val = (LVal != RVal); break;
1349 case TOK_LT: Val = (LVal < RVal); break;
1350 case TOK_GT: Val = (LVal > RVal); break;
1351 case TOK_LE: Val = (LVal <= RVal); break;
1352 case TOK_GE: Val = (LVal >= RVal); break;
1353 default: Internal ("Invalid token");
1356 /* Generate a literal expression and delete the old left and
1361 Root = GenLiteralExpr (Val);
1365 /* Generate an expression tree */
1368 case TOK_EQ: Op = EXPR_EQ; break;
1369 case TOK_NE: Op = EXPR_NE; break;
1370 case TOK_LT: Op = EXPR_LT; break;
1371 case TOK_GT: Op = EXPR_GT; break;
1372 case TOK_LE: Op = EXPR_LE; break;
1373 case TOK_GE: Op = EXPR_GE; break;
1374 default: Internal ("Invalid token");
1376 Root = NewExprNode (Op);
1378 Root->Right = Right;
1383 /* Return the expression tree we've created */
1389 static ExprNode* Expr2 (void)
1390 /* Boolean operators: AND and XOR */
1392 /* Read left hand side */
1393 ExprNode* Root = BoolExpr ();
1395 /* Handle booleans */
1396 while (CurTok.Tok == TOK_BOOLAND || CurTok.Tok == TOK_BOOLXOR) {
1398 long LVal, RVal, Val;
1402 /* Remember the token and skip it */
1403 token_t T = CurTok.Tok;
1406 /* Move root to left side and read the right side */
1408 Right = BoolExpr ();
1410 /* If both expressions are constant, we can evaluate the term */
1411 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1414 case TOK_BOOLAND: Val = ((LVal != 0) && (RVal != 0)); break;
1415 case TOK_BOOLXOR: Val = ((LVal != 0) ^ (RVal != 0)); break;
1416 default: Internal ("Invalid token");
1419 /* Generate a literal expression and delete the old left and
1424 Root = GenLiteralExpr (Val);
1428 /* Generate an expression tree */
1431 case TOK_BOOLAND: Op = EXPR_BOOLAND; break;
1432 case TOK_BOOLXOR: Op = EXPR_BOOLXOR; break;
1433 default: Internal ("Invalid token");
1435 Root = NewExprNode (Op);
1437 Root->Right = Right;
1442 /* Return the expression tree we've created */
1448 static ExprNode* Expr1 (void)
1449 /* Boolean operators: OR */
1451 /* Read left hand side */
1452 ExprNode* Root = Expr2 ();
1454 /* Handle booleans */
1455 while (CurTok.Tok == TOK_BOOLOR) {
1457 long LVal, RVal, Val;
1461 /* Remember the token and skip it */
1462 token_t T = CurTok.Tok;
1465 /* Move root to left side and read the right side */
1469 /* If both expressions are constant, we can evaluate the term */
1470 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1473 case TOK_BOOLOR: Val = ((LVal != 0) || (RVal != 0)); break;
1474 default: Internal ("Invalid token");
1477 /* Generate a literal expression and delete the old left and
1482 Root = GenLiteralExpr (Val);
1486 /* Generate an expression tree */
1489 case TOK_BOOLOR: Op = EXPR_BOOLOR; break;
1490 default: Internal ("Invalid token");
1492 Root = NewExprNode (Op);
1494 Root->Right = Right;
1499 /* Return the expression tree we've created */
1505 static ExprNode* Expr0 (void)
1506 /* Boolean operators: NOT */
1510 /* Handle booleans */
1511 if (CurTok.Tok == TOK_BOOLNOT) {
1516 /* Skip the operator token */
1519 /* Read the argument */
1522 /* If the argument is const, evaluate it directly */
1523 if (IsEasyConst (Left, &Val)) {
1525 Root = GenLiteralExpr (!Val);
1527 Root = NewExprNode (EXPR_BOOLNOT);
1533 /* Read left hand side */
1538 /* Return the expression tree we've created */
1544 ExprNode* Expression (void)
1545 /* Evaluate an expression, build the expression tree on the heap and return
1546 ** a pointer to the root of the tree.
1554 long ConstExpression (void)
1555 /* Parse an expression. Check if the expression is const, and print an error
1556 ** message if not. Return the value of the expression, or a dummy, if it is
1562 /* Read the expression */
1563 ExprNode* Expr = Expression ();
1565 /* Study the expression */
1568 StudyExpr (Expr, &D);
1570 /* Check if the expression is constant */
1571 if (ED_IsConst (&D)) {
1574 Error ("Constant expression expected");
1578 /* Free the expression tree and allocated memory for D */
1582 /* Return the value */
1588 void FreeExpr (ExprNode* Root)
1589 /* Free the expression, Root is pointing to. */
1592 FreeExpr (Root->Left);
1593 FreeExpr (Root->Right);
1594 FreeExprNode (Root);
1600 ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
1601 /* Try to simplify the given expression tree */
1603 if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
1604 /* No external references */
1606 Expr = GenLiteralExpr (D->Val);
1613 ExprNode* GenLiteralExpr (long Val)
1614 /* Return an expression tree that encodes the given literal value */
1616 ExprNode* Expr = NewExprNode (EXPR_LITERAL);
1623 ExprNode* GenLiteral0 (void)
1624 /* Return an expression tree that encodes the the number zero */
1626 return GenLiteralExpr (0);
1631 ExprNode* GenSymExpr (SymEntry* Sym)
1632 /* Return an expression node that encodes the given symbol */
1634 ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
1636 SymAddExprRef (Sym, Expr);
1642 static ExprNode* GenSectionExpr (unsigned SecNum)
1643 /* Return an expression node for the given section */
1645 ExprNode* Expr = NewExprNode (EXPR_SECTION);
1646 Expr->V.SecNum = SecNum;
1652 static ExprNode* GenBankExpr (unsigned SecNum)
1653 /* Return an expression node for the given bank */
1655 ExprNode* Expr = NewExprNode (EXPR_BANK);
1656 Expr->V.SecNum = SecNum;
1662 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
1663 /* Generate an addition from the two operands */
1666 if (IsEasyConst (Left, &Val) && Val == 0) {
1669 } else if (IsEasyConst (Right, &Val) && Val == 0) {
1673 ExprNode* Root = NewExprNode (EXPR_PLUS);
1675 Root->Right = Right;
1682 ExprNode* GenCurrentPC (void)
1683 /* Return the current program counter as expression */
1687 if (GetRelocMode ()) {
1688 /* Create SegmentBase + Offset */
1689 Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
1690 GenLiteralExpr (GetPC ()));
1692 /* Absolute mode, just return PC value */
1693 Root = GenLiteralExpr (GetPC ());
1701 ExprNode* GenSwapExpr (ExprNode* Expr)
1702 /* Return an extended expression with lo and hi bytes swapped */
1704 ExprNode* N = NewExprNode (EXPR_SWAP);
1711 ExprNode* GenBranchExpr (unsigned Offs)
1712 /* Return an expression that encodes the difference between current PC plus
1713 ** offset and the target expression (that is, Expression() - (*+Offs) ).
1720 /* Read Expression() */
1723 /* If the expression is a cheap constant, generate a simpler tree */
1724 if (IsEasyConst (N, &Val)) {
1726 /* Free the constant expression tree */
1729 /* Generate the final expression:
1731 ** Val - ((Seg + PC) + Offs)
1732 ** Val - Seg - PC - Offs
1733 ** (Val - PC - Offs) - Seg
1735 Root = GenLiteralExpr (Val - GetPC () - Offs);
1736 if (GetRelocMode ()) {
1738 Root = NewExprNode (EXPR_MINUS);
1740 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1745 /* Generate the expression:
1747 ** N - ((Seg + PC) + Offs)
1748 ** N - Seg - PC - Offs
1749 ** N - (PC + Offs) - Seg
1751 Root = NewExprNode (EXPR_MINUS);
1753 Root->Right = GenLiteralExpr (GetPC () + Offs);
1754 if (GetRelocMode ()) {
1756 Root = NewExprNode (EXPR_MINUS);
1758 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1762 /* Return the result */
1768 ExprNode* GenULabelExpr (unsigned Num)
1769 /* Return an expression for an unnamed label with the given index */
1771 ExprNode* Node = NewExprNode (EXPR_ULABEL);
1774 /* Return the new node */
1780 ExprNode* GenByteExpr (ExprNode* Expr)
1781 /* Force the given expression into a byte and return the result */
1783 /* Use the low byte operator to force the expression into byte size */
1784 return LoByte (Expr);
1789 ExprNode* GenWordExpr (ExprNode* Expr)
1790 /* Force the given expression into a word and return the result. */
1792 /* Use the low byte operator to force the expression into word size */
1793 return LoWord (Expr);
1798 ExprNode* GenFarAddrExpr (ExprNode* Expr)
1799 /* Force the given expression into a far address and return the result. */
1803 /* Special handling for const expressions */
1804 if (IsEasyConst (Expr, &Val)) {
1806 Expr = GenLiteralExpr (Val & 0xFFFFFF);
1808 ExprNode* Operand = Expr;
1809 Expr = NewExprNode (EXPR_FARADDR);
1810 Expr->Left = Operand;
1817 ExprNode* GenDWordExpr (ExprNode* Expr)
1818 /* Force the given expression into a dword and return the result. */
1822 /* Special handling for const expressions */
1823 if (IsEasyConst (Expr, &Val)) {
1825 Expr = GenLiteralExpr (Val & 0xFFFFFFFF);
1827 ExprNode* Operand = Expr;
1828 Expr = NewExprNode (EXPR_DWORD);
1829 Expr->Left = Operand;
1836 ExprNode* GenNE (ExprNode* Expr, long Val)
1837 /* Generate an expression that compares Expr and Val for inequality */
1839 /* Generate a compare node */
1840 ExprNode* Root = NewExprNode (EXPR_NE);
1842 Root->Right = GenLiteralExpr (Val);
1844 /* Return the result */
1850 int IsConstExpr (ExprNode* Expr, long* Val)
1851 /* Return true if the given expression is a constant expression, that is, one
1852 ** with no references to external symbols. If Val is not NULL and the
1853 ** expression is constant, the constant value is stored here.
1858 /* Study the expression */
1861 StudyExpr (Expr, &D);
1863 /* Check if the expression is constant */
1864 IsConst = ED_IsConst (&D);
1865 if (IsConst && Val != 0) {
1869 /* Delete allocated memory and return the result */
1876 ExprNode* CloneExpr (ExprNode* Expr)
1877 /* Clone the given expression tree. The function will simply clone symbol
1878 ** nodes, it will not resolve them.
1883 /* Accept NULL pointers */
1888 /* Clone the node */
1892 Clone = GenLiteralExpr (Expr->V.IVal);
1896 Clone = GenULabelExpr (Expr->V.IVal);
1900 Clone = GenSymExpr (Expr->V.Sym);
1904 Clone = GenSectionExpr (Expr->V.SecNum);
1908 Clone = GenBankExpr (Expr->V.SecNum);
1912 /* Generate a new node */
1913 Clone = NewExprNode (Expr->Op);
1914 /* Clone the tree nodes */
1915 Clone->Left = CloneExpr (Expr->Left);
1916 Clone->Right = CloneExpr (Expr->Right);
1926 void WriteExpr (ExprNode* Expr)
1927 /* Write the given expression to the object file */
1929 /* Null expressions are encoded by a type byte of zero */
1931 ObjWrite8 (EXPR_NULL);
1935 /* If the is a leafnode, write the expression attribute, otherwise
1936 ** write the expression operands.
1941 ObjWrite8 (EXPR_LITERAL);
1942 ObjWrite32 (Expr->V.IVal);
1946 if (SymIsImport (Expr->V.Sym)) {
1947 ObjWrite8 (EXPR_SYMBOL);
1948 ObjWriteVar (GetSymImportId (Expr->V.Sym));
1950 WriteExpr (GetSymExpr (Expr->V.Sym));
1955 ObjWrite8 (EXPR_SECTION);
1956 ObjWriteVar (Expr->V.SecNum);
1960 WriteExpr (ULabResolve (Expr->V.IVal));
1964 /* Not a leaf node */
1965 ObjWrite8 (Expr->Op);
1966 WriteExpr (Expr->Left);
1967 WriteExpr (Expr->Right);
1975 void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
1976 /* Mark the address size of the given expression tree as guessed. The address
1977 ** size passed as argument is the one NOT used, because the actual address
1978 ** size wasn't known. Example: Zero page addressing was not used because symbol
1979 ** is undefined, and absolute addressing was available.
1980 ** This function will actually parse the expression tree for undefined symbols,
1981 ** and mark these symbols accordingly.
1984 /* Accept NULL expressions */
1989 /* Check the type code */
1990 switch (EXPR_NODETYPE (Expr->Op)) {
1993 if (Expr->Op == EXPR_SYMBOL) {
1994 if (!SymIsDef (Expr->V.Sym)) {
1995 /* Symbol is undefined, mark it */
1996 SymGuessedAddrSize (Expr->V.Sym, AddrSize);
2001 case EXPR_BINARYNODE:
2002 ExprGuessedAddrSize (Expr->Right, AddrSize);
2005 case EXPR_UNARYNODE:
2006 ExprGuessedAddrSize (Expr->Left, AddrSize);
2013 ExprNode* MakeBoundedExpr (ExprNode* Expr, unsigned Size)
2014 /* Force the given expression into a specific size of ForceRange is true */
2018 case 1: Expr = GenByteExpr (Expr); break;
2019 case 2: Expr = GenWordExpr (Expr); break;
2020 case 3: Expr = GenFarAddrExpr (Expr); break;
2021 case 4: Expr = GenDWordExpr (Expr); break;
2022 default: Internal ("Invalid size in BoundedExpr: %u", Size);
2030 ExprNode* BoundedExpr (ExprNode* (*ExprFunc) (void), unsigned Size)
2031 /* Parse an expression and force it within a given size if ForceRange is true */
2033 return MakeBoundedExpr (ExprFunc (), Size);