- when parsing compound types, do NOT destroy old declarations if
[cparser] / ast.c
diff --git a/ast.c b/ast.c
index 7bac0da..545f513 100644 (file)
--- a/ast.c
+++ b/ast.c
 #include <stdlib.h>
 #include <ctype.h>
 
+#ifdef __INTEL_COMPILER
+#include <mathimf.h>
+#else
+#include <math.h>
+#endif
+
 #include "adt/error.h"
 
 struct obstack ast_obstack;
@@ -54,29 +60,30 @@ void change_indent(int delta)
 
 void print_indent(void)
 {
-       for(int i = 0; i < indent; ++i)
-               fprintf(out, "\t");
+       for (int i = 0; i < indent; ++i)
+               fputc('\t', out);
 }
 
 enum precedence_t {
        PREC_BOTTOM  =  0,
-       PREC_COMMA   =  2, /* ,                                    left to right */
-       PREC_ASSIGN  =  4, /* = += -= *= /= %= <<= >>= &= ^= |=    right to left */
-       PREC_COND    =  6, /* ?:                                   right to left */
-       PREC_LOG_OR  =  8, /* ||                                   left to right */
-       PREC_LOG_AND = 10, /* &&                                   left to right */
-       PREC_BIT_OR  = 12, /* |                                    left to right */
-       PREC_BIT_XOR = 14, /* ^                                    left to right */
-       PREC_BIT_AND = 16, /* &                                    left to right */
-       PREC_EQ      = 18, /* == !=                                left to right */
-       PREC_CMP     = 20, /* < <= > >=                            left to right */
-       PREC_SHF     = 22, /* << >>                                left to right */
-       PREC_PLUS    = 24, /* + -                                  left to right */
-       PREC_MUL     = 26, /* * / %                                left to right */
-       PREC_UNARY   = 28, /* ! ~ ++ -- + - (type) * & sizeof      right to left */
-       PREC_ACCESS  = 30, /* () [] -> .                           left to right */
-       PREC_PRIM    = 32, /* primary */
-       PREC_TOP     = 34
+       PREC_EXPR    =  2,
+       PREC_COMMA   =  4, /* ,                                    left to right */
+       PREC_ASSIGN  =  6, /* = += -= *= /= %= <<= >>= &= ^= |=    right to left */
+       PREC_COND    =  8, /* ?:                                   right to left */
+       PREC_LOG_OR  = 10, /* ||                                   left to right */
+       PREC_LOG_AND = 12, /* &&                                   left to right */
+       PREC_BIT_OR  = 14, /* |                                    left to right */
+       PREC_BIT_XOR = 16, /* ^                                    left to right */
+       PREC_BIT_AND = 18, /* &                                    left to right */
+       PREC_EQ      = 20, /* == !=                                left to right */
+       PREC_CMP     = 22, /* < <= > >=                            left to right */
+       PREC_SHF     = 24, /* << >>                                left to right */
+       PREC_PLUS    = 26, /* + -                                  left to right */
+       PREC_MUL     = 28, /* * / %                                left to right */
+       PREC_UNARY   = 30, /* ! ~ ++ -- + - (type) * & sizeof      right to left */
+       PREC_ACCESS  = 32, /* () [] -> .                           left to right */
+       PREC_PRIM    = 34, /* primary */
+       PREC_TOP     = 36
 };
 
 /**
@@ -107,7 +114,7 @@ static unsigned get_expression_precedence(expression_kind_t kind)
                [EXPR_STRING_LITERAL]            = PREC_PRIM,
                [EXPR_WIDE_STRING_LITERAL]       = PREC_PRIM,
                [EXPR_COMPOUND_LITERAL]          = PREC_UNARY,
-               [EXPR_CALL]                      = PREC_PRIM,
+               [EXPR_CALL]                      = PREC_ACCESS,
                [EXPR_CONDITIONAL]               = PREC_COND,
                [EXPR_SELECT]                    = PREC_ACCESS,
                [EXPR_ARRAY_ACCESS]              = PREC_ACCESS,
@@ -123,6 +130,7 @@ static unsigned get_expression_precedence(expression_kind_t kind)
                [EXPR_VA_START]                  = PREC_PRIM,
                [EXPR_VA_ARG]                    = PREC_PRIM,
                [EXPR_STATEMENT]                 = PREC_ACCESS,
+               [EXPR_LABEL_ADDRESS]             = PREC_PRIM,
 
                [EXPR_UNARY_NEGATE]              = PREC_UNARY,
                [EXPR_UNARY_PLUS]                = PREC_UNARY,
@@ -199,10 +207,33 @@ static void print_const(const const_expression_t *cnst)
        if (is_type_integer(type)) {
                fprintf(out, "%lld", cnst->v.int_value);
        } else if (is_type_float(type)) {
-               fprintf(out, "%Lf", cnst->v.float_value);
+               long double const val = cnst->v.float_value;
+#ifdef _WIN32
+               /* ARG, no way to print long double */
+               fprintf(out, "%.20g", (double)val);
+#else
+               fprintf(out, "%.20Lg", val);
+#endif
+               if (isfinite(val) && truncl(val) == val)
+                       fputs(".0", out);
        } else {
                panic("unknown constant");
        }
+
+       char const* suffix;
+       switch (type->atomic.akind) {
+               case ATOMIC_TYPE_UINT:        suffix = "U";   break;
+               case ATOMIC_TYPE_LONG:        suffix = "L";   break;
+               case ATOMIC_TYPE_ULONG:       suffix = "UL";  break;
+               case ATOMIC_TYPE_LONGLONG:    suffix = "LL";  break;
+               case ATOMIC_TYPE_ULONGLONG:   suffix = "ULL"; break;
+               case ATOMIC_TYPE_FLOAT:       suffix = "F";   break;
+               case ATOMIC_TYPE_LONG_DOUBLE: suffix = "L";   break;
+
+               default: suffix = NULL; break;
+       }
+       if (suffix != NULL)
+               fputs(suffix, out);
 }
 
 /**
@@ -210,11 +241,12 @@ static void print_const(const const_expression_t *cnst)
  *
  * @param string  the string constant
  * @param border  the border char
+ * @param skip    number of chars to skip at the end
  */
-static void print_quoted_string(const string_t *const string, char border)
+static void print_quoted_string(const string_t *const string, char border, int skip)
 {
        fputc(border, out);
-       const char *end = string->begin + string->size - 1;
+       const char *end = string->begin + string->size - skip;
        for (const char *c = string->begin; c != end; ++c) {
                if (*c == border) {
                        fputc('\\', out);
@@ -229,6 +261,11 @@ static void print_quoted_string(const string_t *const string, char border)
                case '\t':  fputs("\\t", out); break;
                case '\v':  fputs("\\v", out); break;
                case '\?':  fputs("\\?", out); break;
+               case 27:
+                       if (c_mode & _GNUC) {
+                               fputs("\\e", out); break;
+                       }
+                       /*fallthrough*/
                default:
                        if(!isprint(*c)) {
                                fprintf(out, "\\%03o", *c);
@@ -244,15 +281,17 @@ static void print_quoted_string(const string_t *const string, char border)
 /**
  * Prints a wide string literal expression.
  *
- * @param wstr  the wide string literal expression
+ * @param wstr    the wide string literal expression
+ * @param border  the border char
+ * @param skip    number of chars to skip at the end
  */
 static void print_quoted_wide_string(const wide_string_t *const wstr,
-                                     char border)
+                                     char border, int skip)
 {
        fputc('L', out);
        fputc(border, out);
-       for (const wchar_rep_t *c = wstr->begin, *end = wstr->begin + wstr->size-1;
-            c != end; ++c) {
+       const wchar_rep_t *end = wstr->begin + wstr->size - skip;
+       for (const wchar_rep_t *c = wstr->begin; c != end; ++c) {
                switch (*c) {
                        case L'\"':  fputs("\\\"", out); break;
                        case L'\\':  fputs("\\\\", out); break;
@@ -264,6 +303,11 @@ static void print_quoted_wide_string(const wide_string_t *const wstr,
                        case L'\t':  fputs("\\t",  out); break;
                        case L'\v':  fputs("\\v",  out); break;
                        case L'\?':  fputs("\\?",  out); break;
+                       case 27:
+                               if (c_mode & _GNUC) {
+                                       fputs("\\e", out); break;
+                               }
+                               /*fallthrough*/
                        default: {
                                const unsigned tc = *c;
                                if (tc < 0x80U) {
@@ -298,12 +342,12 @@ static void print_quoted_wide_string(const wide_string_t *const wstr,
  */
 static void print_character_constant(const const_expression_t *cnst)
 {
-       print_quoted_string(&cnst->v.character, '\'');
+       print_quoted_string(&cnst->v.character, '\'', 0);
 }
 
 static void print_wide_character_constant(const const_expression_t *cnst)
 {
-       print_quoted_wide_string(&cnst->v.wide_character, '\'');
+       print_quoted_wide_string(&cnst->v.wide_character, '\'', 0);
 }
 
 /**
@@ -314,7 +358,7 @@ static void print_wide_character_constant(const const_expression_t *cnst)
 static void print_string_literal(
                const string_literal_expression_t *string_literal)
 {
-       print_quoted_string(&string_literal->value, '"');
+       print_quoted_string(&string_literal->value, '"', 1);
 }
 
 /**
@@ -338,7 +382,7 @@ static void print_funcname(
 static void print_wide_string_literal(
        const wide_string_literal_expression_t *const wstr)
 {
-       print_quoted_wide_string(&wstr->value, '"');
+       print_quoted_wide_string(&wstr->value, '"', 1);
 }
 
 static void print_compound_literal(
@@ -359,12 +403,12 @@ static void print_call_expression(const call_expression_t *call)
 {
        unsigned prec = get_expression_precedence(call->base.kind);
        print_expression_prec(call->function, prec);
-       fprintf(out, "(");
+       fputc('(', out);
        call_argument_t *argument = call->arguments;
        int              first    = 1;
        while(argument != NULL) {
                if(!first) {
-                       fprintf(out, ", ");
+                       fputs(", ", out);
                } else {
                        first = 0;
                }
@@ -372,7 +416,7 @@ static void print_call_expression(const call_expression_t *call)
 
                argument = argument->next;
        }
-       fprintf(out, ")");
+       fputc(')', out);
 }
 
 /**
@@ -445,14 +489,14 @@ static void print_unary_expression(const unary_expression_t *unexpr)
 {
        unsigned prec = get_expression_precedence(unexpr->base.kind);
        switch(unexpr->base.kind) {
-       case EXPR_UNARY_NEGATE:           fputs("-", out);  break;
-       case EXPR_UNARY_PLUS:             fputs("+", out);  break;
-       case EXPR_UNARY_NOT:              fputs("!", out);  break;
-       case EXPR_UNARY_BITWISE_NEGATE:   fputs("~", out);  break;
+       case EXPR_UNARY_NEGATE:           fputc('-', out);  break;
+       case EXPR_UNARY_PLUS:             fputc('+', out);  break;
+       case EXPR_UNARY_NOT:              fputc('!', out);  break;
+       case EXPR_UNARY_BITWISE_NEGATE:   fputc('~', out);  break;
        case EXPR_UNARY_PREFIX_INCREMENT: fputs("++", out); break;
        case EXPR_UNARY_PREFIX_DECREMENT: fputs("--", out); break;
-       case EXPR_UNARY_DEREFERENCE:      fputs("*", out);  break;
-       case EXPR_UNARY_TAKE_ADDRESS:     fputs("&", out);  break;
+       case EXPR_UNARY_DEREFERENCE:      fputc('*', out);  break;
+       case EXPR_UNARY_TAKE_ADDRESS:     fputc('&', out);  break;
 
        case EXPR_UNARY_POSTFIX_INCREMENT:
                print_expression_prec(unexpr->value, prec);
@@ -463,11 +507,6 @@ static void print_unary_expression(const unary_expression_t *unexpr)
                fputs("--", out);
                return;
        case EXPR_UNARY_CAST_IMPLICIT:
-               if(!print_implicit_casts) {
-                       print_expression_prec(unexpr->value, prec);
-                       return;
-               }
-               /* fallthrough */
        case EXPR_UNARY_CAST:
                fputc('(', out);
                print_type(unexpr->base.type);
@@ -491,7 +530,17 @@ static void print_unary_expression(const unary_expression_t *unexpr)
  */
 static void print_reference_expression(const reference_expression_t *ref)
 {
-       fprintf(out, "%s", ref->declaration->symbol->string);
+       fputs(ref->declaration->symbol->string, out);
+}
+
+/**
+ * Prints a label address expression.
+ *
+ * @param ref   the reference expression
+ */
+static void print_label_address_expression(const label_address_expression_t *le)
+{
+       fprintf(out, "&&%s", le->declaration->symbol->string);
 }
 
 /**
@@ -505,12 +554,12 @@ static void print_array_expression(const array_access_expression_t *expression)
        if(!expression->flipped) {
                print_expression_prec(expression->array_ref, prec);
                fputc('[', out);
-               print_expression_prec(expression->index, prec);
+               print_expression_prec(expression->index, PREC_BOTTOM);
                fputc(']', out);
        } else {
                print_expression_prec(expression->index, prec);
                fputc('[', out);
-               print_expression_prec(expression->array_ref, prec);
+               print_expression_prec(expression->array_ref, PREC_BOTTOM);
                fputc(']', out);
        }
 }
@@ -589,14 +638,15 @@ static void print_builtin_prefetch(const builtin_prefetch_expression_t *expressi
  */
 static void print_conditional(const conditional_expression_t *expression)
 {
-       unsigned prec = get_expression_precedence(expression->base.kind);
-       fputs("(", out);
-       print_expression_prec(expression->condition, prec);
+       print_expression_prec(expression->condition, PREC_LOG_OR);
        fputs(" ? ", out);
-       print_expression_prec(expression->true_expression, prec);
-       fputs(" : ", out);
-       print_expression_prec(expression->false_expression, prec);
-       fputs(")", out);
+       if (expression->true_expression != NULL) {
+               print_expression_prec(expression->true_expression, PREC_EXPR);
+               fputs(" : ", out);
+       } else {
+               fputs(": ", out);
+       }
+       print_expression_prec(expression->false_expression, PREC_COND);
 }
 
 /**
@@ -641,7 +691,7 @@ static void print_select(const select_expression_t *expression)
        } else {
                fputc('.', out);
        }
-       fputs(expression->symbol->string, out);
+       fputs(expression->compound_entry->symbol->string, out);
 }
 
 /**
@@ -667,7 +717,7 @@ static void print_designator(const designator_t *designator)
        for ( ; designator != NULL; designator = designator->next) {
                if (designator->symbol == NULL) {
                        fputc('[', out);
-                       print_expression_prec(designator->array_index, PREC_ACCESS);
+                       print_expression_prec(designator->array_index, PREC_BOTTOM);
                        fputc(']', out);
                } else {
                        fputc('.', out);
@@ -711,6 +761,9 @@ static void print_statement_expression(const statement_expression_t *expression)
  */
 static void print_expression_prec(const expression_t *expression, unsigned top_prec)
 {
+       if (expression->kind == EXPR_UNARY_CAST_IMPLICIT && !print_implicit_casts) {
+               expression = expression->unary.value;
+       }
        unsigned prec = get_expression_precedence(expression->base.kind);
        if (print_parenthesis && top_prec != PREC_BOTTOM)
                top_prec = PREC_TOP;
@@ -719,7 +772,7 @@ static void print_expression_prec(const expression_t *expression, unsigned top_p
        switch(expression->kind) {
        case EXPR_UNKNOWN:
        case EXPR_INVALID:
-               fprintf(out, "$invalid expression$");
+               fputs("$invalid expression$", out);
                break;
        case EXPR_CHARACTER_CONSTANT:
                print_character_constant(&expression->conste);
@@ -754,6 +807,9 @@ static void print_expression_prec(const expression_t *expression, unsigned top_p
        case EXPR_ARRAY_ACCESS:
                print_array_expression(&expression->array_access);
                break;
+       case EXPR_LABEL_ADDRESS:
+               print_label_address_expression(&expression->label_address);
+               break;
        EXPR_UNARY_CASES
                print_unary_expression(&expression->unary);
                break;
@@ -812,10 +868,11 @@ static void print_compound_statement(const compound_statement_t *block)
        ++indent;
 
        statement_t *statement = block->statements;
-       while(statement != NULL) {
+       while (statement != NULL) {
                if (statement->base.kind == STATEMENT_CASE_LABEL)
                        --indent;
-               print_indent();
+               if (statement->kind != STATEMENT_LABEL)
+                       print_indent();
                print_statement(statement);
 
                statement = statement->base.next;
@@ -832,7 +889,7 @@ static void print_compound_statement(const compound_statement_t *block)
  */
 static void print_return_statement(const return_statement_t *statement)
 {
-       fprintf(out, "return ");
+       fputs("return ", out);
        if(statement->value != NULL)
                print_expression(statement->value);
        fputs(";\n", out);
@@ -856,9 +913,13 @@ static void print_expression_statement(const expression_statement_t *statement)
  */
 static void print_goto_statement(const goto_statement_t *statement)
 {
-       fprintf(out, "goto ");
-       fputs(statement->label->symbol->string, out);
-       fprintf(stderr, "(%p)", (void*) statement->label);
+       fputs("goto ", out);
+       if (statement->expression != NULL) {
+               fputc('*', out);
+               print_expression(statement->expression);
+       } else {
+               fputs(statement->label->symbol->string, out);
+       }
        fputs(";\n", out);
 }
 
@@ -869,8 +930,8 @@ static void print_goto_statement(const goto_statement_t *statement)
  */
 static void print_label_statement(const label_statement_t *statement)
 {
-       fprintf(stderr, "(%p)", (void*) statement->label);
        fprintf(out, "%s:\n", statement->label->symbol->string);
+       print_indent();
        print_statement(statement->statement);
 }
 
@@ -942,20 +1003,39 @@ static void print_case_label(const case_label_statement_t *statement)
 static void print_declaration_statement(
                const declaration_statement_t *statement)
 {
-       int first = 1;
+       bool first = true;
        declaration_t *declaration = statement->declarations_begin;
-       for( ; declaration != statement->declarations_end->next;
-              declaration = declaration->next) {
-           if(declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)
-               continue;
 
-               if(!first) {
-                       print_indent();
-               } else {
-                       first = 0;
+       if (declaration->namespc == NAMESPACE_LOCAL_LABEL) {
+               fputs("__label__ ", out);
+               for (;
+                       declaration != statement->declarations_end->next;
+                       declaration = declaration->next) {
+                       if (!first) {
+                               fputs(", ", out);
+                       } else {
+                               first = false;
+                       }
+                       fputs(declaration->symbol->string, out);
+               }
+               fputs(";\n", out);
+       } else {
+               for (;
+                        declaration != statement->declarations_end->next;
+                        declaration = declaration->next) {
+                       if (declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)
+                               continue;
+                       if (declaration->implicit)
+                               continue;
+
+                       if (!first) {
+                               print_indent();
+                       } else {
+                               first = false;
+                       }
+                       print_declaration(declaration);
+                       fputc('\n', out);
                }
-               print_declaration(declaration);
-               fputc('\n', out);
        }
 }
 
@@ -995,10 +1075,13 @@ static void print_do_while_statement(const do_while_statement_t *statement)
 static void print_for_statement(const for_statement_t *statement)
 {
        fputs("for (", out);
-       if(statement->scope.declarations != NULL) {
+       declaration_t *decl = statement->scope.declarations;
+       while (decl != NULL && decl->implicit)
+               decl = decl->next;
+       if (decl != NULL) {
                assert(statement->initialisation == NULL);
-               print_declaration(statement->scope.declarations);
-               if(statement->scope.declarations->next != NULL) {
+               print_declaration(decl);
+               if (decl->next != NULL) {
                        panic("multiple declarations in for statement not supported yet");
                }
                fputc(' ', out);
@@ -1015,7 +1098,7 @@ static void print_for_statement(const for_statement_t *statement)
        if(statement->step != NULL) {
                print_expression(statement->step);
        }
-       fputs(")", out);
+       fputs(") ", out);
        print_statement(statement->body);
 }
 
@@ -1034,7 +1117,7 @@ static void print_asm_arguments(asm_argument_t *arguments)
                if(argument->symbol) {
                        fprintf(out, "[%s] ", argument->symbol->string);
                }
-               print_quoted_string(&argument->constraints, '"');
+               print_quoted_string(&argument->constraints, '"', 1);
                fputs(" (", out);
                print_expression(argument->expression);
                fputs(")", out);
@@ -1053,7 +1136,7 @@ static void print_asm_clobbers(asm_clobber_t *clobbers)
                if(clobber != clobbers)
                        fputs(", ", out);
 
-               print_quoted_string(&clobber->clobber, '"');
+               print_quoted_string(&clobber->clobber, '"', 1);
        }
 }
 
@@ -1069,7 +1152,7 @@ static void print_asm_statement(const asm_statement_t *statement)
                fputs("volatile ", out);
        }
        fputs("(", out);
-       print_quoted_string(&statement->asm_text, '"');
+       print_quoted_string(&statement->asm_text, '"', 1);
        if(statement->inputs == NULL && statement->outputs == NULL
                        && statement->clobbers == NULL)
                goto end_of_print_asm_statement;
@@ -1129,7 +1212,7 @@ static void print_leave_statement(const leave_statement_t *statement)
  */
 void print_statement(const statement_t *statement)
 {
-       switch(statement->kind) {
+       switch (statement->kind) {
        case STATEMENT_EMPTY:
                fputs(";\n", out);
                break;
@@ -1185,7 +1268,7 @@ void print_statement(const statement_t *statement)
                print_leave_statement(&statement->leave);
                break;
        case STATEMENT_INVALID:
-               fprintf(out, "$invalid statement$");
+               fputs("$invalid statement$", out);
                break;
        }
 }
@@ -1247,10 +1330,10 @@ void print_initializer(const initializer_t *initializer)
                return;
        }
        case INITIALIZER_STRING:
-               print_quoted_string(&initializer->string.string, '"');
+               print_quoted_string(&initializer->string.string, '"', 1);
                return;
        case INITIALIZER_WIDE_STRING:
-               print_quoted_wide_string(&initializer->wide_string.string, '"');
+               print_quoted_wide_string(&initializer->wide_string.string, '"', 1);
                return;
        case INITIALIZER_DESIGNATOR:
                print_designator(initializer->designator.designator);
@@ -1271,9 +1354,10 @@ static void print_ms_modifiers(const declaration_t *declaration) {
        decl_modifiers_t modifiers = declaration->modifiers;
 
        /* DM_FORCEINLINE handled outside. */
-       if((modifiers & ~DM_FORCEINLINE) != 0 ||
-           declaration->alignment != 0 || declaration->deprecated != 0 ||
-           declaration->get_property_sym != NULL || declaration->put_property_sym != NULL) {
+       if ((modifiers & ~DM_FORCEINLINE) != 0    ||
+           declaration->alignment        != 0    ||
+           declaration->get_property_sym != NULL ||
+           declaration->put_property_sym != NULL) {
                char *next = "(";
 
                fputs("__declspec", out);
@@ -1304,7 +1388,7 @@ static void print_ms_modifiers(const declaration_t *declaration) {
                if(modifiers & DM_NOINLINE) {
                        fputs(next, out); next = ", "; fputs("noinline", out);
                }
-               if(declaration->deprecated != 0) {
+               if (modifiers & DM_DEPRECATED) {
                        fputs(next, out); next = ", "; fputs("deprecated", out);
                        if(declaration->deprecated_string != NULL)
                                fprintf(out, "(\"%s\")", declaration->deprecated_string);
@@ -1318,15 +1402,15 @@ static void print_ms_modifiers(const declaration_t *declaration) {
                if(modifiers & DM_NOALIAS) {
                        fputs(next, out); next = ", "; fputs("noalias", out);
                }
-           if(declaration->get_property_sym != NULL || declaration->put_property_sym != NULL) {
-               char *comma = "";
-                       fputs(next, out); next = ", "; fprintf(out, "property(");
-               if(declaration->get_property_sym != NULL) {
-                       fprintf(out, "get=%s", declaration->get_property_sym->string);
-                       comma = ", ";
+               if(declaration->get_property_sym != NULL || declaration->put_property_sym != NULL) {
+                       char *comma = "";
+                       fputs(next, out); next = ", "; fputs("property(", out);
+                       if(declaration->get_property_sym != NULL) {
+                               fprintf(out, "get=%s", declaration->get_property_sym->string);
+                               comma = ", ";
                        }
-               if(declaration->put_property_sym != NULL)
-                       fprintf(out, "%sput=%s", comma, declaration->put_property_sym->string);
+                       if(declaration->put_property_sym != NULL)
+                               fprintf(out, "%sput=%s", comma, declaration->put_property_sym->string);
                        fputc(')', out);
                }
                fputs(") ", out);
@@ -1341,14 +1425,13 @@ static void print_ms_modifiers(const declaration_t *declaration) {
 static void print_normal_declaration(const declaration_t *declaration)
 {
        print_storage_class((storage_class_tag_t) declaration->declared_storage_class);
-       if(declaration->is_inline) {
-               if(declaration->modifiers & DM_FORCEINLINE)
+       if (declaration->is_inline) {
+               if (declaration->modifiers & DM_FORCEINLINE) {
                        fputs("__forceinline ", out);
-               else {
-                       if(declaration->modifiers & DM_MICROSOFT_INLINE)
-                               fputs("__inline ", out);
-                       else
-                               fputs("inline ", out);
+               } else if (declaration->modifiers & DM_MICROSOFT_INLINE) {
+                       fputs("__inline ", out);
+               } else {
+                       fputs("inline ", out);
                }
        }
        print_ms_modifiers(declaration);
@@ -1384,33 +1467,39 @@ void print_expression(const expression_t *expression) {
  */
 void print_declaration(const declaration_t *declaration)
 {
-       if(declaration->namespc != NAMESPACE_NORMAL &&
-                       declaration->symbol == NULL)
+       if (declaration->namespc != NAMESPACE_NORMAL &&
+           declaration->symbol == NULL)
                return;
 
-       switch(declaration->namespc) {
+       switch (declaration->namespc) {
        case NAMESPACE_NORMAL:
                print_normal_declaration(declaration);
                break;
        case NAMESPACE_STRUCT:
                fputs("struct ", out);
                fputs(declaration->symbol->string, out);
-               fputc(' ', out);
-               print_compound_definition(declaration);
+               if (declaration->init.complete) {
+                       fputc(' ', out);
+                       print_compound_definition(declaration);
+               }
                fputc(';', out);
                break;
        case NAMESPACE_UNION:
                fputs("union ", out);
                fputs(declaration->symbol->string, out);
-               fputc(' ', out);
-               print_compound_definition(declaration);
+               if (declaration->init.complete) {
+                       fputc(' ', out);
+                       print_compound_definition(declaration);
+               }
                fputc(';', out);
                break;
        case NAMESPACE_ENUM:
                fputs("enum ", out);
                fputs(declaration->symbol->string, out);
-               fputc(' ', out);
-               print_enum_definition(declaration);
+               if (declaration->init.complete) {
+                       fputc(' ', out);
+                       print_enum_definition(declaration);
+               }
                fputc(';', out);
                break;
        }
@@ -1432,6 +1521,8 @@ void print_ast(const translation_unit_t *unit)
                if(declaration->namespc != NAMESPACE_NORMAL &&
                                declaration->symbol == NULL)
                        continue;
+               if (declaration->implicit)
+                       continue;
 
                print_indent();
                print_declaration(declaration);
@@ -1517,10 +1608,11 @@ bool is_address_constant(const expression_t *expression)
 
        case EXPR_UNARY_CAST: {
                type_t *dest = skip_typeref(expression->base.type);
-               if (!is_type_pointer(dest) &&
-                               ! (dest->kind == TYPE_ATOMIC
-                                       && (get_atomic_type_flags(dest->atomic.akind) & ATOMIC_TYPE_FLAG_INTEGER)
-                                       && (get_atomic_type_size(dest->atomic.akind) >= get_atomic_type_size(get_intptr_kind()))))
+               if (!is_type_pointer(dest) && (
+                       dest->kind != TYPE_ATOMIC                                               ||
+                       !(get_atomic_type_flags(dest->atomic.akind) & ATOMIC_TYPE_FLAG_INTEGER) ||
+                       (get_atomic_type_size(dest->atomic.akind) < get_atomic_type_size(get_intptr_kind())
+                   )))
                        return false;
 
                return (is_constant_expression(expression->unary.value)
@@ -1549,9 +1641,21 @@ bool is_address_constant(const expression_t *expression)
                if(is_type_array(type)) {
                        return is_object_with_linker_constant_address(expression);
                }
+               /* Prevent stray errors */
+               if (!is_type_valid(type))
+                       return true;
                return false;
        }
 
+       case EXPR_ARRAY_ACCESS: {
+               type_t *const type =
+                       skip_typeref(revert_automatic_type_conversion(expression));
+               return
+                       is_type_array(type)                                    &&
+                       is_constant_expression(expression->array_access.index) &&
+                       is_address_constant(expression->array_access.array_ref);
+       }
+
        default:
                return false;
        }
@@ -1583,8 +1687,6 @@ static bool is_constant_pointer(const expression_t *expression)
                return true;
 
        switch (expression->kind) {
-       case EXPR_SELECT:
-               return is_constant_pointer(expression->select.compound);
        case EXPR_UNARY_CAST:
                return is_constant_pointer(expression->unary.value);
        default:
@@ -1605,9 +1707,17 @@ static bool is_object_with_constant_address(const expression_t *expression)
                        return is_object_with_constant_address(compound);
                }
        }
-       case EXPR_ARRAY_ACCESS:
-               return is_constant_pointer(expression->array_access.array_ref)
-                       && is_constant_expression(expression->array_access.index);
+
+       case EXPR_ARRAY_ACCESS: {
+               array_access_expression_t const* const array_access =
+                       &expression->array_access;
+               return
+                       is_constant_expression(array_access->index) && (
+                               is_object_with_constant_address(array_access->array_ref) ||
+                               is_constant_pointer(array_access->array_ref)
+                       );
+       }
+
        case EXPR_UNARY_DEREFERENCE:
                return is_constant_pointer(expression->unary.value);
        default:
@@ -1617,21 +1727,32 @@ static bool is_object_with_constant_address(const expression_t *expression)
 
 bool is_constant_expression(const expression_t *expression)
 {
-       switch(expression->kind) {
+       switch (expression->kind) {
 
        case EXPR_CONST:
        case EXPR_CHARACTER_CONSTANT:
        case EXPR_WIDE_CHARACTER_CONSTANT:
        case EXPR_STRING_LITERAL:
        case EXPR_WIDE_STRING_LITERAL:
-       case EXPR_SIZEOF:
        case EXPR_CLASSIFY_TYPE:
        case EXPR_FUNCNAME:
        case EXPR_OFFSETOF:
        case EXPR_ALIGNOF:
        case EXPR_BUILTIN_CONSTANT_P:
+       case EXPR_LABEL_ADDRESS:
                return true;
 
+       case EXPR_SIZEOF: {
+               type_t *type = expression->typeprop.type;
+               if (type == NULL)
+                       type = expression->typeprop.tp_expression->base.type;
+
+               type = skip_typeref(type);
+               if (is_type_array(type) && type->array.is_vla)
+                       return false;
+               return true;
+       }
+
        case EXPR_BUILTIN_SYMBOL:
        case EXPR_BUILTIN_PREFETCH:
        case EXPR_SELECT:
@@ -1656,6 +1777,7 @@ bool is_constant_expression(const expression_t *expression)
        case EXPR_BINARY_BITWISE_XOR_ASSIGN:
        case EXPR_BINARY_BITWISE_OR_ASSIGN:
        case EXPR_BINARY_COMMA:
+       case EXPR_ARRAY_ACCESS:
                return false;
 
        case EXPR_UNARY_TAKE_ADDRESS:
@@ -1718,10 +1840,6 @@ bool is_constant_expression(const expression_t *expression)
                        return is_constant_expression(expression->conditional.false_expression);
        }
 
-       case EXPR_ARRAY_ACCESS:
-               return is_constant_expression(expression->array_access.array_ref)
-                       && is_constant_expression(expression->array_access.index);
-
        case EXPR_REFERENCE: {
                declaration_t *declaration = expression->reference.declaration;
                if(declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)