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 |
82 | static ExprNode* FreeExprNodes = 0; |
83 | static unsigned FreeNodeCount = 0; |
84 | |
85 | |
86 | |
87 | /*****************************************************************************/ |
88 | /* Helpers */ |
89 | /*****************************************************************************/ |
90 | |
91 | |
92 | |
93 | static 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 | |
117 | static 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 | |
146 | static ExprNode* Expr0 (void); |
147 | |
148 | |
149 | |
150 | int IsByteRange (long Val) |
151 | /* Return true if this is a byte value */ |
152 | { |
153 | return (Val & ~0xFFL) == 0; |
154 | } |
155 | |
156 | |
157 | |
158 | int IsWordRange (long Val) |
159 | /* Return true if this is a word value */ |
160 | { |
161 | return (Val & ~0xFFFFL) == 0; |
162 | } |
163 | |
164 | |
165 | |
166 | int IsFarRange (long Val) |
167 | /* Return true if this is a far (24 bit) value */ |
168 | { |
169 | return (Val & ~0xFFFFFFL) == 0; |
170 | } |
171 | |
172 | |
173 | |
174 | int 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 | |
203 | static 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 | |
223 | static 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 | |
243 | static 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 | |
256 | static 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 | |
276 | static 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 | |
296 | static 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 | |
316 | static 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 | |
339 | ExprNode* FuncBank (void) |
340 | /* Handle the .BANK builtin function */ |
341 | { |
342 | return Bank (Expression ()); |
343 | } |
344 | |
345 | |
346 | |
347 | ExprNode* FuncBankByte (void) |
348 | /* Handle the .BANKBYTE builtin function */ |
349 | { |
350 | return BankByte (Expression ()); |
351 | } |
352 | |
353 | |
354 | |
355 | static 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 | |
391 | static 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 | |
409 | static 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 | |
421 | static 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 | |
441 | ExprNode* FuncHiByte (void) |
442 | /* Handle the .HIBYTE builtin function */ |
443 | { |
444 | return HiByte (Expression ()); |
445 | } |
446 | |
447 | |
448 | |
449 | static ExprNode* FuncHiWord (void) |
450 | /* Handle the .HIWORD builtin function */ |
451 | { |
452 | return HiWord (Expression ()); |
453 | } |
454 | |
455 | |
456 | |
457 | static 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 | |
487 | ExprNode* FuncLoByte (void) |
488 | /* Handle the .LOBYTE builtin function */ |
489 | { |
490 | return LoByte (Expression ()); |
491 | } |
492 | |
493 | |
494 | |
495 | static ExprNode* FuncLoWord (void) |
496 | /* Handle the .LOWORD builtin function */ |
497 | { |
498 | return LoWord (Expression ()); |
499 | } |
500 | |
501 | |
502 | |
503 | static 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 | |
605 | static ExprNode* FuncMatch (void) |
606 | /* Handle the .MATCH function */ |
607 | { |
608 | return DoMatch (tcSameToken); |
609 | } |
610 | |
611 | |
612 | |
613 | static 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 | |
642 | static 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 | |
671 | static 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 | |
683 | static 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 | |
762 | static 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 | |
857 | static 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 | |
892 | ExitPoint: |
893 | /* Free string buffer memory */ |
894 | SB_Done (&Str); |
895 | |
896 | /* Return the char expression */ |
897 | return GenLiteralExpr (C); |
898 | } |
899 | |
900 | |
901 | |
902 | static 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 | |
932 | static 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 | |
968 | static ExprNode* FuncXMatch (void) |
969 | /* Handle the .XMATCH function */ |
970 | { |
971 | return DoMatch (tcIdentical); |
972 | } |
973 | |
974 | |
975 | |
976 | static 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 | |
1004 | static 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 | |
1224 | static 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 | |
1328 | static 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 | |
1390 | static 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 | |
1459 | static 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 | |
1518 | static 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 | |
1575 | static 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 | |
1614 | ExprNode* 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 | |
1624 | long 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 | |
1658 | void 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 | |
1670 | ExprNode* 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 | |
1683 | ExprNode* 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 | |
1693 | ExprNode* GenLiteral0 (void) |
1694 | /* Return an expression tree that encodes the the number zero */ |
1695 | { |
1696 | return GenLiteralExpr (0); |
1697 | } |
1698 | |
1699 | |
1700 | |
1701 | ExprNode* 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 | |
1712 | static 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 | |
1722 | static 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 | |
1732 | ExprNode* 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 | |
1752 | ExprNode* 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 | |
1771 | ExprNode* 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 | |
1781 | ExprNode* 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 | |
1838 | ExprNode* 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 | |
1850 | ExprNode* 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 | |
1859 | ExprNode* 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 | |
1868 | ExprNode* 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 | |
1890 | ExprNode* 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 | |
1909 | ExprNode* 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 | |
1928 | ExprNode* 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 | |
1942 | int 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 | |
1968 | ExprNode* 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 | |
2018 | void 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 | |
2067 | void 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 | |
2105 | ExprNode* 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 | |
2122 | ExprNode* 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 | |