ExprNode* ReadExpr (FILE* F, ObjData* O) /* Read an expression from the given file */ { ExprNode* Expr; /* Read the node tag and handle NULL nodes */ unsigned char Op = Read8 (F); if (Op == EXPR_NULL) { return 0; } /* Create a new node */ Expr = NewExprNode (O, Op); /* Check the tag and handle the different expression types */ if (EXPR_IS_LEAF (Op)) { switch (Op) { case EXPR_LITERAL: Expr->V.IVal = Read32Signed (F); break; case EXPR_SYMBOL: /* Read the import number */ Expr->V.ImpNum = ReadVar (F); break; case EXPR_SECTION: /* Read the section number */ Expr->V.SecNum = ReadVar (F); break; default: Error ("Invalid expression op: %02X", Op); } } else { /* Not a leaf node */ Expr->Left = ReadExpr (F, O); Expr->Right = ReadExpr (F, O); } /* Return the tree */ return Expr; }
static void SkipExpr (FILE* F) /* Skip an expression from the given file */ { /* Read the node tag and handle NULL nodes */ unsigned char Op = Read8 (F); if (Op == EXPR_NULL) { return; } /* Check the tag and handle the different expression types */ if (EXPR_IS_LEAF (Op)) { switch (Op) { case EXPR_LITERAL: (void) Read32Signed (F); break; case EXPR_SYMBOL: /* Read the import number */ (void) ReadVar (F); break; case EXPR_SECTION: case EXPR_BANK: /* Read the segment number */ (void) ReadVar (F); break; default: Error ("Invalid expression op: %02X", Op); } } else { /* Not a leaf node */ SkipExpr (F); SkipExpr (F); } }
int IsConstExpr (ExprNode* Root) /* Return true if the given expression is a constant expression, that is, one * with no references to external symbols. */ { int Const; Export* E; Section* S; MemoryArea* M; if (EXPR_IS_LEAF (Root->Op)) { switch (Root->Op) { case EXPR_LITERAL: return 1; case EXPR_SYMBOL: /* Get the referenced export */ E = GetExprExport (Root); /* If this export has a mark set, we've already encountered it. * This means that the export is used to define it's own value, * which in turn means, that we have a circular reference. */ if (ExportHasMark (E)) { CircularRefError (E); Const = 0; } else { MarkExport (E); Const = IsConstExport (E); UnmarkExport (E); } return Const; case EXPR_SECTION: /* A section expression is const if the segment it is in is * not relocatable and already placed. */ S = GetExprSection (Root); M = S->Seg->MemArea; return M != 0 && (M->Flags & MF_PLACED) != 0 && !M->Relocatable; case EXPR_SEGMENT: /* A segment is const if it is not relocatable and placed */ M = Root->V.Seg->MemArea; return M != 0 && (M->Flags & MF_PLACED) != 0 && !M->Relocatable; case EXPR_MEMAREA: /* A memory area is const if it is not relocatable and placed */ return !Root->V.Mem->Relocatable && (Root->V.Mem->Flags & MF_PLACED); default: /* Anything else is not const */ return 0; } } else if (EXPR_IS_UNARY (Root->Op)) { SegExprDesc D; /* Special handling for the BANK pseudo function */ switch (Root->Op) { case EXPR_BANK: /* Get segment references for the expression */ GetSegExprVal (Root->Left, &D); /* The expression is const if the expression contains exactly * one segment that is assigned to a memory area which has a * bank attribute that is constant. */ return (D.TooComplex == 0 && D.Seg != 0 && D.Seg->MemArea != 0 && D.Seg->MemArea->BankExpr != 0 && IsConstExpr (D.Seg->MemArea->BankExpr)); default: /* All others handled normal */ return IsConstExpr (Root->Left); } } else { /* We must handle shortcut boolean expressions here */ switch (Root->Op) { case EXPR_BOOLAND: if (IsConstExpr (Root->Left)) { /* lhs is const, if it is zero, don't eval right */ if (GetExprVal (Root->Left) == 0) { return 1; } else { return IsConstExpr (Root->Right); } } else { /* lhs not const --> tree not const */ return 0; } break; case EXPR_BOOLOR: if (IsConstExpr (Root->Left)) { /* lhs is const, if it is not zero, don't eval right */ if (GetExprVal (Root->Left) != 0) { return 1; } else { return IsConstExpr (Root->Right); } } else { /* lhs not const --> tree not const */ return 0; } break; default: /* All others are handled normal */ return IsConstExpr (Root->Left) && IsConstExpr (Root->Right); } } }