1/*****************************************************************************/
2/* */
3/* error.c */
4/* */
5/* Error handling for the ca65 macroassembler */
6/* */
7/* */
8/* */
9/* (C) 1998-2012, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <stdarg.h>
39
40/* common */
41#include "strbuf.h"
42
43/* ca65 */
44#include "error.h"
45#include "filetab.h"
46#include "lineinfo.h"
47#include "nexttok.h"
48
49
50
51/*****************************************************************************/
52/* Data */
53/*****************************************************************************/
54
55
56
57/* Warning level */
58unsigned WarnLevel = 1;
59
60/* Statistics */
61unsigned ErrorCount = 0;
62unsigned WarningCount = 0;
63
64/* Maximum number of additional notifications */
65#define MAX_NOTES 8
66
67
68
69/*****************************************************************************/
70/* Helper functions */
71/*****************************************************************************/
72
73
74
75static void VPrintMsg (const FilePos* Pos, const char* Desc,
76 const char* Format, va_list ap)
77/* Format and output an error/warning message. */
78{
79 StrBuf S = STATIC_STRBUF_INITIALIZER;
80
81 /* Format the actual message */
82 StrBuf Msg = STATIC_STRBUF_INITIALIZER;
83 SB_VPrintf (&Msg, Format, ap);
84 SB_Terminate (&Msg);
85
86 /* Format the message header */
87 SB_Printf (&S, "%s(%u): %s: ",
88 SB_GetConstBuf (GetFileName (Pos->Name)),
89 Pos->Line,
90 Desc);
91
92 /* Append the message to the message header */
93 SB_Append (&S, &Msg);
94
95 /* Delete the formatted message */
96 SB_Done (&Msg);
97
98 /* Add a new line and terminate the generated full message */
99 SB_AppendChar (&S, '\n');
100 SB_Terminate (&S);
101
102 /* Output the full message */
103 fputs (SB_GetConstBuf (&S), stderr);
104
105 /* Delete the buffer for the full message */
106 SB_Done (&S);
107}
108
109
110
111static void PrintMsg (const FilePos* Pos, const char* Desc,
112 const char* Format, ...)
113/* Format and output an error/warning message. */
114{
115 va_list ap;
116 va_start (ap, Format);
117 VPrintMsg (Pos, Desc, Format, ap);
118 va_end (ap);
119}
120
121
122
123static void AddNotifications (const Collection* LineInfos)
124/* Output additional notifications for an error or warning */
125{
126 unsigned I;
127 unsigned Output;
128 unsigned Skipped;
129
130 /* The basic line info is always in slot zero. It has been used to
131 ** output the actual error or warning. The following slots may contain
132 ** more information. Check them and print additional notifications if
133 ** they're present, but limit the number to a reasonable value.
134 */
135 for (I = 1, Output = 0, Skipped = 0; I < CollCount (LineInfos); ++I) {
136 /* Get next line info */
137 const LineInfo* LI = CollConstAt (LineInfos, I);
138 /* Check the type and output an appropriate note */
139 const char* Msg;
140 switch (GetLineInfoType (LI)) {
141
142 case LI_TYPE_ASM:
143 Msg = "Expanded from here";
144 break;
145
146 case LI_TYPE_EXT:
147 Msg = "Assembly code generated from this line";
148 break;
149
150 case LI_TYPE_MACRO:
151 Msg = "Macro was defined here";
152 break;
153
154 case LI_TYPE_MACPARAM:
155 Msg = "Macro parameter came from here";
156 break;
157
158 default:
159 /* No output */
160 Msg = 0;
161 break;
162
163 }
164
165 /* Output until an upper limit of messages is reached */
166 if (Msg) {
167 if (Output < MAX_NOTES) {
168 PrintMsg (GetSourcePos (LI), "Note", "%s", Msg);
169 ++Output;
170 } else {
171 ++Skipped;
172 }
173 }
174 }
175
176 /* Add a note if we have more stuff that we won't output */
177 if (Skipped > 0) {
178 const LineInfo* LI = CollConstAt (LineInfos, 0);
179 PrintMsg (GetSourcePos (LI), "Note",
180 "Dropping %u additional line infos", Skipped);
181 }
182}
183
184
185
186/*****************************************************************************/
187/* Warnings */
188/*****************************************************************************/
189
190
191
192static void WarningMsg (const Collection* LineInfos, const char* Format, va_list ap)
193/* Print warning message. */
194{
195 /* The first entry in the collection is that of the actual source pos */
196 const LineInfo* LI = CollConstAt (LineInfos, 0);
197
198 /* Output a warning for this position */
199 VPrintMsg (GetSourcePos (LI), "Warning", Format, ap);
200
201 /* Add additional notifications if necessary */
202 AddNotifications (LineInfos);
203
204 /* Count warnings */
205 ++WarningCount;
206}
207
208
209
210void Warning (unsigned Level, const char* Format, ...)
211/* Print warning message. */
212{
213 if (Level <= WarnLevel) {
214
215 va_list ap;
216 Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
217
218 /* Get line infos for the current position */
219 GetFullLineInfo (&LineInfos);
220
221 /* Output the message */
222 va_start (ap, Format);
223 WarningMsg (&LineInfos, Format, ap);
224 va_end (ap);
225
226 /* Free the line info list */
227 ReleaseFullLineInfo (&LineInfos);
228 DoneCollection (&LineInfos);
229 }
230}
231
232
233
234void PWarning (const FilePos* Pos, unsigned Level, const char* Format, ...)
235/* Print warning message giving an explicit file and position. */
236{
237 if (Level <= WarnLevel) {
238 va_list ap;
239 va_start (ap, Format);
240 VPrintMsg (Pos, "Warning", Format, ap);
241 va_end (ap);
242
243 /* Count warnings */
244 ++WarningCount;
245 }
246}
247
248
249
250void LIWarning (const Collection* LineInfos, unsigned Level, const char* Format, ...)
251/* Print warning message using the given line infos */
252{
253 if (Level <= WarnLevel) {
254 /* Output the message */
255 va_list ap;
256 va_start (ap, Format);
257 WarningMsg (LineInfos, Format, ap);
258 va_end (ap);
259 }
260}
261
262
263
264/*****************************************************************************/
265/* Errors */
266/*****************************************************************************/
267
268
269
270void ErrorMsg (const Collection* LineInfos, const char* Format, va_list ap)
271/* Print an error message */
272{
273 /* The first entry in the collection is that of the actual source pos */
274 const LineInfo* LI = CollConstAt (LineInfos, 0);
275
276 /* Output an error for this position */
277 VPrintMsg (GetSourcePos (LI), "Error", Format, ap);
278
279 /* Add additional notifications if necessary */
280 AddNotifications (LineInfos);
281
282 /* Count errors */
283 ++ErrorCount;
284}
285
286
287
288void Error (const char* Format, ...)
289/* Print an error message */
290{
291 va_list ap;
292 Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
293
294 /* Get line infos for the current position */
295 GetFullLineInfo (&LineInfos);
296
297 /* Output the message */
298 va_start (ap, Format);
299 ErrorMsg (&LineInfos, Format, ap);
300 va_end (ap);
301
302 /* Free the line info list */
303 ReleaseFullLineInfo (&LineInfos);
304 DoneCollection (&LineInfos);
305}
306
307
308
309void PError (const FilePos* Pos, const char* Format, ...)
310/* Print an error message giving an explicit file and position. */
311{
312 va_list ap;
313 va_start (ap, Format);
314 VPrintMsg (Pos, "Error", Format, ap);
315 va_end (ap);
316
317 /* Count errors */
318 ++ErrorCount;
319}
320
321
322
323void LIError (const Collection* LineInfos, const char* Format, ...)
324/* Print an error message using the given line infos. */
325{
326 /* Output an error for this position */
327 va_list ap;
328 va_start (ap, Format);
329 ErrorMsg (LineInfos, Format, ap);
330 va_end (ap);
331}
332
333
334
335void ErrorSkip (const char* Format, ...)
336/* Print an error message and skip the rest of the line */
337{
338 va_list ap;
339 Collection LineInfos = STATIC_COLLECTION_INITIALIZER;
340
341 /* Get line infos for the current position */
342 GetFullLineInfo (&LineInfos);
343
344 /* Output the message */
345 va_start (ap, Format);
346 ErrorMsg (&LineInfos, Format, ap);
347 va_end (ap);
348
349 /* Free the line info list */
350 ReleaseFullLineInfo (&LineInfos);
351 DoneCollection (&LineInfos);
352
353 /* Skip tokens until we reach the end of the line */
354 SkipUntilSep ();
355}
356
357
358
359/*****************************************************************************/
360/* Code */
361/*****************************************************************************/
362
363
364
365void Fatal (const char* Format, ...)
366/* Print a message about a fatal error and die */
367{
368 va_list ap;
369 StrBuf S = STATIC_STRBUF_INITIALIZER;
370
371 va_start (ap, Format);
372 SB_VPrintf (&S, Format, ap);
373 SB_Terminate (&S);
374 va_end (ap);
375
376 fprintf (stderr, "Fatal error: %s\n", SB_GetConstBuf (&S));
377
378 SB_Done (&S);
379
380 /* And die... */
381 exit (EXIT_FAILURE);
382}
383
384
385
386void Internal (const char* Format, ...)
387/* Print a message about an internal assembler error and die. */
388{
389 va_list ap;
390 StrBuf S = STATIC_STRBUF_INITIALIZER;
391
392 va_start (ap, Format);
393 SB_VPrintf (&S, Format, ap);
394 SB_Terminate (&S);
395 va_end (ap);
396
397 fprintf (stderr, "Internal assembler error: %s\n", SB_GetConstBuf (&S));
398
399 SB_Done (&S);
400
401 exit (EXIT_FAILURE);
402}
403