improve tests, new ms types test
[cparser] / ast.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2008 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 "ast_t.h"
23 #include "symbol_t.h"
24 #include "type_t.h"
25 #include "parser.h"
26
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31
32 #include "adt/error.h"
33
34 struct obstack ast_obstack;
35
36 static FILE *out;
37 static int   indent;
38
39 /** If set, implicit casts are printed. */
40 bool print_implicit_casts = false;
41
42 /** If set parenthesis are printed to indicate operator precedence. */
43 bool print_parenthesis = false;
44
45 static void print_statement(const statement_t *statement);
46 static void print_expression_prec(const expression_t *expression, unsigned prec);
47
48 void change_indent(int delta)
49 {
50         indent += delta;
51         assert(indent >= 0);
52 }
53
54 void print_indent(void)
55 {
56         for(int i = 0; i < indent; ++i)
57                 fprintf(out, "\t");
58 }
59
60 enum precedence_t {
61         PREC_BOTTOM  =  0,
62         PREC_COMMA   =  2, /* ,                                    left to right */
63         PREC_ASSIGN  =  4, /* = += -= *= /= %= <<= >>= &= ^= |=    right to left */
64         PREC_COND    =  6, /* ?:                                   right to left */
65         PREC_LOG_OR  =  8, /* ||                                   left to right */
66         PREC_LOG_AND = 10, /* &&                                   left to right */
67         PREC_BIT_OR  = 12, /* |                                    left to right */
68         PREC_BIT_XOR = 14, /* ^                                    left to right */
69         PREC_BIT_AND = 16, /* &                                    left to right */
70         PREC_EQ      = 18, /* == !=                                left to right */
71         PREC_CMP     = 20, /* < <= > >=                            left to right */
72         PREC_SHF     = 22, /* << >>                                left to right */
73         PREC_PLUS    = 24, /* + -                                  left to right */
74         PREC_MUL     = 26, /* * / %                                left to right */
75         PREC_UNARY   = 28, /* ! ~ ++ -- + - (type) * & sizeof      right to left */
76         PREC_ACCESS  = 30, /* () [] -> .                           left to right */
77         PREC_PRIM    = 32, /* primary */
78         PREC_TOP     = 34
79 };
80
81 /**
82  * Returns 1 if a given precedence level has right-to-left
83  * associativity, else -1.
84  *
85  * @param precedence   the operator precedence
86  */
87 static int right_to_left(unsigned precedence) {
88         return (precedence == PREC_ASSIGN || precedence == PREC_COND ||
89                 precedence == PREC_UNARY) ? 1 : -1;
90 }
91
92 /**
93  * Return the precedence of an expression given by its kind.
94  *
95  * @param kind   the expression kind
96  */
97 static unsigned get_expression_precedence(expression_kind_t kind)
98 {
99         static const unsigned prec[] = {
100                 [EXPR_UNKNOWN]                   = PREC_PRIM,
101                 [EXPR_INVALID]                   = PREC_PRIM,
102                 [EXPR_REFERENCE]                 = PREC_PRIM,
103                 [EXPR_CHARACTER_CONSTANT]        = PREC_PRIM,
104                 [EXPR_WIDE_CHARACTER_CONSTANT]   = PREC_PRIM,
105                 [EXPR_CONST]                     = PREC_PRIM,
106                 [EXPR_STRING_LITERAL]            = PREC_PRIM,
107                 [EXPR_WIDE_STRING_LITERAL]       = PREC_PRIM,
108                 [EXPR_COMPOUND_LITERAL]          = PREC_UNARY,
109                 [EXPR_CALL]                      = PREC_PRIM,
110                 [EXPR_CONDITIONAL]               = PREC_COND,
111                 [EXPR_SELECT]                    = PREC_ACCESS,
112                 [EXPR_ARRAY_ACCESS]              = PREC_ACCESS,
113                 [EXPR_SIZEOF]                    = PREC_UNARY,
114                 [EXPR_CLASSIFY_TYPE]             = PREC_UNARY,
115                 [EXPR_ALIGNOF]                   = PREC_UNARY,
116
117                 [EXPR_FUNCTION]                  = PREC_PRIM,
118                 [EXPR_PRETTY_FUNCTION]           = PREC_PRIM,
119                 [EXPR_BUILTIN_SYMBOL]            = PREC_PRIM,
120                 [EXPR_BUILTIN_CONSTANT_P]        = PREC_PRIM,
121                 [EXPR_BUILTIN_PREFETCH]          = PREC_PRIM,
122                 [EXPR_OFFSETOF]                  = PREC_PRIM,
123                 [EXPR_VA_START]                  = PREC_PRIM,
124                 [EXPR_VA_ARG]                    = PREC_PRIM,
125                 [EXPR_STATEMENT]                 = PREC_ACCESS,
126
127                 [EXPR_UNARY_NEGATE]              = PREC_UNARY,
128                 [EXPR_UNARY_PLUS]                = PREC_UNARY,
129                 [EXPR_UNARY_BITWISE_NEGATE]      = PREC_UNARY,
130                 [EXPR_UNARY_NOT]                 = PREC_UNARY,
131                 [EXPR_UNARY_DEREFERENCE]         = PREC_UNARY,
132                 [EXPR_UNARY_TAKE_ADDRESS]        = PREC_UNARY,
133                 [EXPR_UNARY_POSTFIX_INCREMENT]   = PREC_UNARY,
134                 [EXPR_UNARY_POSTFIX_DECREMENT]   = PREC_UNARY,
135                 [EXPR_UNARY_PREFIX_INCREMENT]    = PREC_UNARY,
136                 [EXPR_UNARY_PREFIX_DECREMENT]    = PREC_UNARY,
137                 [EXPR_UNARY_CAST]                = PREC_UNARY,
138                 [EXPR_UNARY_CAST_IMPLICIT]       = PREC_UNARY,
139                 [EXPR_UNARY_ASSUME]              = PREC_PRIM,
140                 [EXPR_UNARY_BITFIELD_EXTRACT]    = PREC_ACCESS,
141
142                 [EXPR_BINARY_ADD]                = PREC_PLUS,
143                 [EXPR_BINARY_SUB]                = PREC_PLUS,
144                 [EXPR_BINARY_MUL]                = PREC_MUL,
145                 [EXPR_BINARY_DIV]                = PREC_MUL,
146                 [EXPR_BINARY_MOD]                = PREC_MUL,
147                 [EXPR_BINARY_EQUAL]              = PREC_EQ,
148                 [EXPR_BINARY_NOTEQUAL]           = PREC_EQ,
149                 [EXPR_BINARY_LESS]               = PREC_CMP,
150                 [EXPR_BINARY_LESSEQUAL]          = PREC_CMP,
151                 [EXPR_BINARY_GREATER]            = PREC_CMP,
152                 [EXPR_BINARY_GREATEREQUAL]       = PREC_CMP,
153                 [EXPR_BINARY_BITWISE_AND]        = PREC_BIT_AND,
154                 [EXPR_BINARY_BITWISE_OR]         = PREC_BIT_OR,
155                 [EXPR_BINARY_BITWISE_XOR]        = PREC_BIT_XOR,
156                 [EXPR_BINARY_LOGICAL_AND]        = PREC_LOG_AND,
157                 [EXPR_BINARY_LOGICAL_OR]         = PREC_LOG_OR,
158                 [EXPR_BINARY_SHIFTLEFT]          = PREC_SHF,
159                 [EXPR_BINARY_SHIFTRIGHT]         = PREC_SHF,
160                 [EXPR_BINARY_ASSIGN]             = PREC_ASSIGN,
161                 [EXPR_BINARY_MUL_ASSIGN]         = PREC_ASSIGN,
162                 [EXPR_BINARY_DIV_ASSIGN]         = PREC_ASSIGN,
163                 [EXPR_BINARY_MOD_ASSIGN]         = PREC_ASSIGN,
164                 [EXPR_BINARY_ADD_ASSIGN]         = PREC_ASSIGN,
165                 [EXPR_BINARY_SUB_ASSIGN]         = PREC_ASSIGN,
166                 [EXPR_BINARY_SHIFTLEFT_ASSIGN]   = PREC_ASSIGN,
167                 [EXPR_BINARY_SHIFTRIGHT_ASSIGN]  = PREC_ASSIGN,
168                 [EXPR_BINARY_BITWISE_AND_ASSIGN] = PREC_ASSIGN,
169                 [EXPR_BINARY_BITWISE_XOR_ASSIGN] = PREC_ASSIGN,
170                 [EXPR_BINARY_BITWISE_OR_ASSIGN]  = PREC_ASSIGN,
171                 [EXPR_BINARY_COMMA]              = PREC_COMMA,
172
173                 [EXPR_BINARY_BUILTIN_EXPECT]     = PREC_PRIM,
174                 [EXPR_BINARY_ISGREATER]          = PREC_PRIM,
175                 [EXPR_BINARY_ISGREATEREQUAL]     = PREC_PRIM,
176                 [EXPR_BINARY_ISLESS]             = PREC_PRIM,
177                 [EXPR_BINARY_ISLESSEQUAL]        = PREC_PRIM,
178                 [EXPR_BINARY_ISLESSGREATER]      = PREC_PRIM,
179                 [EXPR_BINARY_ISUNORDERED]        = PREC_PRIM
180         };
181         assert((unsigned)kind < (sizeof(prec)/sizeof(prec[0])));
182         unsigned res = prec[kind];
183
184         assert(res != PREC_BOTTOM);
185         return res;
186 }
187
188 /**
189  * Print a constant expression.
190  *
191  * @param cnst  the constant expression
192  */
193 static void print_const(const const_expression_t *cnst)
194 {
195         if(cnst->base.type == NULL)
196                 return;
197
198         const type_t *const type = skip_typeref(cnst->base.type);
199
200         if (is_type_integer(type)) {
201                 fprintf(out, "%lld", cnst->v.int_value);
202         } else if (is_type_float(type)) {
203                 fprintf(out, "%Lf", cnst->v.float_value);
204         } else {
205                 panic("unknown constant");
206         }
207 }
208
209 /**
210  * Print a quoted string constant.
211  *
212  * @param string  the string constant
213  * @param border  the border char
214  */
215 static void print_quoted_string(const string_t *const string, char border)
216 {
217         fputc(border, out);
218         const char *end = string->begin + string->size - 1;
219         for (const char *c = string->begin; c != end; ++c) {
220                 if (*c == border) {
221                         fputc('\\', out);
222                 }
223                 switch(*c) {
224                 case '\\':  fputs("\\\\", out); break;
225                 case '\a':  fputs("\\a", out); break;
226                 case '\b':  fputs("\\b", out); break;
227                 case '\f':  fputs("\\f", out); break;
228                 case '\n':  fputs("\\n", out); break;
229                 case '\r':  fputs("\\r", out); break;
230                 case '\t':  fputs("\\t", out); break;
231                 case '\v':  fputs("\\v", out); break;
232                 case '\?':  fputs("\\?", out); break;
233                 default:
234                         if(!isprint(*c)) {
235                                 fprintf(out, "\\%03o", *c);
236                                 break;
237                         }
238                         fputc(*c, out);
239                         break;
240                 }
241         }
242         fputc(border, out);
243 }
244
245 /**
246  * Prints a wide string literal expression.
247  *
248  * @param wstr  the wide string literal expression
249  */
250 static void print_quoted_wide_string(const wide_string_t *const wstr,
251                                      char border)
252 {
253         fputc('L', out);
254         fputc(border, out);
255         for (const wchar_rep_t *c = wstr->begin, *end = wstr->begin + wstr->size-1;
256              c != end; ++c) {
257                 switch (*c) {
258                         case L'\"':  fputs("\\\"", out); break;
259                         case L'\\':  fputs("\\\\", out); break;
260                         case L'\a':  fputs("\\a",  out); break;
261                         case L'\b':  fputs("\\b",  out); break;
262                         case L'\f':  fputs("\\f",  out); break;
263                         case L'\n':  fputs("\\n",  out); break;
264                         case L'\r':  fputs("\\r",  out); break;
265                         case L'\t':  fputs("\\t",  out); break;
266                         case L'\v':  fputs("\\v",  out); break;
267                         case L'\?':  fputs("\\?",  out); break;
268                         default: {
269                                 const unsigned tc = *c;
270                                 if (tc < 0x80U) {
271                                         if (!isprint(*c))  {
272                                                 fprintf(out, "\\%03o", (char)*c);
273                                         } else {
274                                                 fputc(*c, out);
275                                         }
276                                 } else if (tc < 0x800) {
277                                         fputc(0xC0 | (tc >> 6),   out);
278                                         fputc(0x80 | (tc & 0x3F), out);
279                                 } else if (tc < 0x10000) {
280                                         fputc(0xE0 | ( tc >> 12),         out);
281                                         fputc(0x80 | ((tc >>  6) & 0x3F), out);
282                                         fputc(0x80 | ( tc        & 0x3F), out);
283                                 } else {
284                                         fputc(0xF0 | ( tc >> 18),         out);
285                                         fputc(0x80 | ((tc >> 12) & 0x3F), out);
286                                         fputc(0x80 | ((tc >>  6) & 0x3F), out);
287                                         fputc(0x80 | ( tc        & 0x3F), out);
288                                 }
289                         }
290                 }
291         }
292         fputc(border, out);
293 }
294
295 /**
296  * Print a constant character expression.
297  *
298  * @param cnst  the constant character expression
299  */
300 static void print_character_constant(const const_expression_t *cnst)
301 {
302         print_quoted_string(&cnst->v.character, '\'');
303 }
304
305 static void print_wide_character_constant(const const_expression_t *cnst)
306 {
307         print_quoted_wide_string(&cnst->v.wide_character, '\'');
308 }
309
310 /**
311  * Prints a string literal expression.
312  *
313  * @param string_literal  the string literal expression
314  */
315 static void print_string_literal(
316                 const string_literal_expression_t *string_literal)
317 {
318         print_quoted_string(&string_literal->value, '"');
319 }
320
321 static void print_wide_string_literal(
322         const wide_string_literal_expression_t *const wstr)
323 {
324         print_quoted_wide_string(&wstr->value, '"');
325 }
326
327 static void print_compound_literal(
328                 const compound_literal_expression_t *expression)
329 {
330         fputc('(', out);
331         print_type(expression->type);
332         fputs(") ", out);
333         print_initializer(expression->initializer);
334 }
335
336 /**
337  * Prints a call expression.
338  *
339  * @param call  the call expression
340  */
341 static void print_call_expression(const call_expression_t *call)
342 {
343         unsigned prec = get_expression_precedence(call->base.kind);
344         print_expression_prec(call->function, prec);
345         fprintf(out, "(");
346         call_argument_t *argument = call->arguments;
347         int              first    = 1;
348         while(argument != NULL) {
349                 if(!first) {
350                         fprintf(out, ", ");
351                 } else {
352                         first = 0;
353                 }
354                 print_expression_prec(argument->expression, PREC_COMMA + 1);
355
356                 argument = argument->next;
357         }
358         fprintf(out, ")");
359 }
360
361 /**
362  * Prints a binary expression.
363  *
364  * @param binexpr   the binary expression
365  */
366 static void print_binary_expression(const binary_expression_t *binexpr)
367 {
368         unsigned prec = get_expression_precedence(binexpr->base.kind);
369         int      r2l  = right_to_left(prec);
370
371         if(binexpr->base.kind == EXPR_BINARY_BUILTIN_EXPECT) {
372                 fputs("__builtin_expect(", out);
373                 print_expression_prec(binexpr->left, prec);
374                 fputs(", ", out);
375                 print_expression_prec(binexpr->right, prec);
376                 fputc(')', out);
377                 return;
378         }
379
380         print_expression_prec(binexpr->left, prec + r2l);
381         if (binexpr->base.kind != EXPR_BINARY_COMMA) {
382                 fputc(' ', out);
383         }
384         switch (binexpr->base.kind) {
385         case EXPR_BINARY_COMMA:              fputs(",", out);     break;
386         case EXPR_BINARY_ASSIGN:             fputs("=", out);     break;
387         case EXPR_BINARY_ADD:                fputs("+", out);     break;
388         case EXPR_BINARY_SUB:                fputs("-", out);     break;
389         case EXPR_BINARY_MUL:                fputs("*", out);     break;
390         case EXPR_BINARY_MOD:                fputs("%", out);     break;
391         case EXPR_BINARY_DIV:                fputs("/", out);     break;
392         case EXPR_BINARY_BITWISE_OR:         fputs("|", out);     break;
393         case EXPR_BINARY_BITWISE_AND:        fputs("&", out);     break;
394         case EXPR_BINARY_BITWISE_XOR:        fputs("^", out);     break;
395         case EXPR_BINARY_LOGICAL_OR:         fputs("||", out);    break;
396         case EXPR_BINARY_LOGICAL_AND:        fputs("&&", out);    break;
397         case EXPR_BINARY_NOTEQUAL:           fputs("!=", out);    break;
398         case EXPR_BINARY_EQUAL:              fputs("==", out);    break;
399         case EXPR_BINARY_LESS:               fputs("<", out);     break;
400         case EXPR_BINARY_LESSEQUAL:          fputs("<=", out);    break;
401         case EXPR_BINARY_GREATER:            fputs(">", out);     break;
402         case EXPR_BINARY_GREATEREQUAL:       fputs(">=", out);    break;
403         case EXPR_BINARY_SHIFTLEFT:          fputs("<<", out);    break;
404         case EXPR_BINARY_SHIFTRIGHT:         fputs(">>", out);    break;
405
406         case EXPR_BINARY_ADD_ASSIGN:         fputs("+=", out);    break;
407         case EXPR_BINARY_SUB_ASSIGN:         fputs("-=", out);    break;
408         case EXPR_BINARY_MUL_ASSIGN:         fputs("*=", out);    break;
409         case EXPR_BINARY_MOD_ASSIGN:         fputs("%=", out);    break;
410         case EXPR_BINARY_DIV_ASSIGN:         fputs("/=", out);    break;
411         case EXPR_BINARY_BITWISE_OR_ASSIGN:  fputs("|=", out);    break;
412         case EXPR_BINARY_BITWISE_AND_ASSIGN: fputs("&=", out);    break;
413         case EXPR_BINARY_BITWISE_XOR_ASSIGN: fputs("^=", out);    break;
414         case EXPR_BINARY_SHIFTLEFT_ASSIGN:   fputs("<<=", out);   break;
415         case EXPR_BINARY_SHIFTRIGHT_ASSIGN:  fputs(">>=", out);   break;
416         default: panic("invalid binexpression found");
417         }
418         fputc(' ', out);
419         print_expression_prec(binexpr->right, prec - r2l);
420 }
421
422 /**
423  * Prints an unary expression.
424  *
425  * @param unexpr   the unary expression
426  */
427 static void print_unary_expression(const unary_expression_t *unexpr)
428 {
429         unsigned prec = get_expression_precedence(unexpr->base.kind);
430         switch(unexpr->base.kind) {
431         case EXPR_UNARY_NEGATE:           fputs("-", out);  break;
432         case EXPR_UNARY_PLUS:             fputs("+", out);  break;
433         case EXPR_UNARY_NOT:              fputs("!", out);  break;
434         case EXPR_UNARY_BITWISE_NEGATE:   fputs("~", out);  break;
435         case EXPR_UNARY_PREFIX_INCREMENT: fputs("++", out); break;
436         case EXPR_UNARY_PREFIX_DECREMENT: fputs("--", out); break;
437         case EXPR_UNARY_DEREFERENCE:      fputs("*", out);  break;
438         case EXPR_UNARY_TAKE_ADDRESS:     fputs("&", out);  break;
439
440         case EXPR_UNARY_BITFIELD_EXTRACT:
441                 print_expression_prec(unexpr->value, prec);
442                 return;
443
444         case EXPR_UNARY_POSTFIX_INCREMENT:
445                 print_expression_prec(unexpr->value, prec);
446                 fputs("++", out);
447                 return;
448         case EXPR_UNARY_POSTFIX_DECREMENT:
449                 print_expression_prec(unexpr->value, prec);
450                 fputs("--", out);
451                 return;
452         case EXPR_UNARY_CAST_IMPLICIT:
453                 if(!print_implicit_casts) {
454                         print_expression_prec(unexpr->value, prec);
455                         return;
456                 }
457                 /* fallthrough */
458         case EXPR_UNARY_CAST:
459                 fputc('(', out);
460                 print_type(unexpr->base.type);
461                 fputc(')', out);
462                 break;
463         case EXPR_UNARY_ASSUME:
464                 fputs("__assume(", out);
465                 print_expression_prec(unexpr->value, PREC_COMMA + 1);
466                 fputc(')', out);
467                 return;
468         default:
469                 panic("invalid unary expression found");
470         }
471         print_expression_prec(unexpr->value, prec);
472 }
473
474 /**
475  * Prints a reference expression.
476  *
477  * @param ref   the reference expression
478  */
479 static void print_reference_expression(const reference_expression_t *ref)
480 {
481         fprintf(out, "%s", ref->declaration->symbol->string);
482 }
483
484 /**
485  * Prints an array expression.
486  *
487  * @param expression   the array expression
488  */
489 static void print_array_expression(const array_access_expression_t *expression)
490 {
491         unsigned prec = get_expression_precedence(expression->base.kind);
492         if(!expression->flipped) {
493                 print_expression_prec(expression->array_ref, prec);
494                 fputc('[', out);
495                 print_expression_prec(expression->index, prec);
496                 fputc(']', out);
497         } else {
498                 print_expression_prec(expression->index, prec);
499                 fputc('[', out);
500                 print_expression_prec(expression->array_ref, prec);
501                 fputc(']', out);
502         }
503 }
504
505 /**
506  * Prints a typeproperty expression (sizeof or __alignof__).
507  *
508  * @param expression   the type property expression
509  */
510 static void print_typeprop_expression(const typeprop_expression_t *expression)
511 {
512         if (expression->base.kind == EXPR_SIZEOF) {
513                 fputs("sizeof", out);
514         } else {
515                 assert(expression->base.kind == EXPR_ALIGNOF);
516                 fputs("__alignof__", out);
517         }
518         if(expression->tp_expression != NULL) {
519                 /* always print the '()' here, sizeof x is right but unusual */
520                 fputc('(', out);
521                 print_expression_prec(expression->tp_expression, PREC_ACCESS);
522                 fputc(')', out);
523         } else {
524                 fputc('(', out);
525                 print_type(expression->type);
526                 fputc(')', out);
527         }
528 }
529
530 /**
531  * Prints an builtin symbol.
532  *
533  * @param expression   the builtin symbol expression
534  */
535 static void print_builtin_symbol(const builtin_symbol_expression_t *expression)
536 {
537         fputs(expression->symbol->string, out);
538 }
539
540 /**
541  * Prints a builtin constant expression.
542  *
543  * @param expression   the builtin constant expression
544  */
545 static void print_builtin_constant(const builtin_constant_expression_t *expression)
546 {
547         fputs("__builtin_constant_p(", out);
548         print_expression_prec(expression->value, PREC_COMMA + 1);
549         fputc(')', out);
550 }
551
552 /**
553  * Prints a builtin prefetch expression.
554  *
555  * @param expression   the builtin prefetch expression
556  */
557 static void print_builtin_prefetch(const builtin_prefetch_expression_t *expression)
558 {
559         fputs("__builtin_prefetch(", out);
560         print_expression_prec(expression->adr, PREC_COMMA + 1);
561         if (expression->rw) {
562                 fputc(',', out);
563                 print_expression_prec(expression->rw, PREC_COMMA + 1);
564         }
565         if (expression->locality) {
566                 fputc(',', out);
567                 print_expression_prec(expression->locality, PREC_COMMA + 1);
568         }
569         fputc(')', out);
570 }
571
572 /**
573  * Prints a conditional expression.
574  *
575  * @param expression   the conditional expression
576  */
577 static void print_conditional(const conditional_expression_t *expression)
578 {
579         unsigned prec = get_expression_precedence(expression->base.kind);
580         fputs("(", out);
581         print_expression_prec(expression->condition, prec);
582         fputs(" ? ", out);
583         print_expression_prec(expression->true_expression, prec);
584         fputs(" : ", out);
585         print_expression_prec(expression->false_expression, prec);
586         fputs(")", out);
587 }
588
589 /**
590  * Prints a va_start expression.
591  *
592  * @param expression   the va_start expression
593  */
594 static void print_va_start(const va_start_expression_t *const expression)
595 {
596         fputs("__builtin_va_start(", out);
597         print_expression_prec(expression->ap, PREC_COMMA + 1);
598         fputs(", ", out);
599         fputs(expression->parameter->symbol->string, out);
600         fputs(")", out);
601 }
602
603 /**
604  * Prints a va_arg expression.
605  *
606  * @param expression   the va_arg expression
607  */
608 static void print_va_arg(const va_arg_expression_t *expression)
609 {
610         fputs("__builtin_va_arg(", out);
611         print_expression_prec(expression->ap, PREC_COMMA + 1);
612         fputs(", ", out);
613         print_type(expression->base.type);
614         fputs(")", out);
615 }
616
617 /**
618  * Prints a select expression (. or ->).
619  *
620  * @param expression   the select expression
621  */
622 static void print_select(const select_expression_t *expression)
623 {
624         unsigned prec = get_expression_precedence(expression->base.kind);
625         print_expression_prec(expression->compound, prec);
626         if(is_type_pointer(expression->compound->base.type)) {
627                 fputs("->", out);
628         } else {
629                 fputc('.', out);
630         }
631         fputs(expression->symbol->string, out);
632 }
633
634 /**
635  * Prints a type classify expression.
636  *
637  * @param expr   the type classify expression
638  */
639 static void print_classify_type_expression(
640         const classify_type_expression_t *const expr)
641 {
642         fputs("__builtin_classify_type(", out);
643         print_expression_prec(expr->type_expression, PREC_COMMA + 1);
644         fputc(')', out);
645 }
646
647 /**
648  * Prints a designator.
649  *
650  * @param designator  the designator
651  */
652 static void print_designator(const designator_t *designator)
653 {
654         for ( ; designator != NULL; designator = designator->next) {
655                 if (designator->symbol == NULL) {
656                         fputc('[', out);
657                         print_expression_prec(designator->array_index, PREC_ACCESS);
658                         fputc(']', out);
659                 } else {
660                         fputc('.', out);
661                         fputs(designator->symbol->string, out);
662                 }
663         }
664 }
665
666 /**
667  * Prints an offsetof expression.
668  *
669  * @param expression   the offset expression
670  */
671 static void print_offsetof_expression(const offsetof_expression_t *expression)
672 {
673         fputs("__builtin_offsetof", out);
674         fputc('(', out);
675         print_type(expression->type);
676         fputc(',', out);
677         print_designator(expression->designator);
678         fputc(')', out);
679 }
680
681 /**
682  * Prints a statement expression.
683  *
684  * @param expression   the statement expression
685  */
686 static void print_statement_expression(const statement_expression_t *expression)
687 {
688         fputc('(', out);
689         print_statement(expression->statement);
690         fputc(')', out);
691 }
692
693 /**
694  * Prints an expression with parenthesis if needed.
695  *
696  * @param expression  the expression to print
697  * @param top_prec    the precedence of the user of this expression.
698  */
699 static void print_expression_prec(const expression_t *expression, unsigned top_prec)
700 {
701         unsigned prec = get_expression_precedence(expression->base.kind);
702         if (print_parenthesis && top_prec != PREC_BOTTOM)
703                 top_prec = PREC_TOP;
704         if (top_prec > prec)
705                 fputc('(', out);
706         switch(expression->kind) {
707         case EXPR_UNKNOWN:
708         case EXPR_INVALID:
709                 fprintf(out, "$invalid expression$");
710                 break;
711         case EXPR_CHARACTER_CONSTANT:
712                 print_character_constant(&expression->conste);
713                 break;
714         case EXPR_WIDE_CHARACTER_CONSTANT:
715                 print_wide_character_constant(&expression->conste);
716                 break;
717         case EXPR_CONST:
718                 print_const(&expression->conste);
719                 break;
720         case EXPR_FUNCTION:
721         case EXPR_PRETTY_FUNCTION:
722         case EXPR_STRING_LITERAL:
723                 print_string_literal(&expression->string);
724                 break;
725         case EXPR_WIDE_STRING_LITERAL:
726                 print_wide_string_literal(&expression->wide_string);
727                 break;
728         case EXPR_COMPOUND_LITERAL:
729                 print_compound_literal(&expression->compound_literal);
730                 break;
731         case EXPR_CALL:
732                 print_call_expression(&expression->call);
733                 break;
734         EXPR_BINARY_CASES
735                 print_binary_expression(&expression->binary);
736                 break;
737         case EXPR_REFERENCE:
738                 print_reference_expression(&expression->reference);
739                 break;
740         case EXPR_ARRAY_ACCESS:
741                 print_array_expression(&expression->array_access);
742                 break;
743         EXPR_UNARY_CASES
744                 print_unary_expression(&expression->unary);
745                 break;
746         case EXPR_SIZEOF:
747         case EXPR_ALIGNOF:
748                 print_typeprop_expression(&expression->typeprop);
749                 break;
750         case EXPR_BUILTIN_SYMBOL:
751                 print_builtin_symbol(&expression->builtin_symbol);
752                 break;
753         case EXPR_BUILTIN_CONSTANT_P:
754                 print_builtin_constant(&expression->builtin_constant);
755                 break;
756         case EXPR_BUILTIN_PREFETCH:
757                 print_builtin_prefetch(&expression->builtin_prefetch);
758                 break;
759         case EXPR_CONDITIONAL:
760                 print_conditional(&expression->conditional);
761                 break;
762         case EXPR_VA_START:
763                 print_va_start(&expression->va_starte);
764                 break;
765         case EXPR_VA_ARG:
766                 print_va_arg(&expression->va_arge);
767                 break;
768         case EXPR_SELECT:
769                 print_select(&expression->select);
770                 break;
771         case EXPR_CLASSIFY_TYPE:
772                 print_classify_type_expression(&expression->classify_type);
773                 break;
774         case EXPR_OFFSETOF:
775                 print_offsetof_expression(&expression->offsetofe);
776                 break;
777         case EXPR_STATEMENT:
778                 print_statement_expression(&expression->statement);
779                 break;
780
781         default:
782                 /* TODO */
783                 fprintf(out, "some expression of type %d", (int) expression->kind);
784                 break;
785         }
786         if (top_prec > prec)
787                 fputc(')', out);
788 }
789
790 /**
791  * Print an compound statement.
792  *
793  * @param block  the compound statement
794  */
795 static void print_compound_statement(const compound_statement_t *block)
796 {
797         fputs("{\n", out);
798         ++indent;
799
800         statement_t *statement = block->statements;
801         while(statement != NULL) {
802                 if (statement->base.kind == STATEMENT_CASE_LABEL)
803                         --indent;
804                 print_indent();
805                 print_statement(statement);
806
807                 statement = statement->base.next;
808         }
809         --indent;
810         print_indent();
811         fputs("}\n", out);
812 }
813
814 /**
815  * Print a return statement.
816  *
817  * @param statement  the return statement
818  */
819 static void print_return_statement(const return_statement_t *statement)
820 {
821         fprintf(out, "return ");
822         if(statement->value != NULL)
823                 print_expression(statement->value);
824         fputs(";\n", out);
825 }
826
827 /**
828  * Print an expression statement.
829  *
830  * @param statement  the expression statement
831  */
832 static void print_expression_statement(const expression_statement_t *statement)
833 {
834         print_expression(statement->expression);
835         fputs(";\n", out);
836 }
837
838 /**
839  * Print a goto statement.
840  *
841  * @param statement  the goto statement
842  */
843 static void print_goto_statement(const goto_statement_t *statement)
844 {
845         fprintf(out, "goto ");
846         fputs(statement->label->symbol->string, out);
847         fprintf(stderr, "(%p)", (void*) statement->label);
848         fputs(";\n", out);
849 }
850
851 /**
852  * Print a label statement.
853  *
854  * @param statement  the label statement
855  */
856 static void print_label_statement(const label_statement_t *statement)
857 {
858         fprintf(stderr, "(%p)", (void*) statement->label);
859         fprintf(out, "%s:\n", statement->label->symbol->string);
860         print_statement(statement->statement);
861 }
862
863 /**
864  * Print an if statement.
865  *
866  * @param statement  the if statement
867  */
868 static void print_if_statement(const if_statement_t *statement)
869 {
870         fputs("if (", out);
871         print_expression(statement->condition);
872         fputs(") ", out);
873         print_statement(statement->true_statement);
874
875         if(statement->false_statement != NULL) {
876                 print_indent();
877                 fputs("else ", out);
878                 print_statement(statement->false_statement);
879         }
880 }
881
882 /**
883  * Print a switch statement.
884  *
885  * @param statement  the switch statement
886  */
887 static void print_switch_statement(const switch_statement_t *statement)
888 {
889         fputs("switch (", out);
890         print_expression(statement->expression);
891         fputs(") ", out);
892         print_statement(statement->body);
893 }
894
895 /**
896  * Print a case label (including the default label).
897  *
898  * @param statement  the case label statement
899  */
900 static void print_case_label(const case_label_statement_t *statement)
901 {
902         if(statement->expression == NULL) {
903                 fputs("default:\n", out);
904         } else {
905                 fputs("case ", out);
906                 print_expression(statement->expression);
907                 if (statement->end_range != NULL) {
908                         fputs(" ... ", out);
909                         print_expression(statement->end_range);
910                 }
911                 fputs(":\n", out);
912         }
913         ++indent;
914         if(statement->statement != NULL) {
915                 if (statement->statement->base.kind == STATEMENT_CASE_LABEL) {
916                         --indent;
917                 }
918                 print_indent();
919                 print_statement(statement->statement);
920         }
921 }
922
923 /**
924  * Print a declaration statement.
925  *
926  * @param statement   the statement
927  */
928 static void print_declaration_statement(
929                 const declaration_statement_t *statement)
930 {
931         int first = 1;
932         declaration_t *declaration = statement->declarations_begin;
933         for( ; declaration != statement->declarations_end->next;
934                declaration = declaration->next) {
935             if(declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)
936                 continue;
937
938                 if(!first) {
939                         print_indent();
940                 } else {
941                         first = 0;
942                 }
943                 print_declaration(declaration);
944                 fputc('\n', out);
945         }
946 }
947
948 /**
949  * Print a while statement.
950  *
951  * @param statement   the statement
952  */
953 static void print_while_statement(const while_statement_t *statement)
954 {
955         fputs("while (", out);
956         print_expression(statement->condition);
957         fputs(") ", out);
958         print_statement(statement->body);
959 }
960
961 /**
962  * Print a do-while statement.
963  *
964  * @param statement   the statement
965  */
966 static void print_do_while_statement(const do_while_statement_t *statement)
967 {
968         fputs("do ", out);
969         print_statement(statement->body);
970         print_indent();
971         fputs("while (", out);
972         print_expression(statement->condition);
973         fputs(");\n", out);
974 }
975
976 /**
977  * Print a for statement.
978  *
979  * @param statement   the statement
980  */
981 static void print_for_statement(const for_statement_t *statement)
982 {
983         fputs("for (", out);
984         if(statement->scope.declarations != NULL) {
985                 assert(statement->initialisation == NULL);
986                 print_declaration(statement->scope.declarations);
987                 if(statement->scope.declarations->next != NULL) {
988                         panic("multiple declarations in for statement not supported yet");
989                 }
990                 fputc(' ', out);
991         } else {
992                 if(statement->initialisation) {
993                         print_expression(statement->initialisation);
994                 }
995                 fputs("; ", out);
996         }
997         if(statement->condition != NULL) {
998                 print_expression(statement->condition);
999         }
1000         fputs("; ", out);
1001         if(statement->step != NULL) {
1002                 print_expression(statement->step);
1003         }
1004         fputs(")", out);
1005         print_statement(statement->body);
1006 }
1007
1008 /**
1009  * Print assembler constraints.
1010  *
1011  * @param constraints   the constraints
1012  */
1013 static void print_asm_constraints(asm_constraint_t *constraints)
1014 {
1015         asm_constraint_t *constraint = constraints;
1016         for( ; constraint != NULL; constraint = constraint->next) {
1017                 if(constraint != constraints)
1018                         fputs(", ", out);
1019
1020                 if(constraint->symbol) {
1021                         fprintf(out, "[%s] ", constraint->symbol->string);
1022                 }
1023                 print_quoted_string(&constraint->constraints, '"');
1024                 fputs(" (", out);
1025                 print_expression(constraint->expression);
1026                 fputs(")", out);
1027         }
1028 }
1029
1030 /**
1031  * Print assembler clobbers.
1032  *
1033  * @param clobbers   the clobbers
1034  */
1035 static void print_asm_clobbers(asm_clobber_t *clobbers)
1036 {
1037         asm_clobber_t *clobber = clobbers;
1038         for( ; clobber != NULL; clobber = clobber->next) {
1039                 if(clobber != clobbers)
1040                         fputs(", ", out);
1041
1042                 print_quoted_string(&clobber->clobber, '"');
1043         }
1044 }
1045
1046 /**
1047  * Print an assembler statement.
1048  *
1049  * @param statement   the statement
1050  */
1051 static void print_asm_statement(const asm_statement_t *statement)
1052 {
1053         fputs("asm ", out);
1054         if(statement->is_volatile) {
1055                 fputs("volatile ", out);
1056         }
1057         fputs("(", out);
1058         print_quoted_string(&statement->asm_text, '"');
1059         if(statement->inputs == NULL && statement->outputs == NULL
1060                         && statement->clobbers == NULL)
1061                 goto end_of_print_asm_statement;
1062
1063         fputs(" : ", out);
1064         print_asm_constraints(statement->inputs);
1065         if(statement->outputs == NULL && statement->clobbers == NULL)
1066                 goto end_of_print_asm_statement;
1067
1068         fputs(" : ", out);
1069         print_asm_constraints(statement->outputs);
1070         if(statement->clobbers == NULL)
1071                 goto end_of_print_asm_statement;
1072
1073         fputs(" : ", out);
1074         print_asm_clobbers(statement->clobbers);
1075
1076 end_of_print_asm_statement:
1077         fputs(");\n", out);
1078 }
1079
1080 /**
1081  * Print a statement.
1082  *
1083  * @param statement   the statement
1084  */
1085 void print_statement(const statement_t *statement)
1086 {
1087         switch(statement->kind) {
1088         case STATEMENT_EMPTY:
1089                 fputs(";\n", out);
1090                 break;
1091         case STATEMENT_COMPOUND:
1092                 print_compound_statement(&statement->compound);
1093                 break;
1094         case STATEMENT_RETURN:
1095                 print_return_statement(&statement->returns);
1096                 break;
1097         case STATEMENT_EXPRESSION:
1098                 print_expression_statement(&statement->expression);
1099                 break;
1100         case STATEMENT_LABEL:
1101                 print_label_statement(&statement->label);
1102                 break;
1103         case STATEMENT_GOTO:
1104                 print_goto_statement(&statement->gotos);
1105                 break;
1106         case STATEMENT_CONTINUE:
1107                 fputs("continue;\n", out);
1108                 break;
1109         case STATEMENT_BREAK:
1110                 fputs("break;\n", out);
1111                 break;
1112         case STATEMENT_IF:
1113                 print_if_statement(&statement->ifs);
1114                 break;
1115         case STATEMENT_SWITCH:
1116                 print_switch_statement(&statement->switchs);
1117                 break;
1118         case STATEMENT_CASE_LABEL:
1119                 print_case_label(&statement->case_label);
1120                 break;
1121         case STATEMENT_DECLARATION:
1122                 print_declaration_statement(&statement->declaration);
1123                 break;
1124         case STATEMENT_WHILE:
1125                 print_while_statement(&statement->whiles);
1126                 break;
1127         case STATEMENT_DO_WHILE:
1128                 print_do_while_statement(&statement->do_while);
1129                 break;
1130         case STATEMENT_FOR:
1131                 print_for_statement(&statement->fors);
1132                 break;
1133         case STATEMENT_ASM:
1134                 print_asm_statement(&statement->asms);
1135                 break;
1136         case STATEMENT_INVALID:
1137                 fprintf(out, "$invalid statement$");
1138                 break;
1139         }
1140 }
1141
1142 /**
1143  * Print a storage class.
1144  *
1145  * @param storage_class   the storage class
1146  */
1147 static void print_storage_class(storage_class_tag_t storage_class)
1148 {
1149         switch(storage_class) {
1150         case STORAGE_CLASS_ENUM_ENTRY:
1151         case STORAGE_CLASS_NONE:
1152                 break;
1153         case STORAGE_CLASS_TYPEDEF:       fputs("typedef ",        out); break;
1154         case STORAGE_CLASS_EXTERN:        fputs("extern ",         out); break;
1155         case STORAGE_CLASS_STATIC:        fputs("static ",         out); break;
1156         case STORAGE_CLASS_AUTO:          fputs("auto ",           out); break;
1157         case STORAGE_CLASS_REGISTER:      fputs("register ",       out); break;
1158         case STORAGE_CLASS_THREAD:        fputs("__thread",        out); break;
1159         case STORAGE_CLASS_THREAD_EXTERN: fputs("extern __thread", out); break;
1160         case STORAGE_CLASS_THREAD_STATIC: fputs("static __thread", out); break;
1161         }
1162 }
1163
1164 /**
1165  * Print an initializer.
1166  *
1167  * @param initializer  the initializer
1168  */
1169 void print_initializer(const initializer_t *initializer)
1170 {
1171         if(initializer == NULL) {
1172                 fputs("{}", out);
1173                 return;
1174         }
1175
1176         switch(initializer->kind) {
1177         case INITIALIZER_VALUE: {
1178                 const initializer_value_t *value = &initializer->value;
1179                 print_expression(value->value);
1180                 return;
1181         }
1182         case INITIALIZER_LIST: {
1183                 assert(initializer->kind == INITIALIZER_LIST);
1184                 fputs("{ ", out);
1185                 const initializer_list_t *list = &initializer->list;
1186
1187                 for(size_t i = 0 ; i < list->len; ++i) {
1188                         const initializer_t *sub_init = list->initializers[i];
1189                         print_initializer(list->initializers[i]);
1190                         if(i < list->len-1) {
1191                                 if(sub_init == NULL || sub_init->kind != INITIALIZER_DESIGNATOR)
1192                                         fputs(", ", out);
1193                         }
1194                 }
1195                 fputs(" }", out);
1196                 return;
1197         }
1198         case INITIALIZER_STRING:
1199                 print_quoted_string(&initializer->string.string, '"');
1200                 return;
1201         case INITIALIZER_WIDE_STRING:
1202                 print_quoted_wide_string(&initializer->wide_string.string, '"');
1203                 return;
1204         case INITIALIZER_DESIGNATOR:
1205                 print_designator(initializer->designator.designator);
1206                 fputs(" = ", out);
1207                 return;
1208         }
1209
1210         panic("invalid initializer kind found");
1211 }
1212
1213 /**
1214  * Print microsoft extended declaration modifiers.
1215  */
1216 static void print_ms_modifiers(const declaration_t *declaration) {
1217         decl_modifiers_t modifiers = declaration->modifiers;
1218
1219         /* DM_FORCEINLINE handled outside. */
1220         if((modifiers & ~DM_FORCEINLINE) != 0 || declaration->alignment != 0 ||
1221             declaration->get_property_sym != NULL || declaration->put_property_sym != NULL) {
1222                 char *next = "(";
1223
1224                 fputs("__declspec", out);
1225                 if(modifiers & DM_DLLIMPORT) {
1226                         fputs(next, out); next = ", "; fputs("dllimport", out);
1227                 }
1228                 if(modifiers & DM_DLLEXPORT) {
1229                         fputs(next, out); next = ", "; fputs("dllexport", out);
1230                 }
1231                 if(modifiers & DM_THREAD) {
1232                         fputs(next, out); next = ", "; fputs("thread", out);
1233                 }
1234                 if(modifiers & DM_NAKED) {
1235                         fputs(next, out); next = ", "; fputs("naked", out);
1236                 }
1237                 if(modifiers & DM_THREAD) {
1238                         fputs(next, out); next = ", "; fputs("thread", out);
1239                 }
1240                 if(modifiers & DM_SELECTANY) {
1241                         fputs(next, out); next = ", "; fputs("selectany", out);
1242                 }
1243                 if(modifiers & DM_NOTHROW) {
1244                         fputs(next, out); next = ", "; fputs("nothrow", out);
1245                 }
1246                 if(modifiers & DM_NORETURN) {
1247                         fputs(next, out); next = ", "; fputs("noreturn", out);
1248                 }
1249                 if(modifiers & DM_NOINLINE) {
1250                         fputs(next, out); next = ", "; fputs("noinline", out);
1251                 }
1252                 if(modifiers & DM_DEPRECATED) {
1253                         fputs(next, out); next = ", "; fputs("deprecated", out);
1254                         if(declaration->deprecated_string != NULL)
1255                                 fprintf(out, "(\"%s\")", declaration->deprecated_string);
1256                 }
1257                 if(declaration->alignment != 0) {
1258                         fputs(next, out); next = ", "; fprintf(out, "align(%u)", declaration->alignment);
1259                 }
1260                 if(modifiers & DM_RESTRICT) {
1261                         fputs(next, out); next = ", "; fputs("restrict", out);
1262                 }
1263                 if(modifiers & DM_NOALIAS) {
1264                         fputs(next, out); next = ", "; fputs("noalias", out);
1265                 }
1266             if(declaration->get_property_sym != NULL || declaration->put_property_sym != NULL) {
1267                 char *comma = "";
1268                         fputs(next, out); next = ", "; fprintf(out, "property(");
1269                 if(declaration->get_property_sym != NULL) {
1270                         fprintf(out, "get=%s", declaration->get_property_sym->string);
1271                         comma = ", ";
1272                         }
1273                 if(declaration->put_property_sym != NULL)
1274                         fprintf(out, "%sput=%s", comma, declaration->put_property_sym->string);
1275                         fputc(')', out);
1276                 }
1277                 fputs(") ", out);
1278         }
1279 }
1280
1281 /**
1282  * Print a declaration in the NORMAL namespace.
1283  *
1284  * @param declaration  the declaration
1285  */
1286 static void print_normal_declaration(const declaration_t *declaration)
1287 {
1288         print_storage_class((storage_class_tag_t) declaration->declared_storage_class);
1289         if(declaration->is_inline) {
1290                 if(declaration->modifiers & DM_FORCEINLINE)
1291                         fputs("__forceinline ", out);
1292                 else {
1293                         if(declaration->modifiers & DM_MICROSOFT_INLINE)
1294                                 fputs("__inline ", out);
1295                         else
1296                                 fputs("inline ", out);
1297                 }
1298         }
1299         print_ms_modifiers(declaration);
1300         print_type_ext(declaration->type, declaration->symbol,
1301                        &declaration->scope);
1302
1303         if(declaration->type->kind == TYPE_FUNCTION) {
1304                 if(declaration->init.statement != NULL) {
1305                         fputs("\n", out);
1306                         print_statement(declaration->init.statement);
1307                         return;
1308                 }
1309         } else if(declaration->init.initializer != NULL) {
1310                 fputs(" = ", out);
1311                 print_initializer(declaration->init.initializer);
1312         }
1313         fputc(';', out);
1314 }
1315
1316 /**
1317  * Prints an expression.
1318  *
1319  * @param expression  the expression
1320  */
1321 void print_expression(const expression_t *expression) {
1322         print_expression_prec(expression, PREC_BOTTOM);
1323 }
1324
1325 /**
1326  * Print a declaration.
1327  *
1328  * @param declaration  the declaration
1329  */
1330 void print_declaration(const declaration_t *declaration)
1331 {
1332         if(declaration->namespc != NAMESPACE_NORMAL &&
1333                         declaration->symbol == NULL)
1334                 return;
1335
1336         switch(declaration->namespc) {
1337         case NAMESPACE_NORMAL:
1338                 print_normal_declaration(declaration);
1339                 break;
1340         case NAMESPACE_STRUCT:
1341                 fputs("struct ", out);
1342                 fputs(declaration->symbol->string, out);
1343                 fputc(' ', out);
1344                 print_compound_definition(declaration);
1345                 fputc(';', out);
1346                 break;
1347         case NAMESPACE_UNION:
1348                 fputs("union ", out);
1349                 fputs(declaration->symbol->string, out);
1350                 fputc(' ', out);
1351                 print_compound_definition(declaration);
1352                 fputc(';', out);
1353                 break;
1354         case NAMESPACE_ENUM:
1355                 fputs("enum ", out);
1356                 fputs(declaration->symbol->string, out);
1357                 fputc(' ', out);
1358                 print_enum_definition(declaration);
1359                 fputc(';', out);
1360                 break;
1361         }
1362 }
1363
1364 /**
1365  * Print the AST of a translation unit.
1366  *
1367  * @param unit   the translation unit
1368  */
1369 void print_ast(const translation_unit_t *unit)
1370 {
1371         inc_type_visited();
1372
1373         declaration_t *declaration = unit->scope.declarations;
1374         for( ; declaration != NULL; declaration = declaration->next) {
1375                 if(declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)
1376                         continue;
1377                 if(declaration->namespc != NAMESPACE_NORMAL &&
1378                                 declaration->symbol == NULL)
1379                         continue;
1380
1381                 print_indent();
1382                 print_declaration(declaration);
1383                 fputc('\n', out);
1384         }
1385 }
1386
1387 bool is_constant_initializer(const initializer_t *initializer)
1388 {
1389         switch(initializer->kind) {
1390         case INITIALIZER_STRING:
1391         case INITIALIZER_WIDE_STRING:
1392         case INITIALIZER_DESIGNATOR:
1393                 return true;
1394
1395         case INITIALIZER_VALUE:
1396                 return is_constant_expression(initializer->value.value);
1397
1398         case INITIALIZER_LIST:
1399                 for(size_t i = 0; i < initializer->list.len; ++i) {
1400                         initializer_t *sub_initializer = initializer->list.initializers[i];
1401                         if(!is_constant_initializer(sub_initializer))
1402                                 return false;
1403                 }
1404                 return true;
1405         }
1406         panic("invalid initializer kind found");
1407 }
1408
1409 static bool is_object_with_constant_address(const expression_t *expression)
1410 {
1411         switch(expression->kind) {
1412         case EXPR_UNARY_DEREFERENCE:
1413                 return is_address_constant(expression->unary.value);
1414
1415         case EXPR_SELECT: {
1416                 if(is_type_pointer(expression->select.compound->base.type)) {
1417                         /* it's a -> */
1418                         return is_address_constant(expression->select.compound);
1419                 } else {
1420                         return is_object_with_constant_address(expression->select.compound);
1421                 }
1422         }
1423
1424         case EXPR_ARRAY_ACCESS:
1425                 return is_constant_expression(expression->array_access.index)
1426                         && is_address_constant(expression->array_access.array_ref);
1427
1428         case EXPR_REFERENCE: {
1429                 declaration_t *declaration = expression->reference.declaration;
1430                 switch((storage_class_tag_t) declaration->storage_class) {
1431                 case STORAGE_CLASS_NONE:
1432                 case STORAGE_CLASS_EXTERN:
1433                 case STORAGE_CLASS_STATIC:
1434                         return true;
1435                 default:
1436                         return false;
1437                 }
1438         }
1439
1440         default:
1441                 return false;
1442         }
1443 }
1444
1445 bool is_address_constant(const expression_t *expression)
1446 {
1447         switch(expression->kind) {
1448         case EXPR_UNARY_TAKE_ADDRESS:
1449                 return is_object_with_constant_address(expression->unary.value);
1450
1451         case EXPR_UNARY_DEREFERENCE: {
1452                 type_t *real_type = revert_automatic_type_conversion(expression->unary.value);
1453                 /* dereferencing a function is a NOP */
1454                 if(is_type_function(real_type)) {
1455                         return is_address_constant(expression->unary.value);
1456                 }
1457         }
1458
1459         case EXPR_UNARY_CAST:
1460                 return is_type_pointer(skip_typeref(expression->base.type))
1461                         && (is_constant_expression(expression->unary.value)
1462                         || is_address_constant(expression->unary.value));
1463
1464         case EXPR_BINARY_ADD:
1465         case EXPR_BINARY_SUB: {
1466                 expression_t *left  = expression->binary.left;
1467                 expression_t *right = expression->binary.right;
1468
1469                 if(is_type_pointer(skip_typeref(left->base.type))) {
1470                         return is_address_constant(left) && is_constant_expression(right);
1471                 } else if(is_type_pointer(skip_typeref(right->base.type))) {
1472                         return is_constant_expression(left)     && is_address_constant(right);
1473                 }
1474
1475                 return false;
1476         }
1477
1478         case EXPR_REFERENCE: {
1479                 declaration_t *declaration = expression->reference.declaration;
1480                 type_t *type = skip_typeref(declaration->type);
1481                 if(is_type_function(type))
1482                         return true;
1483                 if(is_type_array(type)) {
1484                         return is_object_with_constant_address(expression);
1485                 }
1486                 return false;
1487         }
1488
1489         default:
1490                 return false;
1491         }
1492 }
1493
1494 bool is_constant_expression(const expression_t *expression)
1495 {
1496         switch(expression->kind) {
1497
1498         case EXPR_CONST:
1499         case EXPR_CHARACTER_CONSTANT:
1500         case EXPR_WIDE_CHARACTER_CONSTANT:
1501         case EXPR_STRING_LITERAL:
1502         case EXPR_WIDE_STRING_LITERAL:
1503         case EXPR_SIZEOF:
1504         case EXPR_CLASSIFY_TYPE:
1505         case EXPR_FUNCTION:
1506         case EXPR_PRETTY_FUNCTION:
1507         case EXPR_OFFSETOF:
1508         case EXPR_ALIGNOF:
1509         case EXPR_BUILTIN_CONSTANT_P:
1510                 return true;
1511
1512         case EXPR_BUILTIN_SYMBOL:
1513         case EXPR_BUILTIN_PREFETCH:
1514         case EXPR_CALL:
1515         case EXPR_SELECT:
1516         case EXPR_VA_START:
1517         case EXPR_VA_ARG:
1518         case EXPR_STATEMENT:
1519         case EXPR_UNARY_POSTFIX_INCREMENT:
1520         case EXPR_UNARY_POSTFIX_DECREMENT:
1521         case EXPR_UNARY_PREFIX_INCREMENT:
1522         case EXPR_UNARY_PREFIX_DECREMENT:
1523         case EXPR_UNARY_BITFIELD_EXTRACT:
1524         case EXPR_UNARY_ASSUME: /* has VOID type */
1525         case EXPR_UNARY_TAKE_ADDRESS:
1526         case EXPR_UNARY_DEREFERENCE:
1527         case EXPR_BINARY_ASSIGN:
1528         case EXPR_BINARY_MUL_ASSIGN:
1529         case EXPR_BINARY_DIV_ASSIGN:
1530         case EXPR_BINARY_MOD_ASSIGN:
1531         case EXPR_BINARY_ADD_ASSIGN:
1532         case EXPR_BINARY_SUB_ASSIGN:
1533         case EXPR_BINARY_SHIFTLEFT_ASSIGN:
1534         case EXPR_BINARY_SHIFTRIGHT_ASSIGN:
1535         case EXPR_BINARY_BITWISE_AND_ASSIGN:
1536         case EXPR_BINARY_BITWISE_XOR_ASSIGN:
1537         case EXPR_BINARY_BITWISE_OR_ASSIGN:
1538         case EXPR_BINARY_COMMA:
1539                 return false;
1540
1541         case EXPR_UNARY_NEGATE:
1542         case EXPR_UNARY_PLUS:
1543         case EXPR_UNARY_BITWISE_NEGATE:
1544         case EXPR_UNARY_NOT:
1545                 return is_constant_expression(expression->unary.value);
1546
1547         case EXPR_UNARY_CAST:
1548         case EXPR_UNARY_CAST_IMPLICIT:
1549                 return is_type_arithmetic(skip_typeref(expression->base.type))
1550                         && is_constant_expression(expression->unary.value);
1551
1552         case EXPR_BINARY_ADD:
1553         case EXPR_BINARY_SUB:
1554         case EXPR_BINARY_MUL:
1555         case EXPR_BINARY_DIV:
1556         case EXPR_BINARY_MOD:
1557         case EXPR_BINARY_EQUAL:
1558         case EXPR_BINARY_NOTEQUAL:
1559         case EXPR_BINARY_LESS:
1560         case EXPR_BINARY_LESSEQUAL:
1561         case EXPR_BINARY_GREATER:
1562         case EXPR_BINARY_GREATEREQUAL:
1563         case EXPR_BINARY_BITWISE_AND:
1564         case EXPR_BINARY_BITWISE_OR:
1565         case EXPR_BINARY_BITWISE_XOR:
1566         case EXPR_BINARY_LOGICAL_AND:
1567         case EXPR_BINARY_LOGICAL_OR:
1568         case EXPR_BINARY_SHIFTLEFT:
1569         case EXPR_BINARY_SHIFTRIGHT:
1570         case EXPR_BINARY_BUILTIN_EXPECT:
1571         case EXPR_BINARY_ISGREATER:
1572         case EXPR_BINARY_ISGREATEREQUAL:
1573         case EXPR_BINARY_ISLESS:
1574         case EXPR_BINARY_ISLESSEQUAL:
1575         case EXPR_BINARY_ISLESSGREATER:
1576         case EXPR_BINARY_ISUNORDERED:
1577                 return is_constant_expression(expression->binary.left)
1578                         && is_constant_expression(expression->binary.right);
1579
1580         case EXPR_COMPOUND_LITERAL:
1581                 return is_constant_initializer(expression->compound_literal.initializer);
1582
1583         case EXPR_CONDITIONAL: {
1584                 expression_t *condition = expression->conditional.condition;
1585                 if(!is_constant_expression(condition))
1586                         return false;
1587
1588                 long val = fold_constant(condition);
1589                 if(val != 0)
1590                         return is_constant_expression(expression->conditional.true_expression);
1591                 else
1592                         return is_constant_expression(expression->conditional.false_expression);
1593         }
1594
1595         case EXPR_ARRAY_ACCESS:
1596                 return is_constant_expression(expression->array_access.array_ref)
1597                         && is_constant_expression(expression->array_access.index);
1598
1599         case EXPR_REFERENCE: {
1600                 declaration_t *declaration = expression->reference.declaration;
1601                 if(declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)
1602                         return true;
1603
1604                 return false;
1605         }
1606
1607         case EXPR_INVALID:
1608                 return true;
1609
1610         case EXPR_UNKNOWN:
1611                 break;
1612         }
1613         panic("invalid expression found (is constant expression)");
1614 }
1615
1616 /**
1617  * Initialize the AST construction.
1618  */
1619 void init_ast(void)
1620 {
1621         obstack_init(&ast_obstack);
1622 }
1623
1624 /**
1625  * Free the AST.
1626  */
1627 void exit_ast(void)
1628 {
1629         obstack_free(&ast_obstack, NULL);
1630 }
1631
1632 /**
1633  * Set the output stream for the AST printer.
1634  *
1635  * @param stream  the output stream
1636  */
1637 void ast_set_output(FILE *stream)
1638 {
1639         out = stream;
1640         type_set_output(stream);
1641 }
1642
1643 /**
1644  * Allocate an AST object of the given size.
1645  *
1646  * @param size  the size of the object to allocate
1647  *
1648  * @return  A new allocated object in the AST memeory space.
1649  */
1650 void *(allocate_ast)(size_t size)
1651 {
1652         return _allocate_ast(size);
1653 }