+ if (cnst->base.type == NULL)
+ return;
+
+ const type_t *const type = skip_typeref(cnst->base.type);
+
+ if (is_type_atomic(type, ATOMIC_TYPE_BOOL)) {
+ fputs(cnst->v.int_value ? "true" : "false", out);
+ } else if (is_type_integer(type)) {
+ fprintf(out, "%lld", cnst->v.int_value);
+ } else if (is_type_float(type)) {
+ 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: return;
+ }
+ fputs(suffix, out);
+}
+
+/**
+ * Print a quoted string constant.
+ *
+ * @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, int skip)
+{
+ fputc(border, out);
+ const char *end = string->begin + string->size - skip;
+ for (const char *c = string->begin; c != end; ++c) {
+ unsigned char const tc = *c;
+ if (tc == border) {
+ fputc('\\', out);
+ }
+ switch (tc) {
+ case '\\': fputs("\\\\", out); break;
+ case '\a': fputs("\\a", out); break;
+ case '\b': fputs("\\b", out); break;
+ case '\f': fputs("\\f", out); break;
+ case '\n': fputs("\\n", out); break;
+ case '\r': fputs("\\r", out); break;
+ 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 (tc < 0x80 && !isprint(tc)) {
+ fprintf(out, "\\%03o", (unsigned)tc);
+ } else {
+ fputc(tc, out);
+ }
+ break;
+ }
+ }
+ fputc(border, out);
+}
+
+/**
+ * Prints a 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, int skip)
+{
+ fputc('L', out);
+ fputc(border, out);
+ 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;
+ case L'\a': fputs("\\a", out); break;
+ case L'\b': fputs("\\b", out); break;
+ case L'\f': fputs("\\f", out); break;
+ case L'\n': fputs("\\n", out); break;
+ case L'\r': fputs("\\r", out); break;
+ 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) {
+ if (isprint(*c)) {
+ fputc(*c, out);
+ } else {
+ fprintf(out, "\\%03o", tc);
+ }
+ } else if (tc < 0x800) {
+ fputc(0xC0 | (tc >> 6), out);
+ fputc(0x80 | (tc & 0x3F), out);
+ } else if (tc < 0x10000) {
+ fputc(0xE0 | ( tc >> 12), out);
+ fputc(0x80 | ((tc >> 6) & 0x3F), out);
+ fputc(0x80 | ( tc & 0x3F), out);
+ } else {
+ fputc(0xF0 | ( tc >> 18), out);
+ fputc(0x80 | ((tc >> 12) & 0x3F), out);
+ fputc(0x80 | ((tc >> 6) & 0x3F), out);
+ fputc(0x80 | ( tc & 0x3F), out);
+ }
+ }
+ }
+ }
+ fputc(border, out);
+}
+
+/**
+ * Print a constant character expression.
+ *
+ * @param cnst the constant character expression
+ */
+static void print_character_constant(const const_expression_t *cnst)
+{
+ 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, '\'', 0);
+}
+
+/**
+ * Prints a string literal expression.
+ *
+ * @param string_literal the string literal expression
+ */
+static void print_string_literal(
+ const string_literal_expression_t *string_literal)
+{
+ print_quoted_string(&string_literal->value, '"', 1);
+}
+
+/**
+ * Prints a predefined symbol.
+ */
+static void print_funcname(const funcname_expression_t *funcname)
+{
+ const char *s = "";
+ switch (funcname->kind) {
+ case FUNCNAME_FUNCTION: s = (c_mode & _C99) ? "__func__" : "__FUNCTION__"; break;
+ case FUNCNAME_PRETTY_FUNCTION: s = "__PRETTY_FUNCTION__"; break;
+ case FUNCNAME_FUNCSIG: s = "__FUNCSIG__"; break;
+ case FUNCNAME_FUNCDNAME: s = "__FUNCDNAME__"; break;
+ }
+ fputs(s, out);
+}
+
+static void print_wide_string_literal(
+ const wide_string_literal_expression_t *const wstr)
+{
+ print_quoted_wide_string(&wstr->value, '"', 1);
+}
+
+static void print_compound_literal(
+ const compound_literal_expression_t *expression)
+{
+ fputc('(', out);
+ print_type(expression->type);
+ fputc(')', out);
+ print_initializer(expression->initializer);
+}
+
+static void print_assignment_expression(const expression_t *const expr)
+{
+ print_expression_prec(expr, PREC_ASSIGNMENT);
+}
+
+/**
+ * Prints a call expression.
+ *
+ * @param call the call expression
+ */
+static void print_call_expression(const call_expression_t *call)
+{
+ print_expression_prec(call->function, PREC_POSTFIX);
+ fputc('(', out);