Files
cc65/src/ca65/error.c
uz 4a41865898 Fixed a problem in line info generation: Recorded token lists emitted the
tokens using the standard ASM line info, overwriting the existing one from the
real source line. Since this info was lost, and couldn't be recovered, the
original source location was omitted in error messages.


git-svn-id: svn://svn.cc65.org/cc65/trunk@5905 b7a2c559-68d2-44c3-8de9-860c34a00d81
2012-11-04 12:57:34 +00:00

406 lines
11 KiB
C

/*****************************************************************************/
/* */
/* error.c */
/* */
/* Error handling for the ca65 macroassembler */
/* */
/* */
/* */
/* (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 */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
/* common */
#include "strbuf.h"
/* ca65 */
#include "error.h"
#include "filetab.h"
#include "lineinfo.h"
#include "nexttok.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Warning level */
unsigned WarnLevel = 1;
/* Statistics */
unsigned ErrorCount = 0;
unsigned WarningCount = 0;
/* Maximum number of additional notifications */
#define MAX_NOTES 8
/*****************************************************************************/
/* Helper functions */
/*****************************************************************************/
static void VPrintMsg (const FilePos* Pos, const char* Desc,
const char* Format, va_list ap)
/* Format and output an error/warning message. */
{
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);
}
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);
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. */
{
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 */
/*****************************************************************************/
void ErrorMsg (const Collection* LineInfos, const char* Format, va_list ap)
/* Print an error message */
{
/* 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 (const char* Format, ...)
/* 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 (&LineInfos, Format, ap);
va_end (ap);
/* Free the line info list */
ReleaseFullLineInfo (&LineInfos);
DoneCollection (&LineInfos);
}
void PError (const FilePos* Pos, const char* Format, ...)
/* Print an error message giving an explicit file and position. */
{
va_list 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 (const char* Format, ...)
/* 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 (&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 */
/*****************************************************************************/
void Fatal (const char* Format, ...)
/* Print a message about a fatal error and die */
{
va_list ap;
StrBuf S = STATIC_STRBUF_INITIALIZER;
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 assembler error and die. */
{
va_list ap;
StrBuf S = STATIC_STRBUF_INITIALIZER;
va_start (ap, Format);
SB_VPrintf (&S, Format, ap);
SB_Terminate (&S);
va_end (ap);
fprintf (stderr, "Internal assembler error: %s\n", SB_GetConstBuf (&S));
SB_Done (&S);
exit (EXIT_FAILURE);
}