support for more builtins, additional bugfixes
[cparser] / type.c
1 #include <config.h>
2
3 #include <stdio.h>
4 #include <assert.h>
5 #include "type_t.h"
6 #include "adt/error.h"
7
8 static struct obstack   _type_obst;
9 struct obstack         *type_obst = &_type_obst;
10 static FILE            *out;
11
12 static void intern_print_type_pre(const type_t *type);
13 static void intern_print_type_post(const type_t *type);
14
15 void init_types(void)
16 {
17         obstack_init(type_obst);
18 }
19
20 void exit_types(void)
21 {
22         obstack_free(type_obst, NULL);
23 }
24
25 void type_set_output(FILE *stream)
26 {
27         out = stream;
28 }
29
30 static
31 void print_type_qualifiers(unsigned qualifiers)
32 {
33         if(qualifiers & TYPE_QUALIFIER_CONST) {
34                 fputs("const ", out);
35         }
36         if(qualifiers & TYPE_QUALIFIER_VOLATILE) {
37                 fputs("volatile ", out);
38         }
39         if(qualifiers & TYPE_QUALIFIER_RESTRICT) {
40                 fputs("__restrict ", out);
41         }
42         if(qualifiers & TYPE_QUALIFIER_INLINE) {
43                 fputs("inline ", out);
44         }
45 }
46
47 static
48 void print_atomic_type(const atomic_type_t *type)
49 {
50         print_type_qualifiers(type->type.qualifiers);
51
52         switch(type->atype) {
53         case ATOMIC_TYPE_INVALID:     fputs("INVALIDATOMIC", out); return;
54         case ATOMIC_TYPE_VOID:        fputs("void", out); return;
55         case ATOMIC_TYPE_BOOL:        fputs("bool", out); return;
56         case ATOMIC_TYPE_CHAR:        fputs("char", out); return;
57         case ATOMIC_TYPE_SCHAR:       fputs("signed char", out); return;
58         case ATOMIC_TYPE_UCHAR:       fputs("unsigned char", out); return;
59         case ATOMIC_TYPE_INT:         fputs("int", out); return;
60         case ATOMIC_TYPE_UINT:        fputs("unsigned int", out); return;
61         case ATOMIC_TYPE_SHORT:       fputs("short", out); return;
62         case ATOMIC_TYPE_USHORT:      fputs("unsigned short", out); return;
63         case ATOMIC_TYPE_LONG:        fputs("long", out); return;
64         case ATOMIC_TYPE_ULONG:       fputs("unsigned long", out); return;
65         case ATOMIC_TYPE_LONGLONG:    fputs("long long", out); return;
66         case ATOMIC_TYPE_ULONGLONG:   fputs("unsigned long long", out); return;
67         case ATOMIC_TYPE_LONG_DOUBLE: fputs("long double", out); return;
68         case ATOMIC_TYPE_FLOAT:       fputs("float", out); return;
69         case ATOMIC_TYPE_DOUBLE:      fputs("double", out); return;
70         }
71         fputs("UNKNOWNATOMIC", out);
72 }
73
74 static
75 void print_method_type_pre(const method_type_t *type)
76 {
77         print_type_qualifiers(type->type.qualifiers);
78
79         intern_print_type_pre(type->result_type);
80
81         /* TODO: don't emit braces if we're the toplevel type... */
82         fputc('(', out);
83 }
84
85 static
86 void print_method_type_post(const method_type_t *type, const context_t *context)
87 {
88         /* TODO: don't emit braces if we're the toplevel type... */
89         intern_print_type_post(type->result_type);
90         fputc(')', out);
91
92         fputc('(', out);
93
94         int                 first     = 1;
95         if(context == NULL) {
96                 method_parameter_t *parameter = type->parameters;
97                 for( ; parameter != NULL; parameter = parameter->next) {
98                         if(first) {
99                                 first = 0;
100                         } else {
101                                 fputs(", ", out);
102                         }
103                         print_type(parameter->type);
104                 }
105         } else {
106                 declaration_t *parameter = context->declarations;
107                 for( ; parameter != NULL; parameter = parameter->next) {
108                         if(first) {
109                                 first = 0;
110                         } else {
111                                 fputs(", ", out);
112                         }
113                         print_type_ext(parameter->type, parameter->symbol,
114                                        &parameter->context);
115                 }
116         }
117         if(type->variadic) {
118                 if(first) {
119                         first = 0;
120                 } else {
121                         fputs(", ", out);
122                 }
123                 fputs("...", out);
124         }
125         if(first && !type->unspecified_parameters) {
126                 fputs("void", out);
127         }
128         fputc(')', out);
129 }
130
131 static
132 void print_pointer_type_pre(const pointer_type_t *type)
133 {
134         intern_print_type_pre(type->points_to);
135         fputs("*", out);
136         print_type_qualifiers(type->type.qualifiers);
137 }
138
139 static void print_pointer_type_post(const pointer_type_t *type)
140 {
141         intern_print_type_post(type->points_to);
142 }
143
144 static void print_type_enum(const enum_type_t *type)
145 {
146         print_type_qualifiers(type->type.qualifiers);
147         if(type->symbol != NULL) {
148                 fprintf(out, "enum %s", type->symbol->string);
149         } else {
150                 fprintf(out, "enum {\n");
151
152                 declaration_t *entry = type->entries_begin;
153                 for( ; entry != type->entries_end->next; entry = entry->next) {
154                         fprintf(out, "\t%s", entry->symbol->string);
155                         if(entry->initializer != NULL) {
156                                 fprintf(out, " = ");
157                                 print_expression(entry->initializer);
158                         }
159                         fprintf(out, ",\n");
160                 }
161
162                 fprintf(out, "} ");
163         }
164 }
165
166 static void intern_print_type_pre(const type_t *type)
167 {
168         switch(type->type) {
169         case TYPE_INVALID:
170                 fputs("invalid", out);
171                 return;
172         case TYPE_ENUM:
173                 print_type_enum((const enum_type_t*) type);
174                 return;
175         case TYPE_ATOMIC:
176                 print_atomic_type((const atomic_type_t*) type);
177                 return;
178         case TYPE_COMPOUND_STRUCT:
179         case TYPE_COMPOUND_UNION:
180                 print_type_qualifiers(type->qualifiers);
181                 if(((const compound_type_t*) type)->symbol != NULL) {
182                         fprintf(out, "%s", ((const compound_type_t*) type)->symbol->string);
183                 }
184                 return;
185         case TYPE_BUILTIN:
186                 fputs(((builtin_type_t*) type)->symbol->string, out);
187                 return;
188         case TYPE_METHOD:
189                 print_method_type_pre((const method_type_t*) type);
190                 return;
191         case TYPE_POINTER:
192                 print_pointer_type_pre((const pointer_type_t*) type);
193                 return;
194         }
195         fputs("unknown", out);
196 }
197
198 static
199 void intern_print_type_post(const type_t *type)
200 {
201         switch(type->type) {
202         case TYPE_METHOD:
203                 print_method_type_post((const method_type_t*) type, NULL);
204                 return;
205         case TYPE_POINTER:
206                 print_pointer_type_post((const pointer_type_t*) type);
207                 return;
208         case TYPE_INVALID:
209         case TYPE_ATOMIC:
210         case TYPE_ENUM:
211         case TYPE_COMPOUND_STRUCT:
212         case TYPE_COMPOUND_UNION:
213         case TYPE_BUILTIN:
214                 break;
215         }
216 }
217
218 void print_type(const type_t *type)
219 {
220         print_type_ext(type, NULL, NULL);
221 }
222
223 void print_type_ext(const type_t *type, const symbol_t *symbol,
224                     const context_t *context)
225 {
226         if(type == NULL) {
227                 fputs("nil type", out);
228                 return;
229         }
230
231         intern_print_type_pre(type);
232         if(symbol != NULL) {
233                 fputc(' ', out);
234                 fputs(symbol->string, out);
235         }
236         if(type->type == TYPE_METHOD) {
237                 print_method_type_post((const method_type_t*) type, context);
238         } else {
239                 intern_print_type_post(type);
240         }
241 }
242
243 int type_valid(const type_t *type)
244 {
245         return type->type != TYPE_INVALID;
246 }
247
248 int is_type_int(const type_t *type)
249 {
250         if(type->type != TYPE_ATOMIC)
251                 return 0;
252
253         atomic_type_t *atomic_type = (atomic_type_t*) type;
254         switch(atomic_type->atype) {
255         case ATOMIC_TYPE_CHAR:
256         case ATOMIC_TYPE_SCHAR:
257         case ATOMIC_TYPE_UCHAR:
258         case ATOMIC_TYPE_SHORT:
259         case ATOMIC_TYPE_USHORT:
260         case ATOMIC_TYPE_INT:
261         case ATOMIC_TYPE_UINT:
262         case ATOMIC_TYPE_LONG:
263         case ATOMIC_TYPE_ULONG:
264         case ATOMIC_TYPE_LONGLONG:
265         case ATOMIC_TYPE_ULONGLONG:
266                 return 1;
267         default:
268                 return 0;
269         }
270 }
271
272 static __attribute__((unused))
273 void dbg_type(const type_t *type)
274 {
275         FILE *old_out = out;
276         out = stderr;
277         print_type(type);
278         puts("\n");
279         fflush(stderr);
280         out = old_out;
281 }