]> git.sur5r.net Git - cc65/blob - src/ca65/error.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / ca65 / error.c
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 */
58 unsigned WarnLevel      = 1;
59
60 /* Statistics */
61 unsigned ErrorCount     = 0;
62 unsigned 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
75 static 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
111 static 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
123 static 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 = "Assembler 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
192 static 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
210 void 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
234 void 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
250 void 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
270 void 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
288 void 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
309 void 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
323 void 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
335 void 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
365 void 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
386 void 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
404
405