/*****************************************************************************/
/* */
-/* error.c */
+/* error.c */
/* */
-/* Error handling for the ca65 macroassembler */
+/* Error handling for the ca65 macroassembler */
/* */
/* */
/* */
-/* (C) 1998-2011, Ullrich von Bassewitz */
+/* (C) 1998-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* ca65 */
#include "error.h"
#include "filetab.h"
+#include "lineinfo.h"
#include "nexttok.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* Warning level */
-unsigned WarnLevel = 1;
+unsigned WarnLevel = 1;
/* Statistics */
-unsigned ErrorCount = 0;
-unsigned WarningCount = 0;
+unsigned ErrorCount = 0;
+unsigned WarningCount = 0;
+
+/* Maximum number of additional notifications */
+#define MAX_NOTES 8
/*****************************************************************************/
-/* Warnings */
+/* Helper functions */
/*****************************************************************************/
-void WarningMsg (const FilePos* Pos, unsigned Level, const char* Format, va_list ap)
-/* Print warning message. */
+static void VPrintMsg (const FilePos* Pos, const char* Desc,
+ const char* Format, va_list ap)
+/* Format and output an error/warning message. */
{
- if (Level <= WarnLevel) {
+ StrBuf S = STATIC_STRBUF_INITIALIZER;
- StrBuf S = STATIC_STRBUF_INITIALIZER;
- SB_VPrintf (&S, Format, ap);
- SB_Terminate (&S);
+ /* Format the actual message */
+ StrBuf Msg = STATIC_STRBUF_INITIALIZER;
+ SB_VPrintf (&Msg, Format, ap);
+ SB_Terminate (&Msg);
- fprintf (stderr, "%s(%lu): Warning: %s\n",
- SB_GetConstBuf (GetFileName (Pos->Name)),
- Pos->Line,
- SB_GetConstBuf (&S));
- ++WarningCount;
+ /* Format the message header */
+ SB_Printf (&S, "%s(%u): %s: ",
+ SB_GetConstBuf (GetFileName (Pos->Name)),
+ Pos->Line,
+ Desc);
- SB_Done (&S);
- }
+ /* Append the message to the message header */
+ SB_Append (&S, &Msg);
+
+ /* Delete the formatted message */
+ SB_Done (&Msg);
+
+ /* Add a new line and terminate the generated full message */
+ SB_AppendChar (&S, '\n');
+ SB_Terminate (&S);
+
+ /* Output the full message */
+ fputs (SB_GetConstBuf (&S), stderr);
+
+ /* Delete the buffer for the full message */
+ SB_Done (&S);
}
-void Warning (unsigned Level, const char* Format, ...)
-/* Print warning message. */
+static void PrintMsg (const FilePos* Pos, const char* Desc,
+ const char* Format, ...)
+/* Format and output an error/warning message. */
{
va_list ap;
va_start (ap, Format);
- WarningMsg (&CurTok.Pos, Level, Format, ap);
+ VPrintMsg (Pos, Desc, Format, ap);
va_end (ap);
}
+static void AddNotifications (const Collection* LineInfos)
+/* Output additional notifications for an error or warning */
+{
+ unsigned I;
+ unsigned Output;
+ unsigned Skipped;
+
+ /* The basic line info is always in slot zero. It has been used to
+ * output the actual error or warning. The following slots may contain
+ * more information. Check them and print additional notifications if
+ * they're present, but limit the number to a reasonable value.
+ */
+ for (I = 1, Output = 0, Skipped = 0; I < CollCount (LineInfos); ++I) {
+ /* Get next line info */
+ const LineInfo* LI = CollConstAt (LineInfos, I);
+ /* Check the type and output an appropriate note */
+ const char* Msg;
+ switch (GetLineInfoType (LI)) {
+
+ case LI_TYPE_ASM:
+ Msg = "Expanded from here";
+ break;
+
+ case LI_TYPE_EXT:
+ Msg = "Assembler code generated from this line";
+ break;
+
+ case LI_TYPE_MACRO:
+ Msg = "Macro was defined here";
+ break;
+
+ case LI_TYPE_MACPARAM:
+ Msg = "Macro parameter came from here";
+ break;
+
+ default:
+ /* No output */
+ Msg = 0;
+ break;
+
+ }
+
+ /* Output until an upper limit of messages is reached */
+ if (Msg) {
+ if (Output < MAX_NOTES) {
+ PrintMsg (GetSourcePos (LI), "Note", "%s", Msg);
+ ++Output;
+ } else {
+ ++Skipped;
+ }
+ }
+ }
+
+ /* Add a note if we have more stuff that we won't output */
+ if (Skipped > 0) {
+ const LineInfo* LI = CollConstAt (LineInfos, 0);
+ PrintMsg (GetSourcePos (LI), "Note",
+ "Dropping %u additional line infos", Skipped);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Warnings */
+/*****************************************************************************/
+
+
+
+static void WarningMsg (const Collection* LineInfos, const char* Format, va_list ap)
+/* Print warning message. */
+{
+ /* The first entry in the collection is that of the actual source pos */
+ const LineInfo* LI = CollConstAt (LineInfos, 0);
+
+ /* Output a warning for this position */
+ VPrintMsg (GetSourcePos (LI), "Warning", Format, ap);
+
+ /* Add additional notifications if necessary */
+ AddNotifications (LineInfos);
+
+ /* Count warnings */
+ ++WarningCount;
+}
+
+
+
+void Warning (unsigned Level, const char* Format, ...)
+/* Print warning message. */
+{
+ if (Level <= WarnLevel) {
+
+ va_list ap;
+ Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
+
+ /* Get line infos for the current position */
+ GetFullLineInfo (&LineInfos);
+
+ /* Output the message */
+ va_start (ap, Format);
+ WarningMsg (&LineInfos, Format, ap);
+ va_end (ap);
+
+ /* Free the line info list */
+ ReleaseFullLineInfo (&LineInfos);
+ DoneCollection (&LineInfos);
+ }
+}
+
+
+
void PWarning (const FilePos* Pos, unsigned Level, const char* Format, ...)
/* Print warning message giving an explicit file and position. */
{
- va_list ap;
- va_start (ap, Format);
- WarningMsg (Pos, Level, Format, ap);
- va_end (ap);
+ if (Level <= WarnLevel) {
+ va_list ap;
+ va_start (ap, Format);
+ VPrintMsg (Pos, "Warning", Format, ap);
+ va_end (ap);
+
+ /* Count warnings */
+ ++WarningCount;
+ }
+}
+
+
+
+void LIWarning (const Collection* LineInfos, unsigned Level, const char* Format, ...)
+/* Print warning message using the given line infos */
+{
+ if (Level <= WarnLevel) {
+ /* Output the message */
+ va_list ap;
+ va_start (ap, Format);
+ WarningMsg (LineInfos, Format, ap);
+ va_end (ap);
+ }
}
/*****************************************************************************/
-/* Errors */
+/* Errors */
/*****************************************************************************/
-void ErrorMsg (const FilePos* Pos, const char* Format, va_list ap)
+void ErrorMsg (const Collection* LineInfos, const char* Format, va_list ap)
/* Print an error message */
{
- StrBuf S = STATIC_STRBUF_INITIALIZER;
- SB_VPrintf (&S, Format, ap);
- SB_Terminate (&S);
+ /* The first entry in the collection is that of the actual source pos */
+ const LineInfo* LI = CollConstAt (LineInfos, 0);
- fprintf (stderr, "%s(%lu): Error: %s\n",
- SB_GetConstBuf (GetFileName (Pos->Name)),
- Pos->Line,
- SB_GetConstBuf (&S));
- ++ErrorCount;
+ /* Output an error for this position */
+ VPrintMsg (GetSourcePos (LI), "Error", Format, ap);
- SB_Done (&S);
+ /* Add additional notifications if necessary */
+ AddNotifications (LineInfos);
+
+ /* Count errors */
+ ++ErrorCount;
}
/* Print an error message */
{
va_list ap;
+ Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
+
+ /* Get line infos for the current position */
+ GetFullLineInfo (&LineInfos);
+
+ /* Output the message */
va_start (ap, Format);
- ErrorMsg (&CurTok.Pos, Format, ap);
+ ErrorMsg (&LineInfos, Format, ap);
va_end (ap);
+
+ /* Free the line info list */
+ ReleaseFullLineInfo (&LineInfos);
+ DoneCollection (&LineInfos);
}
{
va_list ap;
va_start (ap, Format);
- ErrorMsg (Pos, Format, ap);
+ VPrintMsg (Pos, "Error", Format, ap);
+ va_end (ap);
+
+ /* Count errors */
+ ++ErrorCount;
+}
+
+
+
+void LIError (const Collection* LineInfos, const char* Format, ...)
+/* Print an error message using the given line infos. */
+{
+ /* Output an error for this position */
+ va_list ap;
+ va_start (ap, Format);
+ ErrorMsg (LineInfos, Format, ap);
va_end (ap);
}
/* Print an error message and skip the rest of the line */
{
va_list ap;
+ Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
+
+ /* Get line infos for the current position */
+ GetFullLineInfo (&LineInfos);
+
+ /* Output the message */
va_start (ap, Format);
- ErrorMsg (&CurTok.Pos, Format, ap);
+ ErrorMsg (&LineInfos, Format, ap);
va_end (ap);
+ /* Free the line info list */
+ ReleaseFullLineInfo (&LineInfos);
+ DoneCollection (&LineInfos);
+
+ /* Skip tokens until we reach the end of the line */
SkipUntilSep ();
}
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
exit (EXIT_FAILURE);
}
-
-
-