+ static const unsigned prec[] = {
+ [EXPR_UNKNOWN] = PREC_PRIMARY,
+ [EXPR_INVALID] = PREC_PRIMARY,
+ [EXPR_REFERENCE] = PREC_PRIMARY,
+ [EXPR_REFERENCE_ENUM_VALUE] = PREC_PRIMARY,
+ [EXPR_CHARACTER_CONSTANT] = PREC_PRIMARY,
+ [EXPR_WIDE_CHARACTER_CONSTANT] = PREC_PRIMARY,
+ [EXPR_CONST] = PREC_PRIMARY,
+ [EXPR_STRING_LITERAL] = PREC_PRIMARY,
+ [EXPR_WIDE_STRING_LITERAL] = PREC_PRIMARY,
+ [EXPR_COMPOUND_LITERAL] = PREC_UNARY,
+ [EXPR_CALL] = PREC_POSTFIX,
+ [EXPR_CONDITIONAL] = PREC_CONDITIONAL,
+ [EXPR_SELECT] = PREC_POSTFIX,
+ [EXPR_ARRAY_ACCESS] = PREC_POSTFIX,
+ [EXPR_SIZEOF] = PREC_UNARY,
+ [EXPR_CLASSIFY_TYPE] = PREC_UNARY,
+ [EXPR_ALIGNOF] = PREC_UNARY,
+
+ [EXPR_FUNCNAME] = PREC_PRIMARY,
+ [EXPR_BUILTIN_SYMBOL] = PREC_PRIMARY,
+ [EXPR_BUILTIN_CONSTANT_P] = PREC_PRIMARY,
+ [EXPR_BUILTIN_PREFETCH] = PREC_PRIMARY,
+ [EXPR_OFFSETOF] = PREC_PRIMARY,
+ [EXPR_VA_START] = PREC_PRIMARY,
+ [EXPR_VA_ARG] = PREC_PRIMARY,
+ [EXPR_STATEMENT] = PREC_PRIMARY,
+ [EXPR_LABEL_ADDRESS] = PREC_PRIMARY,
+
+ [EXPR_UNARY_NEGATE] = PREC_UNARY,
+ [EXPR_UNARY_PLUS] = PREC_UNARY,
+ [EXPR_UNARY_BITWISE_NEGATE] = PREC_UNARY,
+ [EXPR_UNARY_NOT] = PREC_UNARY,
+ [EXPR_UNARY_DEREFERENCE] = PREC_UNARY,
+ [EXPR_UNARY_TAKE_ADDRESS] = PREC_UNARY,
+ [EXPR_UNARY_POSTFIX_INCREMENT] = PREC_POSTFIX,
+ [EXPR_UNARY_POSTFIX_DECREMENT] = PREC_POSTFIX,
+ [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,
+ [EXPR_UNARY_THROW] = PREC_ASSIGNMENT,
+
+ [EXPR_BINARY_ADD] = PREC_ADDITIVE,
+ [EXPR_BINARY_SUB] = PREC_ADDITIVE,
+ [EXPR_BINARY_MUL] = PREC_MULTIPLICATIVE,
+ [EXPR_BINARY_DIV] = PREC_MULTIPLICATIVE,
+ [EXPR_BINARY_MOD] = PREC_MULTIPLICATIVE,
+ [EXPR_BINARY_EQUAL] = PREC_EQUALITY,
+ [EXPR_BINARY_NOTEQUAL] = PREC_EQUALITY,
+ [EXPR_BINARY_LESS] = PREC_RELATIONAL,
+ [EXPR_BINARY_LESSEQUAL] = PREC_RELATIONAL,
+ [EXPR_BINARY_GREATER] = PREC_RELATIONAL,
+ [EXPR_BINARY_GREATEREQUAL] = PREC_RELATIONAL,
+ [EXPR_BINARY_BITWISE_AND] = PREC_AND,
+ [EXPR_BINARY_BITWISE_OR] = PREC_OR,
+ [EXPR_BINARY_BITWISE_XOR] = PREC_XOR,
+ [EXPR_BINARY_LOGICAL_AND] = PREC_LOGICAL_AND,
+ [EXPR_BINARY_LOGICAL_OR] = PREC_LOGICAL_OR,
+ [EXPR_BINARY_SHIFTLEFT] = PREC_SHIFT,
+ [EXPR_BINARY_SHIFTRIGHT] = PREC_SHIFT,
+ [EXPR_BINARY_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_MUL_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_DIV_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_MOD_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_ADD_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_SUB_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_SHIFTLEFT_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_SHIFTRIGHT_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_BITWISE_AND_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_BITWISE_XOR_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_BITWISE_OR_ASSIGN] = PREC_ASSIGNMENT,
+ [EXPR_BINARY_COMMA] = PREC_EXPRESSION,
+
+ [EXPR_BINARY_ISGREATER] = PREC_PRIMARY,
+ [EXPR_BINARY_ISGREATEREQUAL] = PREC_PRIMARY,
+ [EXPR_BINARY_ISLESS] = PREC_PRIMARY,
+ [EXPR_BINARY_ISLESSEQUAL] = PREC_PRIMARY,
+ [EXPR_BINARY_ISLESSGREATER] = PREC_PRIMARY,
+ [EXPR_BINARY_ISUNORDERED] = PREC_PRIMARY
+ };
+ assert((unsigned)kind < (sizeof(prec)/sizeof(prec[0])));
+ unsigned res = prec[kind];
+
+ assert(res != PREC_BOTTOM);
+ return res;
+}
+
+/**
+ * Print a constant expression.
+ *
+ * @param cnst the constant expression
+ */
+static void print_const(const const_expression_t *cnst)
+{
+ 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) {