]> git.sur5r.net Git - cc65/blob - src/ca65/expr.c
Emit warnings for symbols that were used suboptimal because of forward
[cc65] / src / ca65 / expr.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  expr.c                                   */
4 /*                                                                           */
5 /*             Expression evaluation for the ca65 macroassembler             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2006 Ullrich von Bassewitz                                       */
10 /*               Römerstraße 52                                              */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <time.h>
38
39 /* common */
40 #include "check.h"
41 #include "cpu.h"
42 #include "exprdefs.h"
43 #include "print.h"
44 #include "shift.h"
45 #include "strbuf.h"
46 #include "tgttrans.h"
47 #include "version.h"
48 #include "xmalloc.h"
49
50 /* ca65 */
51 #include "error.h"
52 #include "expr.h"
53 #include "global.h"
54 #include "instr.h"
55 #include "nexttok.h"
56 #include "objfile.h"
57 #include "segment.h"
58 #include "sizeof.h"
59 #include "studyexpr.h"
60 #include "symbol.h"
61 #include "symtab.h"
62 #include "toklist.h"
63 #include "ulabel.h"
64
65
66
67 /*****************************************************************************/
68 /*                                   Data                                    */
69 /*****************************************************************************/
70
71
72
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.
78  */
79 #define MAX_FREE_NODES  64
80 static ExprNode*        FreeExprNodes = 0;
81 static unsigned         FreeNodeCount = 0;
82
83
84
85 /*****************************************************************************/
86 /*                                  Helpers                                  */
87 /*****************************************************************************/
88
89
90
91 static ExprNode* NewExprNode (unsigned Op)
92 /* Create a new expression node */
93 {
94     ExprNode* N;
95
96     /* Do we have some nodes in the list already? */
97     if (FreeExprNodes) {
98         /* Use first node from list */
99         N = FreeExprNodes;
100         FreeExprNodes = N->Left;
101     } else {
102         /* Allocate fresh memory */
103         N = xmalloc (sizeof (ExprNode));
104     }
105     N->Op = Op;
106     N->Left = N->Right = 0;
107     N->Obj = 0;
108
109     return N;
110 }
111
112
113
114 static void FreeExprNode (ExprNode* E)
115 /* Free a node */
116 {
117     if (E) {
118         if (E->Op == EXPR_SYMBOL) {
119             /* Remove the symbol reference */
120             SymDelExprRef (E->V.Sym, E);
121         }
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;
126             FreeExprNodes = E;
127         } else {
128             /* Free the memory */
129             xfree (E);
130         }
131     }
132 }
133
134
135
136 /*****************************************************************************/
137 /*                                   Code                                    */
138 /*****************************************************************************/
139
140
141
142 static ExprNode* Expr0 (void);
143
144
145
146 int IsByteRange (long Val)
147 /* Return true if this is a byte value */
148 {
149     return (Val & ~0xFFL) == 0;
150 }
151
152
153
154 int IsWordRange (long Val)
155 /* Return true if this is a word value */
156 {
157     return (Val & ~0xFFFFL) == 0;
158 }
159
160
161
162 int IsFarRange (long Val)
163 /* Return true if this is a far (24 bit) value */
164 {
165     return (Val & ~0xFFFFFFL) == 0;
166 }
167
168
169
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.
174  */
175 {
176     /* Resolve symbols, follow symbol chains */
177     while (E->Op == EXPR_SYMBOL) {
178         E = SymResolve (E->V.Sym);
179         if (E == 0) {
180             /* Could not resolve */
181             return 0;
182         }
183     }
184
185     /* Symbols resolved, check for a literal */
186     if (E->Op == EXPR_LITERAL) {
187         if (Val) {
188             *Val = E->V.Val;
189         }
190         return 1;
191     }
192
193     /* Not found to be a const according to our tests */
194     return 0;
195 }
196
197
198
199 static ExprNode* LoByte (ExprNode* Operand)
200 /* Return the low byte of the given expression */
201 {
202     ExprNode* Expr;
203     long      Val;
204
205     /* Special handling for const expressions */
206     if (IsEasyConst (Operand, &Val)) {
207         FreeExpr (Operand);
208         Expr = GenLiteralExpr (Val & 0xFF);
209     } else {
210         /* Extract byte #0 */
211         Expr = NewExprNode (EXPR_BYTE0);
212         Expr->Left = Operand;
213     }
214     return Expr;
215 }
216
217
218
219 static ExprNode* HiByte (ExprNode* Operand)
220 /* Return the high byte of the given expression */
221 {
222     ExprNode* Expr;
223     long      Val;
224
225     /* Special handling for const expressions */
226     if (IsEasyConst (Operand, &Val)) {
227         FreeExpr (Operand);
228         Expr = GenLiteralExpr ((Val >> 8) & 0xFF);
229     } else {
230         /* Extract byte #1 */
231         Expr = NewExprNode (EXPR_BYTE1);
232         Expr->Left = Operand;
233     }
234     return Expr;
235 }
236
237
238
239 static ExprNode* BankByte (ExprNode* Operand)
240 /* Return the bank byte of the given expression */
241 {
242     ExprNode* Expr;
243     long      Val;
244
245     /* Special handling for const expressions */
246     if (IsEasyConst (Operand, &Val)) {
247         FreeExpr (Operand);
248         Expr = GenLiteralExpr ((Val >> 16) & 0xFF);
249     } else {
250         /* Extract byte #2 */
251         Expr = NewExprNode (EXPR_BYTE2);
252         Expr->Left = Operand;
253     }
254     return Expr;
255 }
256
257
258
259 static ExprNode* LoWord (ExprNode* Operand)
260 /* Return the low word of the given expression */
261 {
262     ExprNode* Expr;
263     long      Val;
264
265     /* Special handling for const expressions */
266     if (IsEasyConst (Operand, &Val)) {
267         FreeExpr (Operand);
268         Expr = GenLiteralExpr (Val & 0xFFFF);
269     } else {
270         /* Extract word #0 */
271         Expr = NewExprNode (EXPR_WORD0);
272         Expr->Left = Operand;
273     }
274     return Expr;
275 }
276
277
278
279 static ExprNode* HiWord (ExprNode* Operand)
280 /* Return the high word of the given expression */
281 {
282     ExprNode* Expr;
283     long      Val;
284
285     /* Special handling for const expressions */
286     if (IsEasyConst (Operand, &Val)) {
287         FreeExpr (Operand);
288         Expr = GenLiteralExpr ((Val >> 16) & 0xFFFF);
289     } else {
290         /* Extract word #1 */
291         Expr = NewExprNode (EXPR_WORD1);
292         Expr->Left = Operand;
293     }
294     return Expr;
295 }
296
297
298
299 static ExprNode* Symbol (SymEntry* S)
300 /* Reference a symbol and return an expression for it */
301 {
302     if (S == 0) {
303         /* Some weird error happened before */
304         return GenLiteralExpr (0);
305     } else {
306         /* Mark the symbol as referenced */
307         SymRef (S);
308         /* If the symbol is a variable, return just its value, otherwise
309          * return a reference to the symbol.
310          */
311         if (SymIsVar (S)) {
312             return CloneExpr (GetSymExpr (S));
313         } else {
314             /* Create symbol node */
315             return GenSymExpr (S);
316         }
317     }
318 }
319
320
321
322 static ExprNode* FuncBankByte (void)
323 /* Handle the .BANKBYTE builtin function */
324 {
325     return BankByte (Expression ());
326 }
327
328
329
330 static ExprNode* FuncBlank (void)
331 /* Handle the .BLANK builtin function */
332 {
333     /* We have a list of tokens that ends with the closing paren. Skip
334      * the tokens, and count them. Allow optionally curly braces.
335      */
336     enum Token Term = GetTokListTerm (TOK_RPAREN);
337     unsigned Count = 0;
338     while (Tok != Term) {
339
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.
343          */
344         if (TokIsSep (Tok)) {
345             break;
346         }
347
348         /* One more token */
349         ++Count;
350
351         /* Skip the token */
352         NextTok ();
353     }
354
355     /* If the list was enclosed in curly braces, skip the closing brace */
356     if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
357         NextTok ();
358     }
359
360     /* Return true if the list was empty */
361     return GenLiteralExpr (Count == 0);
362 }
363
364
365
366 static ExprNode* FuncConst (void)
367 /* Handle the .CONST builtin function */
368 {
369     /* Read an expression */
370     ExprNode* Expr = Expression ();
371
372     /* Check the constness of the expression */
373     ExprNode* Result = GenLiteralExpr (IsConstExpr (Expr, 0));
374
375     /* Free the expression */
376     FreeExpr (Expr);
377
378     /* Done */
379     return Result;
380 }
381
382
383
384 static ExprNode* FuncDefined (void)
385 /* Handle the .DEFINED builtin function */
386 {
387     /* Parse the symbol name and search for the symbol */
388     SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
389
390     /* Check if the symbol is defined */
391     return GenLiteralExpr (Sym != 0 && SymIsDef (Sym));
392 }
393
394
395
396 static ExprNode* FuncHiByte (void)
397 /* Handle the .HIBYTE builtin function */
398 {
399     return HiByte (Expression ());
400 }
401
402
403
404 static ExprNode* FuncHiWord (void)
405 /* Handle the .HIWORD builtin function */
406 {
407     return HiWord (Expression ());
408 }
409
410
411
412 static ExprNode* FuncLoByte (void)
413 /* Handle the .LOBYTE builtin function */
414 {
415     return LoByte (Expression ());
416 }
417
418
419
420 static ExprNode* FuncLoWord (void)
421 /* Handle the .LOWORD builtin function */
422 {
423     return LoWord (Expression ());
424 }
425
426
427
428 static ExprNode* DoMatch (enum TC EqualityLevel)
429 /* Handle the .MATCH and .XMATCH builtin functions */
430 {
431     int Result;
432     TokNode* Root = 0;
433     TokNode* Last = 0;
434     TokNode* Node;
435
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.
439      */
440     enum Token Term = GetTokListTerm (TOK_COMMA);
441     while (Tok != Term) {
442
443         /* We may not end-of-line of end-of-file here */
444         if (TokIsSep (Tok)) {
445             Error ("Unexpected end of line");
446             return GenLiteral0 ();
447         }
448
449         /* Get a node with this token */
450         Node = NewTokNode ();
451
452         /* Insert the node into the list */
453         if (Last == 0) {
454             Root = Node;
455         } else {
456             Last->Next = Node;
457         }
458         Last = Node;
459
460         /* Skip the token */
461         NextTok ();
462     }
463
464     /* Skip the terminator token*/
465     NextTok ();
466
467     /* If the token list was enclosed in curly braces, we expect a comma */
468     if (Term == TOK_RCURLY) {
469         ConsumeComma ();
470     }
471
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.
475      */
476     Term = GetTokListTerm (TOK_RPAREN);
477     Result = 1;
478     Node = Root;
479     while (Tok != Term) {
480
481         /* We may not end-of-line of end-of-file here */
482         if (TokIsSep (Tok)) {
483             Error ("Unexpected end of line");
484             return GenLiteral0 ();
485         }
486
487         /* Compare the tokens if the result is not already known */
488         if (Result != 0) {
489             if (Node == 0) {
490                 /* The second list is larger than the first one */
491                 Result = 0;
492             } else if (TokCmp (Node) < EqualityLevel) {
493                 /* Tokens do not match */
494                 Result = 0;
495             }
496         }
497
498         /* Next token in first list */
499         if (Node) {
500             Node = Node->Next;
501         }
502
503         /* Next token in current list */
504         NextTok ();
505     }
506
507     /* If the token list was enclosed in curly braces, eat the closing brace */
508     if (Term == TOK_RCURLY) {
509         NextTok ();
510     }
511
512     /* Check if there are remaining tokens in the first list */
513     if (Node != 0) {
514         Result = 0;
515     }
516
517     /* Free the token list */
518     while (Root) {
519         Node = Root;
520         Root = Root->Next;
521         FreeTokNode (Node);
522     }
523
524     /* Done, return the result */
525     return GenLiteralExpr (Result);
526 }
527
528
529
530 static ExprNode* FuncMatch (void)
531 /* Handle the .MATCH function */
532 {
533     return DoMatch (tcSameToken);
534 }
535
536
537
538 static ExprNode* FuncReferenced (void)
539 /* Handle the .REFERENCED builtin function */
540 {
541     /* Parse the symbol name and search for the symbol */
542     SymEntry* Sym = ParseScopedSymName (SYM_FIND_EXISTING);
543
544     /* Check if the symbol is referenced */
545     return GenLiteralExpr (Sym != 0 && SymIsRef (Sym));
546 }
547
548
549
550 static ExprNode* FuncSizeOf (void)
551 /* Handle the .SIZEOF function */
552 {
553     StrBuf    ScopeName = AUTO_STRBUF_INITIALIZER;
554     char      Name[sizeof (SVal)];
555     SymTable* Scope;
556     SymEntry* Sym;
557     SymEntry* SizeSym;
558     long      Size;
559     int       NoScope;
560
561
562     /* Assume an error */
563     SizeSym = 0;
564
565     /* Check for a cheap local which needs special handling */
566     if (Tok == TOK_LOCAL_IDENT) {
567
568         /* Cheap local symbol */
569         Sym = SymFindLocal (SymLast, SVal, SYM_FIND_EXISTING);
570         if (Sym == 0) {
571             Error ("Unknown symbol or scope: `%s'", SVal);
572         } else {
573             SizeSym = GetSizeOfSymbol (Sym);
574         }
575
576         /* Remember and skip SVal, terminate ScopeName so it is empty */
577         strcpy (Name, SVal);
578         NextTok ();
579         SB_Terminate (&ScopeName);
580
581     } else {
582
583         /* Parse the scope and the name */
584         SymTable* ParentScope = ParseScopedIdent (Name, &ScopeName);
585
586         /* Check if the parent scope is valid */
587         if (ParentScope == 0) {
588             /* No such scope */
589             DoneStrBuf (&ScopeName);
590             return GenLiteral0 ();
591         }
592
593         /* If ScopeName is empty, no explicit scope was specified. We have to
594          * search upper scope levels in this case.
595          */
596         NoScope = SB_IsEmpty (&ScopeName);
597
598         /* First search for a scope with the given name */
599         if (NoScope) {
600             Scope = SymFindAnyScope (ParentScope, Name);
601         } else {
602             Scope = SymFindScope (ParentScope, Name, SYM_FIND_EXISTING);
603         }
604
605         /* If we did find a scope with the name, read the symbol defining the
606          * size, otherwise search for a symbol entry with the name and scope.
607          */
608         if (Scope) {
609             /* Yep, it's a scope */
610             SizeSym = GetSizeOfScope (Scope);
611         } else {
612             if (NoScope) {
613                 Sym = SymFindAny (ParentScope, Name);
614             } else {
615                 Sym = SymFind (ParentScope, Name, SYM_FIND_EXISTING);
616             }
617
618             /* If we found the symbol retrieve the size, otherwise complain */
619             if (Sym) {
620                 SizeSym = GetSizeOfSymbol (Sym);
621             } else {
622                 Error ("Unknown symbol or scope: `%s%s'",
623                        SB_GetConstBuf (&ScopeName), Name);
624             }
625         }
626     }
627
628     /* Check if we have a size */
629     if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
630         Error ("Size of `%s%s' is unknown", SB_GetConstBuf (&ScopeName), Name);
631         Size = 0;
632     }
633
634     /* Free the scope name */
635     DoneStrBuf (&ScopeName);
636
637     /* Return the size */
638     return GenLiteralExpr (Size);
639 }
640
641
642
643 static ExprNode* FuncStrAt (void)
644 /* Handle the .STRAT function */
645 {
646     char Str [sizeof(SVal)];
647     long Index;
648     unsigned char C;
649
650     /* String constant expected */
651     if (Tok != TOK_STRCON) {
652         Error ("String constant expected");
653         NextTok ();
654         return GenLiteral0 ();
655     }
656
657     /* Remember the string and skip it */
658     strcpy (Str, SVal);
659     NextTok ();
660
661     /* Comma must follow */
662     ConsumeComma ();
663
664     /* Expression expected */
665     Index = ConstExpression ();
666
667     /* Must be a valid index */
668     if (Index >= (long) strlen (Str)) {
669         Error ("Range error");
670         return GenLiteral0 ();
671     }
672
673     /* Get the char, handle as unsigned. Be sure to translate it into
674      * the target character set.
675      */
676     C = TgtTranslateChar (Str [(size_t)Index]);
677
678     /* Return the char expression */
679     return GenLiteralExpr (C);
680 }
681
682
683
684 static ExprNode* FuncStrLen (void)
685 /* Handle the .STRLEN function */
686 {
687     int Len;
688
689     /* String constant expected */
690     if (Tok != TOK_STRCON) {
691
692         Error ("String constant expected");
693         /* Smart error recovery */
694         if (Tok != TOK_RPAREN) {
695             NextTok ();
696         }
697         Len = 0;
698
699     } else {
700
701         /* Get the length of the string */
702         Len = strlen (SVal);
703
704         /* Skip the string */
705         NextTok ();
706     }
707
708     /* Return the length */
709     return GenLiteralExpr (Len);
710 }
711
712
713
714 static ExprNode* FuncTCount (void)
715 /* Handle the .TCOUNT function */
716 {
717     /* We have a list of tokens that ends with the closing paren. Skip
718      * the tokens, and count them. Allow optionally curly braces.
719      */
720     enum Token Term = GetTokListTerm (TOK_RPAREN);
721     int Count = 0;
722     while (Tok != Term) {
723
724         /* Check for end of line or end of input. Since the calling function
725          * will check for the closing paren, we don't need to print an error
726          * here, just bail out.
727          */
728         if (TokIsSep (Tok)) {
729             break;
730         }
731
732         /* One more token */
733         ++Count;
734
735         /* Skip the token */
736         NextTok ();
737     }
738
739     /* If the list was enclosed in curly braces, skip the closing brace */
740     if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
741         NextTok ();
742     }
743
744     /* Return the number of tokens */
745     return GenLiteralExpr (Count);
746 }
747
748
749
750 static ExprNode* FuncXMatch (void)
751 /* Handle the .XMATCH function */
752 {
753     return DoMatch (tcIdentical);
754 }
755
756
757
758 static ExprNode* Function (ExprNode* (*F) (void))
759 /* Handle builtin functions */
760 {
761     ExprNode* E;
762
763     /* Skip the keyword */
764     NextTok ();
765
766     /* Expression must be enclosed in braces */
767     if (Tok != TOK_LPAREN) {
768         Error ("'(' expected");
769         SkipUntilSep ();
770         return GenLiteral0 ();
771     }
772     NextTok ();
773
774     /* Call the function itself */
775     E = F ();
776
777     /* Closing brace must follow */
778     ConsumeRParen ();
779
780     /* Return the result of the actual function */
781     return E;
782 }
783
784
785
786 static ExprNode* Factor (void)
787 {
788     ExprNode* L;
789     ExprNode* N;
790     long      Val;
791
792     switch (Tok) {
793
794         case TOK_INTCON:
795             N = GenLiteralExpr (IVal);
796             NextTok ();
797             break;
798
799         case TOK_CHARCON:
800             N = GenLiteralExpr (TgtTranslateChar (IVal));
801             NextTok ();
802             break;
803
804         case TOK_NAMESPACE:
805         case TOK_IDENT:
806             N = Symbol (ParseScopedSymName (SYM_ALLOC_NEW));
807             break;
808
809         case TOK_LOCAL_IDENT:
810             N = Symbol (SymFindLocal (SymLast, SVal, SYM_ALLOC_NEW));
811             NextTok ();
812             break;
813
814         case TOK_ULABEL:
815             N = ULabRef (IVal);
816             NextTok ();
817             break;
818
819         case TOK_PLUS:
820             NextTok ();
821             N = Factor ();
822             break;
823
824         case TOK_MINUS:
825             NextTok ();
826             L = Factor ();
827             if (IsEasyConst (L, &Val)) {
828                 FreeExpr (L);
829                 N = GenLiteralExpr (-Val);
830             } else {
831                 N = NewExprNode (EXPR_UNARY_MINUS);
832                 N->Left = L;
833             }
834             break;
835
836         case TOK_NOT:
837             NextTok ();
838             L = Factor ();
839             if (IsEasyConst (L, &Val)) {
840                 FreeExpr (L);
841                 N = GenLiteralExpr (~Val);
842             } else {
843                 N = NewExprNode (EXPR_NOT);
844                 N->Left = L;
845             }
846             break;
847
848         case TOK_STAR:
849         case TOK_PC:
850             NextTok ();
851             N = GenCurrentPC ();
852             break;
853
854         case TOK_LT:
855             NextTok ();
856             N = LoByte (Factor ());
857             break;
858
859         case TOK_GT:
860             NextTok ();
861             N = HiByte (Factor ());
862             break;
863
864         case TOK_BANK:
865             NextTok ();
866             N = BankByte (Factor ());
867             break;
868
869         case TOK_LPAREN:
870             NextTok ();
871             N = Expr0 ();
872             ConsumeRParen ();
873             break;
874
875         case TOK_BANKBYTE:
876             N = Function (FuncBankByte);
877             break;
878
879         case TOK_BLANK:
880             N = Function (FuncBlank);
881             break;
882
883         case TOK_CONST:
884             N = Function (FuncConst);
885             break;
886
887         case TOK_CPU:
888             N = GenLiteralExpr (CPUIsets[CPU]);
889             NextTok ();
890             break;
891
892         case TOK_DEFINED:
893             N = Function (FuncDefined);
894             break;
895
896         case TOK_HIBYTE:
897             N = Function (FuncHiByte);
898             break;
899
900         case TOK_HIWORD:
901             N = Function (FuncHiWord);
902             break;
903
904         case TOK_LOBYTE:
905             N = Function (FuncLoByte);
906             break;
907
908         case TOK_LOWORD:
909             N = Function (FuncLoWord);
910             break;
911
912         case TOK_MATCH:
913             N = Function (FuncMatch);
914             break;
915
916         case TOK_REFERENCED:
917             N = Function (FuncReferenced);
918             break;
919
920         case TOK_SIZEOF:
921             N = Function (FuncSizeOf);
922             break;
923
924         case TOK_STRAT:
925             N = Function (FuncStrAt);
926             break;
927
928         case TOK_STRLEN:
929             N = Function (FuncStrLen);
930             break;
931
932         case TOK_TCOUNT:
933             N = Function (FuncTCount);
934             break;
935
936         case TOK_TIME:
937             N = GenLiteralExpr (time (0));
938             NextTok ();
939             break;
940
941         case TOK_VERSION:
942             N = GenLiteralExpr (VERSION);
943             NextTok ();
944             break;
945
946         case TOK_XMATCH:
947             N = Function (FuncXMatch);
948             break;
949
950         default:
951             if (LooseCharTerm && Tok == TOK_STRCON && strlen(SVal) == 1) {
952                 /* A character constant */
953                 N = GenLiteralExpr (TgtTranslateChar (SVal[0]));
954             } else {
955                 N = GenLiteral0 ();     /* Dummy */
956                 Error ("Syntax error");
957             }
958             NextTok ();
959             break;
960     }
961     return N;
962 }
963
964
965
966 static ExprNode* Term (void)
967 {
968     /* Read left hand side */
969     ExprNode* Root = Factor ();
970
971     /* Handle multiplicative operations */
972     while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
973            Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
974            Tok == TOK_SHR) {
975
976         long LVal, RVal, Val;
977         ExprNode* Left;
978         ExprNode* Right;
979
980         /* Remember the token and skip it */
981         enum Token T = Tok;
982         NextTok ();
983
984         /* Move root to left side and read the right side */
985         Left  = Root;
986         Right = Factor ();
987
988         /* If both expressions are constant, we can evaluate the term */
989         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
990
991             switch (T) {
992                 case TOK_MUL:
993                     Val = LVal * RVal;
994                     break;
995
996                 case TOK_DIV:
997                     if (RVal == 0) {
998                         Error ("Division by zero");
999                         Val = 1;
1000                     } else {
1001                         Val = LVal / RVal;
1002                     }
1003                     break;
1004
1005                 case TOK_MOD:
1006                     if (RVal == 0) {
1007                         Error ("Modulo operation with zero");
1008                         Val = 1;
1009                     } else {
1010                         Val = LVal % RVal;
1011                     }
1012                     break;
1013
1014                 case TOK_AND:
1015                     Val = LVal & RVal;
1016                     break;
1017
1018                 case TOK_XOR:
1019                     Val = LVal ^ RVal;
1020                     break;
1021
1022                 case TOK_SHL:
1023                     Val = shl_l (LVal, RVal);
1024                     break;
1025
1026                 case TOK_SHR:
1027                     Val = shr_l (LVal, RVal);
1028                     break;
1029
1030                 default:
1031                     Internal ("Invalid token");
1032             }
1033
1034             /* Generate a literal expression and delete the old left and
1035              * right sides.
1036              */
1037             FreeExpr (Left);
1038             FreeExpr (Right);
1039             Root = GenLiteralExpr (Val);
1040
1041         } else {
1042
1043             /* Generate an expression tree */
1044             unsigned char Op;
1045             switch (T) {
1046                 case TOK_MUL:   Op = EXPR_MUL;  break;
1047                 case TOK_DIV:   Op = EXPR_DIV;  break;
1048                 case TOK_MOD:   Op = EXPR_MOD;  break;
1049                 case TOK_AND:   Op = EXPR_AND;  break;
1050                 case TOK_XOR:   Op = EXPR_XOR;  break;
1051                 case TOK_SHL:   Op = EXPR_SHL;  break;
1052                 case TOK_SHR:   Op = EXPR_SHR;  break;
1053                 default:        Internal ("Invalid token");
1054             }
1055             Root        = NewExprNode (Op);
1056             Root->Left  = Left;
1057             Root->Right = Right;
1058
1059         }
1060
1061     }
1062
1063     /* Return the expression tree we've created */
1064     return Root;
1065 }
1066
1067
1068
1069 static ExprNode* SimpleExpr (void)
1070 {
1071     /* Read left hand side */
1072     ExprNode* Root = Term ();
1073
1074     /* Handle additive operations */
1075     while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
1076
1077         long LVal, RVal, Val;
1078         ExprNode* Left;
1079         ExprNode* Right;
1080
1081         /* Remember the token and skip it */
1082         enum Token T = Tok;
1083         NextTok ();
1084
1085         /* Move root to left side and read the right side */
1086         Left  = Root;
1087         Right = Term ();
1088
1089         /* If both expressions are constant, we can evaluate the term */
1090         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1091
1092             switch (T) {
1093                 case TOK_PLUS:  Val = LVal + RVal;      break;
1094                 case TOK_MINUS: Val = LVal - RVal;      break;
1095                 case TOK_OR:    Val = LVal | RVal;      break;
1096                 default:        Internal ("Invalid token");
1097             }
1098
1099             /* Generate a literal expression and delete the old left and
1100              * right sides.
1101              */
1102             FreeExpr (Left);
1103             FreeExpr (Right);
1104             Root = GenLiteralExpr (Val);
1105
1106         } else {
1107
1108             /* Generate an expression tree */
1109             unsigned char Op;
1110             switch (T) {
1111                 case TOK_PLUS:  Op = EXPR_PLUS;  break;
1112                 case TOK_MINUS: Op = EXPR_MINUS; break;
1113                 case TOK_OR:    Op = EXPR_OR;    break;
1114                 default:        Internal ("Invalid token");
1115             }
1116             Root        = NewExprNode (Op);
1117             Root->Left  = Left;
1118             Root->Right = Right;
1119
1120         }
1121     }
1122
1123     /* Return the expression tree we've created */
1124     return Root;
1125 }
1126
1127
1128
1129 static ExprNode* BoolExpr (void)
1130 /* Evaluate a boolean expression */
1131 {
1132     /* Read left hand side */
1133     ExprNode* Root = SimpleExpr ();
1134
1135     /* Handle booleans */
1136     while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
1137            Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
1138
1139         long LVal, RVal, Val;
1140         ExprNode* Left;
1141         ExprNode* Right;
1142
1143         /* Remember the token and skip it */
1144         enum Token T = Tok;
1145         NextTok ();
1146
1147         /* Move root to left side and read the right side */
1148         Left  = Root;
1149         Right = SimpleExpr ();
1150
1151         /* If both expressions are constant, we can evaluate the term */
1152         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1153
1154             switch (T) {
1155                 case TOK_EQ:    Val = (LVal == RVal);   break;
1156                 case TOK_NE:    Val = (LVal != RVal);   break;
1157                 case TOK_LT:    Val = (LVal < RVal);    break;
1158                 case TOK_GT:    Val = (LVal > RVal);    break;
1159                 case TOK_LE:    Val = (LVal <= RVal);   break;
1160                 case TOK_GE:    Val = (LVal >= RVal);   break;
1161                 default:        Internal ("Invalid token");
1162             }
1163
1164             /* Generate a literal expression and delete the old left and
1165              * right sides.
1166              */
1167             FreeExpr (Left);
1168             FreeExpr (Right);
1169             Root = GenLiteralExpr (Val);
1170
1171         } else {
1172
1173             /* Generate an expression tree */
1174             unsigned char Op;
1175             switch (T) {
1176                 case TOK_EQ:    Op = EXPR_EQ;   break;
1177                 case TOK_NE:    Op = EXPR_NE;   break;
1178                 case TOK_LT:    Op = EXPR_LT;   break;
1179                 case TOK_GT:    Op = EXPR_GT;   break;
1180                 case TOK_LE:    Op = EXPR_LE;   break;
1181                 case TOK_GE:    Op = EXPR_GE;   break;
1182                 default:        Internal ("Invalid token");
1183             }
1184             Root        = NewExprNode (Op);
1185             Root->Left  = Left;
1186             Root->Right = Right;
1187
1188         }
1189     }
1190
1191     /* Return the expression tree we've created */
1192     return Root;
1193 }
1194
1195
1196
1197 static ExprNode* Expr2 (void)
1198 /* Boolean operators: AND and XOR */
1199 {
1200     /* Read left hand side */
1201     ExprNode* Root = BoolExpr ();
1202
1203     /* Handle booleans */
1204     while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
1205
1206         long LVal, RVal, Val;
1207         ExprNode* Left;
1208         ExprNode* Right;
1209
1210         /* Remember the token and skip it */
1211         enum Token T = Tok;
1212         NextTok ();
1213
1214         /* Move root to left side and read the right side */
1215         Left  = Root;
1216         Right = BoolExpr ();
1217
1218         /* If both expressions are constant, we can evaluate the term */
1219         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1220
1221             switch (T) {
1222                 case TOK_BOOLAND:   Val = ((LVal != 0) && (RVal != 0)); break;
1223                 case TOK_BOOLXOR:   Val = ((LVal != 0) ^  (RVal != 0)); break;
1224                 default:        Internal ("Invalid token");
1225             }
1226
1227             /* Generate a literal expression and delete the old left and
1228              * right sides.
1229              */
1230             FreeExpr (Left);
1231             FreeExpr (Right);
1232             Root = GenLiteralExpr (Val);
1233
1234         } else {
1235
1236             /* Generate an expression tree */
1237             unsigned char Op;
1238             switch (T) {
1239                 case TOK_BOOLAND:   Op = EXPR_BOOLAND; break;
1240                 case TOK_BOOLXOR:   Op = EXPR_BOOLXOR; break;
1241                 default:            Internal ("Invalid token");
1242             }
1243             Root        = NewExprNode (Op);
1244             Root->Left  = Left;
1245             Root->Right = Right;
1246
1247         }
1248     }
1249
1250     /* Return the expression tree we've created */
1251     return Root;
1252 }
1253
1254
1255
1256 static ExprNode* Expr1 (void)
1257 /* Boolean operators: OR */
1258 {
1259     /* Read left hand side */
1260     ExprNode* Root = Expr2 ();
1261
1262     /* Handle booleans */
1263     while (Tok == TOK_BOOLOR) {
1264
1265         long LVal, RVal, Val;
1266         ExprNode* Left;
1267         ExprNode* Right;
1268
1269         /* Remember the token and skip it */
1270         enum Token T = Tok;
1271         NextTok ();
1272
1273         /* Move root to left side and read the right side */
1274         Left  = Root;
1275         Right = Expr2 ();
1276
1277         /* If both expressions are constant, we can evaluate the term */
1278         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1279
1280             switch (T) {
1281                 case TOK_BOOLOR:    Val = ((LVal != 0) || (RVal != 0)); break;
1282                 default:        Internal ("Invalid token");
1283             }
1284
1285             /* Generate a literal expression and delete the old left and
1286              * right sides.
1287              */
1288             FreeExpr (Left);
1289             FreeExpr (Right);
1290             Root = GenLiteralExpr (Val);
1291
1292         } else {
1293
1294             /* Generate an expression tree */
1295             unsigned char Op;
1296             switch (T) {
1297                 case TOK_BOOLOR:    Op = EXPR_BOOLOR;  break;
1298                 default:            Internal ("Invalid token");
1299             }
1300             Root        = NewExprNode (Op);
1301             Root->Left  = Left;
1302             Root->Right = Right;
1303
1304         }
1305     }
1306
1307     /* Return the expression tree we've created */
1308     return Root;
1309 }
1310
1311
1312
1313 static ExprNode* Expr0 (void)
1314 /* Boolean operators: NOT */
1315 {
1316     ExprNode* Root;
1317
1318     /* Handle booleans */
1319     if (Tok == TOK_BOOLNOT) {
1320
1321         long Val;
1322         ExprNode* Left;
1323
1324         /* Skip the operator token */
1325         NextTok ();
1326
1327         /* Read the argument */
1328         Left = Expr0 ();
1329
1330         /* If the argument is const, evaluate it directly */
1331         if (IsEasyConst (Left, &Val)) {
1332             FreeExpr (Left);
1333             Root = GenLiteralExpr (!Val);
1334         } else {
1335             Root = NewExprNode (EXPR_BOOLNOT);
1336             Root->Left = Left;
1337         }
1338
1339     } else {
1340
1341         /* Read left hand side */
1342         Root = Expr1 ();
1343
1344     }
1345
1346     /* Return the expression tree we've created */
1347     return Root;
1348 }
1349
1350
1351
1352 ExprNode* Expression (void)
1353 /* Evaluate an expression, build the expression tree on the heap and return
1354  * a pointer to the root of the tree.
1355  */
1356 {
1357     return Expr0 ();
1358 }
1359
1360
1361
1362 long ConstExpression (void)
1363 /* Parse an expression. Check if the expression is const, and print an error
1364  * message if not. Return the value of the expression, or a dummy, if it is
1365  * not constant.
1366  */
1367 {
1368     long Val;
1369
1370     /* Read the expression */
1371     ExprNode* Expr = Expression ();
1372
1373     /* Study the expression */
1374     ExprDesc D;
1375     ED_Init (&D);
1376     StudyExpr (Expr, &D);
1377
1378     /* Check if the expression is constant */
1379     if (ED_IsConst (&D)) {
1380         Val = D.Val;
1381     } else {
1382         Error ("Constant expression expected");
1383         Val = 0;
1384     }
1385
1386     /* Free the expression tree and allocated memory for D */
1387     FreeExpr (Expr);
1388     ED_Done (&D);
1389
1390     /* Return the value */
1391     return Val;
1392 }
1393
1394
1395
1396 void FreeExpr (ExprNode* Root)
1397 /* Free the expression, Root is pointing to. */
1398 {
1399     if (Root) {
1400         FreeExpr (Root->Left);
1401         FreeExpr (Root->Right);
1402         FreeExprNode (Root);
1403     }
1404 }
1405
1406
1407
1408 ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
1409 /* Try to simplify the given expression tree */
1410 {
1411     if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
1412         /* No external references */
1413         FreeExpr (Expr);
1414         Expr = GenLiteralExpr (D->Val);
1415     }
1416     return Expr;
1417 }
1418
1419
1420
1421 ExprNode* GenLiteralExpr (long Val)
1422 /* Return an expression tree that encodes the given literal value */
1423 {
1424     ExprNode* Expr = NewExprNode (EXPR_LITERAL);
1425     Expr->V.Val = Val;
1426     return Expr;
1427 }
1428
1429
1430
1431 ExprNode* GenLiteral0 (void)
1432 /* Return an expression tree that encodes the the number zero */
1433 {
1434     return GenLiteralExpr (0);
1435 }
1436
1437
1438
1439 ExprNode* GenSymExpr (SymEntry* Sym)
1440 /* Return an expression node that encodes the given symbol */
1441 {
1442     ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
1443     Expr->V.Sym = Sym;
1444     SymAddExprRef (Sym, Expr);
1445     return Expr;
1446 }
1447
1448
1449
1450 static ExprNode* GenSectionExpr (unsigned SegNum)
1451 /* Return an expression node for the given section */
1452 {
1453     ExprNode* Expr = NewExprNode (EXPR_SECTION);
1454     Expr->V.SegNum = SegNum;
1455     return Expr;
1456 }
1457
1458
1459
1460 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
1461 /* Generate an addition from the two operands */
1462 {
1463     long Val;
1464     if (IsEasyConst (Left, &Val) && Val == 0) {
1465         FreeExpr (Left);
1466         return Right;
1467     } else if (IsEasyConst (Right, &Val) && Val == 0) {
1468         FreeExpr (Right);
1469         return Left;
1470     } else {
1471         ExprNode* Root = NewExprNode (EXPR_PLUS);
1472         Root->Left = Left;
1473         Root->Right = Right;
1474         return Root;
1475     }
1476 }
1477
1478
1479
1480 ExprNode* GenCurrentPC (void)
1481 /* Return the current program counter as expression */
1482 {
1483     ExprNode* Root;
1484
1485     if (RelocMode) {
1486         /* Create SegmentBase + Offset */
1487         Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
1488                            GenLiteralExpr (GetPC ()));
1489     } else {
1490         /* Absolute mode, just return PC value */
1491         Root = GenLiteralExpr (GetPC ());
1492     }
1493
1494     return Root;
1495 }
1496
1497
1498
1499 ExprNode* GenSwapExpr (ExprNode* Expr)
1500 /* Return an extended expression with lo and hi bytes swapped */
1501 {
1502     ExprNode* N = NewExprNode (EXPR_SWAP);
1503     N->Left = Expr;
1504     return N;
1505 }
1506
1507
1508
1509 ExprNode* GenBranchExpr (unsigned Offs)
1510 /* Return an expression that encodes the difference between current PC plus
1511  * offset and the target expression (that is, Expression() - (*+Offs) ).
1512  */
1513 {
1514     ExprNode* N;
1515     ExprNode* Root;
1516     long      Val;
1517
1518     /* Read Expression() */
1519     N = Expression ();
1520
1521     /* If the expression is a cheap constant, generate a simpler tree */
1522     if (IsEasyConst (N, &Val)) {
1523
1524         /* Free the constant expression tree */
1525         FreeExpr (N);
1526
1527         /* Generate the final expression:
1528          * Val - (* + Offs)
1529          * Val - ((Seg + PC) + Offs)
1530          * Val - Seg - PC - Offs
1531          * (Val - PC - Offs) - Seg
1532          */
1533         Root = GenLiteralExpr (Val - GetPC () - Offs);
1534         if (RelocMode) {
1535             N = Root;
1536             Root = NewExprNode (EXPR_MINUS);
1537             Root->Left  = N;
1538             Root->Right = GenSectionExpr (GetCurrentSegNum ());
1539         }
1540
1541     } else {
1542
1543         /* Generate the expression:
1544          * N - (* + Offs)
1545          * N - ((Seg + PC) + Offs)
1546          * N - Seg - PC - Offs
1547          * N - (PC + Offs) - Seg
1548          */
1549         Root = NewExprNode (EXPR_MINUS);
1550         Root->Left  = N;
1551         Root->Right = GenLiteralExpr (GetPC () + Offs);
1552         if (RelocMode) {
1553             N = Root;
1554             Root = NewExprNode (EXPR_MINUS);
1555             Root->Left  = N;
1556             Root->Right = GenSectionExpr (GetCurrentSegNum ());
1557         }
1558     }
1559
1560     /* Return the result */
1561     return Root;
1562 }
1563
1564
1565
1566 ExprNode* GenULabelExpr (unsigned Num)
1567 /* Return an expression for an unnamed label with the given index */
1568 {
1569     ExprNode* Node = NewExprNode (EXPR_ULABEL);
1570     Node->V.Val = Num;
1571
1572     /* Return the new node */
1573     return Node;
1574 }
1575
1576
1577
1578 ExprNode* GenByteExpr (ExprNode* Expr)
1579 /* Force the given expression into a byte and return the result */
1580 {
1581     /* Use the low byte operator to force the expression into byte size */
1582     return LoByte (Expr);
1583 }
1584
1585
1586
1587 ExprNode* GenWordExpr (ExprNode* Expr)
1588 /* Force the given expression into a word and return the result. */
1589 {
1590     /* Use the low byte operator to force the expression into word size */
1591     return LoWord (Expr);
1592 }
1593
1594
1595
1596 ExprNode* GenNE (ExprNode* Expr, long Val)
1597 /* Generate an expression that compares Expr and Val for inequality */
1598 {
1599     /* Generate a compare node */
1600     ExprNode* Root = NewExprNode (EXPR_NE);
1601     Root->Left  = Expr;
1602     Root->Right = GenLiteralExpr (Val);
1603
1604     /* Return the result */
1605     return Root;
1606 }
1607
1608
1609
1610 int IsConstExpr (ExprNode* Expr, long* Val)
1611 /* Return true if the given expression is a constant expression, that is, one
1612  * with no references to external symbols. If Val is not NULL and the
1613  * expression is constant, the constant value is stored here.
1614  */
1615 {
1616     int IsConst;
1617
1618     /* Study the expression */
1619     ExprDesc D;
1620     ED_Init (&D);
1621     StudyExpr (Expr, &D);
1622
1623     /* Check if the expression is constant */
1624     IsConst = ED_IsConst (&D);
1625     if (IsConst && Val != 0) {
1626         *Val = D.Val;
1627     }
1628
1629     /* Delete allocated memory and return the result */
1630     ED_Done (&D);
1631     return IsConst;
1632 }
1633
1634
1635
1636 ExprNode* CloneExpr (ExprNode* Expr)
1637 /* Clone the given expression tree. The function will simply clone symbol
1638  * nodes, it will not resolve them.
1639  */
1640 {
1641     ExprNode* Clone;
1642
1643     /* Accept NULL pointers */
1644     if (Expr == 0) {
1645         return 0;
1646     }
1647
1648     /* Clone the node */
1649     switch (Expr->Op) {
1650
1651         case EXPR_LITERAL:
1652             Clone = GenLiteralExpr (Expr->V.Val);
1653             break;
1654
1655         case EXPR_ULABEL:
1656             Clone = GenULabelExpr (Expr->V.Val);
1657             break;
1658
1659         case EXPR_SYMBOL:
1660             Clone = GenSymExpr (Expr->V.Sym);
1661             break;
1662
1663         case EXPR_SECTION:
1664             Clone = GenSectionExpr (Expr->V.SegNum);
1665             break;
1666
1667         default:
1668             /* Generate a new node */
1669             Clone = NewExprNode (Expr->Op);
1670             /* Clone the tree nodes */
1671             Clone->Left = CloneExpr (Expr->Left);
1672             Clone->Right = CloneExpr (Expr->Right);
1673             break;
1674     }
1675
1676     /* Done */
1677     return Clone;
1678 }
1679
1680
1681
1682 void WriteExpr (ExprNode* Expr)
1683 /* Write the given expression to the object file */
1684 {
1685     /* Null expressions are encoded by a type byte of zero */
1686     if (Expr == 0) {
1687         ObjWrite8 (EXPR_NULL);
1688         return;
1689     }
1690
1691     /* If the is a leafnode, write the expression attribute, otherwise
1692      * write the expression operands.
1693      */
1694     switch (Expr->Op) {
1695
1696         case EXPR_LITERAL:
1697             ObjWrite8 (EXPR_LITERAL);
1698             ObjWrite32 (Expr->V.Val);
1699             break;
1700
1701         case EXPR_SYMBOL:
1702             if (SymIsImport (Expr->V.Sym)) {
1703                 ObjWrite8 (EXPR_SYMBOL);
1704                 ObjWriteVar (GetSymIndex (Expr->V.Sym));
1705             } else {
1706                 WriteExpr (GetSymExpr (Expr->V.Sym));
1707             }
1708             break;
1709
1710         case EXPR_SECTION:
1711             ObjWrite8 (EXPR_SECTION);
1712             ObjWrite8 (Expr->V.SegNum);
1713             break;
1714
1715         case EXPR_ULABEL:
1716             WriteExpr (ULabResolve (Expr->V.Val));
1717             break;
1718
1719         default:
1720             /* Not a leaf node */
1721             ObjWrite8 (Expr->Op);
1722             WriteExpr (Expr->Left);
1723             WriteExpr (Expr->Right);
1724             break;
1725
1726     }
1727 }
1728
1729
1730
1731 void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
1732 /* Mark the address size of the given expression tree as guessed. The address
1733  * size passed as argument is the one NOT used, because the actual address
1734  * size wasn't known. Example: Zero page addressing was not used because symbol
1735  * is undefined, and absolute addressing was available.
1736  * This function will actually parse the expression tree for undefined symbols,
1737  * and mark these symbols accordingly.
1738  */
1739 {
1740     /* Accept NULL expressions */
1741     if (Expr == 0) {
1742         return;
1743     }
1744
1745     /* Check the type code */
1746     switch (Expr->Op & EXPR_TYPEMASK) {
1747
1748         case EXPR_LEAFNODE:
1749             if (Expr->Op == EXPR_SYMBOL) {
1750                 if (!SymIsDef (Expr->V.Sym)) {
1751                     /* Symbol is undefined, mark it */
1752                     SymGuessedAddrSize (Expr->V.Sym, AddrSize);
1753                 }
1754             }
1755             return;
1756
1757         case EXPR_BINARYNODE:
1758             ExprGuessedAddrSize (Expr->Right, AddrSize);
1759             /* FALLTHROUGH */
1760
1761         case EXPR_UNARYNODE:
1762             ExprGuessedAddrSize (Expr->Left, AddrSize);
1763             break;
1764     }
1765 }
1766
1767
1768