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