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