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