fix cases where compoundlits are constant/get an entity
[cparser] / diagnostic.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <stdarg.h>
21 #include <stdio.h>
22
23 #include "diagnostic.h"
24 #include "adt/error.h"
25 #include "entity_t.h"
26 #include "separator_t.h"
27 #include "symbol_t.h"
28 #include "token_t.h"
29 #include "ast.h"
30 #include "type.h"
31 #include "warning.h"
32
33 /** Number of occurred errors. */
34 unsigned error_count             = 0;
35 /** Number of occurred warnings. */
36 unsigned warning_count           = 0;
37 bool     show_column             = true;
38 bool     diagnostics_show_option = true;
39
40 static const source_position_t *curr_pos = NULL;
41
42 /**
43  * prints an additional source position
44  */
45 static void print_source_position(FILE *out, const source_position_t *pos)
46 {
47         fprintf(out, "at line %u", pos->lineno);
48         if (show_column)
49                 fprintf(out, ":%u", (unsigned)pos->colno);
50         if (curr_pos == NULL || curr_pos->input_name != pos->input_name)
51                 fprintf(out, " of \"%s\"", pos->input_name);
52 }
53
54 static void fpututf32(utf32 const c, FILE *const out)
55 {
56         if (c < 0x80U) {
57                 fputc(c, out);
58         } else if (c < 0x800) {
59                 fputc(0xC0 | (c >> 6), out);
60                 fputc(0x80 | (c & 0x3F), out);
61         } else if (c < 0x10000) {
62                 fputc(0xE0 | ( c >> 12), out);
63                 fputc(0x80 | ((c >>  6) & 0x3F), out);
64                 fputc(0x80 | ( c        & 0x3F), out);
65         } else {
66                 fputc(0xF0 | ( c >> 18), out);
67                 fputc(0x80 | ((c >> 12) & 0x3F), out);
68                 fputc(0x80 | ((c >>  6) & 0x3F), out);
69                 fputc(0x80 | ( c        & 0x3F), out);
70         }
71 }
72
73 /**
74  * Issue a diagnostic message.
75  */
76 static void diagnosticvf(char const *fmt, va_list ap)
77 {
78         for (char const *f; (f = strchr(fmt, '%')); fmt = f) {
79                 fwrite(fmt, sizeof(*fmt), f - fmt, stderr); // Print till '%'.
80                 ++f; // Skip '%'.
81
82                 bool extended  = false;
83                 bool flag_zero = false;
84                 bool flag_long = false;
85                 for (;; ++f) {
86                         switch (*f) {
87                         case '#': extended  = true; break;
88                         case '0': flag_zero = true; break;
89                         case 'l': flag_long = true; break;
90                         default:  goto done_flags;
91                         }
92                 }
93 done_flags:;
94
95                 int field_width = 0;
96                 if (*f == '*') {
97                         ++f;
98                         field_width = va_arg(ap, int);
99                 }
100
101                 switch (*f++) {
102                 case '%':
103                         fputc('%', stderr);
104                         break;
105
106                 case 'c': {
107                         if (flag_long) {
108                                 const utf32 val = va_arg(ap, utf32);
109                                 fpututf32(val, stderr);
110                         } else {
111                                 const unsigned char val = (unsigned char) va_arg(ap, int);
112                                 fputc(val, stderr);
113                         }
114                         break;
115                 }
116
117                 case 'd': {
118                         const int val = va_arg(ap, int);
119                         fprintf(stderr, "%d", val);
120                         break;
121                 }
122
123                 case 's': {
124                         const char* const str = va_arg(ap, const char*);
125                         fputs(str, stderr);
126                         break;
127                 }
128
129                 case 'S': {
130                         const string_t *str = va_arg(ap, const string_t*);
131                         for (size_t i = 0; i < str->size; ++i) {
132                                 fputc(str->begin[i], stderr);
133                         }
134                         break;
135                 }
136
137                 case 'u': {
138                         const unsigned int val = va_arg(ap, unsigned int);
139                         fprintf(stderr, "%u", val);
140                         break;
141                 }
142
143                 case 'X': {
144                         unsigned int const val = va_arg(ap, unsigned int);
145                         char const  *const fmt = flag_zero ? "%0*X" : "%*X";
146                         fprintf(stderr, fmt, field_width, val);
147                         break;
148                 }
149
150                 case 'Y': {
151                         const symbol_t *const symbol = va_arg(ap, const symbol_t*);
152                         if (symbol == NULL)
153                                 fputs("(null)", stderr);
154                         else
155                                 fputs(symbol->string, stderr);
156                         break;
157                 }
158
159                 case 'E': {
160                         const expression_t* const expr = va_arg(ap, const expression_t*);
161                         print_expression(expr);
162                         break;
163                 }
164
165                 case 'Q': {
166                         const unsigned qualifiers = va_arg(ap, unsigned);
167                         print_type_qualifiers(qualifiers, QUAL_SEP_NONE);
168                         break;
169                 }
170
171                 case 'T': {
172                         const type_t* const type = va_arg(ap, const type_t*);
173                         const symbol_t*     sym  = NULL;
174                         if (extended) {
175                                 sym = va_arg(ap, const symbol_t*);
176                         }
177                         print_type_ext(type, sym, NULL);
178                         break;
179                 }
180
181                 case 'K': {
182                         const token_t* const token = va_arg(ap, const token_t*);
183                         print_token(stderr, token);
184                         break;
185                 }
186
187                 case 'k': {
188                         if (extended) {
189                                 va_list* const toks = va_arg(ap, va_list*);
190                                 separator_t    sep  = { "", va_arg(ap, const char*) };
191                                 for (;;) {
192                                         const token_kind_t tok = (token_kind_t)va_arg(*toks, int);
193                                         if (tok == 0)
194                                                 break;
195                                         fputs(sep_next(&sep), stderr);
196                                         print_token_kind(stderr, tok);
197                                 }
198                         } else {
199                                 const token_kind_t token = (token_kind_t)va_arg(ap, int);
200                                 print_token_kind(stderr, token);
201                         }
202                         break;
203                 }
204
205                 case 'N': {
206                         entity_t const *const ent = va_arg(ap, entity_t const*);
207                         if (extended && is_declaration(ent)) {
208                                 print_type_ext(ent->declaration.type, ent->base.symbol, NULL);
209                         } else {
210                                 char     const *const kind = get_entity_kind_name(ent->kind);
211                                 symbol_t const *const sym  = ent->base.symbol;
212                                 if (sym) {
213                                         fprintf(stderr, "%s %s", kind, sym->string);
214                                 } else {
215                                         fprintf(stderr, "anonymous %s", kind);
216                                 }
217                         }
218                         break;
219                 }
220
221                 case 'P': {
222                         const source_position_t *pos = va_arg(ap, const source_position_t *);
223                         print_source_position(stderr, pos);
224                         break;
225                 }
226
227                 default:
228                         panic("unknown format specifier");
229                 }
230         }
231         fputs(fmt, stderr); // Print rest.
232 }
233
234 void diagnosticf(const char *const fmt, ...)
235 {
236         va_list ap;
237         va_start(ap, fmt);
238         curr_pos = NULL;
239         diagnosticvf(fmt, ap);
240         va_end(ap);
241 }
242
243 static void diagnosticposvf(source_position_t const *const pos, char const *const kind, char const *const fmt, va_list ap)
244 {
245         FILE *const out = stderr;
246         if (pos) {
247                 fprintf(out, "%s:", pos->input_name);
248                 if (pos->lineno != 0) {
249                         fprintf(out, "%u:", pos->lineno);
250                         if (show_column)
251                                 fprintf(out, "%u:", (unsigned)pos->colno);
252                 }
253                 fputc(' ', out);
254         }
255         fprintf(out, "%s: ", kind);
256         curr_pos = pos;
257         diagnosticvf(fmt, ap);
258 }
259
260 static void errorvf(const source_position_t *pos,
261                     const char *const fmt, va_list ap)
262 {
263         ++error_count;
264         diagnosticposvf(pos, "error", fmt, ap);
265         fputc('\n', stderr);
266         if (is_warn_on(WARN_FATAL_ERRORS))
267                 exit(EXIT_FAILURE);
268 }
269
270 void errorf(const source_position_t *pos, const char *const fmt, ...)
271 {
272         va_list ap;
273         va_start(ap, fmt);
274         errorvf(pos, fmt, ap);
275         va_end(ap);
276 }
277
278 void warningf(warning_t const warn, source_position_t const* pos, char const *const fmt, ...)
279 {
280         va_list ap;
281         va_start(ap, fmt);
282         warning_switch_t const *const s = get_warn_switch(warn);
283         switch ((unsigned) s->state) {
284                         char const* kind;
285                 case WARN_STATE_ON:
286                         if (is_warn_on(WARN_ERROR)) {
287                 case WARN_STATE_ON | WARN_STATE_ERROR:
288                                 ++error_count;
289                                 kind = "error";
290                         } else {
291                 case WARN_STATE_ON | WARN_STATE_NO_ERROR:
292                                 ++warning_count;
293                                 kind = "warning";
294                         }
295                         diagnosticposvf(pos, kind, fmt, ap);
296                         if (diagnostics_show_option)
297                                 fprintf(stderr, " [-W%s]\n", s->name);
298                         else
299                                 fputc('\n', stderr);
300                         break;
301
302                 default:
303                         break;
304         }
305         va_end(ap);
306 }
307
308 static void internal_errorvf(const source_position_t *pos,
309                     const char *const fmt, va_list ap)
310 {
311         diagnosticposvf(pos, "internal error", fmt, ap);
312         fputc('\n', stderr);
313 }
314
315 void internal_errorf(const source_position_t *pos, const char *const fmt, ...)
316 {
317         va_list ap;
318         va_start(ap, fmt);
319         internal_errorvf(pos, fmt, ap);
320         va_end(ap);
321         abort();
322 }