diff --git a/src/ld65/asserts.c b/src/ld65/asserts.c index 7aa5a6aef..13fe80040 100644 --- a/src/ld65/asserts.c +++ b/src/ld65/asserts.c @@ -110,8 +110,7 @@ void CheckAssertions (void) const LineInfo* LI; const FilePos* Pos; - const char* Module; - unsigned Line; + const char* Message; /* Get the assertion */ Assertion* A = CollAtUnchecked (&Assertions, I); @@ -121,25 +120,18 @@ void CheckAssertions (void) continue; } - /* Retrieve the relevant line info for this assertion */ - LI = CollConstAt (&A->LineInfos, 0); - - /* Get the source file position of the assertion plus file and line - ** number. - */ - Pos = GetSourcePos (LI); - Line = GetSourceLine (LI); - Module = GetSourceName (LI); + /* Get some assertion data */ + Message = GetString (A->Msg); + LI = CollConstAt (&A->LineInfos, 0); + Pos = GetSourcePos (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); + AddPNote (Pos, "The assert message is: \"%s\"", Message); + PWarning (Pos, "Cannot evaluate this source code assertion"); } else if (GetExprVal (A->Expr) == 0) { /* Assertion failed */ - const char* Message = GetString (A->Msg); - switch (A->Action) { case ASSERT_ACT_WARN: @@ -153,9 +145,8 @@ void CheckAssertions (void) break; default: - Internal ("Invalid assertion action (%u) in module '%s', " - "line %u (file corrupt?)", - A->Action, Module, Line); + AddPNote (Pos, "The file might be corrupt or wrong version"); + PError (Pos, "Invalid assertion action %u", A->Action); break; } } diff --git a/src/ld65/config.c b/src/ld65/config.c index f178fe550..3722b5cbe 100644 --- a/src/ld65/config.c +++ b/src/ld65/config.c @@ -321,9 +321,8 @@ static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name) /* Check for duplicate names */ MemoryArea* M = CfgFindMemory (Name); if (M) { - PError (&CfgErrorPos, - "Memory area `%s' defined twice", - GetString (Name)); + PError (&CfgErrorPos, "Memory area `%s' defined twice", + GetString (Name)); } /* Create a new memory area */ @@ -440,7 +439,8 @@ static void ParseMemory (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), + "Memory attribute"); AttrTok = CfgTok; /* An optional assignment follows */ @@ -500,7 +500,7 @@ static void ParseMemory (void) case CFGTOK_TYPE: FlagAttr (&M->Attr, MA_TYPE, "TYPE"); - CfgSpecialToken (Types, ENTRY_COUNT (Types), "TYPE"); + CfgSpecialToken (Types, ENTRY_COUNT (Types), "Memory type"); if (CfgTok == CFGTOK_RO) { M->Flags |= MF_RO; } @@ -554,7 +554,7 @@ static void ParseFiles (void) /* The MEMORY section must preceed the FILES section */ if ((SectionsEncountered & SE_MEMORY) == 0) { - PError (&CfgErrorPos, "MEMORY must precede FILES"); + PError (&CfgErrorPos, "`MEMORY' must precede `FILES'"); } /* Parse all files */ @@ -568,9 +568,8 @@ static void ParseFiles (void) /* Search for the file, it must exist */ F = FindFile (GetStrBufId (&CfgSVal)); if (F == 0) { - PError (&CfgErrorPos, - "File `%s' not found in MEMORY section", - SB_GetConstBuf (&CfgSVal)); + PError (&CfgErrorPos, "File `%s' not found in `MEMORY' section", + SB_GetConstBuf (&CfgSVal)); } /* Skip the token and the following colon */ @@ -582,7 +581,8 @@ static void ParseFiles (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), + "File attribute"); AttrTok = CfgTok; /* An optional assignment follows */ @@ -595,11 +595,10 @@ static void ParseFiles (void) case CFGTOK_FORMAT: if (F->Format != BINFMT_DEFAULT) { /* We've set the format already! */ - PError (&CfgErrorPos, - "Cannot set a file format twice"); + PError (&CfgErrorPos, "Cannot set a file format twice"); } /* Read the format token */ - CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format"); + CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "File format"); switch (CfgTok) { case CFGTOK_BIN: @@ -667,7 +666,7 @@ static void ParseSegments (void) /* The MEMORY section must preceed the SEGMENTS section */ if ((SectionsEncountered & SE_MEMORY) == 0) { - PError (&CfgErrorPos, "MEMORY must precede SEGMENTS"); + PError (&CfgErrorPos, "`MEMORY' must precede `SEGMENTS'"); } while (CfgTok == CFGTOK_IDENT) { @@ -686,7 +685,7 @@ static void ParseSegments (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Segment attribute"); AttrTok = CfgTok; /* An optional assignment follows */ @@ -759,7 +758,7 @@ static void ParseSegments (void) case CFGTOK_TYPE: FlagAttr (&S->Attr, SA_TYPE, "TYPE"); - CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type"); + CfgSpecialToken (Types, ENTRY_COUNT (Types), "Segment type"); switch (CfgTok) { case CFGTOK_RO: S->Flags |= SF_RO; break; case CFGTOK_RW: /* Default */ break; @@ -794,8 +793,8 @@ static void ParseSegments (void) */ if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) { PWarning (&CfgErrorPos, - "ALIGN_LOAD attribute specified, but no separate " - "LOAD and RUN memory areas assigned"); + "`ALIGN_LOAD' attribute specified, but no separate " + "`LOAD' and `RUN' memory areas assigned"); /* Remove the flag */ S->Flags &= ~SF_ALIGN_LOAD; } @@ -805,16 +804,16 @@ static void ParseSegments (void) */ if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) { PWarning (&CfgErrorPos, - "Segment with type `bss' has both LOAD and RUN " - "memory areas assigned"); + "Segment with type `bss' has both `LOAD' and `RUN' " + "memory areas assigned"); } /* Don't allow read/write data to be put into a readonly area */ if ((S->Flags & SF_RO) == 0) { if (S->Run->Flags & MF_RO) { PError (&CfgErrorPos, - "Cannot put r/w segment `%s' in r/o memory area `%s'", - GetString (S->Name), GetString (S->Run->Name)); + "Cannot place r/w segment `%s' in r/o memory area `%s'", + GetString (S->Name), GetString (S->Run->Name)); } } @@ -824,7 +823,7 @@ static void ParseSegments (void) ((S->Flags & SF_START) != 0); if (Count > 1) { PError (&CfgErrorPos, - "Only one of ALIGN, START, OFFSET may be used"); + "Only one of `ALIGN', `START' or `OFFSET' may be used"); } /* Skip the semicolon */ @@ -881,7 +880,7 @@ static void ParseO65 (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "O65 attribute"); AttrTok = CfgTok; /* An optional assignment follows */ @@ -924,7 +923,7 @@ static void ParseO65 (void) /* Cannot have this attribute twice */ FlagAttr (&AttrFlags, atType, "TYPE"); /* Get the type of the executable */ - CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type"); + CfgSpecialToken (Types, ENTRY_COUNT (Types), "O65 type"); switch (CfgTok) { case CFGTOK_SMALL: @@ -952,7 +951,9 @@ static void ParseO65 (void) CfgRangeCheck (O65OS_MIN, O65OS_MAX); OS = (unsigned) CfgIVal; } else { - CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type"); + CfgSpecialToken (OperatingSystems, + ENTRY_COUNT (OperatingSystems), + "O65 OS specification"); switch (CfgTok) { case CFGTOK_LUNIX: OS = O65OS_LUNIX; break; case CFGTOK_OSA65: OS = O65OS_OSA65; break; @@ -994,12 +995,12 @@ static void ParseO65 (void) if (OS == O65OS_CC65) { if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) { PError (&CfgErrorPos, - "OS type CC65 may not have imports or exports for ids < $8000"); + "OS type CC65 may not have imports or exports for ids < $8000"); } } else { if (AttrFlags & atID) { PError (&CfgErrorPos, - "Operating system does not support the ID attribute"); + "Operating system does not support the ID attribute"); } } @@ -1033,7 +1034,7 @@ static void ParseXex (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Xex attribute"); AttrTok = CfgTok; /* An optional assignment follows */ @@ -1071,7 +1072,7 @@ static void ParseXex (void) CfgNextTok (); /* Add to XEX */ if (XexAddInitAd (XexFmtDesc, InitMem, InitAd)) - PError (&CfgErrorPos, "INITAD already given for memory area"); + PError (&CfgErrorPos, "`INITAD' already given for memory area"); break; default: @@ -1104,7 +1105,7 @@ static void ParseFormats (void) /* Map the identifier to a token */ cfgtok_t FormatTok; - CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format"); + CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format attribute"); FormatTok = CfgTok; /* Skip the name and the following colon */ @@ -1190,7 +1191,8 @@ static void ParseConDes (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), + "CONDES attribute"); AttrTok = CfgTok; /* An optional assignment follows */ @@ -1232,7 +1234,7 @@ static void ParseConDes (void) case CFGTOK_ORDER: /* Don't allow this twice */ FlagAttr (&AttrFlags, atOrder, "ORDER"); - CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order"); + CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "CONDES order"); switch (CfgTok) { case CFGTOK_DECREASING: Order = cdDecreasing; break; case CFGTOK_INCREASING: Order = cdIncreasing; break; @@ -1257,7 +1259,7 @@ static void ParseConDes (void) CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX); Type = (int) CfgIVal; } else { - CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type"); + CfgSpecialToken (Types, ENTRY_COUNT (Types), "CONDES type"); switch (CfgTok) { case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break; case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break; @@ -1291,8 +1293,8 @@ static void ParseConDes (void) /* Check if the condes has already attributes defined */ if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) { PError (&CfgErrorPos, - "CONDES attributes for type %d are already defined", - Type); + "`CONDES' attributes for type %d are already defined", + Type); } /* Define the attributes */ @@ -1334,7 +1336,8 @@ static void ParseStartAddress (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), + "Start address attribute"); AttrTok = CfgTok; /* An optional assignment follows */ @@ -1389,7 +1392,7 @@ static void ParseFeatures (void) /* Map the identifier to a token */ cfgtok_t FeatureTok; - CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature"); + CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature attribute"); FeatureTok = CfgTok; /* Skip the name and the following colon */ @@ -1479,7 +1482,8 @@ static void ParseSymbols (void) /* Map the identifier to a token */ cfgtok_t AttrTok; - CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); + CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), + "Symbol attribute"); AttrTok = CfgTok; /* Skip the attribute name */ @@ -1495,7 +1499,8 @@ static void ParseSymbols (void) /* Don't allow this twice */ FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE"); /* Map the type to a token */ - CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize"); + CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), + "Address size specification"); switch (CfgTok) { case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break; case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break; @@ -1511,7 +1516,8 @@ static void ParseSymbols (void) /* Don't allow this twice */ FlagAttr (&AttrFlags, atType, "TYPE"); /* Map the type to a token */ - CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type"); + CfgSpecialToken (Types, ENTRY_COUNT (Types), + "Address size type"); switch (CfgTok) { case CFGTOK_EXPORT: Type = CfgSymExport; break; case CFGTOK_IMPORT: Type = CfgSymImport; break; @@ -1606,7 +1612,8 @@ static void ParseConfig (void) do { /* Read the block ident */ - CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier"); + CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), + "Configuration block identifier"); BlockTok = CfgTok; CfgNextTok (); @@ -1704,8 +1711,8 @@ static void ProcessSegments (void) */ if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) { PWarning (GetSourcePos (S->LI), - "Segment `%s' with type `bss' contains initialized data", - GetString (S->Name)); + "Segment `%s' with type `bss' contains initialized data", + GetString (S->Name)); } /* If this segment does exist in any of the object files, insert the @@ -1732,9 +1739,8 @@ static void ProcessSegments (void) /* Print a warning if the segment is not optional */ if ((S->Flags & SF_OPTIONAL) == 0) { - PWarning (&CfgErrorPos, - "Segment `%s' does not exist", - GetString (S->Name)); + PWarning (&CfgErrorPos, "Segment `%s' does not exist", + GetString (S->Name)); } /* Discard the descriptor and remove it from the collection */ @@ -1914,8 +1920,8 @@ unsigned CfgProcess (void) */ if (!IsConstExpr (M->StartExpr)) { PError (GetSourcePos (M->LI), - "Start address of memory area `%s' is not constant", - GetString (M->Name)); + "Start address of memory area `%s' is not constant", + GetString (M->Name)); } Addr = M->Start = GetExprVal (M->StartExpr); M->Flags |= MF_PLACED; @@ -1939,14 +1945,14 @@ unsigned CfgProcess (void) /* Resolve the size expression */ if (!IsConstExpr (M->SizeExpr)) { PError (GetSourcePos (M->LI), - "Size of memory area `%s' is not constant", - GetString (M->Name)); + "Size of memory area `%s' is not constant", + GetString (M->Name)); } M->Size = GetExprVal (M->SizeExpr); if (M->Size >= 0x80000000) { PError (GetSourcePos (M->LI), - "Size of memory area `%s' is negative: %ld", - GetString (M->Name), (long)M->Size); + "Size of memory area `%s' is negative: %ld", + GetString (M->Name), (long)M->Size); } /* Walk through the segments in this memory area */ @@ -1969,16 +1975,16 @@ unsigned CfgProcess (void) ++Overwrites; } else { PError (GetSourcePos (M->LI), - "Segment `%s' of type `overwrite' requires either" - " `START' or `OFFSET' attribute to be specified", - GetString (S->Name)); + "Segment `%s' of type `overwrite' requires either" + " `START' or `OFFSET' attribute to be specified", + GetString (S->Name)); } } else { if (Overwrites > 0) { PError (GetSourcePos (M->LI), - "Segment `%s' is preceded by at least one segment" - " of type `overwrite'", - GetString (S->Name)); + "Segment `%s' is preceded by at least one segment" + " of type `overwrite'", + GetString (S->Name)); } } @@ -2003,9 +2009,9 @@ unsigned CfgProcess (void) ** in the linker. */ PWarning (GetSourcePos (S->LI), - "Segment `%s' isn't aligned properly; the" - " resulting executable might not be functional.", - GetString (S->Name)); + "Segment `%s' isn't aligned properly; the" + " resulting executable might not be functional.", + GetString (S->Name)); } if (S->Flags & SF_ALIGN) { @@ -2018,9 +2024,9 @@ unsigned CfgProcess (void) */ if (M->FillLevel == 0 && NewAddr > Addr) { PWarning (GetSourcePos (S->LI), - "The first segment in memory area `%s' " - "needs fill bytes for alignment.", - GetString (M->Name)); + "The first segment in memory area `%s' " + "needs fill bytes for alignment.", + GetString (M->Name)); } /* Use the aligned address */ @@ -2039,8 +2045,8 @@ unsigned CfgProcess (void) if (S->Flags & SF_OVERWRITE) { if (NewAddr < M->Start) { PError (GetSourcePos (S->LI), - "Segment `%s' begins before memory area `%s'", - GetString (S->Name), GetString (M->Name)); + "Segment `%s' begins before memory area `%s'", + GetString (S->Name), GetString (M->Name)); } else { Addr = NewAddr; } @@ -2049,15 +2055,23 @@ unsigned CfgProcess (void) /* Offset already too large */ ++Overflows; if (S->Flags & SF_OFFSET) { - PWarning (GetSourcePos (S->LI), - "Segment `%s' offset is too small in `%s' by %lu byte%s", - GetString (S->Name), GetString (M->Name), - Addr - NewAddr, (Addr - NewAddr == 1) ? "" : "s"); + PWarning ( + GetSourcePos (S->LI), + "Segment `%s' offset is too small in `%s' by %lu byte%s", + GetString (S->Name), + GetString (M->Name), + Addr - NewAddr, + (Addr - NewAddr == 1) ? "" : "s" + ); } else { - PWarning (GetSourcePos (S->LI), - "Segment `%s' start address is too low in `%s' by %lu byte%s", - GetString (S->Name), GetString (M->Name), - Addr - NewAddr, (Addr - NewAddr == 1) ? "" : "s"); + PWarning ( + GetSourcePos (S->LI), + "Segment `%s' start address is too low in `%s' by %lu byte%s", + GetString (S->Name), + GetString (M->Name), + Addr - NewAddr, + (Addr - NewAddr == 1) ? "" : "s" + ); } } else { Addr = NewAddr; @@ -2101,10 +2115,14 @@ unsigned CfgProcess (void) if (FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) { ++Overflows; M->Flags |= MF_OVERFLOW; - PWarning (GetSourcePos (M->LI), - "Segment `%s' overflows memory area `%s' by %lu byte%s", - GetString (S->Name), GetString (M->Name), - FillLevel - M->Size, (FillLevel - M->Size == 1) ? "" : "s"); + PWarning ( + GetSourcePos (M->LI), + "Segment `%s' overflows memory area `%s' by %lu byte%s", + GetString (S->Name), + GetString (M->Name), + FillLevel - M->Size, + (FillLevel - M->Size == 1) ? "" : "s" + ); } if (FillLevel > M->FillLevel) { /* Regular segments increase FillLevel. Overwrite segments may diff --git a/src/ld65/error.c b/src/ld65/error.c index 8f3f5dfc7..185aec898 100644 --- a/src/ld65/error.c +++ b/src/ld65/error.c @@ -329,7 +329,7 @@ void Internal (const char* Format, ...) -void AddCfgNote (const FilePos* Pos, const char* Format, ...) +void AddPNote (const FilePos* Pos, const char* Format, ...) /* Add a notifcation message using file name and line number of the config file. ** See comment for AddNote() above. */ diff --git a/src/ld65/error.h b/src/ld65/error.h index c688302e8..529605fee 100644 --- a/src/ld65/error.h +++ b/src/ld65/error.h @@ -76,7 +76,7 @@ void Error (const char* Format, ...) attribute((noreturn, format(printf,1,2))); void Internal (const char* Format, ...) attribute((noreturn, format(printf,1,2))); /* Print an internal error message and die */ -void AddCfgNote (const FilePos* Pos, const char* Format, ...) attribute((format(printf,2,3))); +void AddPNote (const FilePos* Pos, const char* Format, ...) attribute((format(printf,2,3))); /* Add a notifcation message using file name and line number of the config file. ** See comment for AddNote() above. */ diff --git a/src/ld65/scanner.c b/src/ld65/scanner.c index 5b7f46bd0..ee2629674 100644 --- a/src/ld65/scanner.c +++ b/src/ld65/scanner.c @@ -443,6 +443,28 @@ void CfgRangeCheck (unsigned long Lo, unsigned long Hi) +static void SpecialTokenHelp (const IdentTok* Table, unsigned Size, StrBuf* Msg) +/* Create a help message for errors in CfgSpecialToken. StrBuf must be +** initialized and is overwritten. +*/ +{ + unsigned I; + + SB_AppendStr (Msg, "You may use one of `"); + for (I = 0; I < Size; ++I) { + if (I == Size - 1) { + SB_AppendStr (Msg, " or `"); + } else if (I > 0) { + SB_AppendStr (Msg, ", `"); + } + SB_AppendStr (Msg, Table[I].Ident); + SB_AppendChar (Msg, '\''); + } + SB_Terminate (Msg); /* So we may use %s */ +} + + + void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name) /* Map an identifier to one of the special tokens in the table */ { @@ -461,8 +483,17 @@ void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name) } } - /* Not found */ - PError (&CfgErrorPos, "%s expected, got `%s'", Name, SB_GetConstBuf(&CfgSVal)); + /* Not found. Add a helpful note about the possible names only if + ** there is a not too large number of them. + */ + if (Size > 0 && Size <= 5) { + StrBuf Note = AUTO_STRBUF_INITIALIZER; + SpecialTokenHelp (Table, Size, &Note); + AddPNote (&CfgErrorPos, "%s", SB_GetConstBuf (&Note)); + SB_Done (&Note); + } + PError (&CfgErrorPos, "%s expected but got `%s'", Name, + SB_GetConstBuf(&CfgSVal)); return; }