+
+ default:
+ panic("invalid unary expression found");
+ }
+ print_expression_prec(unexpr->value, prec);
+}
+
+/**
+ * Prints a reference expression.
+ *
+ * @param ref the reference expression
+ */
+static void print_reference_expression(const reference_expression_t *ref)
+{
+ print_string(ref->entity->base.symbol->string);
+}
+
+/**
+ * Prints a label address expression.
+ *
+ * @param ref the reference expression
+ */
+static void print_label_address_expression(const label_address_expression_t *le)
+{
+ print_format("&&%s", le->label->base.symbol->string);
+}
+
+/**
+ * Prints an array expression.
+ *
+ * @param expression the array expression
+ */
+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_expression(expression->index);
+ print_string("]");
+ } else {
+ print_expression_prec(expression->index, PREC_POSTFIX);
+ print_string("[");
+ print_expression(expression->array_ref);
+ print_string("]");
+ }
+}
+
+/**
+ * Prints a typeproperty expression (sizeof or __alignof__).
+ *
+ * @param expression the type property expression
+ */
+static void print_typeprop_expression(const typeprop_expression_t *expression)
+{
+ if (expression->base.kind == EXPR_SIZEOF) {
+ print_string("sizeof");
+ } else {
+ assert(expression->base.kind == EXPR_ALIGNOF);
+ print_string("__alignof__");
+ }
+ if (expression->tp_expression != NULL) {
+ /* PREC_TOP: always print the '()' here, sizeof x is right but unusual */
+ print_expression_prec(expression->tp_expression, PREC_TOP);
+ } else {
+ print_string("(");
+ print_type(expression->type);
+ print_string(")");
+ }
+}
+
+/**
+ * Prints a builtin constant expression.
+ *
+ * @param expression the builtin constant expression
+ */
+static void print_builtin_constant(const builtin_constant_expression_t *expression)
+{
+ print_string("__builtin_constant_p(");
+ print_assignment_expression(expression->value);
+ print_string(")");
+}
+
+/**
+ * Prints a builtin types compatible expression.
+ *
+ * @param expression the builtin types compatible expression
+ */
+static void print_builtin_types_compatible(
+ const builtin_types_compatible_expression_t *expression)
+{
+ print_string("__builtin_types_compatible_p(");
+ print_type(expression->left);
+ print_string(", ");
+ print_type(expression->right);
+ print_string(")");
+}
+
+/**
+ * Prints a conditional expression.
+ *
+ * @param expression the conditional expression
+ */
+static void print_conditional(const conditional_expression_t *expression)
+{
+ print_expression_prec(expression->condition, PREC_LOGICAL_OR);
+ if (expression->true_expression != NULL) {
+ print_string(" ? ");
+ print_expression_prec(expression->true_expression, PREC_EXPRESSION);
+ print_string(" : ");
+ } else {
+ print_string(" ?: ");
+ }
+ precedence_t prec = c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL;
+ print_expression_prec(expression->false_expression, prec);
+}
+
+/**
+ * Prints a va_start expression.
+ *
+ * @param expression the va_start expression
+ */
+static void print_va_start(const va_start_expression_t *const expression)
+{
+ print_string("__builtin_va_start(");
+ print_assignment_expression(expression->ap);
+ print_string(", ");
+ print_string(expression->parameter->base.base.symbol->string);
+ print_string(")");
+}
+
+/**
+ * Prints a va_arg expression.
+ *
+ * @param expression the va_arg expression
+ */
+static void print_va_arg(const va_arg_expression_t *expression)
+{
+ print_string("__builtin_va_arg(");
+ print_assignment_expression(expression->ap);
+ print_string(", ");
+ print_type(expression->base.type);
+ print_string(")");
+}
+
+/**
+ * Prints a va_copy expression.
+ *
+ * @param expression the va_copy expression
+ */
+static void print_va_copy(const va_copy_expression_t *expression)
+{
+ print_string("__builtin_va_copy(");
+ print_assignment_expression(expression->dst);
+ print_string(", ");
+ print_assignment_expression(expression->src);
+ print_string(")");
+}
+
+/**
+ * Prints a select expression (. or ->).
+ *
+ * @param expression the select 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_string(expression->compound_entry->base.symbol->string);
+}
+
+/**
+ * Prints a type classify expression.
+ *
+ * @param expr the type classify expression
+ */
+static void print_classify_type_expression(
+ const classify_type_expression_t *const expr)
+{
+ print_string("__builtin_classify_type(");
+ print_assignment_expression(expr->type_expression);
+ print_string(")");
+}
+
+/**
+ * Prints a designator.
+ *
+ * @param designator the designator
+ */
+static void print_designator(const designator_t *designator)
+{
+ for ( ; designator != NULL; designator = designator->next) {
+ if (designator->symbol == NULL) {
+ print_string("[");
+ print_expression(designator->array_index);
+ print_string("]");
+ } else {
+ print_string(".");
+ print_string(designator->symbol->string);
+ }
+ }
+}
+
+/**
+ * Prints an offsetof expression.
+ *
+ * @param expression the offset expression
+ */
+static void print_offsetof_expression(const offsetof_expression_t *expression)
+{
+ print_string("__builtin_offsetof(");
+ print_type(expression->type);
+ print_string(",");
+ print_designator(expression->designator);
+ print_string(")");
+}
+
+/**
+ * Prints a statement expression.
+ *
+ * @param expression the statement expression
+ */
+static void print_statement_expression(const statement_expression_t *expression)
+{
+ print_string("(");
+ print_statement(expression->statement);
+ print_string(")");
+}
+
+/**
+ * Prints an expression with parenthesis if needed.
+ *
+ * @param expression the expression to print
+ * @param top_prec the precedence of the user of this expression.
+ */
+static void print_expression_prec(const expression_t *expression, unsigned top_prec)
+{
+ if (expression->kind == EXPR_UNARY_CAST
+ && expression->base.implicit && !print_implicit_casts) {
+ expression = expression->unary.value;
+ }
+
+ bool parenthesized =
+ expression->base.parenthesized ||
+ (print_parenthesis && top_prec != PREC_BOTTOM) ||
+ top_prec > get_expression_precedence(expression->base.kind);
+
+ if (parenthesized)
+ print_string("(");
+ switch (expression->kind) {
+ case EXPR_ERROR:
+ print_string("$error$");
+ break;
+ case EXPR_WIDE_STRING_LITERAL:
+ case EXPR_STRING_LITERAL:
+ print_string_literal(&expression->string_literal);