static void PrintConstantDecl(FILE *f, AST *ast) { const char *name = ast->d.string; AST *expr = NULL; Symbol *sym; if (!IsConstExpr(ast)) { ERROR(ast, "%s is not constant", name); return; } sym = LookupSymbol(name); if (!sym) { ERROR(ast, "constant symbol %s not declared??", name); return; } expr = (AST *)sym->val; if (gl_ccode) { fprintf(f, "#define %s (", ast->d.string); PrintConstant(f, expr); fprintf(f, ")\n"); } else { fprintf(f, " static const int %s = ", ast->d.string); PrintConstant(f, expr); fprintf(f, ";\n"); } }
static void SymReplaceExprRefs (SymEntry* S) /* Replace the references to this symbol by a copy of the symbol expression */ { unsigned I; long Val; /* Check if the expression is const and get its value */ int IsConst = IsConstExpr (S->Expr, &Val); CHECK (IsConst); /* Loop over all references */ for (I = 0; I < CollCount (&S->ExprRefs); ++I) { /* Get the expression node */ ExprNode* E = CollAtUnchecked (&S->ExprRefs, I); /* Safety */ CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S); /* We cannot touch the root node, since there are pointers to it. ** Replace it by a literal node. */ E->Op = EXPR_LITERAL; E->V.IVal = Val; } /* Remove all symbol references from the symbol */ CollDeleteAll (&S->ExprRefs); }
int SymIsConst (const SymEntry* S, long* Val) /* Return true if the given symbol has a constant value. If Val is not NULL ** and the symbol has a constant value, store it's value there. */ { /* Check for constness */ return (SymHasExpr (S) && IsConstExpr (S->Expr, Val)); }
long GetSymVal (SymEntry* S) /* Return the value of a symbol assuming it's constant. FAIL will be called ** in case the symbol is undefined or not constant. */ { long Val; CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val)); return Val; }
void CheckAssertions (void) /* Check all assertions */ { unsigned I; /* Walk over all assertions */ for (I = 0; I < CollCount (&Assertions); ++I) { const LineInfo* LI; const char* Module; unsigned Line; /* Get the assertion */ Assertion* A = CollAtUnchecked (&Assertions, I); /* Ignore assertions that shouldn't be handled at link time */ if (!AssertAtLinkTime (A->Action)) { continue; } /* Retrieve the relevant line info for this assertion */ LI = CollConstAt (&A->LineInfos, 0); /* Get file name and line number from the source */ Module = GetSourceName (LI); Line = GetSourceLine (LI); /* If the expression is not constant, we're not able to handle it */ if (!IsConstExpr (A->Expr)) { Warning ("Cannot evaluate assertion in module `%s', line %u", Module, Line); } else if (GetExprVal (A->Expr) == 0) { /* Assertion failed */ const char* Message = GetString (A->Msg); switch (A->Action) { case ASSERT_ACT_WARN: case ASSERT_ACT_LDWARN: Warning ("%s(%u): %s", Module, Line, Message); break; case ASSERT_ACT_ERROR: case ASSERT_ACT_LDERROR: Error ("%s(%u): %s", Module, Line, Message); break; default: Internal ("Invalid assertion action (%u) in module `%s', " "line %u (file corrupt?)", A->Action, Module, Line); break; } } } }
int IsConstExport (const Export* E) /* Return true if the expression associated with this export is const */ { if (E->Expr == 0) { /* External symbols cannot be const */ return 0; } else { return IsConstExpr (E->Expr); } }
void CheckAssertions (void) /* Check all assertions and evaluate the ones we can evaluate here. */ { unsigned I; /* Get the number of assertions */ unsigned Count = CollCount (&Assertions); /* Check the assertions */ for (I = 0; I < Count; ++I) { long Val; /* Get the next assertion */ Assertion* A = CollAtUnchecked (&Assertions, I); /* Ignore it, if it should only be evaluated by the linker */ if (!AssertAtAsmTime (A->Action)) { continue; } /* Can we evaluate the expression? */ if (IsConstExpr (A->Expr, &Val) && Val == 0) { /* Apply the action */ const char* Msg = GetString (A->Msg); switch (A->Action) { case ASSERT_ACT_WARN: LIWarning (&A->LI, 0, "%s", Msg); break; case ASSERT_ACT_ERROR: LIError (&A->LI, "%s", Msg); break; default: Internal ("Illegal assert action specifier"); break; } } } }
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); } } }
void DoConditionals (void) /* Catch all for conditional directives */ { IfDesc* D; do { switch (CurTok.Tok) { case TOK_ELSE: D = GetCurrentIf (); /* Allow an .ELSE */ ElseClause (D, ".ELSE"); /* Remember the data for the .ELSE */ if (D) { ReleaseFullLineInfo (&D->LineInfos); GetFullLineInfo (&D->LineInfos); D->Name = ".ELSE"; } /* Calculate the new overall condition */ CalcOverallIfCond (); /* Skip .ELSE */ NextTok (); ExpectSep (); break; case TOK_ELSEIF: D = GetCurrentIf (); /* Handle as if there was an .ELSE first */ ElseClause (D, ".ELSEIF"); /* Calculate the new overall if condition */ CalcOverallIfCond (); /* Allocate and prepare a new descriptor */ D = AllocIf (".ELSEIF", 0); NextTok (); /* Ignore the new condition if we are inside a false .ELSE ** branch. This way we won't get any errors about undefined ** symbols or similar... */ if (IfCond) { SetIfCond (D, ConstExpression ()); ExpectSep (); } /* Get the new overall condition */ CalcOverallIfCond (); break; case TOK_ENDIF: /* We're done with this .IF.. - remove the descriptor(s) */ FreeIf (); /* Be sure not to read the next token until the .IF stack ** has been cleanup up, since we may be at end of file. */ NextTok (); ExpectSep (); /* Get the new overall condition */ CalcOverallIfCond (); break; case TOK_IF: D = AllocIf (".IF", 1); NextTok (); if (IfCond) { SetIfCond (D, ConstExpression ()); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFBLANK: D = AllocIf (".IFBLANK", 1); NextTok (); if (IfCond) { if (TokIsSep (CurTok.Tok)) { SetIfCond (D, 1); } else { SetIfCond (D, 0); SkipUntilSep (); } } CalcOverallIfCond (); break; case TOK_IFCONST: D = AllocIf (".IFCONST", 1); NextTok (); if (IfCond) { ExprNode* Expr = Expression(); SetIfCond (D, IsConstExpr (Expr, 0)); FreeExpr (Expr); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFDEF: D = AllocIf (".IFDEF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym != 0 && SymIsDef (Sym)); } CalcOverallIfCond (); break; case TOK_IFNBLANK: D = AllocIf (".IFNBLANK", 1); NextTok (); if (IfCond) { if (TokIsSep (CurTok.Tok)) { SetIfCond (D, 0); } else { SetIfCond (D, 1); SkipUntilSep (); } } CalcOverallIfCond (); break; case TOK_IFNCONST: D = AllocIf (".IFNCONST", 1); NextTok (); if (IfCond) { ExprNode* Expr = Expression(); SetIfCond (D, !IsConstExpr (Expr, 0)); FreeExpr (Expr); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFNDEF: D = AllocIf (".IFNDEF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym == 0 || !SymIsDef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFNREF: D = AllocIf (".IFNREF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym == 0 || !SymIsRef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; case TOK_IFP02: D = AllocIf (".IFP02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_6502); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFP4510: D = AllocIf (".IFP4510", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_4510); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFP816: D = AllocIf (".IFP816", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65816); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFPC02: D = AllocIf (".IFPC02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65C02); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFPSC02: D = AllocIf (".IFPSC02", 1); NextTok (); if (IfCond) { SetIfCond (D, GetCPU() == CPU_65SC02); } ExpectSep (); CalcOverallIfCond (); break; case TOK_IFREF: D = AllocIf (".IFREF", 1); NextTok (); if (IfCond) { SymEntry* Sym = ParseAnySymName (SYM_FIND_EXISTING); SetIfCond (D, Sym != 0 && SymIsRef (Sym)); ExpectSep (); } CalcOverallIfCond (); break; default: /* Skip tokens */ NextTok (); } } while (IfCond == 0 && CurTok.Tok != TOK_EOF); }