main: rework preprocessor invocation
[cparser] / wrappergen / write_fluffy.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <config.h>
21
22 #include <errno.h>
23 #include <string.h>
24
25 #include "write_fluffy.h"
26 #include "separator_t.h"
27 #include "symbol_t.h"
28 #include "ast_t.h"
29 #include "type_t.h"
30 #include "entity_t.h"
31 #include "type.h"
32 #include "adt/error.h"
33 #include "printer.h"
34
35 static const scope_t *global_scope;
36 static FILE          *out;
37
38 static void write_type(const type_t *type);
39
40 static const char *get_atomic_type_string(const atomic_type_kind_t type)
41 {
42         switch(type) {
43         case ATOMIC_TYPE_VOID:        return "void";
44         case ATOMIC_TYPE_CHAR:        return "byte";
45         case ATOMIC_TYPE_SCHAR:       return "byte";
46         case ATOMIC_TYPE_UCHAR:       return "unsigned byte";
47         case ATOMIC_TYPE_SHORT:       return "short";
48         case ATOMIC_TYPE_USHORT:      return "unsigned short";
49         case ATOMIC_TYPE_INT:         return "int";
50         case ATOMIC_TYPE_UINT:        return "unsigned int";
51         case ATOMIC_TYPE_LONG:        return "int";
52         case ATOMIC_TYPE_ULONG:       return "unsigned int";
53         case ATOMIC_TYPE_LONGLONG:    return "long";
54         case ATOMIC_TYPE_ULONGLONG:   return "unsigned long";
55         case ATOMIC_TYPE_FLOAT:       return "float";
56         case ATOMIC_TYPE_DOUBLE:      return "double";
57         case ATOMIC_TYPE_LONG_DOUBLE: return "double";
58         case ATOMIC_TYPE_BOOL:        return "bool";
59         default:                      panic("unsupported atomic type");
60         }
61 }
62
63 static void write_atomic_type(const atomic_type_t *type)
64 {
65         fprintf(out, "%s", get_atomic_type_string(type->akind));
66 }
67
68 static void write_pointer_type(const pointer_type_t *type)
69 {
70         write_type(type->points_to);
71         fputc('*', out);
72 }
73
74 static entity_t *find_typedef(const type_t *type)
75 {
76         /* first: search for a matching typedef in the global type... */
77         entity_t *entity = global_scope->entities;
78         for ( ; entity != NULL; entity = entity->base.next) {
79                 if (entity->kind != ENTITY_TYPEDEF)
80                         continue;
81                 if (entity->typedefe.type == type)
82                         break;
83         }
84
85         return entity;
86 }
87
88 static void write_compound_type(const compound_type_t *type)
89 {
90         entity_t *entity = find_typedef((const type_t*) type);
91         if(entity != NULL) {
92                 fprintf(out, "%s", entity->base.symbol->string);
93                 return;
94         }
95
96         /* does the struct have a name? */
97         symbol_t *symbol = type->compound->base.symbol;
98         if(symbol != NULL) {
99                 /* TODO: make sure we create a struct for it... */
100                 fprintf(out, "%s", symbol->string);
101                 return;
102         }
103         /* TODO: create a struct and use its name here... */
104         fprintf(out, "/* TODO anonymous struct */byte");
105 }
106
107 static void write_enum_type(const enum_type_t *type)
108 {
109         entity_t *entity = find_typedef((const type_t*) type);
110         if (entity != NULL) {
111                 fprintf(out, "%s", entity->base.symbol->string);
112                 return;
113         }
114
115         /* does the enum have a name? */
116         symbol_t *symbol = type->enume->base.symbol;
117         if (symbol != NULL) {
118                 /* TODO: make sure we create an enum for it... */
119                 fprintf(out, "%s", symbol->string);
120                 return;
121         }
122         /* TODO: create a struct and use its name here... */
123         fprintf(out, "/* TODO anonymous enum */byte");
124 }
125
126 static void write_function_type(const function_type_t *type)
127 {
128         fprintf(out, "(func(");
129
130         function_parameter_t *parameter = type->parameters;
131         separator_t           sep       = { "", ", " };
132         while(parameter != NULL) {
133                 fputs(sep_next(&sep), out);
134
135 #if 0
136                 if(parameter->symbol != NULL) {
137                         fprintf(out, "%s : ", parameter->symbol->string);
138                 } else {
139                         /* TODO make up some unused names (or allow _ in fluffy?) */
140                         fprintf(out, "_ : ");
141                 }
142 #endif
143                 fputs("_ : ", out);
144                 write_type(parameter->type);
145
146                 parameter = parameter->next;
147         }
148
149         fprintf(out, ") : ");
150         write_type(type->return_type);
151         fprintf(out, ")");
152 }
153
154 static void write_type(const type_t *type)
155 {
156         switch(type->kind) {
157         case TYPE_ATOMIC:
158                 write_atomic_type(&type->atomic);
159                 return;
160         case TYPE_POINTER:
161                 write_pointer_type(&type->pointer);
162                 return;
163         case TYPE_COMPOUND_UNION:
164         case TYPE_COMPOUND_STRUCT:
165                 write_compound_type(&type->compound);
166                 return;
167         case TYPE_ENUM:
168                 write_enum_type(&type->enumt);
169                 return;
170         case TYPE_FUNCTION:
171                 write_function_type(&type->function);
172                 return;
173         case TYPE_COMPLEX:
174         case TYPE_IMAGINARY:
175         default:
176                 fprintf(out, "/* TODO type */");
177                 break;
178         }
179 }
180
181 static void write_compound_entry(const entity_t *entity)
182 {
183         fprintf(out, "\t%s : ", entity->base.symbol->string);
184         write_type(entity->declaration.type);
185         fprintf(out, "\n");
186 }
187
188 static void write_compound(const symbol_t *symbol, const compound_type_t *type)
189 {
190         fprintf(out, "%s %s:\n",
191                 type->base.kind == TYPE_COMPOUND_STRUCT ? "struct" : "union",
192                         symbol->string);
193
194         const entity_t *entity = type->compound->members.entities;
195         for ( ; entity != NULL; entity = entity->base.next) {
196                 write_compound_entry(entity);
197         }
198
199         fprintf(out, "\n");
200 }
201
202 static void write_expression(const expression_t *expression);
203
204 static void write_unary_expression(const unary_expression_t *expression)
205 {
206         switch(expression->base.kind) {
207         case EXPR_UNARY_NEGATE:
208                 fputc('-', out);
209                 break;
210         case EXPR_UNARY_NOT:
211                 fputc('!', out);
212                 break;
213         default:
214                 panic("unimplemented unary expression");
215         }
216         write_expression(expression->value);
217 }
218
219 static void write_expression(const expression_t *expression)
220 {
221         switch(expression->kind) {
222         case EXPR_LITERAL_INTEGER:
223                 fprintf(out, "%s", expression->literal.value.begin);
224                 break;
225         case EXPR_UNARY_CASES:
226                 write_unary_expression((const unary_expression_t*) expression);
227                 break;
228         default:
229                 panic("not implemented expression");
230         }
231 }
232
233 static void write_enum(const symbol_t *symbol, const enum_type_t *type)
234 {
235         fprintf(out, "enum %s:\n", symbol->string);
236
237         entity_t *entry = type->enume->base.next;
238         for ( ; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
239                         entry = entry->base.next) {
240                 fprintf(out, "\t%s", entry->base.symbol->string);
241                 if(entry->enum_value.value != NULL) {
242                         fprintf(out, " <- ");
243                         write_expression(entry->enum_value.value);
244                 }
245                 fputc('\n', out);
246         }
247         fprintf(out, "typealias %s <- int\n", symbol->string);
248         fprintf(out, "\n");
249 }
250
251 static void write_variable(const entity_t *entity)
252 {
253         fprintf(out, "var %s : ", entity->base.symbol->string);
254         write_type(entity->declaration.type);
255         fprintf(out, "\n");
256 }
257
258 static void write_function(const entity_t *entity)
259 {
260         if (entity->function.body != NULL) {
261                 fprintf(stderr, "Warning: can't convert function bodies (at %s)\n",
262                         entity->base.symbol->string);
263         }
264
265         fprintf(out, "func extern %s(", entity->base.symbol->string);
266
267         const function_type_t *function_type
268                 = (const function_type_t*) entity->declaration.type;
269
270         entity_t   *parameter = entity->function.parameters.entities;
271         separator_t sep       = { "", ", " };
272         for( ; parameter != NULL; parameter = parameter->base.next) {
273                 assert(parameter->kind == ENTITY_PARAMETER);
274                 fputs(sep_next(&sep), out);
275                 if(parameter->base.symbol != NULL) {
276                         fprintf(out, "%s : ", parameter->base.symbol->string);
277                 } else {
278                         fputs("_ : ", out);
279                 }
280                 write_type(parameter->declaration.type);
281         }
282         if(function_type->variadic) {
283                 fputs(sep_next(&sep), out);
284                 fputs("...", out);
285         }
286         fprintf(out, ")");
287
288         const type_t *return_type = skip_typeref(function_type->return_type);
289         if (!is_type_void(return_type)) {
290                 fprintf(out, " : ");
291                 write_type(return_type);
292         }
293         fputc('\n', out);
294 }
295
296 void write_fluffy_decls(FILE *output, const translation_unit_t *unit)
297 {
298         out            = output;
299         global_scope = &unit->scope;
300
301         print_to_file(out);
302         fprintf(out, "/* WARNING: Automatically generated file */\n");
303
304         /* write structs,unions + enums */
305         entity_t *entity = unit->scope.entities;
306         for( ; entity != NULL; entity = entity->base.next) {
307                 if (entity->kind != ENTITY_TYPEDEF)
308                         continue;
309
310                 type_t *type = entity->typedefe.type;
311                 if (is_type_compound(type)) {
312                         write_compound(entity->base.symbol, &type->compound);
313                 } else if(type->kind == TYPE_ENUM) {
314                         write_enum(entity->base.symbol, &type->enumt);
315                 }
316         }
317
318         /* write global variables */
319         entity = unit->scope.entities;
320         for( ; entity != NULL; entity = entity->base.next) {
321                 if (entity->kind != ENTITY_VARIABLE)
322                         continue;
323
324                 write_variable(entity);
325         }
326
327         /* write functions */
328         entity = unit->scope.entities;
329         for( ; entity != NULL; entity = entity->base.next) {
330                 if (entity->kind != ENTITY_FUNCTION)
331                         continue;
332
333                 write_function(entity);
334         }
335 }