1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* error.c */ |
4 | /* */ |
5 | /* Error handling for the cc65 C compiler */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 1998-2011, 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 "print.h" |
42 | |
43 | /* cc65 */ |
44 | #include "global.h" |
45 | #include "input.h" |
46 | #include "lineinfo.h" |
47 | #include "scanner.h" |
48 | #include "stmt.h" |
49 | #include "error.h" |
50 | |
51 | |
52 | |
53 | /*****************************************************************************/ |
54 | /* Data */ |
55 | /*****************************************************************************/ |
56 | |
57 | |
58 | |
59 | /* Count of errors/warnings */ |
60 | unsigned ErrorCount = 0; |
61 | unsigned WarningCount = 0; |
62 | |
63 | /* Warning and error options */ |
64 | IntStack WarnEnable = INTSTACK(1); /* Enable warnings */ |
65 | IntStack WarningsAreErrors = INTSTACK(0); /* Treat warnings as errors */ |
66 | /* Warn about: */ |
67 | IntStack WarnConstComparison= INTSTACK(1); /* - constant comparison results */ |
68 | IntStack WarnNoEffect = INTSTACK(1); /* - statements without an effect */ |
69 | IntStack WarnRemapZero = INTSTACK(1); /* - remapping character code zero */ |
70 | IntStack WarnStructParam = INTSTACK(1); /* - structs passed by val */ |
71 | IntStack WarnUnknownPragma = INTSTACK(1); /* - unknown #pragmas */ |
72 | IntStack WarnUnusedLabel = INTSTACK(1); /* - unused labels */ |
73 | IntStack WarnUnusedParam = INTSTACK(1); /* - unused parameters */ |
74 | IntStack WarnUnusedVar = INTSTACK(1); /* - unused variables */ |
75 | |
76 | /* Map the name of a warning to the intstack that holds its state */ |
77 | typedef struct WarnMapEntry WarnMapEntry; |
78 | struct WarnMapEntry { |
79 | IntStack* Stack; |
80 | const char* Name; |
81 | }; |
82 | static WarnMapEntry WarnMap[] = { |
83 | /* Keep names sorted, even if it isn't used for now */ |
84 | { &WarnConstComparison, "const-comparison" }, |
85 | { &WarningsAreErrors, "error" }, |
86 | { &WarnNoEffect, "no-effect" }, |
87 | { &WarnRemapZero, "remap-zero" }, |
88 | { &WarnStructParam, "struct-param" }, |
89 | { &WarnUnknownPragma, "unknown-pragma" }, |
90 | { &WarnUnusedLabel, "unused-label" }, |
91 | { &WarnUnusedParam, "unused-param" }, |
92 | { &WarnUnusedVar, "unused-var" }, |
93 | }; |
94 | |
95 | |
96 | |
97 | /*****************************************************************************/ |
98 | /* Handling of fatal errors */ |
99 | /*****************************************************************************/ |
100 | |
101 | |
102 | |
103 | void Fatal (const char* Format, ...) |
104 | /* Print a message about a fatal error and die */ |
105 | { |
106 | va_list ap; |
107 | |
108 | const char* FileName; |
109 | unsigned LineNum; |
110 | if (CurTok.LI) { |
111 | FileName = GetInputName (CurTok.LI); |
112 | LineNum = GetInputLine (CurTok.LI); |
113 | } else { |
114 | FileName = GetCurrentFile (); |
115 | LineNum = GetCurrentLine (); |
116 | } |
117 | |
118 | fprintf (stderr, "%s(%u): Fatal: " , FileName, LineNum); |
119 | |
120 | va_start (ap, Format); |
121 | vfprintf (stderr, Format, ap); |
122 | va_end (ap); |
123 | fprintf (stderr, "\n" ); |
124 | |
125 | if (Line) { |
126 | Print (stderr, 1, "Input: %.*s\n" , (int) SB_GetLen (Line), SB_GetConstBuf (Line)); |
127 | } |
128 | exit (EXIT_FAILURE); |
129 | } |
130 | |
131 | |
132 | |
133 | void Internal (const char* Format, ...) |
134 | /* Print a message about an internal compiler error and die. */ |
135 | { |
136 | va_list ap; |
137 | |
138 | const char* FileName; |
139 | unsigned LineNum; |
140 | if (CurTok.LI) { |
141 | FileName = GetInputName (CurTok.LI); |
142 | LineNum = GetInputLine (CurTok.LI); |
143 | } else { |
144 | FileName = GetCurrentFile (); |
145 | LineNum = GetCurrentLine (); |
146 | } |
147 | |
148 | fprintf (stderr, "%s(%u): Internal compiler error:\n" , |
149 | FileName, LineNum); |
150 | |
151 | va_start (ap, Format); |
152 | vfprintf (stderr, Format, ap); |
153 | va_end (ap); |
154 | fprintf (stderr, "\n" ); |
155 | |
156 | if (Line) { |
157 | fprintf (stderr, "\nInput: %.*s\n" , (int) SB_GetLen (Line), SB_GetConstBuf (Line)); |
158 | } |
159 | |
160 | /* Use abort to create a core dump */ |
161 | abort (); |
162 | } |
163 | |
164 | |
165 | |
166 | /*****************************************************************************/ |
167 | /* Handling of errors */ |
168 | /*****************************************************************************/ |
169 | |
170 | |
171 | |
172 | static void IntError (const char* Filename, unsigned LineNo, const char* Msg, va_list ap) |
173 | /* Print an error message - internal function*/ |
174 | { |
175 | fprintf (stderr, "%s(%u): Error: " , Filename, LineNo); |
176 | vfprintf (stderr, Msg, ap); |
177 | fprintf (stderr, "\n" ); |
178 | |
179 | if (Line) { |
180 | Print (stderr, 1, "Input: %.*s\n" , (int) SB_GetLen (Line), SB_GetConstBuf (Line)); |
181 | } |
182 | ++ErrorCount; |
183 | if (ErrorCount > 10) { |
184 | Fatal ("Too many errors" ); |
185 | } |
186 | } |
187 | |
188 | |
189 | |
190 | void Error (const char* Format, ...) |
191 | /* Print an error message */ |
192 | { |
193 | va_list ap; |
194 | va_start (ap, Format); |
195 | IntError (GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Format, ap); |
196 | va_end (ap); |
197 | } |
198 | |
199 | |
200 | |
201 | void LIError (const LineInfo* LI, const char* Format, ...) |
202 | /* Print an error message with the line info given explicitly */ |
203 | { |
204 | va_list ap; |
205 | va_start (ap, Format); |
206 | IntError (GetInputName (LI), GetInputLine (LI), Format, ap); |
207 | va_end (ap); |
208 | } |
209 | |
210 | |
211 | |
212 | void PPError (const char* Format, ...) |
213 | /* Print an error message. For use within the preprocessor. */ |
214 | { |
215 | va_list ap; |
216 | va_start (ap, Format); |
217 | IntError (GetCurrentFile(), GetCurrentLine(), Format, ap); |
218 | va_end (ap); |
219 | } |
220 | |
221 | |
222 | |
223 | /*****************************************************************************/ |
224 | /* Handling of warnings */ |
225 | /*****************************************************************************/ |
226 | |
227 | |
228 | |
229 | static void IntWarning (const char* Filename, unsigned LineNo, const char* Msg, va_list ap) |
230 | /* Print warning message - internal function. */ |
231 | { |
232 | if (IS_Get (&WarningsAreErrors)) { |
233 | |
234 | /* Treat the warning as an error */ |
235 | IntError (Filename, LineNo, Msg, ap); |
236 | |
237 | } else if (IS_Get (&WarnEnable)) { |
238 | |
239 | fprintf (stderr, "%s(%u): Warning: " , Filename, LineNo); |
240 | vfprintf (stderr, Msg, ap); |
241 | fprintf (stderr, "\n" ); |
242 | |
243 | if (Line) { |
244 | Print (stderr, 1, "Input: %.*s\n" , (int) SB_GetLen (Line), SB_GetConstBuf (Line)); |
245 | } |
246 | ++WarningCount; |
247 | |
248 | } |
249 | } |
250 | |
251 | |
252 | |
253 | void Warning (const char* Format, ...) |
254 | /* Print warning message. */ |
255 | { |
256 | va_list ap; |
257 | va_start (ap, Format); |
258 | IntWarning (GetInputName (CurTok.LI), GetInputLine (CurTok.LI), Format, ap); |
259 | va_end (ap); |
260 | } |
261 | |
262 | |
263 | |
264 | void LIWarning (const LineInfo* LI, const char* Format, ...) |
265 | /* Print a warning message with the line info given explicitly */ |
266 | { |
267 | va_list ap; |
268 | va_start (ap, Format); |
269 | IntWarning (GetInputName (LI), GetInputLine (LI), Format, ap); |
270 | va_end (ap); |
271 | } |
272 | |
273 | |
274 | |
275 | void PPWarning (const char* Format, ...) |
276 | /* Print warning message. For use within the preprocessor. */ |
277 | { |
278 | va_list ap; |
279 | va_start (ap, Format); |
280 | IntWarning (GetCurrentFile(), GetCurrentLine(), Format, ap); |
281 | va_end (ap); |
282 | } |
283 | |
284 | |
285 | |
286 | IntStack* FindWarning (const char* Name) |
287 | /* Search for a warning in the WarnMap table and return a pointer to the |
288 | ** intstack that holds its state. Return NULL if there is no such warning. |
289 | */ |
290 | { |
291 | unsigned I; |
292 | |
293 | /* For now, do a linear search */ |
294 | for (I = 0; I < sizeof(WarnMap) / sizeof (WarnMap[0]); ++I) { |
295 | if (strcmp (WarnMap[I].Name, Name) == 0) { |
296 | return WarnMap[I].Stack; |
297 | } |
298 | } |
299 | return 0; |
300 | } |
301 | |
302 | |
303 | |
304 | void ListWarnings (FILE* F) |
305 | /* Print a list of warning types/names to the given file */ |
306 | { |
307 | unsigned I; |
308 | for (I = 0; I < sizeof(WarnMap) / sizeof (WarnMap[0]); ++I) { |
309 | fprintf (F, "%s\n" , WarnMap[I].Name); |
310 | } |
311 | } |
312 | |
313 | |
314 | |
315 | /*****************************************************************************/ |
316 | /* Code */ |
317 | /*****************************************************************************/ |
318 | |
319 | |
320 | |
321 | void ErrorReport (void) |
322 | /* Report errors (called at end of compile) */ |
323 | { |
324 | Print (stdout, 1, "%u errors, %u warnings\n" , ErrorCount, WarningCount); |
325 | } |
326 | |