1 /*****************************************************************************/
5 /* Expression evaluation for the ca65 macroassembler */
9 /* (C) 1998-2003 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 /*****************************************************************************/
58 #include "studyexpr.h"
66 /*****************************************************************************/
68 /*****************************************************************************/
72 /* Since all expressions are first packed into expression trees, and each
73 * expression tree node is allocated on the heap, we add some type of special
74 * purpose memory allocation here: Instead of freeing the nodes, we save some
75 * number of freed nodes for later and remember them in a single linked list
76 * using the Left link.
78 #define MAX_FREE_NODES 64
79 static ExprNode* FreeExprNodes = 0;
80 static unsigned FreeNodeCount = 0;
84 /*****************************************************************************/
86 /*****************************************************************************/
90 static ExprNode* NewExprNode (unsigned Op)
91 /* Create a new expression node */
95 /* Do we have some nodes in the list already? */
97 /* Use first node from list */
99 FreeExprNodes = N->Left;
101 /* Allocate fresh memory */
102 N = xmalloc (sizeof (ExprNode));
105 N->Left = N->Right = 0;
113 static void FreeExprNode (ExprNode* E)
117 if (E->Op == EXPR_SYMBOL) {
118 /* Remove the symbol reference */
119 SymDelExprRef (E->V.Sym, E);
121 /* Place the symbol into the free nodes list if possible */
122 if (FreeNodeCount < MAX_FREE_NODES) {
123 /* Remember this node for later */
124 E->Left = FreeExprNodes;
127 /* Free the memory */
135 /*****************************************************************************/
137 /*****************************************************************************/
141 static ExprNode* Expr0 (void);
145 int IsByteRange (long Val)
146 /* Return true if this is a byte value */
148 return (Val & ~0xFFL) == 0;
153 int IsWordRange (long Val)
154 /* Return true if this is a word value */
156 return (Val & ~0xFFFFL) == 0;
161 int IsFarRange (long Val)
162 /* Return true if this is a far (24 bit) value */
164 return (Val & ~0xFFFFFFL) == 0;
169 static int IsEasyConst (const ExprNode* E, long* Val)
170 /* Do some light checking if the given node is a constant. Don't care if E is
171 * a complex expression. If E is a constant, return true and place its value
172 * into Val, provided that Val is not NULL.
175 /* Resolve symbols, follow symbol chains */
176 while (E->Op == EXPR_SYMBOL) {
177 E = SymResolve (E->V.Sym);
179 /* Could not resolve */
184 /* Symbols resolved, check for a literal */
185 if (E->Op == EXPR_LITERAL) {
192 /* Not found to be a const according to our tests */
198 static ExprNode* FuncBlank (void)
199 /* Handle the .BLANK builtin function */
203 /* Assume no tokens if the closing brace follows (this is not correct in
204 * all cases, since the token may be the closing brace, but this will
205 * give a syntax error anyway and may not be handled by .BLANK.
207 if (Tok != TOK_RPAREN) {
208 /* Skip any tokens */
210 while (!TokIsSep (Tok)) {
211 if (Tok == TOK_LPAREN) {
213 } else if (Tok == TOK_RPAREN) {
225 return GenLiteralExpr (Result);
230 static ExprNode* FuncConst (void)
231 /* Handle the .CONST builtin function */
233 /* Read an expression */
234 ExprNode* Expr = Expression ();
236 /* Check the constness of the expression */
237 ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
239 /* Free the expression */
248 static ExprNode* FuncDefined (void)
249 /* Handle the .DEFINED builtin function */
251 /* Parse the symbol name and search for the symbol */
252 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
254 /* Check if the symbol is defined */
255 return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
260 static ExprNode* DoMatch (enum TC EqualityLevel)
261 /* Handle the .MATCH and .XMATCH builtin functions */
268 /* A list of tokens follows. Read this list and remember it building a
269 * single linked list of tokens including attributes. The list is
270 * terminated by a comma.
272 while (Tok != TOK_COMMA) {
274 /* We may not end-of-line of end-of-file here */
275 if (TokIsSep (Tok)) {
276 Error ("Unexpected end of line");
280 /* Get a node with this token */
281 Node = NewTokNode ();
283 /* Insert the node into the list */
298 /* Read the second list which is terminated by the right parenthesis and
299 * compare each token against the one in the first list.
303 while (Tok != TOK_RPAREN) {
305 /* We may not end-of-line of end-of-file here */
306 if (TokIsSep (Tok)) {
307 Error ("Unexpected end of line");
311 /* Compare the tokens if the result is not already known */
314 /* The second list is larger than the first one */
316 } else if (TokCmp (Node) < EqualityLevel) {
317 /* Tokens do not match */
322 /* Next token in first list */
327 /* Next token in current list */
331 /* Check if there are remaining tokens in the first list */
336 /* Free the token list */
343 /* Done, return the result */
344 return GenLiteralExpr (Result);
349 static ExprNode* FuncMatch (void)
350 /* Handle the .MATCH function */
352 return DoMatch (tcSameToken);
357 static ExprNode* FuncReferenced (void)
358 /* Handle the .REFERENCED builtin function */
360 /* Parse the symbol name and search for the symbol */
361 SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
363 /* Check if the symbol is referenced */
364 return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
369 static ExprNode* FuncSizeOf (void)
370 /* Handle the .SIZEOF function */
374 /* Get the struct for the scoped struct name */
375 SymTable* Struct = ParseScopedSymTable (SYM_FIND_EXISTING);
377 /* Check if the given symbol is really a struct */
378 if (GetSymTabType (Struct) != ST_STRUCT) {
379 Error ("Argument to .SIZEOF is not a struct");
382 Size = GetStructSize (Struct);
385 /* Return the size */
386 return GenLiteralExpr (Size);
391 static ExprNode* FuncStrAt (void)
392 /* Handle the .STRAT function */
394 char Str [sizeof(SVal)];
398 /* String constant expected */
399 if (Tok != TOK_STRCON) {
400 Error ("String constant expected");
406 /* Remember the string and skip it */
410 /* Comma must follow */
413 /* Expression expected */
414 Index = ConstExpression ();
416 /* Must be a valid index */
417 if (Index >= (long) strlen (Str)) {
418 Error ("Range error");
422 /* Get the char, handle as unsigned. Be sure to translate it into
423 * the target character set.
425 C = TgtTranslateChar (Str [(size_t)Index]);
427 /* Return the char expression */
428 return GenLiteralExpr (C);
433 static ExprNode* FuncStrLen (void)
434 /* Handle the .STRLEN function */
438 /* String constant expected */
439 if (Tok != TOK_STRCON) {
441 Error ("String constant expected");
442 /* Smart error recovery */
443 if (Tok != TOK_RPAREN) {
450 /* Get the length of the string */
453 /* Skip the string */
457 /* Return the length */
458 return GenLiteralExpr (Len);
463 static ExprNode* FuncTCount (void)
464 /* Handle the .TCOUNT function */
466 /* We have a list of tokens that ends with the closing paren. Skip
467 * the tokens, handling nested braces and count them.
471 while (Parens != 0 || Tok != TOK_RPAREN) {
473 /* Check for end of line or end of input. Since the calling function
474 * will check for the closing paren, we don't need to print an error
475 * here, just bail out.
477 if (TokIsSep (Tok)) {
484 /* Keep track of the nesting level */
486 case TOK_LPAREN: ++Parens; break;
487 case TOK_RPAREN: --Parens; break;
495 /* Return the number of tokens */
496 return GenLiteralExpr (Count);
501 static ExprNode* FuncXMatch (void)
502 /* Handle the .XMATCH function */
504 return DoMatch (tcIdentical);
509 static ExprNode* Function (ExprNode* (*F) (void))
510 /* Handle builtin functions */
514 /* Skip the keyword */
517 /* Expression must be enclosed in braces */
518 if (Tok != TOK_LPAREN) {
519 Error ("'(' expected");
521 return GenLiteralExpr (0);
525 /* Call the function itself */
528 /* Closing brace must follow */
531 /* Return the result of the actual function */
537 static ExprNode* Symbol (SymEntry* S)
538 /* Reference a symbol and return an expression for it */
541 /* Some weird error happened before */
542 return GenLiteralExpr (0);
544 /* Mark the symbol as referenced */
546 /* Remove the symbol if possible */
547 if (SymHasExpr (S)) {
548 return CloneExpr (GetSymExpr (S));
550 /* Create symbol node */
551 return GenSymExpr (S);
558 static ExprNode* Factor (void)
567 N = GenLiteralExpr (IVal);
572 N = GenLiteralExpr (TgtTranslateChar (IVal));
578 N = Symbol (ParseScopedSymName (SYM_ALLOC_NEW));
581 case TOK_LOCAL_IDENT:
582 N = Symbol (SymFindLocal (SVal, SYM_ALLOC_NEW));
594 if (IsEasyConst (L, &Val)) {
596 N = GenLiteralExpr (-Val);
598 N = NewExprNode (EXPR_UNARY_MINUS);
606 if (IsEasyConst (L, &Val)) {
608 N = GenLiteralExpr (~Val);
610 N = NewExprNode (EXPR_NOT);
624 if (IsEasyConst (L, &Val)) {
626 N = GenLiteralExpr (Val & 0xFF);
628 N = NewExprNode (EXPR_BYTE0);
636 if (IsEasyConst (L, &Val)) {
638 N = GenLiteralExpr ((Val >> 8) & 0xFF);
640 N = NewExprNode (EXPR_BYTE1);
648 if (IsEasyConst (L, &Val)) {
650 N = GenLiteralExpr ((Val >> 16) & 0xFF);
652 N = NewExprNode (EXPR_BYTE2);
664 N = Function (FuncBlank);
668 N = Function (FuncConst);
672 N = GenLiteralExpr (CPUIsets[CPU]);
677 N = Function (FuncDefined);
681 N = Function (FuncMatch);
685 N = Function (FuncReferenced);
689 N = Function (FuncSizeOf);
693 N = Function (FuncStrAt);
697 N = Function (FuncStrLen);
701 N = Function (FuncTCount);
705 N = GenLiteralExpr (time (0));
710 N = GenLiteralExpr (VERSION);
715 N = Function (FuncXMatch);
719 if (LooseCharTerm && Tok == TOK_STRCON && strlen(SVal) == 1) {
720 /* A character constant */
721 N = GenLiteralExpr (TgtTranslateChar (SVal[0]));
723 N = GenLiteralExpr (0); /* Dummy */
724 Error ("Syntax error");
734 static ExprNode* Term (void)
736 /* Read left hand side */
737 ExprNode* Root = Factor ();
739 /* Handle multiplicative operations */
740 while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
741 Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
744 long LVal, RVal, Val;
748 /* Remember the token and skip it */
752 /* Move root to left side and read the right side */
756 /* If both expressions are constant, we can evaluate the term */
757 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
766 Error ("Division by zero");
775 Error ("Modulo operation with zero");
791 Val = shl_l (LVal, RVal);
795 Val = shr_l (LVal, RVal);
799 Internal ("Invalid token");
802 /* Generate a literal expression and delete the old left and
807 Root = GenLiteralExpr (Val);
811 /* Generate an expression tree */
814 case TOK_MUL: Op = EXPR_MUL; break;
815 case TOK_DIV: Op = EXPR_DIV; break;
816 case TOK_MOD: Op = EXPR_MOD; break;
817 case TOK_AND: Op = EXPR_AND; break;
818 case TOK_XOR: Op = EXPR_XOR; break;
819 case TOK_SHL: Op = EXPR_SHL; break;
820 case TOK_SHR: Op = EXPR_SHR; break;
821 default: Internal ("Invalid token");
823 Root = NewExprNode (Op);
831 /* Return the expression tree we've created */
837 static ExprNode* SimpleExpr (void)
839 /* Read left hand side */
840 ExprNode* Root = Term ();
842 /* Handle additive operations */
843 while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
845 long LVal, RVal, Val;
849 /* Remember the token and skip it */
853 /* Move root to left side and read the right side */
857 /* If both expressions are constant, we can evaluate the term */
858 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
861 case TOK_PLUS: Val = LVal + RVal; break;
862 case TOK_MINUS: Val = LVal - RVal; break;
863 case TOK_OR: Val = LVal | RVal; break;
864 default: Internal ("Invalid token");
867 /* Generate a literal expression and delete the old left and
872 Root = GenLiteralExpr (Val);
876 /* Generate an expression tree */
879 case TOK_PLUS: Op = EXPR_PLUS; break;
880 case TOK_MINUS: Op = EXPR_MINUS; break;
881 case TOK_OR: Op = EXPR_OR; break;
882 default: Internal ("Invalid token");
884 Root = NewExprNode (Op);
891 /* Return the expression tree we've created */
897 static ExprNode* BoolExpr (void)
898 /* Evaluate a boolean expression */
900 /* Read left hand side */
901 ExprNode* Root = SimpleExpr ();
903 /* Handle booleans */
904 while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
905 Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
907 long LVal, RVal, Val;
911 /* Remember the token and skip it */
915 /* Move root to left side and read the right side */
917 Right = SimpleExpr ();
919 /* If both expressions are constant, we can evaluate the term */
920 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
923 case TOK_EQ: Val = (LVal == RVal); break;
924 case TOK_NE: Val = (LVal != RVal); break;
925 case TOK_LT: Val = (LVal < RVal); break;
926 case TOK_GT: Val = (LVal > RVal); break;
927 case TOK_LE: Val = (LVal <= RVal); break;
928 case TOK_GE: Val = (LVal >= RVal); break;
929 default: Internal ("Invalid token");
932 /* Generate a literal expression and delete the old left and
937 Root = GenLiteralExpr (Val);
941 /* Generate an expression tree */
944 case TOK_EQ: Op = EXPR_EQ; break;
945 case TOK_NE: Op = EXPR_NE; break;
946 case TOK_LT: Op = EXPR_LT; break;
947 case TOK_GT: Op = EXPR_GT; break;
948 case TOK_LE: Op = EXPR_LE; break;
949 case TOK_GE: Op = EXPR_GE; break;
950 default: Internal ("Invalid token");
952 Root = NewExprNode (Op);
959 /* Return the expression tree we've created */
965 static ExprNode* Expr2 (void)
966 /* Boolean operators: AND and XOR */
968 /* Read left hand side */
969 ExprNode* Root = BoolExpr ();
971 /* Handle booleans */
972 while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
974 long LVal, RVal, Val;
978 /* Remember the token and skip it */
982 /* Move root to left side and read the right side */
986 /* If both expressions are constant, we can evaluate the term */
987 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
990 case TOK_BOOLAND: Val = ((LVal != 0) && (RVal != 0)); break;
991 case TOK_BOOLXOR: Val = ((LVal != 0) ^ (RVal != 0)); break;
992 default: Internal ("Invalid token");
995 /* Generate a literal expression and delete the old left and
1000 Root = GenLiteralExpr (Val);
1004 /* Generate an expression tree */
1007 case TOK_BOOLAND: Op = EXPR_BOOLAND; break;
1008 case TOK_BOOLXOR: Op = EXPR_BOOLXOR; break;
1009 default: Internal ("Invalid token");
1011 Root = NewExprNode (Op);
1013 Root->Right = Right;
1018 /* Return the expression tree we've created */
1024 static ExprNode* Expr1 (void)
1025 /* Boolean operators: OR */
1027 /* Read left hand side */
1028 ExprNode* Root = Expr2 ();
1030 /* Handle booleans */
1031 while (Tok == TOK_BOOLOR) {
1033 long LVal, RVal, Val;
1037 /* Remember the token and skip it */
1041 /* Move root to left side and read the right side */
1045 /* If both expressions are constant, we can evaluate the term */
1046 if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1049 case TOK_BOOLOR: Val = ((LVal != 0) || (RVal != 0)); break;
1050 default: Internal ("Invalid token");
1053 /* Generate a literal expression and delete the old left and
1058 Root = GenLiteralExpr (Val);
1062 /* Generate an expression tree */
1065 case TOK_BOOLOR: Op = EXPR_BOOLOR; break;
1066 default: Internal ("Invalid token");
1068 Root = NewExprNode (Op);
1070 Root->Right = Right;
1075 /* Return the expression tree we've created */
1081 static ExprNode* Expr0 (void)
1082 /* Boolean operators: NOT */
1086 /* Handle booleans */
1087 if (Tok == TOK_BOOLNOT) {
1092 /* Skip the operator token */
1095 /* Read the argument */
1098 /* If the argument is const, evaluate it directly */
1099 if (IsEasyConst (Left, &Val)) {
1101 Root = GenLiteralExpr (!Val);
1103 Root = NewExprNode (EXPR_BOOLNOT);
1109 /* Read left hand side */
1114 /* Return the expression tree we've created */
1120 ExprNode* Expression (void)
1121 /* Evaluate an expression, build the expression tree on the heap and return
1122 * a pointer to the root of the tree.
1126 return SimplifyExpr (Expr0 ());
1129 ExprNode* Expr = Expr0 ();
1130 printf ("Before: "); DumpExpr (Expr, SymResolve);
1131 Expr = SimplifyExpr (Expr);
1132 printf ("After: "); DumpExpr (Expr, SymResolve);
1139 long ConstExpression (void)
1140 /* Parse an expression. Check if the expression is const, and print an error
1141 * message if not. Return the value of the expression, or a dummy, if it is
1148 /* Read the expression */
1149 ExprNode* Expr = Expr0 ();
1152 ExprNode* Expr = Expression ();
1155 /* Study the expression */
1158 StudyExpr (Expr, &D);
1160 /* Check if the expression is constant */
1161 if (ED_IsConst (&D)) {
1164 Error ("Constant expression expected");
1168 /* Free the expression tree and allocated memory for D */
1172 /* Return the value */
1178 void FreeExpr (ExprNode* Root)
1179 /* Free the expression, Root is pointing to. */
1182 FreeExpr (Root->Left);
1183 FreeExpr (Root->Right);
1184 FreeExprNode (Root);
1190 ExprNode* SimplifyExpr (ExprNode* Expr)
1191 /* Try to simplify the given expression tree */
1193 if (Expr && Expr->Op != EXPR_LITERAL) {
1195 /* Create an expression description and initialize it */
1199 /* Study the expression */
1200 StudyExpr (Expr, &D);
1202 /* Now check if we can generate a literal value */
1203 if (ED_IsConst (&D)) {
1204 /* No external references */
1206 Expr = GenLiteralExpr (D.Val);
1209 /* Free allocated memory */
1217 ExprNode* GenLiteralExpr (long Val)
1218 /* Return an expression tree that encodes the given literal value */
1220 ExprNode* Expr = NewExprNode (EXPR_LITERAL);
1227 ExprNode* GenSymExpr (SymEntry* Sym)
1228 /* Return an expression node that encodes the given symbol */
1230 ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
1232 SymAddExprRef (Sym, Expr);
1238 static ExprNode* GenSectionExpr (unsigned SegNum)
1239 /* Return an expression node for the given section */
1241 ExprNode* Expr = NewExprNode (EXPR_SECTION);
1242 Expr->V.SegNum = SegNum;
1248 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
1249 /* Generate an addition from the two operands */
1251 ExprNode* Root = NewExprNode (EXPR_PLUS);
1253 Root->Right = Right;
1259 ExprNode* GenCurrentPC (void)
1260 /* Return the current program counter as expression */
1265 /* Create SegmentBase + Offset */
1266 Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
1267 GenLiteralExpr (GetPC ()));
1269 /* Absolute mode, just return PC value */
1270 Root = GenLiteralExpr (GetPC ());
1278 ExprNode* GenSwapExpr (ExprNode* Expr)
1279 /* Return an extended expression with lo and hi bytes swapped */
1281 ExprNode* N = NewExprNode (EXPR_SWAP);
1288 ExprNode* GenBranchExpr (unsigned Offs)
1289 /* Return an expression that encodes the difference between current PC plus
1290 * offset and the target expression (that is, Expression() - (*+Offs) ).
1297 /* Read Expression() */
1300 /* If the expression is a cheap constant, generate a simpler tree */
1301 if (IsEasyConst (N, &Val)) {
1303 /* Free the constant expression tree */
1306 /* Generate the final expression:
1308 * Val - ((Seg + PC) + Offs)
1309 * Val - Seg - PC - Offs
1310 * (Val - PC - Offs) - Seg
1312 Root = GenLiteralExpr (Val - GetPC () - Offs);
1315 Root = NewExprNode (EXPR_MINUS);
1317 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1322 /* Generate the expression:
1324 * N - ((Seg + PC) + Offs)
1325 * N - Seg - PC - Offs
1326 * N - (PC + Offs) - Seg
1328 Root = NewExprNode (EXPR_MINUS);
1330 Root->Right = GenLiteralExpr (GetPC () + Offs);
1333 Root = NewExprNode (EXPR_MINUS);
1335 Root->Right = GenSectionExpr (GetCurrentSegNum ());
1339 /* Return the result */
1345 ExprNode* GenULabelExpr (unsigned Num)
1346 /* Return an expression for an unnamed label with the given index */
1348 ExprNode* Node = NewExprNode (EXPR_ULABEL);
1351 /* Return the new node */
1357 ExprNode* GenByteExpr (ExprNode* Expr)
1358 /* Force the given expression into a byte and return the result */
1360 /* Use the low byte operator to force the expression into byte size */
1361 ExprNode* Root = NewExprNode (EXPR_BYTE0);
1364 /* Return the result */
1370 ExprNode* GenWordExpr (ExprNode* Expr)
1371 /* Force the given expression into a word and return the result. */
1373 /* AND the expression by $FFFF to force it into word size */
1374 ExprNode* Root = NewExprNode (EXPR_AND);
1376 Root->Right = GenLiteralExpr (0xFFFF);
1378 /* Return the result */
1384 ExprNode* GenNE (ExprNode* Expr, long Val)
1385 /* Generate an expression that compares Expr and Val for inequality */
1387 /* Generate a compare node */
1388 ExprNode* Root = NewExprNode (EXPR_NE);
1390 Root->Right = GenLiteralExpr (Val);
1392 /* Return the result */
1398 int IsConstExpr (ExprNode* Expr, long* Val)
1399 /* Return true if the given expression is a constant expression, that is, one
1400 * with no references to external symbols. If Val is not NULL and the
1401 * expression is constant, the constant value is stored here.
1406 /* Study the expression */
1409 StudyExpr (Expr, &D);
1411 /* Check if the expression is constant */
1412 IsConst = ED_IsConst (&D);
1413 if (IsConst && Val != 0) {
1417 /* Delete allocated memory and return the result */
1424 static void CheckAddrSize (const ExprNode* N, unsigned char* AddrSize)
1425 /* Internal routine that is recursively called to check for the address size
1426 * of the expression tree.
1430 unsigned char Left, Right;
1433 switch (N->Op & EXPR_TYPEMASK) {
1439 if (SymIsZP (N->V.Sym)) {
1440 if (*AddrSize < ADDR_SIZE_ZP) {
1441 *AddrSize = ADDR_SIZE_ZP;
1443 } else if (SymHasExpr (N->V.Sym)) {
1444 /* Check if this expression is a byte expression */
1445 CheckAddrSize (GetSymExpr (N->V.Sym), AddrSize);
1447 /* Undefined symbol, use absolute */
1448 if (*AddrSize < ADDR_SIZE_ABS) {
1449 *AddrSize = ADDR_SIZE_ABS;
1455 A = GetSegAddrSize (N->V.SegNum);
1456 if (A > *AddrSize) {
1464 case EXPR_UNARYNODE:
1471 /* No need to look at the expression */
1472 *AddrSize = ADDR_SIZE_ZP;
1477 /* No need to look at the expression */
1478 *AddrSize = ADDR_SIZE_ABS;
1482 CheckAddrSize (N->Left, AddrSize);
1487 case EXPR_BINARYNODE:
1488 Left = Right = ADDR_SIZE_DEFAULT;
1489 CheckAddrSize (N->Left, &Left);
1490 CheckAddrSize (N->Right, &Right);
1491 A = (Left > Right)? Left : Right;
1492 if (A > *AddrSize) {
1498 Internal ("Unknown expression op: %02X", N->Op);
1505 int IsByteExpr (ExprNode* Root)
1506 /* Return true if this is a byte expression */
1510 if (IsConstExpr (Root, &Val)) {
1511 return IsByteRange (Val);
1513 unsigned char AddrSize = ADDR_SIZE_DEFAULT;
1514 CheckAddrSize (Root, &AddrSize);
1515 return (AddrSize == ADDR_SIZE_ZP);
1521 ExprNode* CloneExpr (ExprNode* Expr)
1522 /* Clone the given expression tree. The function will simply clone symbol
1523 * nodes, it will not resolve them.
1528 /* Accept NULL pointers */
1533 /* Clone the node */
1537 Clone = GenLiteralExpr (Expr->V.Val);
1541 Clone = GenULabelExpr (Expr->V.Val);
1545 Clone = GenSymExpr (Expr->V.Sym);
1549 Clone = GenSectionExpr (Expr->V.SegNum);
1553 /* Generate a new node */
1554 Clone = NewExprNode (Expr->Op);
1555 /* Clone the tree nodes */
1556 Clone->Left = CloneExpr (Expr->Left);
1557 Clone->Right = CloneExpr (Expr->Right);
1567 void WriteExpr (ExprNode* Expr)
1568 /* Write the given expression to the object file */
1570 /* Null expressions are encoded by a type byte of zero */
1572 ObjWrite8 (EXPR_NULL);
1576 /* If the is a leafnode, write the expression attribute, otherwise
1577 * write the expression operands.
1582 ObjWrite8 (EXPR_LITERAL);
1583 ObjWrite32 (Expr->V.Val);
1587 if (SymIsImport (Expr->V.Sym)) {
1588 ObjWrite8 (EXPR_SYMBOL);
1589 ObjWriteVar (GetSymIndex (Expr->V.Sym));
1591 WriteExpr (GetSymExpr (Expr->V.Sym));
1596 ObjWrite8 (EXPR_SECTION);
1597 ObjWrite8 (Expr->V.SegNum);
1601 WriteExpr (ULabResolve (Expr->V.Val));
1605 /* Not a leaf node */
1606 ObjWrite8 (Expr->Op);
1607 WriteExpr (Expr->Left);
1608 WriteExpr (Expr->Right);