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