+ print_string(")");
+}
+
+/**
+ * Prints a binary expression.
+ *
+ * @param binexpr the binary expression
+ */
+static void print_binary_expression(const binary_expression_t *binexpr)
+{
+ unsigned prec = get_expression_precedence(binexpr->base.kind);
+ int r2l = right_to_left(prec);
+
+ print_expression_prec(binexpr->left, prec + r2l);
+ char const* op;
+ switch (binexpr->base.kind) {
+ case EXPR_BINARY_COMMA: op = ", "; break;
+ case EXPR_BINARY_ASSIGN: op = " = "; break;
+ case EXPR_BINARY_ADD: op = " + "; break;
+ case EXPR_BINARY_SUB: op = " - "; break;
+ case EXPR_BINARY_MUL: op = " * "; break;
+ case EXPR_BINARY_MOD: op = " % "; break;
+ case EXPR_BINARY_DIV: op = " / "; break;
+ case EXPR_BINARY_BITWISE_OR: op = " | "; break;
+ case EXPR_BINARY_BITWISE_AND: op = " & "; break;
+ case EXPR_BINARY_BITWISE_XOR: op = " ^ "; break;
+ case EXPR_BINARY_LOGICAL_OR: op = " || "; break;
+ case EXPR_BINARY_LOGICAL_AND: op = " && "; break;
+ case EXPR_BINARY_NOTEQUAL: op = " != "; break;
+ case EXPR_BINARY_EQUAL: op = " == "; break;
+ case EXPR_BINARY_LESS: op = " < "; break;
+ case EXPR_BINARY_LESSEQUAL: op = " <= "; break;
+ case EXPR_BINARY_GREATER: op = " > "; break;
+ case EXPR_BINARY_GREATEREQUAL: op = " >= "; break;
+ case EXPR_BINARY_SHIFTLEFT: op = " << "; break;
+ case EXPR_BINARY_SHIFTRIGHT: op = " >> "; break;
+
+ case EXPR_BINARY_ADD_ASSIGN: op = " += "; break;
+ case EXPR_BINARY_SUB_ASSIGN: op = " -= "; break;
+ case EXPR_BINARY_MUL_ASSIGN: op = " *= "; break;
+ case EXPR_BINARY_MOD_ASSIGN: op = " %= "; break;
+ case EXPR_BINARY_DIV_ASSIGN: op = " /= "; break;
+ case EXPR_BINARY_BITWISE_OR_ASSIGN: op = " |= "; break;
+ case EXPR_BINARY_BITWISE_AND_ASSIGN: op = " &= "; break;
+ case EXPR_BINARY_BITWISE_XOR_ASSIGN: op = " ^= "; break;
+ case EXPR_BINARY_SHIFTLEFT_ASSIGN: op = " <<= "; break;
+ case EXPR_BINARY_SHIFTRIGHT_ASSIGN: op = " >>= "; break;
+ default: panic("invalid binexpression found");
+ }
+ print_string(op);
+ print_expression_prec(binexpr->right, prec + 1 - r2l);
+}
+
+/**
+ * Prints an unary expression.
+ *
+ * @param unexpr the unary expression
+ */
+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_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_DELETE: print_string("delete "); break;
+ case EXPR_UNARY_DELETE_ARRAY: print_string("delete [] "); break;
+
+ case EXPR_UNARY_POSTFIX_INCREMENT:
+ print_expression_prec(unexpr->value, prec);
+ print_string("++");
+ return;
+ case EXPR_UNARY_POSTFIX_DECREMENT:
+ print_expression_prec(unexpr->value, prec);
+ print_string("--");
+ return;
+ case EXPR_UNARY_CAST:
+ print_string("(");
+ print_type(unexpr->base.type);
+ print_string(")");
+ break;
+ case EXPR_UNARY_ASSUME:
+ print_string("__assume(");
+ print_assignment_expression(unexpr->value);
+ print_string(")");
+ return;
+
+ case EXPR_UNARY_THROW:
+ if (unexpr->value == NULL) {
+ print_string("throw");
+ return;
+ }
+ print_string("throw ");
+ break;
+
+ 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(")");