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