options -w and -Wfatal-errors implemented
[cparser] / diagnostic.c
1 #include <stdarg.h>
2 #include <stdio.h>
3
4 #include "adt/error.h"
5 #include "ast.h"
6 #include "diagnostic.h"
7 #include "token_t.h"
8 #include "type.h"
9
10 /** Number of occurred diagnostics. */
11 unsigned diagnostic_count = 0;
12 /** Number of occurred errors. */
13 unsigned error_count      = 0;
14 /** Number of occurred warnings. */
15 unsigned warning_count    = 0;
16 /** true if warnings should be inhibited */
17 bool inhibit_all_warnings = false;
18 /** true if warnings should be treated as errors */
19 bool warnings_are_errors  = false;
20 /** true if the first error should stop the compilation */
21 bool fatal_errors = false;
22
23 /**
24  * Issue a diagnostic message.
25  */
26 static void diagnosticvf(const char *const fmt, va_list ap)
27 {
28         for (const char* f = fmt; *f != '\0'; ++f) {
29                 if (*f == '%') {
30                         ++f;
31
32                         bool extended = false;
33                         if (*f == '#') {
34                                 extended = true;
35                                 ++f;
36                         }
37
38                         switch (*f) {
39                                 case '%':
40                                         fputc(*f, stderr);
41                                         break;
42
43                                 case 'C': {
44                                         const wint_t val = va_arg(ap, wint_t);
45                                         fputwc(val, stderr);
46                                         break;
47                                 }
48
49                                 case 'c': {
50                                         const unsigned char val = (unsigned char) va_arg(ap, int);
51                                         fputc(val, stderr);
52                                         break;
53                                 }
54
55                                 case 'd': {
56                                         const int val = va_arg(ap, int);
57                                         fprintf(stderr, "%d", val);
58                                         break;
59                                 }
60
61                                 case 's': {
62                                         const char* const str = va_arg(ap, const char*);
63                                         fputs(str, stderr);
64                                         break;
65                                 }
66
67                                 case 'Y': {
68                                         const symbol_t *const symbol = va_arg(ap, const symbol_t*);
69                                         fputs(symbol->string, stderr);
70                                         break;
71                                 }
72
73                                 case 'E': {
74                                         const expression_t* const expr = va_arg(ap, const expression_t*);
75                                         print_expression(expr);
76                                         break;
77                                 }
78
79                                 case 'Q': {
80                                         const unsigned qualifiers = va_arg(ap, unsigned);
81                                         print_type_qualifiers(qualifiers);
82                                         break;
83                                 }
84
85                                 case 'T': {
86                                         const type_t* const type = va_arg(ap, const type_t*);
87                                         const symbol_t*     sym  = NULL;
88                                         if (extended) {
89                                                 sym = va_arg(ap, const symbol_t*);
90                                         }
91                                         print_type_ext(type, sym, NULL);
92                                         break;
93                                 }
94
95                                 case 'K': {
96                                         const token_t* const token = va_arg(ap, const token_t*);
97                                         print_token(stderr, token);
98                                         break;
99                                 }
100
101                                 case 'k': {
102                                         if (extended) {
103                                                 bool              first     = false;
104                                                 va_list*          toks      = va_arg(ap, va_list*);
105                                                 const char* const delimiter = va_arg(ap, const char*);
106                                                 for (;;) {
107                                                         const token_type_t tok = va_arg(*toks, token_type_t);
108                                                         if (tok == 0)
109                                                                 break;
110                                                         if (first) {
111                                                                 first = false;
112                                                         } else {
113                                                                 fputs(delimiter, stderr);
114                                                         }
115                                                         print_token_type(stderr, tok);
116                                                 }
117                                         } else {
118                                                 const token_type_t token = va_arg(ap, token_type_t);
119                                                 print_token_type(stderr, token);
120                                         }
121                                         break;
122                                 }
123
124                                 default:
125                                         panic("unknown format specifier");
126                         }
127                 } else {
128                         fputc(*f, stderr);
129                 }
130         }
131 }
132
133 void diagnosticf(const char *const fmt, ...)
134 {
135         va_list ap;
136         va_start(ap, fmt);
137         ++diagnostic_count;
138         diagnosticvf(fmt, ap);
139         va_end(ap);
140 }
141
142 static void errorvf(const source_position_t pos,
143                     const char *const fmt, va_list ap)
144 {
145         fprintf(stderr, "%s:%u: error: ", pos.input_name, pos.linenr);
146         ++error_count;
147         diagnosticvf(fmt, ap);
148         fputc('\n', stderr);
149
150         if (fatal_errors)
151                 abort();
152 }
153 void errorf(const source_position_t pos, const char *const fmt, ...)
154 {
155         va_list ap;
156         va_start(ap, fmt);
157         errorvf(pos, fmt, ap);
158         va_end(ap);
159
160         if (fatal_errors)
161                 exit(1);
162 }
163
164 static void warningvf(const source_position_t pos,
165                       const char *const fmt, va_list ap)
166 {
167         fprintf(stderr, "%s:%u: warning: ", pos.input_name, pos.linenr);
168         ++warning_count;
169         diagnosticvf(fmt, ap);
170         fputc('\n', stderr);
171 }
172
173 void warningf(const source_position_t pos, const char *const fmt, ...)
174 {
175         if (inhibit_all_warnings)
176                 return;
177
178         va_list ap;
179         va_start(ap, fmt);
180         if (warnings_are_errors) {
181                 errorvf(pos, fmt, ap);
182         } else {
183                 warningvf(pos, fmt, ap);
184         }
185         va_end(ap);
186 }