Use print_char('x') instead of print_string("x").
[cparser] / ast.c
diff --git a/ast.c b/ast.c
index af2a2d3..c62110a 100644 (file)
--- a/ast.c
+++ b/ast.c
 struct obstack ast_obstack;
 
 static int indent;
+static int case_indent;
 
-/** If set, implicit casts are printed. */
 bool print_implicit_casts = false;
-
-/** If set parenthesis are printed to indicate operator precedence. */
 bool print_parenthesis = false;
 
 static void print_statement(const statement_t *statement);
@@ -66,12 +64,7 @@ void change_indent(int delta)
 void print_indent(void)
 {
        for (int i = 0; i < indent; ++i)
-               print_string("\t");
-}
-
-static void print_symbol(const symbol_t *symbol)
-{
-       print_string(symbol->string);
+               print_char('\t');
 }
 
 static void print_stringrep(const string_t *string)
@@ -108,8 +101,6 @@ static int right_to_left(unsigned precedence)
 static unsigned get_expression_precedence(expression_kind_t kind)
 {
        static const unsigned prec[] = {
-               [EXPR_UNKNOWN]                           = PREC_PRIMARY,
-               [EXPR_INVALID]                           = PREC_PRIMARY,
                [EXPR_REFERENCE]                         = PREC_PRIMARY,
                [EXPR_REFERENCE_ENUM_VALUE]              = PREC_PRIMARY,
                [EXPR_LITERAL_INTEGER]                   = PREC_PRIMARY,
@@ -152,7 +143,6 @@ static unsigned get_expression_precedence(expression_kind_t kind)
                [EXPR_UNARY_PREFIX_INCREMENT]            = PREC_UNARY,
                [EXPR_UNARY_PREFIX_DECREMENT]            = PREC_UNARY,
                [EXPR_UNARY_CAST]                        = PREC_UNARY,
-               [EXPR_UNARY_CAST_IMPLICIT]               = PREC_UNARY,
                [EXPR_UNARY_ASSUME]                      = PREC_PRIMARY,
                [EXPR_UNARY_DELETE]                      = PREC_UNARY,
                [EXPR_UNARY_DELETE_ARRAY]                = PREC_UNARY,
@@ -216,9 +206,9 @@ static void print_quoted_string(const string_t *const string, char border,
        print_char(border);
        const char *end = string->begin + string->size - skip;
        for (const char *c = string->begin; c != end; ++c) {
-               unsigned char const tc = *c;
+               const char tc = *c;
                if (tc == border) {
-                       print_string("\\");
+                       print_char('\\');
                }
                switch (tc) {
                case '\\': print_string("\\\\"); break;
@@ -236,7 +226,7 @@ static void print_quoted_string(const string_t *const string, char border,
                        }
                        /* FALLTHROUGH */
                default:
-                       if (tc < 0x80 && !isprint(tc)) {
+                       if ((unsigned)tc < 0x80 && !isprint(tc)) {
                                print_format("\\%03o", (unsigned)tc);
                        } else {
                                print_char(tc);
@@ -270,8 +260,8 @@ static void print_literal(const literal_expression_t *literal)
        case EXPR_LITERAL_INTEGER_OCTAL:
        case EXPR_LITERAL_FLOATINGPOINT:
                print_stringrep(&literal->value);
-               if (literal->suffix != NULL)
-                       print_symbol(literal->suffix);
+               if (literal->suffix.size > 0)
+                       print_stringrep(&literal->suffix);
                return;
        case EXPR_LITERAL_WIDE_CHARACTER:
                print_char('L');
@@ -303,9 +293,9 @@ static void print_funcname(const funcname_expression_t *funcname)
 static void print_compound_literal(
                const compound_literal_expression_t *expression)
 {
-       print_string("(");
+       print_char('(');
        print_type(expression->type);
-       print_string(")");
+       print_char(')');
        print_initializer(expression->initializer);
 }
 
@@ -322,7 +312,7 @@ static void print_assignment_expression(const expression_t *const expr)
 static void print_call_expression(const call_expression_t *call)
 {
        print_expression_prec(call->function, PREC_POSTFIX);
-       print_string("(");
+       print_char('(');
        call_argument_t *argument = call->arguments;
        int              first    = 1;
        while (argument != NULL) {
@@ -335,7 +325,7 @@ static void print_call_expression(const call_expression_t *call)
 
                argument = argument->next;
        }
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -397,14 +387,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:           print_string("-"); break;
-       case EXPR_UNARY_PLUS:             print_string("+"); break;
-       case EXPR_UNARY_NOT:              print_string("!"); break;
-       case EXPR_UNARY_BITWISE_NEGATE:   print_string("~"); break;
+       case EXPR_UNARY_NEGATE:           print_char  ('-' ); break;
+       case EXPR_UNARY_PLUS:             print_char  ('+' ); break;
+       case EXPR_UNARY_NOT:              print_char  ('!' ); break;
+       case EXPR_UNARY_BITWISE_NEGATE:   print_char  ('~' ); break;
        case EXPR_UNARY_PREFIX_INCREMENT: print_string("++"); break;
        case EXPR_UNARY_PREFIX_DECREMENT: print_string("--"); break;
-       case EXPR_UNARY_DEREFERENCE:      print_string("*"); break;
-       case EXPR_UNARY_TAKE_ADDRESS:     print_string("&"); break;
+       case EXPR_UNARY_DEREFERENCE:      print_char  ('*' ); break;
+       case EXPR_UNARY_TAKE_ADDRESS:     print_char  ('&' ); break;
        case EXPR_UNARY_DELETE:           print_string("delete "); break;
        case EXPR_UNARY_DELETE_ARRAY:     print_string("delete [] "); break;
 
@@ -416,16 +406,15 @@ static void print_unary_expression(const unary_expression_t *unexpr)
                print_expression_prec(unexpr->value, prec);
                print_string("--");
                return;
-       case EXPR_UNARY_CAST_IMPLICIT:
        case EXPR_UNARY_CAST:
-               print_string("(");
+               print_char('(');
                print_type(unexpr->base.type);
-               print_string(")");
+               print_char(')');
                break;
        case EXPR_UNARY_ASSUME:
                print_string("__assume(");
                print_assignment_expression(unexpr->value);
-               print_string(")");
+               print_char(')');
                return;
 
        case EXPR_UNARY_THROW:
@@ -471,14 +460,14 @@ static void print_array_expression(const array_access_expression_t *expression)
 {
        if (!expression->flipped) {
                print_expression_prec(expression->array_ref, PREC_POSTFIX);
-               print_string("[");
+               print_char('[');
                print_expression(expression->index);
-               print_string("]");
+               print_char(']');
        } else {
                print_expression_prec(expression->index, PREC_POSTFIX);
-               print_string("[");
+               print_char('[');
                print_expression(expression->array_ref);
-               print_string("]");
+               print_char(']');
        }
 }
 
@@ -499,9 +488,9 @@ static void print_typeprop_expression(const typeprop_expression_t *expression)
                /* PREC_TOP: always print the '()' here, sizeof x is right but unusual */
                print_expression_prec(expression->tp_expression, PREC_TOP);
        } else {
-               print_string("(");
+               print_char('(');
                print_type(expression->type);
-               print_string(")");
+               print_char(')');
        }
 }
 
@@ -514,7 +503,7 @@ static void print_builtin_constant(const builtin_constant_expression_t *expressi
 {
        print_string("__builtin_constant_p(");
        print_assignment_expression(expression->value);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -529,7 +518,7 @@ static void print_builtin_types_compatible(
        print_type(expression->left);
        print_string(", ");
        print_type(expression->right);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -562,7 +551,7 @@ static void print_va_start(const va_start_expression_t *const expression)
        print_assignment_expression(expression->ap);
        print_string(", ");
        print_string(expression->parameter->base.base.symbol->string);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -576,7 +565,7 @@ static void print_va_arg(const va_arg_expression_t *expression)
        print_assignment_expression(expression->ap);
        print_string(", ");
        print_type(expression->base.type);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -590,7 +579,7 @@ static void print_va_copy(const va_copy_expression_t *expression)
        print_assignment_expression(expression->dst);
        print_string(", ");
        print_assignment_expression(expression->src);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -601,10 +590,16 @@ static void print_va_copy(const va_copy_expression_t *expression)
 static void print_select(const select_expression_t *expression)
 {
        print_expression_prec(expression->compound, PREC_POSTFIX);
+       /* do not print anything for anonymous struct/union selects
+        * FIXME: if the anonymous select was a '->' this will print '.'
+        */
+       if (expression->compound_entry->base.symbol == NULL)
+               return;
+
        if (is_type_pointer(skip_typeref(expression->compound->base.type))) {
                print_string("->");
        } else {
-               print_string(".");
+               print_char('.');
        }
        print_string(expression->compound_entry->base.symbol->string);
 }
@@ -619,7 +614,7 @@ static void print_classify_type_expression(
 {
        print_string("__builtin_classify_type(");
        print_assignment_expression(expr->type_expression);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -631,11 +626,11 @@ static void print_designator(const designator_t *designator)
 {
        for ( ; designator != NULL; designator = designator->next) {
                if (designator->symbol == NULL) {
-                       print_string("[");
+                       print_char('[');
                        print_expression(designator->array_index);
-                       print_string("]");
+                       print_char(']');
                } else {
-                       print_string(".");
+                       print_char('.');
                        print_string(designator->symbol->string);
                }
        }
@@ -650,9 +645,9 @@ static void print_offsetof_expression(const offsetof_expression_t *expression)
 {
        print_string("__builtin_offsetof(");
        print_type(expression->type);
-       print_string(",");
+       print_char(',');
        print_designator(expression->designator);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -662,9 +657,9 @@ static void print_offsetof_expression(const offsetof_expression_t *expression)
  */
 static void print_statement_expression(const statement_expression_t *expression)
 {
-       print_string("(");
+       print_char('(');
        print_statement(expression->statement);
-       print_string(")");
+       print_char(')');
 }
 
 /**
@@ -675,7 +670,8 @@ 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) {
+       if (expression->kind == EXPR_UNARY_CAST
+           && expression->base.implicit && !print_implicit_casts) {
                expression = expression->unary.value;
        }
 
@@ -685,11 +681,10 @@ static void print_expression_prec(const expression_t *expression, unsigned top_p
                top_prec > get_expression_precedence(expression->base.kind);
 
        if (parenthesized)
-               print_string("(");
+               print_char('(');
        switch (expression->kind) {
-       case EXPR_UNKNOWN:
-       case EXPR_INVALID:
-               print_string("$invalid expression$");
+       case EXPR_ERROR:
+               print_string("$error$");
                break;
        case EXPR_WIDE_STRING_LITERAL:
        case EXPR_STRING_LITERAL:
@@ -757,16 +752,27 @@ static void print_expression_prec(const expression_t *expression, unsigned top_p
        case EXPR_STATEMENT:
                print_statement_expression(&expression->statement);
                break;
+       }
+       if (parenthesized)
+               print_char(')');
+}
+
+static void print_indented_statement(statement_t const *const stmt)
+{
+       switch (stmt->kind) {
+       case STATEMENT_LABEL:
+               break;
+
+       case STATEMENT_CASE_LABEL:
+               for (int i = 0; i != case_indent; ++i)
+                       print_char('\t');
+               break;
 
-#if 0
        default:
-               /* TODO */
-               print_format("some expression of type %d", (int)expression->kind);
+               print_indent();
                break;
-#endif
        }
-       if (parenthesized)
-               print_string(")");
+       print_statement(stmt);
 }
 
 /**
@@ -781,17 +787,14 @@ static void print_compound_statement(const compound_statement_t *block)
 
        statement_t *statement = block->statements;
        while (statement != NULL) {
-               if (statement->base.kind == STATEMENT_CASE_LABEL)
-                       --indent;
-               if (statement->kind != STATEMENT_LABEL)
-                       print_indent();
-               print_statement(statement);
+               print_indented_statement(statement);
+               print_char('\n');
 
                statement = statement->base.next;
        }
        --indent;
        print_indent();
-       print_string(block->stmt_expr ? "}" : "}\n");
+       print_char('}');
 }
 
 /**
@@ -805,9 +808,9 @@ static void print_return_statement(const return_statement_t *statement)
        if (val != NULL) {
                print_string("return ");
                print_expression(val);
-               print_string(";\n");
+               print_char(';');
        } else {
-               print_string("return;\n");
+               print_string("return;");
        }
 }
 
@@ -819,7 +822,7 @@ static void print_return_statement(const return_statement_t *statement)
 static void print_expression_statement(const expression_statement_t *statement)
 {
        print_expression(statement->expression);
-       print_string(";\n");
+       print_char(';');
 }
 
 /**
@@ -831,12 +834,12 @@ static void print_goto_statement(const goto_statement_t *statement)
 {
        print_string("goto ");
        if (statement->expression != NULL) {
-               print_string("*");
+               print_char('*');
                print_expression(statement->expression);
        } else {
                print_string(statement->label->base.symbol->string);
        }
-       print_string(";\n");
+       print_char(';');
 }
 
 /**
@@ -847,8 +850,30 @@ static void print_goto_statement(const goto_statement_t *statement)
 static void print_label_statement(const label_statement_t *statement)
 {
        print_format("%s:\n", statement->label->base.symbol->string);
-       print_indent();
-       print_statement(statement->statement);
+       print_indented_statement(statement->statement);
+}
+
+static void print_inner_statement(statement_t const *const stmt)
+{
+       if (stmt->kind == STATEMENT_COMPOUND) {
+               print_char(' ');
+               print_compound_statement(&stmt->compound);
+       } else {
+               print_char('\n');
+               ++indent;
+               print_indented_statement(stmt);
+               --indent;
+       }
+}
+
+static void print_after_inner_statement(statement_t const *const stmt)
+{
+       if (stmt->kind == STATEMENT_COMPOUND) {
+               print_char(' ');
+       } else {
+               print_char('\n');
+               print_indent();
+       }
 }
 
 /**
@@ -860,13 +885,19 @@ static void print_if_statement(const if_statement_t *statement)
 {
        print_string("if (");
        print_expression(statement->condition);
-       print_string(") ");
-       print_statement(statement->true_statement);
-
-       if (statement->false_statement != NULL) {
-               print_indent();
-               print_string("else ");
-               print_statement(statement->false_statement);
+       print_char(')');
+       print_inner_statement(statement->true_statement);
+
+       statement_t const *const f = statement->false_statement;
+       if (f) {
+               print_after_inner_statement(statement->true_statement);
+               print_string("else");
+               if (f->kind == STATEMENT_IF) {
+                       print_char(' ');
+                       print_if_statement(&f->ifs);
+               } else {
+                       print_inner_statement(f);
+               }
        }
 }
 
@@ -877,10 +908,15 @@ static void print_if_statement(const if_statement_t *statement)
  */
 static void print_switch_statement(const switch_statement_t *statement)
 {
+       int const old_case_indent = case_indent;
+       case_indent = indent;
+
        print_string("switch (");
        print_expression(statement->expression);
-       print_string(") ");
-       print_statement(statement->body);
+       print_char(')');
+       print_inner_statement(statement->body);
+
+       case_indent = old_case_indent;
 }
 
 /**
@@ -901,21 +937,14 @@ static void print_case_label(const case_label_statement_t *statement)
                }
                print_string(":\n");
        }
-       ++indent;
-       if (statement->statement != NULL) {
-               if (statement->statement->base.kind == STATEMENT_CASE_LABEL) {
-                       --indent;
-               }
-               print_indent();
-               print_statement(statement->statement);
-       }
+       print_indented_statement(statement->statement);
 }
 
 static void print_typedef(const entity_t *entity)
 {
        print_string("typedef ");
        print_type_ext(entity->typedefe.type, entity->base.symbol, NULL);
-       print_string(";");
+       print_char(';');
 }
 
 /**
@@ -944,7 +973,7 @@ static void print_declaration_statement(
        bool first = true;
        entity_t *entity = statement->declarations_begin;
        if (entity == NULL) {
-               print_string("/* empty declaration statement */\n");
+               print_string("/* empty declaration statement */");
                return;
        }
 
@@ -956,13 +985,13 @@ static void print_declaration_statement(
                        continue;
 
                if (!first) {
+                       print_char('\n');
                        print_indent();
                } else {
                        first = false;
                }
 
                print_entity(entity);
-               print_string("\n");
        }
 }
 
@@ -975,8 +1004,8 @@ static void print_while_statement(const while_statement_t *statement)
 {
        print_string("while (");
        print_expression(statement->condition);
-       print_string(") ");
-       print_statement(statement->body);
+       print_char(')');
+       print_inner_statement(statement->body);
 }
 
 /**
@@ -986,12 +1015,12 @@ static void print_while_statement(const while_statement_t *statement)
  */
 static void print_do_while_statement(const do_while_statement_t *statement)
 {
-       print_string("do ");
-       print_statement(statement->body);
-       print_indent();
+       print_string("do");
+       print_inner_statement(statement->body);
+       print_after_inner_statement(statement->body);
        print_string("while (");
        print_expression(statement->condition);
-       print_string(");\n");
+       print_string(");");
 }
 
 /**
@@ -1004,7 +1033,7 @@ static void print_for_statement(const for_statement_t *statement)
        print_string("for (");
        if (statement->initialisation != NULL) {
                print_expression(statement->initialisation);
-               print_string(";");
+               print_char(';');
        } else {
                entity_t const *entity = statement->scope.entities;
                for (; entity != NULL; entity = entity->base.next) {
@@ -1015,16 +1044,16 @@ static void print_for_statement(const for_statement_t *statement)
                }
        }
        if (statement->condition != NULL) {
-               print_string(" ");
+               print_char(' ');
                print_expression(statement->condition);
        }
-       print_string(";");
+       print_char(';');
        if (statement->step != NULL) {
-               print_string(" ");
+               print_char(' ');
                print_expression(statement->step);
        }
-       print_string(") ");
-       print_statement(statement->body);
+       print_char(')');
+       print_inner_statement(statement->body);
 }
 
 /**
@@ -1045,7 +1074,7 @@ static void print_asm_arguments(asm_argument_t *arguments)
                print_quoted_string(&argument->constraints, '"', 1);
                print_string(" (");
                print_expression(argument->expression);
-               print_string(")");
+               print_char(')');
        }
 }
 
@@ -1076,7 +1105,7 @@ static void print_asm_statement(const asm_statement_t *statement)
        if (statement->is_volatile) {
                print_string("volatile ");
        }
-       print_string("(");
+       print_char('(');
        print_quoted_string(&statement->asm_text, '"', 1);
        if (statement->outputs  == NULL &&
            statement->inputs   == NULL &&
@@ -1097,7 +1126,7 @@ static void print_asm_statement(const asm_statement_t *statement)
        print_asm_clobbers(statement->clobbers);
 
 end_of_print_asm_statement:
-       print_string(");\n");
+       print_string(");");
 }
 
 /**
@@ -1107,17 +1136,17 @@ end_of_print_asm_statement:
  */
 static void print_ms_try_statement(const ms_try_statement_t *statement)
 {
-       print_string("__try ");
-       print_statement(statement->try_statement);
-       print_indent();
+       print_string("__try");
+       print_inner_statement(statement->try_statement);
+       print_after_inner_statement(statement->try_statement);
        if (statement->except_expression != NULL) {
                print_string("__except(");
                print_expression(statement->except_expression);
-               print_string(") ");
+               print_char(')');
        } else {
-               print_string("__finally ");
+               print_string("__finally");
        }
-       print_statement(statement->final_statement);
+       print_inner_statement(statement->final_statement);
 }
 
 /**
@@ -1128,7 +1157,7 @@ static void print_ms_try_statement(const ms_try_statement_t *statement)
 static void print_leave_statement(const leave_statement_t *statement)
 {
        (void)statement;
-       print_string("__leave;\n");
+       print_string("__leave;");
 }
 
 /**
@@ -1140,7 +1169,7 @@ void print_statement(const statement_t *statement)
 {
        switch (statement->kind) {
        case STATEMENT_EMPTY:
-               print_string(";\n");
+               print_char(';');
                break;
        case STATEMENT_COMPOUND:
                print_compound_statement(&statement->compound);
@@ -1158,10 +1187,10 @@ void print_statement(const statement_t *statement)
                print_goto_statement(&statement->gotos);
                break;
        case STATEMENT_CONTINUE:
-               print_string("continue;\n");
+               print_string("continue;");
                break;
        case STATEMENT_BREAK:
-               print_string("break;\n");
+               print_string("break;");
                break;
        case STATEMENT_IF:
                print_if_statement(&statement->ifs);
@@ -1193,8 +1222,8 @@ void print_statement(const statement_t *statement)
        case STATEMENT_LEAVE:
                print_leave_statement(&statement->leave);
                break;
-       case STATEMENT_INVALID:
-               print_string("$invalid statement$\n");
+       case STATEMENT_ERROR:
+               print_string("$error statement$");
                break;
        }
 }
@@ -1303,7 +1332,7 @@ static void print_ms_modifiers(const declaration_t *declaration)
                                }
                                if (variable->put_property_sym != NULL)
                                        print_format("%sput=%s", comma, variable->put_property_sym->string);
-                               print_string(")");
+                               print_char(')');
                        }
                }
        }
@@ -1366,7 +1395,7 @@ static void print_scope(const scope_t *scope)
        for ( ; entity != NULL; entity = entity->base.next) {
                print_indent();
                print_entity(entity);
-               print_string("\n");
+               print_char('\n');
        }
 }
 
@@ -1375,7 +1404,7 @@ static void print_namespace(const namespace_t *namespace)
        print_string("namespace ");
        if (namespace->base.symbol != NULL) {
                print_string(namespace->base.symbol->string);
-               print_string(" ");
+               print_char(' ');
        }
 
        print_string("{\n");
@@ -1416,9 +1445,9 @@ void print_declaration(const entity_t *entity)
                                        &entity->function.parameters);
 
                        if (entity->function.statement != NULL) {
-                               print_string("\n");
-                               print_indent();
-                               print_statement(entity->function.statement);
+                               print_char('\n');
+                               print_indented_statement(entity->function.statement);
+                               print_char('\n');
                                return;
                        }
                        break;
@@ -1433,11 +1462,18 @@ void print_declaration(const entity_t *entity)
                        }
                        break;
 
+               case ENTITY_COMPOUND_MEMBER:
+                       print_type_ext(declaration->type, declaration->base.symbol, NULL);
+                       if (entity->compound_member.bitfield) {
+                               print_format(" : %u", entity->compound_member.bit_size);
+                       }
+                       break;
+
                default:
                        print_type_ext(declaration->type, declaration->base.symbol, NULL);
                        break;
        }
-       print_string(";");
+       print_char(';');
 }
 
 /**
@@ -1478,28 +1514,23 @@ void print_entity(const entity_t *entity)
                return;
        case ENTITY_STRUCT:
                print_string("struct ");
-               print_string(entity->base.symbol->string);
-               if (entity->structe.complete) {
-                       print_string(" ");
-                       print_compound_definition(&entity->structe);
-               }
-               print_string(";");
-               return;
+               goto print_compound;
        case ENTITY_UNION:
                print_string("union ");
+print_compound:
                print_string(entity->base.symbol->string);
-               if (entity->unione.complete) {
-                       print_string(" ");
-                       print_compound_definition(&entity->unione);
+               if (entity->compound.complete) {
+                       print_char(' ');
+                       print_compound_definition(&entity->compound);
                }
-               print_string(";");
+               print_char(';');
                return;
        case ENTITY_ENUM:
                print_string("enum ");
                print_string(entity->base.symbol->string);
-               print_string(" ");
+               print_char(' ');
                print_enum_definition(&entity->enume);
-               print_string(";");
+               print_char(';');
                return;
        case ENTITY_NAMESPACE:
                print_namespace(&entity->namespacee);
@@ -1507,13 +1538,11 @@ void print_entity(const entity_t *entity)
        case ENTITY_LOCAL_LABEL:
                print_string("__label__ ");
                print_string(entity->base.symbol->string);
-               print_string(";");
+               print_char(';');
                return;
        case ENTITY_LABEL:
        case ENTITY_ENUM_VALUE:
                panic("print_entity used on unexpected entity type");
-       case ENTITY_INVALID:
-               break;
        }
        panic("Invalid entity type encountered");
 }
@@ -1537,7 +1566,7 @@ void print_ast(const translation_unit_t *unit)
 
                print_indent();
                print_entity(entity);
-               print_string("\n");
+               print_char('\n');
        }
 }
 
@@ -1550,7 +1579,7 @@ expression_classification_t is_constant_initializer(const initializer_t *initial
                return EXPR_CLASS_CONSTANT;
 
        case INITIALIZER_VALUE:
-               return is_constant_expression(initializer->value.value);
+               return is_linker_constant(initializer->value.value);
 
        case INITIALIZER_LIST: {
                expression_classification_t all = EXPR_CLASS_CONSTANT;
@@ -1567,50 +1596,59 @@ expression_classification_t is_constant_initializer(const initializer_t *initial
        panic("invalid initializer kind found");
 }
 
-static expression_classification_t is_object_with_linker_constant_address(const expression_t *expression)
+/**
+ * Checks if an expression references an object with a constant/known location
+ * to the linker. Example:
+ *  - "x", "*&x" with x being a global variable. The value of x need not be
+ *         constant but the address of x is.
+ *  - "a.b.c" when a has a constant/known location to the linker
+ */
+static expression_classification_t is_object_with_linker_constant_address(
+       const expression_t *expression)
 {
        switch (expression->kind) {
        case EXPR_UNARY_DEREFERENCE:
-               return is_address_constant(expression->unary.value);
+               return is_linker_constant(expression->unary.value);
 
        case EXPR_SELECT: {
                type_t *base_type = skip_typeref(expression->select.compound->base.type);
                if (is_type_pointer(base_type)) {
                        /* it's a -> */
-                       return is_address_constant(expression->select.compound);
+                       return is_linker_constant(expression->select.compound);
                } else {
                        return is_object_with_linker_constant_address(expression->select.compound);
                }
        }
 
        case EXPR_ARRAY_ACCESS: {
-               expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
+               expression_classification_t const ref = is_linker_constant(expression->array_access.array_ref);
                expression_classification_t const idx = is_constant_expression(expression->array_access.index);
                return ref < idx ? ref : idx;
        }
 
        case EXPR_REFERENCE: {
                entity_t *entity = expression->reference.entity;
-               if (is_declaration(entity)) {
-                       switch ((storage_class_tag_t)entity->declaration.storage_class) {
-                       case STORAGE_CLASS_NONE:
-                       case STORAGE_CLASS_EXTERN:
-                       case STORAGE_CLASS_STATIC:
-                               return
-                                       entity->kind != ENTITY_VARIABLE ||
-                                       !entity->variable.thread_local ? EXPR_CLASS_CONSTANT :
-                                       EXPR_CLASS_VARIABLE;
-
-                       case STORAGE_CLASS_REGISTER:
-                       case STORAGE_CLASS_TYPEDEF:
-                       case STORAGE_CLASS_AUTO:
-                               break;
-                       }
+               if (!is_declaration(entity))
+                       return EXPR_CLASS_VARIABLE;
+
+               switch ((storage_class_tag_t)entity->declaration.storage_class) {
+               case STORAGE_CLASS_NONE:
+               case STORAGE_CLASS_EXTERN:
+               case STORAGE_CLASS_STATIC:
+                       return
+                               entity->kind != ENTITY_VARIABLE ||
+                               !entity->variable.thread_local ? EXPR_CLASS_CONSTANT :
+                               EXPR_CLASS_VARIABLE;
+
+               case STORAGE_CLASS_REGISTER:
+               case STORAGE_CLASS_TYPEDEF:
+               case STORAGE_CLASS_AUTO:
+                       break;
                }
                return EXPR_CLASS_VARIABLE;
        }
 
-       case EXPR_INVALID:
+       case EXPR_ERROR:
                return EXPR_CLASS_ERROR;
 
        default:
@@ -1618,7 +1656,7 @@ static expression_classification_t is_object_with_linker_constant_address(const
        }
 }
 
-expression_classification_t is_address_constant(const expression_t *expression)
+expression_classification_t is_linker_constant(const expression_t *expression)
 {
        switch (expression->kind) {
        case EXPR_STRING_LITERAL:
@@ -1627,6 +1665,9 @@ expression_classification_t is_address_constant(const expression_t *expression)
        case EXPR_LABEL_ADDRESS:
                return EXPR_CLASS_CONSTANT;
 
+       case EXPR_COMPOUND_LITERAL:
+               return is_constant_initializer(expression->compound_literal.initializer);
+
        case EXPR_UNARY_TAKE_ADDRESS:
                return is_object_with_linker_constant_address(expression->unary.value);
 
@@ -1635,7 +1676,7 @@ expression_classification_t is_address_constant(const expression_t *expression)
                        = revert_automatic_type_conversion(expression->unary.value);
                /* dereferencing a function is a NOP */
                if (is_type_function(real_type)) {
-                       return is_address_constant(expression->unary.value);
+                       return is_linker_constant(expression->unary.value);
                }
                /* FALLTHROUGH */
        }
@@ -1645,13 +1686,11 @@ expression_classification_t is_address_constant(const expression_t *expression)
                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())
+                               get_atomic_type_size(dest->atomic.akind) < get_type_size(type_void_ptr)
                    ))
-                       return EXPR_CLASS_VARIABLE;
+                       return is_constant_expression(expression);
 
-               expression_classification_t const expr = is_constant_expression(expression->unary.value);
-               expression_classification_t const addr = is_address_constant(expression->unary.value);
-               return expr > addr ? expr : addr;
+               return is_linker_constant(expression->unary.value);
        }
 
        case EXPR_BINARY_ADD:
@@ -1662,17 +1701,17 @@ expression_classification_t is_address_constant(const expression_t *expression)
                type_t       *const rtype = skip_typeref(right->base.type);
 
                if (is_type_pointer(ltype)) {
-                       expression_classification_t const l = is_address_constant(left);
+                       expression_classification_t const l = is_linker_constant(left);
                        expression_classification_t const r = is_constant_expression(right);
                        return l < r ? l : r;
                } else if (is_type_pointer(rtype)) {
                        expression_classification_t const l = is_constant_expression(left);
-                       expression_classification_t const r = is_address_constant(right);
+                       expression_classification_t const r = is_linker_constant(right);
                        return l < r ? l : r;
                } else if (!is_type_valid(ltype) || !is_type_valid(rtype)) {
                        return EXPR_CLASS_ERROR;
                } else {
-                       return EXPR_CLASS_VARIABLE;
+                       return is_constant_expression(expression);
                }
        }
 
@@ -1698,9 +1737,7 @@ expression_classification_t is_address_constant(const expression_t *expression)
                        skip_typeref(revert_automatic_type_conversion(expression));
                if (!is_type_array(type))
                        return EXPR_CLASS_VARIABLE;
-               expression_classification_t const ref = is_address_constant(expression->array_access.array_ref);
-               expression_classification_t const idx = is_constant_expression(expression->array_access.index);
-               return ref < idx ? ref : idx;
+               return is_linker_constant(expression->array_access.array_ref);
        }
 
        case EXPR_CONDITIONAL: {
@@ -1711,17 +1748,33 @@ expression_classification_t is_address_constant(const expression_t *expression)
 
                if (fold_constant_to_bool(c)) {
                        expression_t const *const t = expression->conditional.true_expression;
-                       return is_address_constant(t != NULL ? t : c);
+                       return is_linker_constant(t != NULL ? t : c);
                } else {
-                       return is_address_constant(expression->conditional.false_expression);
+                       return is_linker_constant(expression->conditional.false_expression);
                }
        }
 
-       case EXPR_INVALID:
-               return EXPR_CLASS_ERROR;
+       case EXPR_SELECT: {
+               entity_t *entity = expression->select.compound_entry;
+               if (!is_declaration(entity))
+                       return EXPR_CLASS_VARIABLE;
+               type_t *type = skip_typeref(entity->declaration.type);
+               if (is_type_array(type)) {
+                       /* arrays automatically convert to their address */
+                       expression_t *compound  = expression->select.compound;
+                       type_t       *base_type = skip_typeref(compound->base.type);
+                       if (is_type_pointer(base_type)) {
+                               /* it's a -> */
+                               return is_linker_constant(compound);
+                       } else {
+                               return is_object_with_linker_constant_address(compound);
+                       }
+               }
+               return EXPR_CLASS_VARIABLE;
+       }
 
        default:
-               return EXPR_CLASS_VARIABLE;
+               return is_constant_expression(expression);
        }
 }
 
@@ -1739,15 +1792,8 @@ static expression_classification_t is_builtin_const_call(const expression_t *exp
                return EXPR_CLASS_VARIABLE;
 
        switch (ref->entity->function.btk) {
-       case bk_gnu_builtin_huge_val:
-       case bk_gnu_builtin_huge_valf:
-       case bk_gnu_builtin_huge_vall:
-       case bk_gnu_builtin_inf:
-       case bk_gnu_builtin_inff:
-       case bk_gnu_builtin_infl:
-       case bk_gnu_builtin_nan:
-       case bk_gnu_builtin_nanf:
-       case bk_gnu_builtin_nanl:
+       case BUILTIN_INF:
+       case BUILTIN_NAN:
                return EXPR_CLASS_CONSTANT;
        default:
                return EXPR_CLASS_VARIABLE;
@@ -1797,7 +1843,7 @@ static expression_classification_t is_object_with_constant_address(const express
        case EXPR_UNARY_DEREFERENCE:
                return is_constant_pointer(expression->unary.value);
 
-       case EXPR_INVALID:
+       case EXPR_ERROR:
                return EXPR_CLASS_ERROR;
 
        default:
@@ -1874,8 +1920,7 @@ expression_classification_t is_constant_expression(const expression_t *expressio
        case EXPR_UNARY_NOT:
                return is_constant_expression(expression->unary.value);
 
-       case EXPR_UNARY_CAST:
-       case EXPR_UNARY_CAST_IMPLICIT: {
+       case EXPR_UNARY_CAST: {
                type_t *const type = skip_typeref(expression->base.type);
                if (is_type_scalar(type))
                        return is_constant_expression(expression->unary.value);
@@ -1948,39 +1993,18 @@ expression_classification_t is_constant_expression(const expression_t *expressio
                }
        }
 
-       case EXPR_INVALID:
+       case EXPR_ERROR:
                return EXPR_CLASS_ERROR;
-
-       case EXPR_UNKNOWN:
-               break;
        }
        panic("invalid expression found (is constant expression)");
 }
 
-/**
- * Initialize the AST construction.
- */
 void init_ast(void)
 {
        obstack_init(&ast_obstack);
 }
 
-/**
- * Free the AST.
- */
 void exit_ast(void)
 {
        obstack_free(&ast_obstack, NULL);
 }
-
-/**
- * Allocate an AST object of the given size.
- *
- * @param size  the size of the object to allocate
- *
- * @return  A new allocated object in the AST memeory space.
- */
-void *(allocate_ast)(size_t size)
-{
-       return _allocate_ast(size);
-}