X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fca65%2Ferror.c;h=ffda60ecdbbd78f6db1a0687bc9d0689e2a43486;hb=361da29e51c2eb2a944a0fbfca854a040dd88fdc;hp=f8f0eabfa953e43a6e51262a0784aa17ad9f074c;hpb=1167d99a9be41e33416a65da431bf93cbacde34c;p=cc65 diff --git a/src/ca65/error.c b/src/ca65/error.c index f8f0eabfa..ffda60ecd 100644 --- a/src/ca65/error.c +++ b/src/ca65/error.c @@ -1,15 +1,15 @@ /*****************************************************************************/ /* */ -/* error.c */ +/* error.c */ /* */ -/* Error handling for the ca65 macroassembler */ +/* Error handling for the ca65 macroassembler */ /* */ /* */ /* */ -/* (C) 1998-2002 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 */ @@ -37,240 +37,346 @@ #include #include +/* 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", - "Cannot read from 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", - "`=' 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", - "Illegal scope specifier", - "Syntax error", - "Symbol `%s' is already defined", - "Undefined symbol `%s'", - "Symbol `%s' is already marked as import", - "Symbol `%s' is already marked as export", - "Exported symbol `%s' is undefined", - "Exported values must be constant", - "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 `%s' 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", - "Segment stack overflow", - "Segment stack is empty", - "Segment stack is not empty at end of assembly", - "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", - ".IF nesting too deep", - "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); } @@ -278,14 +384,19 @@ void Fatal (unsigned FatNum, ...) 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"); + + fprintf (stderr, "Internal assembler error: %s\n", SB_GetConstBuf (&S)); + + SB_Done (&S); exit (EXIT_FAILURE); }