add %Y diagnostic modifier for symbols and make use of it
[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
11 //#define ABORT_ON_ERROR
12
13 /** Number of occurred diagnostics. */
14 unsigned diagnostic_count = 0;
15 /** Number of occurred errors. */
16 unsigned error_count      = 0;
17 /** Number of occurred warnings. */
18 unsigned warning_count    = 0;
19
20 /**
21  * Issue a diagnostic message.
22  */
23 static void diagnosticvf(const char *const fmt, va_list ap)
24 {
25         for (const char* f = fmt; *f != '\0'; ++f) {
26                 if (*f == '%') {
27                         ++f;
28
29                         bool extended = false;
30                         if (*f == '#') {
31                                 extended = true;
32                                 ++f;
33                         }
34
35                         switch (*f) {
36                                 case '%':
37                                         fputc(*f, stderr);
38                                         break;
39
40                                 case 'C': {
41                                         const wint_t val = va_arg(ap, wint_t);
42                                         fputwc(val, stderr);
43                                         break;
44                                 }
45
46                                 case 'c': {
47                                         const unsigned char val = (unsigned char) va_arg(ap, int);
48                                         fputc(val, stderr);
49                                         break;
50                                 }
51
52                                 case 'd': {
53                                         const int val = va_arg(ap, int);
54                                         fprintf(stderr, "%d", val);
55                                         break;
56                                 }
57
58                                 case 's': {
59                                         const char* const str = va_arg(ap, const char*);
60                                         fputs(str, stderr);
61                                         break;
62                                 }
63
64                                 case 'Y': {
65                                         const symbol_t *const symbol = va_arg(ap, const symbol_t*);
66                                         fputs(symbol->string, stderr);
67                                         break;
68                                 }
69
70                                 case 'E': {
71                                         const expression_t* const expr = va_arg(ap, const expression_t*);
72                                         print_expression(expr);
73                                         break;
74                                 }
75
76                                 case 'Q': {
77                                         const unsigned qualifiers = va_arg(ap, unsigned);
78                                         print_type_qualifiers(qualifiers);
79                                         break;
80                                 }
81
82                                 case 'T': {
83                                         const type_t* const type = va_arg(ap, const type_t*);
84                                         const symbol_t*     sym  = NULL;
85                                         if (extended) {
86                                                 sym = va_arg(ap, const symbol_t*);
87                                         }
88                                         print_type_ext(type, sym, NULL);
89                                         break;
90                                 }
91
92                                 case 'K': {
93                                         const token_t* const token = va_arg(ap, const token_t*);
94                                         print_token(stderr, token);
95                                         break;
96                                 }
97
98                                 case 'k': {
99                                         if (extended) {
100                                                 bool              first     = false;
101                                                 va_list*          toks      = va_arg(ap, va_list*);
102                                                 const char* const delimiter = va_arg(ap, const char*);
103                                                 for (;;) {
104                                                         const token_type_t tok = va_arg(*toks, token_type_t);
105                                                         if (tok == 0)
106                                                                 break;
107                                                         if (first) {
108                                                                 first = false;
109                                                         } else {
110                                                                 fputs(delimiter, stderr);
111                                                         }
112                                                         print_token_type(stderr, tok);
113                                                 }
114                                         } else {
115                                                 const token_type_t token = va_arg(ap, token_type_t);
116                                                 print_token_type(stderr, token);
117                                         }
118                                         break;
119                                 }
120
121                                 default:
122                                         panic("unknown format specifier");
123                         }
124                 } else {
125                         fputc(*f, stderr);
126                 }
127         }
128 }
129
130 void diagnosticf(const char *const fmt, ...)
131 {
132         va_list ap;
133         va_start(ap, fmt);
134         ++diagnostic_count;
135         diagnosticvf(fmt, ap);
136         va_end(ap);
137 }
138
139 void errorf(const source_position_t pos, const char *const fmt, ...)
140 {
141         ++error_count;
142         fprintf(stderr, "%s:%u: error: ", pos.input_name, pos.linenr);
143         va_list ap;
144         va_start(ap, fmt);
145         diagnosticvf(fmt, ap);
146         va_end(ap);
147         fputc('\n', stderr);
148
149 #ifdef ABORT_ON_ERROR
150         abort();
151 #endif
152 }
153
154 void warningf(const source_position_t pos, const char *const fmt, ...)
155 {
156         ++warning_count;
157         fprintf(stderr, "%s:%u: warning: ", pos.input_name, pos.linenr);
158         va_list ap;
159         va_start(ap, fmt);
160         diagnosticvf(fmt, ap);
161         va_end(ap);
162         fputc('\n', stderr);
163 }