+ return;
+ }
+
+ panic("invalid initializer kind found");
+}
+
+/**
+ * Print microsoft extended declaration modifiers.
+ */
+static void print_ms_modifiers(const declaration_t *declaration)
+{
+ if((c_mode & _MS) == 0)
+ return;
+
+ decl_modifiers_t modifiers = declaration->modifiers;
+
+ bool ds_shown = false;
+ const char *next = "(";
+
+ if (declaration->base.kind == ENTITY_VARIABLE) {
+ variable_t *variable = (variable_t*) declaration;
+ if (variable->alignment != 0
+ || variable->get_property_sym != NULL
+ || variable->put_property_sym != NULL) {
+ if (!ds_shown) {
+ fputs("__declspec", out);
+ ds_shown = true;
+ }
+
+ if(variable->alignment != 0) {
+ fputs(next, out); next = ", "; fprintf(out, "align(%u)", variable->alignment);
+ }
+ if(variable->get_property_sym != NULL
+ || variable->put_property_sym != NULL) {
+ char *comma = "";
+ fputs(next, out); next = ", "; fputs("property(", out);
+ if(variable->get_property_sym != NULL) {
+ fprintf(out, "get=%s", variable->get_property_sym->string);
+ comma = ", ";
+ }
+ if(variable->put_property_sym != NULL)
+ fprintf(out, "%sput=%s", comma, variable->put_property_sym->string);
+ fputc(')', out);
+ }
+ }
+ }
+
+ /* DM_FORCEINLINE handled outside. */
+ if ((modifiers & ~DM_FORCEINLINE) != 0) {
+ if (!ds_shown) {
+ fputs("__declspec", out);
+ ds_shown = true;
+ }
+ if(modifiers & DM_DLLIMPORT) {
+ fputs(next, out); next = ", "; fputs("dllimport", out);
+ }
+ if(modifiers & DM_DLLEXPORT) {
+ fputs(next, out); next = ", "; fputs("dllexport", out);
+ }
+ if(modifiers & DM_THREAD) {
+ fputs(next, out); next = ", "; fputs("thread", out);
+ }
+ if(modifiers & DM_NAKED) {
+ fputs(next, out); next = ", "; fputs("naked", out);
+ }
+ if(modifiers & DM_THREAD) {
+ fputs(next, out); next = ", "; fputs("thread", out);
+ }
+ if(modifiers & DM_SELECTANY) {
+ fputs(next, out); next = ", "; fputs("selectany", out);
+ }
+ if(modifiers & DM_NOTHROW) {
+ fputs(next, out); next = ", "; fputs("nothrow", out);
+ }
+ if(modifiers & DM_NORETURN) {
+ fputs(next, out); next = ", "; fputs("noreturn", out);
+ }
+ if(modifiers & DM_NOINLINE) {
+ fputs(next, out); next = ", "; fputs("noinline", out);
+ }
+ if (modifiers & DM_DEPRECATED) {
+ fputs(next, out); next = ", "; fputs("deprecated", out);
+ if(declaration->deprecated_string != NULL)
+ fprintf(out, "(\"%s\")",
+ declaration->deprecated_string);
+ }
+ if(modifiers & DM_RESTRICT) {
+ fputs(next, out); next = ", "; fputs("restrict", out);
+ }
+ if(modifiers & DM_NOALIAS) {
+ fputs(next, out); next = ", "; fputs("noalias", out);
+ }
+ }
+
+ if (ds_shown)
+ fputs(") ", out);
+}
+
+static void print_scope(const scope_t *scope)
+{
+ const entity_t *entity = scope->entities;
+ for ( ; entity != NULL; entity = entity->base.next) {
+ print_indent();
+ print_entity(entity);
+ fputs("\n", out);
+ }
+}
+
+static void print_namespace(const namespace_t *namespace)
+{
+ fputs("namespace ", out);
+ if (namespace->base.symbol != NULL) {
+ fputs(namespace->base.symbol->string, out);
+ fputc(' ', out);
+ }
+
+ fputs("{\n", out);
+ ++indent;
+
+ print_scope(&namespace->members);
+
+ --indent;
+ print_indent();
+ fputs("}\n", out);
+}
+
+/**
+ * Print a variable or function declaration
+ */
+void print_declaration(const entity_t *entity)
+{
+ assert(is_declaration(entity));
+ const declaration_t *declaration = &entity->declaration;
+
+ print_storage_class((storage_class_tag_t) declaration->declared_storage_class);
+ if (entity->kind == ENTITY_FUNCTION) {
+ function_t *function = (function_t*) declaration;
+ if (function->is_inline) {
+ if (declaration->modifiers & DM_FORCEINLINE) {
+ fputs("__forceinline ", out);
+ } else if (declaration->modifiers & DM_MICROSOFT_INLINE) {
+ fputs("__inline ", out);
+ } else {
+ fputs("inline ", out);
+ }
+ }
+ }
+ print_ms_modifiers(declaration);
+ switch (entity->kind) {
+ case ENTITY_FUNCTION:
+ print_type_ext(entity->declaration.type, entity->base.symbol,
+ &entity->function.parameters);
+
+ if (entity->function.statement != NULL) {
+ fputc('\n', out);
+ print_indent();
+ print_statement(entity->function.statement);
+ return;
+ }
+ break;
+
+ case ENTITY_VARIABLE:
+ if (entity->variable.thread_local)
+ fputs("__thread ", out);
+ print_type_ext(declaration->type, declaration->base.symbol, NULL);
+ if (entity->variable.initializer != NULL) {
+ fputs(" = ", out);
+ print_initializer(entity->variable.initializer);
+ }
+ break;
+
+ default:
+ print_type_ext(declaration->type, declaration->base.symbol, NULL);
+ break;
+ }
+ fputc(';', out);
+}
+
+/**
+ * Prints an expression.
+ *
+ * @param expression the expression
+ */
+void print_expression(const expression_t *expression)
+{
+ print_expression_prec(expression, PREC_BOTTOM);
+}
+
+/**
+ * Print a declaration.
+ *
+ * @param declaration the declaration
+ */
+void print_entity(const entity_t *entity)
+{
+ if (entity->base.namespc != NAMESPACE_NORMAL && entity->base.symbol == NULL)
+ return;
+
+ switch ((entity_kind_tag_t) entity->kind) {
+ case ENTITY_VARIABLE:
+ case ENTITY_COMPOUND_MEMBER:
+ print_declaration(entity);
+ return;
+ case ENTITY_FUNCTION:
+ print_declaration(entity);
+ return;
+ case ENTITY_TYPEDEF:
+ print_typedef(entity);
+ return;
+ case ENTITY_STRUCT:
+ fputs("struct ", out);
+ fputs(entity->base.symbol->string, out);
+ if (entity->structe.complete) {
+ fputc(' ', out);
+ print_compound_definition(&entity->structe);
+ }
+ fputc(';', out);
+ return;
+ case ENTITY_UNION:
+ fputs("union ", out);
+ fputs(entity->base.symbol->string, out);
+ if (entity->unione.complete) {
+ fputc(' ', out);
+ print_compound_definition(&entity->unione);
+ }
+ fputc(';', out);
+ return;
+ case ENTITY_ENUM:
+ fputs("enum ", out);
+ fputs(entity->base.symbol->string, out);
+ fputc(' ', out);
+ print_enum_definition(&entity->enume);
+ fputc(';', out);
+ return;
+ case ENTITY_NAMESPACE:
+ print_namespace(&entity->namespacee);
+ return;
+ case ENTITY_LABEL:
+ case ENTITY_ENUM_VALUE:
+ case ENTITY_LOCAL_LABEL:
+ panic("print_entity used on unexpected entity type");
+ case ENTITY_INVALID:
+ break;