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