1 /*****************************************************************************/
5 /* Expression evaluation for the ld65 linker */
9 /* (C) 1998-2000 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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. */
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: */
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 */
32 /*****************************************************************************/
36 #include "../common/exprdefs.h"
37 #include "../common/xmalloc.h"
47 /*****************************************************************************/
49 /*****************************************************************************/
53 static ExprNode* NewExprNode (ObjData* O)
54 /* Create a new expression node */
56 /* Allocate fresh memory */
57 ExprNode* N = xmalloc (sizeof (ExprNode));
69 static void FreeExprNode (ExprNode* E)
78 /*****************************************************************************/
79 /* Dump an expression tree on stdout for debugging */
80 /*****************************************************************************/
84 static void InternalDumpExpr (const ExprNode* Expr)
85 /* Dump an expression in UPN */
90 InternalDumpExpr (Expr->Left);
91 InternalDumpExpr (Expr->Right);
96 printf (" $%04lX", Expr->V.Val & 0xFFFF);
163 case EXPR_UNARY_MINUS:
184 printf (" BOOL_AND");
192 printf (" BOOL_XOR");
196 printf (" BOOL_NOT");
200 Internal ("Unknown Op type: %u", Expr->Op);
207 void DumpExpr (const ExprNode* Expr)
208 /* Dump an expression tree to stdout */
210 InternalDumpExpr (Expr);
216 /*****************************************************************************/
218 /*****************************************************************************/
222 void FreeExpr (ExprNode* Root)
223 /* Free the expression, Root is pointing to. */
226 FreeExpr (Root->Left);
227 FreeExpr (Root->Right);
234 int IsConstExpr (ExprNode* Root)
235 /* Return true if the given expression is a constant expression, that is, one
236 * with no references to external symbols.
242 if (EXPR_IS_LEAF (Root->Op)) {
249 /* Get the referenced export */
250 E = GetExprExport (Root);
251 /* If this export has a mark set, we've already encountered it.
252 * This means that the export is used to define it's own value,
253 * which in turn means, that we have a circular reference.
255 if (ExportHasMark (E)) {
256 Error ("Circular reference for symbol `%s', %s(%u)",
257 E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
261 Const = IsConstExport (E);
270 } else if (EXPR_IS_UNARY (Root->Op)) {
272 return IsConstExpr (Root->Left);
276 /* We must handle shortcut boolean expressions here */
280 if (IsConstExpr (Root->Left)) {
281 /* lhs is const, if it is zero, don't eval right */
282 if (GetExprVal (Root->Left) == 0) {
285 return IsConstExpr (Root->Right);
288 /* lhs not const --> tree not const */
294 if (IsConstExpr (Root->Left)) {
295 /* lhs is const, if it is not zero, don't eval right */
296 if (GetExprVal (Root->Left) != 0) {
299 return IsConstExpr (Root->Right);
302 /* lhs not const --> tree not const */
308 /* All others are handled normal */
309 return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
316 Import* GetExprImport (ExprNode* Expr)
317 /* Get the import data structure for a symbol expression node */
319 /* Check that this is really a symbol */
320 PRECONDITION (Expr->Op == EXPR_SYMBOL);
322 /* Return the import */
323 return Expr->Obj->Imports [Expr->V.ImpNum];
328 Export* GetExprExport (ExprNode* Expr)
329 /* Get the exported symbol for a symbol expression node */
331 /* Check that this is really a symbol */
332 PRECONDITION (Expr->Op == EXPR_SYMBOL);
334 /* Return the export */
335 return Expr->Obj->Imports [Expr->V.ImpNum]->V.Exp;
340 Section* GetExprSection (ExprNode* Expr)
341 /* Get the segment for a segment expression node */
343 /* Check that this is really a segment node */
344 PRECONDITION (Expr->Op == EXPR_SEGMENT);
346 /* Return the export */
347 return Expr->Obj->Sections [Expr->V.SegNum];
352 long GetExprVal (ExprNode* Expr)
353 /* Get the value of a constant expression */
355 long Right, Left, Val;
365 /* Get the referenced export */
366 E = GetExprExport (Expr);
367 /* If this export has a mark set, we've already encountered it.
368 * This means that the export is used to define it's own value,
369 * which in turn means, that we have a circular reference.
371 if (ExportHasMark (E)) {
372 CircularRefError (E);
376 Val = GetExportVal (E);
382 S = GetExprSection (Expr);
383 return S->Offs + S->Seg->PC;
386 return Expr->V.MemArea->Start;
389 return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
392 return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
395 return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
398 Left = GetExprVal (Expr->Left);
399 Right = GetExprVal (Expr->Right);
401 Error ("Division by zero");
406 Left = GetExprVal (Expr->Left);
407 Right = GetExprVal (Expr->Right);
409 Error ("Modulo operation with zero");
414 return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
417 return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
420 return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
423 return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
426 return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
429 return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
432 return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
435 return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
438 return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
441 return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
444 return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
446 case EXPR_UNARY_MINUS:
447 return -GetExprVal (Expr->Left);
450 return ~GetExprVal (Expr->Left);
453 return GetExprVal (Expr->Left) & 0xFF;
456 return (GetExprVal (Expr->Left) >> 8) & 0xFF;
459 Left = GetExprVal (Expr->Left);
460 return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
463 return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
466 return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
469 return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
472 return !GetExprVal (Expr->Left);
475 Internal ("Unknown expression Op type: %u", Expr->Op);
483 ExprNode* LiteralExpr (long Val, ObjData* O)
484 /* Return an expression tree that encodes the given literal value */
486 ExprNode* Expr = NewExprNode (O);
487 Expr->Op = EXPR_LITERAL;
494 ExprNode* MemExpr (Memory* Mem, long Offs, ObjData* O)
495 /* Return an expression tree that encodes an offset into the memory area */
499 ExprNode* Expr = NewExprNode (O);
500 Expr->Op = EXPR_MEMAREA;
501 Expr->V.MemArea = Mem;
503 Root = NewExprNode (O);
504 Root->Op = EXPR_PLUS;
506 Root->Right = LiteralExpr (Offs, O);
513 ExprNode* ReadExpr (FILE* F, ObjData* O)
514 /* Read an expression from the given file */
518 /* Read the node tag and handle NULL nodes */
519 unsigned char Op = Read8 (F);
520 if (Op == EXPR_NULL) {
524 /* Create a new node */
525 Expr = NewExprNode (O);
528 /* Check the tag and handle the different expression types */
529 if (EXPR_IS_LEAF (Op)) {
533 Expr->V.Val = Read32Signed (F);
537 /* Read the import number */
538 Expr->V.ImpNum = Read16 (F);
542 /* Read the segment number */
543 Expr->V.SegNum = Read8 (F);
547 Error ("Invalid expression op: %02X", Op);
553 /* Not a leaf node */
554 Expr->Left = ReadExpr (F, O);
555 Expr->Right = ReadExpr (F, O);
559 /* Return the tree */
565 int EqualExpr (ExprNode* E1, ExprNode* E2)
566 /* Check if two expressions are identical. */
568 /* If one pointer is NULL, both must be NULL */
569 if ((E1 == 0) ^ (E2 == 0)) {
576 /* Both pointers not NULL, check OP */
577 if (E1->Op != E2->Op) {
581 /* OPs are identical, check data for leafs, or subtrees */
585 /* Value must be identical */
586 return (E1->V.Val == E2->V.Val);
589 /* Import number must be identical */
590 return (E1->V.ImpNum == E2->V.ImpNum);
593 /* Segment number must be identical */
594 return (E1->V.SegNum == E2->V.SegNum);
597 /* Memory area must be identical */
598 return (E1->V.MemArea == E2->V.MemArea);
601 /* Not a leaf node */
602 return EqualExpr (E1->Left, E2->Left) && EqualExpr (E1->Right, E2->Right);