]> git.sur5r.net Git - cc65/blob - src/ca65/expr.c
Move the version numbers from the interface of the version module into a new
[cc65] / src / ca65 / expr.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  expr.c                                   */
4 /*                                                                           */
5 /*             Expression evaluation for the ca65 macroassembler             */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2009, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 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.IVal;
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 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     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 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 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     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 = STATIC_STRBUF_INITIALIZER;
554     StrBuf    Name = STATIC_STRBUF_INITIALIZER;
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: `%m%p'", &SVal);
572         } else {
573             SizeSym = GetSizeOfSymbol (Sym);
574         }
575
576         /* Remember and skip SVal, terminate ScopeName so it is empty */
577         SB_Copy (&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             SB_Done (&ScopeName);
590             SB_Done (&Name);
591             return GenLiteral0 ();
592         }
593
594         /* If ScopeName is empty, no explicit scope was specified. We have to
595          * search upper scope levels in this case.
596          */
597         NoScope = SB_IsEmpty (&ScopeName);
598
599         /* First search for a scope with the given name */
600         if (NoScope) {
601             Scope = SymFindAnyScope (ParentScope, &Name);
602         } else {
603             Scope = SymFindScope (ParentScope, &Name, SYM_FIND_EXISTING);
604         }
605
606         /* If we did find a scope with the name, read the symbol defining the
607          * size, otherwise search for a symbol entry with the name and scope.
608          */
609         if (Scope) {
610             /* Yep, it's a scope */
611             SizeSym = GetSizeOfScope (Scope);
612         } else {
613             if (NoScope) {
614                 Sym = SymFindAny (ParentScope, &Name);
615             } else {
616                 Sym = SymFind (ParentScope, &Name, SYM_FIND_EXISTING);
617             }
618
619             /* If we found the symbol retrieve the size, otherwise complain */
620             if (Sym) {
621                 SizeSym = GetSizeOfSymbol (Sym);
622             } else {
623                 Error ("Unknown symbol or scope: `%m%p%m%p'",
624                        &ScopeName, &Name);
625             }
626         }
627     }
628
629     /* Check if we have a size */
630     if (SizeSym == 0 || !SymIsConst (SizeSym, &Size)) {
631         Error ("Size of `%m%p%m%p' is unknown", &ScopeName, &Name);
632         Size = 0;
633     }
634
635     /* Free the string buffers */
636     SB_Done (&ScopeName);
637     SB_Done (&Name);
638
639     /* Return the size */
640     return GenLiteralExpr (Size);
641 }
642
643
644
645 static ExprNode* FuncStrAt (void)
646 /* Handle the .STRAT function */
647 {
648     StrBuf Str = STATIC_STRBUF_INITIALIZER;
649     long Index;
650     unsigned char C = 0;
651
652     /* String constant expected */
653     if (Tok != TOK_STRCON) {
654         Error ("String constant expected");
655         NextTok ();
656         goto ExitPoint;
657     }
658
659     /* Remember the string and skip it */
660     SB_Copy (&Str, &SVal);
661     NextTok ();
662
663     /* Comma must follow */
664     ConsumeComma ();
665
666     /* Expression expected */
667     Index = ConstExpression ();
668
669     /* Must be a valid index */
670     if (Index >= (long) SB_GetLen (&Str)) {
671         Error ("Range error");
672         goto ExitPoint;
673     }
674
675     /* Get the char, handle as unsigned. Be sure to translate it into
676      * the target character set.
677      */
678     C = TgtTranslateChar (SB_At (&Str, (unsigned)Index));
679
680 ExitPoint:
681     /* Free string buffer memory */
682     SB_Done (&Str);
683
684     /* Return the char expression */
685     return GenLiteralExpr (C);
686 }
687
688
689
690 static ExprNode* FuncStrLen (void)
691 /* Handle the .STRLEN function */
692 {
693     int Len;
694
695     /* String constant expected */
696     if (Tok != TOK_STRCON) {
697
698         Error ("String constant expected");
699         /* Smart error recovery */
700         if (Tok != TOK_RPAREN) {
701             NextTok ();
702         }
703         Len = 0;
704
705     } else {
706
707         /* Get the length of the string */
708         Len = SB_GetLen (&SVal);
709
710         /* Skip the string */
711         NextTok ();
712     }
713
714     /* Return the length */
715     return GenLiteralExpr (Len);
716 }
717
718
719
720 static ExprNode* FuncTCount (void)
721 /* Handle the .TCOUNT function */
722 {
723     /* We have a list of tokens that ends with the closing paren. Skip
724      * the tokens, and count them. Allow optionally curly braces.
725      */
726     Token Term = GetTokListTerm (TOK_RPAREN);
727     int Count = 0;
728     while (Tok != Term) {
729
730         /* Check for end of line or end of input. Since the calling function
731          * will check for the closing paren, we don't need to print an error
732          * here, just bail out.
733          */
734         if (TokIsSep (Tok)) {
735             break;
736         }
737
738         /* One more token */
739         ++Count;
740
741         /* Skip the token */
742         NextTok ();
743     }
744
745     /* If the list was enclosed in curly braces, skip the closing brace */
746     if (Term == TOK_RCURLY && Tok == TOK_RCURLY) {
747         NextTok ();
748     }
749
750     /* Return the number of tokens */
751     return GenLiteralExpr (Count);
752 }
753
754
755
756 static ExprNode* FuncXMatch (void)
757 /* Handle the .XMATCH function */
758 {
759     return DoMatch (tcIdentical);
760 }
761
762
763
764 static ExprNode* Function (ExprNode* (*F) (void))
765 /* Handle builtin functions */
766 {
767     ExprNode* E;
768
769     /* Skip the keyword */
770     NextTok ();
771
772     /* Expression must be enclosed in braces */
773     if (Tok != TOK_LPAREN) {
774         Error ("'(' expected");
775         SkipUntilSep ();
776         return GenLiteral0 ();
777     }
778     NextTok ();
779
780     /* Call the function itself */
781     E = F ();
782
783     /* Closing brace must follow */
784     ConsumeRParen ();
785
786     /* Return the result of the actual function */
787     return E;
788 }
789
790
791
792 static ExprNode* Factor (void)
793 {
794     ExprNode* L;
795     ExprNode* N;
796     long      Val;
797
798     switch (Tok) {
799
800         case TOK_INTCON:
801             N = GenLiteralExpr (IVal);
802             NextTok ();
803             break;
804
805         case TOK_CHARCON:
806             N = GenLiteralExpr (TgtTranslateChar (IVal));
807             NextTok ();
808             break;
809
810         case TOK_NAMESPACE:
811         case TOK_IDENT:
812             N = Symbol (ParseScopedSymName (SYM_ALLOC_NEW));
813             break;
814
815         case TOK_LOCAL_IDENT:
816             N = Symbol (SymFindLocal (SymLast, &SVal, SYM_ALLOC_NEW));
817             NextTok ();
818             break;
819
820         case TOK_ULABEL:
821             N = ULabRef (IVal);
822             NextTok ();
823             break;
824
825         case TOK_PLUS:
826             NextTok ();
827             N = Factor ();
828             break;
829
830         case TOK_MINUS:
831             NextTok ();
832             L = Factor ();
833             if (IsEasyConst (L, &Val)) {
834                 FreeExpr (L);
835                 N = GenLiteralExpr (-Val);
836             } else {
837                 N = NewExprNode (EXPR_UNARY_MINUS);
838                 N->Left = L;
839             }
840             break;
841
842         case TOK_NOT:
843             NextTok ();
844             L = Factor ();
845             if (IsEasyConst (L, &Val)) {
846                 FreeExpr (L);
847                 N = GenLiteralExpr (~Val);
848             } else {
849                 N = NewExprNode (EXPR_NOT);
850                 N->Left = L;
851             }
852             break;
853
854         case TOK_STAR:
855         case TOK_PC:
856             NextTok ();
857             N = GenCurrentPC ();
858             break;
859
860         case TOK_LT:
861             NextTok ();
862             N = LoByte (Factor ());
863             break;
864
865         case TOK_GT:
866             NextTok ();
867             N = HiByte (Factor ());
868             break;
869
870         case TOK_BANK:
871             NextTok ();
872             N = BankByte (Factor ());
873             break;
874
875         case TOK_LPAREN:
876             NextTok ();
877             N = Expr0 ();
878             ConsumeRParen ();
879             break;
880
881         case TOK_BANKBYTE:
882             N = Function (FuncBankByte);
883             break;
884
885         case TOK_BLANK:
886             N = Function (FuncBlank);
887             break;
888
889         case TOK_CONST:
890             N = Function (FuncConst);
891             break;
892
893         case TOK_CPU:
894             N = GenLiteralExpr (CPUIsets[CPU]);
895             NextTok ();
896             break;
897
898         case TOK_DEFINED:
899             N = Function (FuncDefined);
900             break;
901
902         case TOK_HIBYTE:
903             N = Function (FuncHiByte);
904             break;
905
906         case TOK_HIWORD:
907             N = Function (FuncHiWord);
908             break;
909
910         case TOK_LOBYTE:
911             N = Function (FuncLoByte);
912             break;
913
914         case TOK_LOWORD:
915             N = Function (FuncLoWord);
916             break;
917
918         case TOK_MATCH:
919             N = Function (FuncMatch);
920             break;
921
922         case TOK_REFERENCED:
923             N = Function (FuncReferenced);
924             break;
925
926         case TOK_SIZEOF:
927             N = Function (FuncSizeOf);
928             break;
929
930         case TOK_STRAT:
931             N = Function (FuncStrAt);
932             break;
933
934         case TOK_STRLEN:
935             N = Function (FuncStrLen);
936             break;
937
938         case TOK_TCOUNT:
939             N = Function (FuncTCount);
940             break;
941
942         case TOK_TIME:
943             N = GenLiteralExpr (time (0));
944             NextTok ();
945             break;
946
947         case TOK_VERSION:
948             N = GenLiteralExpr (GetVersionAsNumber ());
949             NextTok ();
950             break;
951
952         case TOK_XMATCH:
953             N = Function (FuncXMatch);
954             break;
955
956         default:
957             if (LooseCharTerm && Tok == TOK_STRCON && SB_GetLen (&SVal) == 1) {
958                 /* A character constant */
959                 N = GenLiteralExpr (TgtTranslateChar (SB_At (&SVal, 0)));
960             } else {
961                 N = GenLiteral0 ();     /* Dummy */
962                 Error ("Syntax error");
963             }
964             NextTok ();
965             break;
966     }
967     return N;
968 }
969
970
971
972 static ExprNode* Term (void)
973 {
974     /* Read left hand side */
975     ExprNode* Root = Factor ();
976
977     /* Handle multiplicative operations */
978     while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
979            Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
980            Tok == TOK_SHR) {
981
982         long LVal, RVal, Val;
983         ExprNode* Left;
984         ExprNode* Right;
985
986         /* Remember the token and skip it */
987         Token T = Tok;
988         NextTok ();
989
990         /* Move root to left side and read the right side */
991         Left  = Root;
992         Right = Factor ();
993
994         /* If both expressions are constant, we can evaluate the term */
995         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
996
997             switch (T) {
998                 case TOK_MUL:
999                     Val = LVal * RVal;
1000                     break;
1001
1002                 case TOK_DIV:
1003                     if (RVal == 0) {
1004                         Error ("Division by zero");
1005                         Val = 1;
1006                     } else {
1007                         Val = LVal / RVal;
1008                     }
1009                     break;
1010
1011                 case TOK_MOD:
1012                     if (RVal == 0) {
1013                         Error ("Modulo operation with zero");
1014                         Val = 1;
1015                     } else {
1016                         Val = LVal % RVal;
1017                     }
1018                     break;
1019
1020                 case TOK_AND:
1021                     Val = LVal & RVal;
1022                     break;
1023
1024                 case TOK_XOR:
1025                     Val = LVal ^ RVal;
1026                     break;
1027
1028                 case TOK_SHL:
1029                     Val = shl_l (LVal, RVal);
1030                     break;
1031
1032                 case TOK_SHR:
1033                     Val = shr_l (LVal, RVal);
1034                     break;
1035
1036                 default:
1037                     Internal ("Invalid token");
1038             }
1039
1040             /* Generate a literal expression and delete the old left and
1041              * right sides.
1042              */
1043             FreeExpr (Left);
1044             FreeExpr (Right);
1045             Root = GenLiteralExpr (Val);
1046
1047         } else {
1048
1049             /* Generate an expression tree */
1050             unsigned char Op;
1051             switch (T) {
1052                 case TOK_MUL:   Op = EXPR_MUL;  break;
1053                 case TOK_DIV:   Op = EXPR_DIV;  break;
1054                 case TOK_MOD:   Op = EXPR_MOD;  break;
1055                 case TOK_AND:   Op = EXPR_AND;  break;
1056                 case TOK_XOR:   Op = EXPR_XOR;  break;
1057                 case TOK_SHL:   Op = EXPR_SHL;  break;
1058                 case TOK_SHR:   Op = EXPR_SHR;  break;
1059                 default:        Internal ("Invalid token");
1060             }
1061             Root        = NewExprNode (Op);
1062             Root->Left  = Left;
1063             Root->Right = Right;
1064
1065         }
1066
1067     }
1068
1069     /* Return the expression tree we've created */
1070     return Root;
1071 }
1072
1073
1074
1075 static ExprNode* SimpleExpr (void)
1076 {
1077     /* Read left hand side */
1078     ExprNode* Root = Term ();
1079
1080     /* Handle additive operations */
1081     while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
1082
1083         long LVal, RVal, Val;
1084         ExprNode* Left;
1085         ExprNode* Right;
1086
1087         /* Remember the token and skip it */
1088         Token T = Tok;
1089         NextTok ();
1090
1091         /* Move root to left side and read the right side */
1092         Left  = Root;
1093         Right = Term ();
1094
1095         /* If both expressions are constant, we can evaluate the term */
1096         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1097
1098             switch (T) {
1099                 case TOK_PLUS:  Val = LVal + RVal;      break;
1100                 case TOK_MINUS: Val = LVal - RVal;      break;
1101                 case TOK_OR:    Val = LVal | RVal;      break;
1102                 default:        Internal ("Invalid token");
1103             }
1104
1105             /* Generate a literal expression and delete the old left and
1106              * right sides.
1107              */
1108             FreeExpr (Left);
1109             FreeExpr (Right);
1110             Root = GenLiteralExpr (Val);
1111
1112         } else {
1113
1114             /* Generate an expression tree */
1115             unsigned char Op;
1116             switch (T) {
1117                 case TOK_PLUS:  Op = EXPR_PLUS;  break;
1118                 case TOK_MINUS: Op = EXPR_MINUS; break;
1119                 case TOK_OR:    Op = EXPR_OR;    break;
1120                 default:        Internal ("Invalid token");
1121             }
1122             Root        = NewExprNode (Op);
1123             Root->Left  = Left;
1124             Root->Right = Right;
1125
1126         }
1127     }
1128
1129     /* Return the expression tree we've created */
1130     return Root;
1131 }
1132
1133
1134
1135 static ExprNode* BoolExpr (void)
1136 /* Evaluate a boolean expression */
1137 {
1138     /* Read left hand side */
1139     ExprNode* Root = SimpleExpr ();
1140
1141     /* Handle booleans */
1142     while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
1143            Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
1144
1145         long LVal, RVal, Val;
1146         ExprNode* Left;
1147         ExprNode* Right;
1148
1149         /* Remember the token and skip it */
1150         Token T = Tok;
1151         NextTok ();
1152
1153         /* Move root to left side and read the right side */
1154         Left  = Root;
1155         Right = SimpleExpr ();
1156
1157         /* If both expressions are constant, we can evaluate the term */
1158         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1159
1160             switch (T) {
1161                 case TOK_EQ:    Val = (LVal == RVal);   break;
1162                 case TOK_NE:    Val = (LVal != RVal);   break;
1163                 case TOK_LT:    Val = (LVal < RVal);    break;
1164                 case TOK_GT:    Val = (LVal > RVal);    break;
1165                 case TOK_LE:    Val = (LVal <= RVal);   break;
1166                 case TOK_GE:    Val = (LVal >= RVal);   break;
1167                 default:        Internal ("Invalid token");
1168             }
1169
1170             /* Generate a literal expression and delete the old left and
1171              * right sides.
1172              */
1173             FreeExpr (Left);
1174             FreeExpr (Right);
1175             Root = GenLiteralExpr (Val);
1176
1177         } else {
1178
1179             /* Generate an expression tree */
1180             unsigned char Op;
1181             switch (T) {
1182                 case TOK_EQ:    Op = EXPR_EQ;   break;
1183                 case TOK_NE:    Op = EXPR_NE;   break;
1184                 case TOK_LT:    Op = EXPR_LT;   break;
1185                 case TOK_GT:    Op = EXPR_GT;   break;
1186                 case TOK_LE:    Op = EXPR_LE;   break;
1187                 case TOK_GE:    Op = EXPR_GE;   break;
1188                 default:        Internal ("Invalid token");
1189             }
1190             Root        = NewExprNode (Op);
1191             Root->Left  = Left;
1192             Root->Right = Right;
1193
1194         }
1195     }
1196
1197     /* Return the expression tree we've created */
1198     return Root;
1199 }
1200
1201
1202
1203 static ExprNode* Expr2 (void)
1204 /* Boolean operators: AND and XOR */
1205 {
1206     /* Read left hand side */
1207     ExprNode* Root = BoolExpr ();
1208
1209     /* Handle booleans */
1210     while (Tok == TOK_BOOLAND || Tok == TOK_BOOLXOR) {
1211
1212         long LVal, RVal, Val;
1213         ExprNode* Left;
1214         ExprNode* Right;
1215
1216         /* Remember the token and skip it */
1217         Token T = Tok;
1218         NextTok ();
1219
1220         /* Move root to left side and read the right side */
1221         Left  = Root;
1222         Right = BoolExpr ();
1223
1224         /* If both expressions are constant, we can evaluate the term */
1225         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1226
1227             switch (T) {
1228                 case TOK_BOOLAND:   Val = ((LVal != 0) && (RVal != 0)); break;
1229                 case TOK_BOOLXOR:   Val = ((LVal != 0) ^  (RVal != 0)); break;
1230                 default:        Internal ("Invalid token");
1231             }
1232
1233             /* Generate a literal expression and delete the old left and
1234              * right sides.
1235              */
1236             FreeExpr (Left);
1237             FreeExpr (Right);
1238             Root = GenLiteralExpr (Val);
1239
1240         } else {
1241
1242             /* Generate an expression tree */
1243             unsigned char Op;
1244             switch (T) {
1245                 case TOK_BOOLAND:   Op = EXPR_BOOLAND; break;
1246                 case TOK_BOOLXOR:   Op = EXPR_BOOLXOR; break;
1247                 default:            Internal ("Invalid token");
1248             }
1249             Root        = NewExprNode (Op);
1250             Root->Left  = Left;
1251             Root->Right = Right;
1252
1253         }
1254     }
1255
1256     /* Return the expression tree we've created */
1257     return Root;
1258 }
1259
1260
1261
1262 static ExprNode* Expr1 (void)
1263 /* Boolean operators: OR */
1264 {
1265     /* Read left hand side */
1266     ExprNode* Root = Expr2 ();
1267
1268     /* Handle booleans */
1269     while (Tok == TOK_BOOLOR) {
1270
1271         long LVal, RVal, Val;
1272         ExprNode* Left;
1273         ExprNode* Right;
1274
1275         /* Remember the token and skip it */
1276         Token T = Tok;
1277         NextTok ();
1278
1279         /* Move root to left side and read the right side */
1280         Left  = Root;
1281         Right = Expr2 ();
1282
1283         /* If both expressions are constant, we can evaluate the term */
1284         if (IsEasyConst (Left, &LVal) && IsEasyConst (Right, &RVal)) {
1285
1286             switch (T) {
1287                 case TOK_BOOLOR:    Val = ((LVal != 0) || (RVal != 0)); break;
1288                 default:        Internal ("Invalid token");
1289             }
1290
1291             /* Generate a literal expression and delete the old left and
1292              * right sides.
1293              */
1294             FreeExpr (Left);
1295             FreeExpr (Right);
1296             Root = GenLiteralExpr (Val);
1297
1298         } else {
1299
1300             /* Generate an expression tree */
1301             unsigned char Op;
1302             switch (T) {
1303                 case TOK_BOOLOR:    Op = EXPR_BOOLOR;  break;
1304                 default:            Internal ("Invalid token");
1305             }
1306             Root        = NewExprNode (Op);
1307             Root->Left  = Left;
1308             Root->Right = Right;
1309
1310         }
1311     }
1312
1313     /* Return the expression tree we've created */
1314     return Root;
1315 }
1316
1317
1318
1319 static ExprNode* Expr0 (void)
1320 /* Boolean operators: NOT */
1321 {
1322     ExprNode* Root;
1323
1324     /* Handle booleans */
1325     if (Tok == TOK_BOOLNOT) {
1326
1327         long Val;
1328         ExprNode* Left;
1329
1330         /* Skip the operator token */
1331         NextTok ();
1332
1333         /* Read the argument */
1334         Left = Expr0 ();
1335
1336         /* If the argument is const, evaluate it directly */
1337         if (IsEasyConst (Left, &Val)) {
1338             FreeExpr (Left);
1339             Root = GenLiteralExpr (!Val);
1340         } else {
1341             Root = NewExprNode (EXPR_BOOLNOT);
1342             Root->Left = Left;
1343         }
1344
1345     } else {
1346
1347         /* Read left hand side */
1348         Root = Expr1 ();
1349
1350     }
1351
1352     /* Return the expression tree we've created */
1353     return Root;
1354 }
1355
1356
1357
1358 ExprNode* Expression (void)
1359 /* Evaluate an expression, build the expression tree on the heap and return
1360  * a pointer to the root of the tree.
1361  */
1362 {
1363     return Expr0 ();
1364 }
1365
1366
1367
1368 long ConstExpression (void)
1369 /* Parse an expression. Check if the expression is const, and print an error
1370  * message if not. Return the value of the expression, or a dummy, if it is
1371  * not constant.
1372  */
1373 {
1374     long Val;
1375
1376     /* Read the expression */
1377     ExprNode* Expr = Expression ();
1378
1379     /* Study the expression */
1380     ExprDesc D;
1381     ED_Init (&D);
1382     StudyExpr (Expr, &D);
1383
1384     /* Check if the expression is constant */
1385     if (ED_IsConst (&D)) {
1386         Val = D.Val;
1387     } else {
1388         Error ("Constant expression expected");
1389         Val = 0;
1390     }
1391
1392     /* Free the expression tree and allocated memory for D */
1393     FreeExpr (Expr);
1394     ED_Done (&D);
1395
1396     /* Return the value */
1397     return Val;
1398 }
1399
1400
1401
1402 void FreeExpr (ExprNode* Root)
1403 /* Free the expression, Root is pointing to. */
1404 {
1405     if (Root) {
1406         FreeExpr (Root->Left);
1407         FreeExpr (Root->Right);
1408         FreeExprNode (Root);
1409     }
1410 }
1411
1412
1413
1414 ExprNode* SimplifyExpr (ExprNode* Expr, const ExprDesc* D)
1415 /* Try to simplify the given expression tree */
1416 {
1417     if (Expr->Op != EXPR_LITERAL && ED_IsConst (D)) {
1418         /* No external references */
1419         FreeExpr (Expr);
1420         Expr = GenLiteralExpr (D->Val);
1421     }
1422     return Expr;
1423 }
1424
1425
1426
1427 ExprNode* GenLiteralExpr (long Val)
1428 /* Return an expression tree that encodes the given literal value */
1429 {
1430     ExprNode* Expr = NewExprNode (EXPR_LITERAL);
1431     Expr->V.IVal = Val;
1432     return Expr;
1433 }
1434
1435
1436
1437 ExprNode* GenLiteral0 (void)
1438 /* Return an expression tree that encodes the the number zero */
1439 {
1440     return GenLiteralExpr (0);
1441 }
1442
1443
1444
1445 ExprNode* GenSymExpr (SymEntry* Sym)
1446 /* Return an expression node that encodes the given symbol */
1447 {
1448     ExprNode* Expr = NewExprNode (EXPR_SYMBOL);
1449     Expr->V.Sym = Sym;
1450     SymAddExprRef (Sym, Expr);
1451     return Expr;
1452 }
1453
1454
1455
1456 static ExprNode* GenSectionExpr (unsigned SegNum)
1457 /* Return an expression node for the given section */
1458 {
1459     ExprNode* Expr = NewExprNode (EXPR_SECTION);
1460     Expr->V.SegNum = SegNum;
1461     return Expr;
1462 }
1463
1464
1465
1466 ExprNode* GenAddExpr (ExprNode* Left, ExprNode* Right)
1467 /* Generate an addition from the two operands */
1468 {
1469     long Val;
1470     if (IsEasyConst (Left, &Val) && Val == 0) {
1471         FreeExpr (Left);
1472         return Right;
1473     } else if (IsEasyConst (Right, &Val) && Val == 0) {
1474         FreeExpr (Right);
1475         return Left;
1476     } else {
1477         ExprNode* Root = NewExprNode (EXPR_PLUS);
1478         Root->Left = Left;
1479         Root->Right = Right;
1480         return Root;
1481     }
1482 }
1483
1484
1485
1486 ExprNode* GenCurrentPC (void)
1487 /* Return the current program counter as expression */
1488 {
1489     ExprNode* Root;
1490
1491     if (GetRelocMode ()) {
1492         /* Create SegmentBase + Offset */
1493         Root = GenAddExpr (GenSectionExpr (GetCurrentSegNum ()),
1494                            GenLiteralExpr (GetPC ()));
1495     } else {
1496         /* Absolute mode, just return PC value */
1497         Root = GenLiteralExpr (GetPC ());
1498     }
1499
1500     return Root;
1501 }
1502
1503
1504
1505 ExprNode* GenSwapExpr (ExprNode* Expr)
1506 /* Return an extended expression with lo and hi bytes swapped */
1507 {
1508     ExprNode* N = NewExprNode (EXPR_SWAP);
1509     N->Left = Expr;
1510     return N;
1511 }
1512
1513
1514
1515 ExprNode* GenBranchExpr (unsigned Offs)
1516 /* Return an expression that encodes the difference between current PC plus
1517  * offset and the target expression (that is, Expression() - (*+Offs) ).
1518  */
1519 {
1520     ExprNode* N;
1521     ExprNode* Root;
1522     long      Val;
1523
1524     /* Read Expression() */
1525     N = Expression ();
1526
1527     /* If the expression is a cheap constant, generate a simpler tree */
1528     if (IsEasyConst (N, &Val)) {
1529
1530         /* Free the constant expression tree */
1531         FreeExpr (N);
1532
1533         /* Generate the final expression:
1534          * Val - (* + Offs)
1535          * Val - ((Seg + PC) + Offs)
1536          * Val - Seg - PC - Offs
1537          * (Val - PC - Offs) - Seg
1538          */
1539         Root = GenLiteralExpr (Val - GetPC () - Offs);
1540         if (GetRelocMode ()) {
1541             N = Root;
1542             Root = NewExprNode (EXPR_MINUS);
1543             Root->Left  = N;
1544             Root->Right = GenSectionExpr (GetCurrentSegNum ());
1545         }
1546
1547     } else {
1548
1549         /* Generate the expression:
1550          * N - (* + Offs)
1551          * N - ((Seg + PC) + Offs)
1552          * N - Seg - PC - Offs
1553          * N - (PC + Offs) - Seg
1554          */
1555         Root = NewExprNode (EXPR_MINUS);
1556         Root->Left  = N;
1557         Root->Right = GenLiteralExpr (GetPC () + Offs);
1558         if (GetRelocMode ()) {
1559             N = Root;
1560             Root = NewExprNode (EXPR_MINUS);
1561             Root->Left  = N;
1562             Root->Right = GenSectionExpr (GetCurrentSegNum ());
1563         }
1564     }
1565
1566     /* Return the result */
1567     return Root;
1568 }
1569
1570
1571
1572 ExprNode* GenULabelExpr (unsigned Num)
1573 /* Return an expression for an unnamed label with the given index */
1574 {
1575     ExprNode* Node = NewExprNode (EXPR_ULABEL);
1576     Node->V.IVal        = Num;
1577
1578     /* Return the new node */
1579     return Node;
1580 }
1581
1582
1583
1584 ExprNode* GenByteExpr (ExprNode* Expr)
1585 /* Force the given expression into a byte and return the result */
1586 {
1587     /* Use the low byte operator to force the expression into byte size */
1588     return LoByte (Expr);
1589 }
1590
1591
1592
1593 ExprNode* GenWordExpr (ExprNode* Expr)
1594 /* Force the given expression into a word and return the result. */
1595 {
1596     /* Use the low byte operator to force the expression into word size */
1597     return LoWord (Expr);
1598 }
1599
1600
1601
1602 ExprNode* GenNE (ExprNode* Expr, long Val)
1603 /* Generate an expression that compares Expr and Val for inequality */
1604 {
1605     /* Generate a compare node */
1606     ExprNode* Root = NewExprNode (EXPR_NE);
1607     Root->Left  = Expr;
1608     Root->Right = GenLiteralExpr (Val);
1609
1610     /* Return the result */
1611     return Root;
1612 }
1613
1614
1615
1616 int IsConstExpr (ExprNode* Expr, long* Val)
1617 /* Return true if the given expression is a constant expression, that is, one
1618  * with no references to external symbols. If Val is not NULL and the
1619  * expression is constant, the constant value is stored here.
1620  */
1621 {
1622     int IsConst;
1623
1624     /* Study the expression */
1625     ExprDesc D;
1626     ED_Init (&D);
1627     StudyExpr (Expr, &D);
1628
1629     /* Check if the expression is constant */
1630     IsConst = ED_IsConst (&D);
1631     if (IsConst && Val != 0) {
1632         *Val = D.Val;
1633     }
1634
1635     /* Delete allocated memory and return the result */
1636     ED_Done (&D);
1637     return IsConst;
1638 }
1639
1640
1641
1642 ExprNode* CloneExpr (ExprNode* Expr)
1643 /* Clone the given expression tree. The function will simply clone symbol
1644  * nodes, it will not resolve them.
1645  */
1646 {
1647     ExprNode* Clone;
1648
1649     /* Accept NULL pointers */
1650     if (Expr == 0) {
1651         return 0;
1652     }
1653
1654     /* Clone the node */
1655     switch (Expr->Op) {
1656
1657         case EXPR_LITERAL:
1658             Clone = GenLiteralExpr (Expr->V.IVal);
1659             break;
1660
1661         case EXPR_ULABEL:
1662             Clone = GenULabelExpr (Expr->V.IVal);
1663             break;
1664
1665         case EXPR_SYMBOL:
1666             Clone = GenSymExpr (Expr->V.Sym);
1667             break;
1668
1669         case EXPR_SECTION:
1670             Clone = GenSectionExpr (Expr->V.SegNum);
1671             break;
1672
1673         default:
1674             /* Generate a new node */
1675             Clone = NewExprNode (Expr->Op);
1676             /* Clone the tree nodes */
1677             Clone->Left = CloneExpr (Expr->Left);
1678             Clone->Right = CloneExpr (Expr->Right);
1679             break;
1680     }
1681
1682     /* Done */
1683     return Clone;
1684 }
1685
1686
1687
1688 void WriteExpr (ExprNode* Expr)
1689 /* Write the given expression to the object file */
1690 {
1691     /* Null expressions are encoded by a type byte of zero */
1692     if (Expr == 0) {
1693         ObjWrite8 (EXPR_NULL);
1694         return;
1695     }
1696
1697     /* If the is a leafnode, write the expression attribute, otherwise
1698      * write the expression operands.
1699      */
1700     switch (Expr->Op) {
1701
1702         case EXPR_LITERAL:
1703             ObjWrite8 (EXPR_LITERAL);
1704             ObjWrite32 (Expr->V.IVal);
1705             break;
1706
1707         case EXPR_SYMBOL:
1708             if (SymIsImport (Expr->V.Sym)) {
1709                 ObjWrite8 (EXPR_SYMBOL);
1710                 ObjWriteVar (GetSymIndex (Expr->V.Sym));
1711             } else {
1712                 WriteExpr (GetSymExpr (Expr->V.Sym));
1713             }
1714             break;
1715
1716         case EXPR_SECTION:
1717             ObjWrite8 (EXPR_SECTION);
1718             ObjWrite8 (Expr->V.SegNum);
1719             break;
1720
1721         case EXPR_ULABEL:
1722             WriteExpr (ULabResolve (Expr->V.IVal));
1723             break;
1724
1725         default:
1726             /* Not a leaf node */
1727             ObjWrite8 (Expr->Op);
1728             WriteExpr (Expr->Left);
1729             WriteExpr (Expr->Right);
1730             break;
1731
1732     }
1733 }
1734
1735
1736
1737 void ExprGuessedAddrSize (const ExprNode* Expr, unsigned char AddrSize)
1738 /* Mark the address size of the given expression tree as guessed. The address
1739  * size passed as argument is the one NOT used, because the actual address
1740  * size wasn't known. Example: Zero page addressing was not used because symbol
1741  * is undefined, and absolute addressing was available.
1742  * This function will actually parse the expression tree for undefined symbols,
1743  * and mark these symbols accordingly.
1744  */
1745 {
1746     /* Accept NULL expressions */
1747     if (Expr == 0) {
1748         return;
1749     }
1750
1751     /* Check the type code */
1752     switch (Expr->Op & EXPR_TYPEMASK) {
1753
1754         case EXPR_LEAFNODE:
1755             if (Expr->Op == EXPR_SYMBOL) {
1756                 if (!SymIsDef (Expr->V.Sym)) {
1757                     /* Symbol is undefined, mark it */
1758                     SymGuessedAddrSize (Expr->V.Sym, AddrSize);
1759                 }
1760             }
1761             return;
1762
1763         case EXPR_BINARYNODE:
1764             ExprGuessedAddrSize (Expr->Right, AddrSize);
1765             /* FALLTHROUGH */
1766
1767         case EXPR_UNARYNODE:
1768             ExprGuessedAddrSize (Expr->Left, AddrSize);
1769             break;
1770     }
1771 }
1772
1773
1774