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