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