/*****************************************************************************/
/* */
-/* error.c */
+/* error.c */
/* */
-/* Error handling for the ca65 macroassembler */
+/* Error handling for the ca65 macroassembler */
/* */
/* */
/* */
-/* (C) 1998-2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2012, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <stdlib.h>
#include <stdarg.h>
+/* common */
+#include "strbuf.h"
+
/* ca65 */
+#include "error.h"
#include "filetab.h"
+#include "lineinfo.h"
#include "nexttok.h"
-#include "error.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 WarnNum, 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. */
{
- static const struct {
- unsigned char Level;
- const char* Msg;
- } Warnings [WARN_COUNT-1] = {
- { 1, "Mask error" },
- { 2, "Symbol `%s' is defined but never used" },
- { 2, "Symbol `%s' is imported but never used" },
- { 1, "Cannot track processor status byte" },
- { 0, "User warning: %s" },
- };
-
- if (Warnings [WarnNum-1].Level <= WarnLevel) {
- fprintf (stderr, "%s(%lu): Warning #%u: ",
- GetFileName (Pos->Name), Pos->Line, WarnNum);
- vfprintf (stderr, Warnings [WarnNum-1].Msg, ap);
- fprintf (stderr, "\n");
- ++WarningCount;
- }
+ StrBuf S = STATIC_STRBUF_INITIALIZER;
+
+ /* Format the actual message */
+ StrBuf Msg = STATIC_STRBUF_INITIALIZER;
+ SB_VPrintf (&Msg, Format, ap);
+ SB_Terminate (&Msg);
+
+ /* Format the message header */
+ SB_Printf (&S, "%s(%u): %s: ",
+ SB_GetConstBuf (GetFileName (Pos->Name)),
+ Pos->Line,
+ Desc);
+
+ /* 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 WarnNum, ...)
-/* 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, WarnNum);
- WarningMsg (&CurPos, WarnNum, ap);
+ va_start (ap, Format);
+ VPrintMsg (Pos, Desc, Format, ap);
va_end (ap);
}
-void PWarning (const FilePos* Pos, unsigned WarnNum, ...)
+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, WarnNum);
- WarningMsg (Pos, WarnNum, 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, unsigned ErrNum, va_list ap)
+void ErrorMsg (const Collection* LineInfos, const char* Format, va_list ap)
/* Print an error message */
{
- static const char* Msgs [ERR_COUNT-1] = {
- "Command/operation not implemented",
- "Cannot open include file `%s': %s",
- "Include nesting too deep",
- "Invalid input character: %02X",
- "Hex digit expected",
- "Digit expected",
- "`0' or `1' expected",
- "Numerical overflow",
- "Control statement expected",
- "Too many characters",
- "`:' expected",
- "`(' expected",
- "`)' expected",
- "`]' expected",
- "`,' expected",
- "Boolean switch value expected (on/off/+/-)",
- "`Y' expected",
- "`X' expected",
- "Integer constant expected",
- "String constant expected",
- "Character constant expected",
- "Constant expression expected",
- "Identifier expected",
- "`.endmacro' expected",
- "Option key expected",
- "Command is only valid in 65816 mode",
- "User error: %s",
- "String constant too long",
- "Newline in string constant",
- "Illegal character constant",
- "Illegal addressing mode",
- "Illegal character to start local symbols",
- "Illegal use of local symbol",
- "Illegal segment name: `%s'",
- "Illegal segment attribute",
- "Illegal macro package name",
- "Illegal emulation feature",
- "Syntax error",
- "Symbol `%s' is already defined",
- "Undefined symbol `%s'",
- "Symbol `%s' is marked as import",
- "Symbol `%s' is marked as export",
- "Exported symbol `%s' is undefined",
- "Exported values must be constant",
- ".IF nesting too deep",
- "Unexpected end of file",
- "Unexpected end of line",
- "Unexpected `%s'",
- "Division by zero",
- "Modulo operation with zero",
- "Range error",
- "Too many macro parameters",
- "Macro parameter expected",
- "Circular reference in symbol definition",
- "Symbol redeclaration mismatch",
- "Alignment value must be a power of 2",
- "Duplicate `.ELSE'",
- "Conditional assembly branch was never closed",
- "Lexical level was not terminated correctly",
- "Segment attribute mismatch",
- "CPU not supported",
- "Counter underflow",
- "Undefined label",
- "Open `%s´",
- "File name `%s' not found in file table",
- };
-
- fprintf (stderr, "%s(%lu): Error #%u: ",
- GetFileName (Pos->Name), Pos->Line, ErrNum);
- vfprintf (stderr, Msgs [ErrNum-1], ap);
- fprintf (stderr, "\n");
+ /* The first entry in the collection is that of the actual source pos */
+ const LineInfo* LI = CollConstAt (LineInfos, 0);
+
+ /* Output an error for this position */
+ VPrintMsg (GetSourcePos (LI), "Error", Format, ap);
+
+ /* Add additional notifications if necessary */
+ AddNotifications (LineInfos);
+
+ /* Count errors */
++ErrorCount;
}
-void Error (unsigned ErrNum, ...)
+void Error (const char* Format, ...)
/* Print an error message */
{
va_list ap;
- va_start (ap, ErrNum);
- ErrorMsg (&CurPos, ErrNum, ap);
+ Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
+
+ /* Get line infos for the current position */
+ GetFullLineInfo (&LineInfos);
+
+ /* Output the message */
+ va_start (ap, Format);
+ ErrorMsg (&LineInfos, Format, ap);
va_end (ap);
+
+ /* Free the line info list */
+ ReleaseFullLineInfo (&LineInfos);
+ DoneCollection (&LineInfos);
}
-void PError (const FilePos* Pos, unsigned ErrNum, ...)
+void PError (const FilePos* Pos, const char* Format, ...)
/* Print an error message giving an explicit file and position. */
{
va_list ap;
- va_start (ap, ErrNum);
- ErrorMsg (Pos, ErrNum, ap);
+ va_start (ap, Format);
+ 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);
}
-void ErrorSkip (unsigned ErrNum, ...)
+void ErrorSkip (const char* Format, ...)
/* Print an error message and skip the rest of the line */
{
va_list ap;
- va_start (ap, ErrNum);
- ErrorMsg (&CurPos, ErrNum, ap);
+ Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
+
+ /* Get line infos for the current position */
+ GetFullLineInfo (&LineInfos);
+
+ /* Output the message */
+ va_start (ap, Format);
+ 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 */
/*****************************************************************************/
-void Fatal (unsigned FatNum, ...)
+void Fatal (const char* Format, ...)
/* Print a message about a fatal error and die */
{
- static const char* Msgs [FAT_COUNT-1] = {
- "Maximum number of input files reached",
- "Out of memory",
- "Too many segments",
- "String too long",
- "Cannot open input file `%s': %s",
- "Cannot stat input file `%s': %s",
- "Cannot open output file `%s': %s",
- "Cannot write to output file `%s': %s",
- "Cannot open listing file: %s",
- "Cannot write to listing file: %s",
- "Cannot read from listing file: %s",
- "Too many nested constructs",
- "Too many symbols",
- };
va_list ap;
+ StrBuf S = STATIC_STRBUF_INITIALIZER;
- va_start (ap, FatNum);
- fprintf (stderr, "Fatal #%u: ", FatNum);
- vfprintf (stderr, Msgs [FatNum-1], ap);
- fprintf (stderr, "\n");
+ va_start (ap, Format);
+ SB_VPrintf (&S, Format, ap);
+ SB_Terminate (&S);
va_end (ap);
+ fprintf (stderr, "Fatal error: %s\n", SB_GetConstBuf (&S));
+
+ SB_Done (&S);
+
/* And die... */
exit (EXIT_FAILURE);
}
void Internal (const char* Format, ...)
-/* Print a message about an internal compiler error and die. */
+/* Print a message about an internal assembler error and die. */
{
va_list ap;
+ StrBuf S = STATIC_STRBUF_INITIALIZER;
+
va_start (ap, Format);
- fprintf (stderr, "Internal assembler error\n");
- vfprintf (stderr, Format, ap);
+ SB_VPrintf (&S, Format, ap);
+ SB_Terminate (&S);
va_end (ap);
- fprintf (stderr, "\n");
-
- exit (EXIT_FAILURE);
-}
+ fprintf (stderr, "Internal assembler error: %s\n", SB_GetConstBuf (&S));
+ SB_Done (&S);
+ exit (EXIT_FAILURE);
+}