+ return unary_expression; \
+}
+
+CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_PLUSPLUS,
+ EXPR_UNARY_POSTFIX_INCREMENT,
+ semantic_incdec)
+CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_MINUSMINUS,
+ EXPR_UNARY_POSTFIX_DECREMENT,
+ semantic_incdec)
+
+static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
+{
+ /* TODO: handle complex + imaginary types */
+
+ /* § 6.3.1.8 Usual arithmetic conversions */
+ if(type_left == type_long_double || type_right == type_long_double) {
+ return type_long_double;
+ } else if(type_left == type_double || type_right == type_double) {
+ return type_double;
+ } else if(type_left == type_float || type_right == type_float) {
+ return type_float;
+ }
+
+ type_right = promote_integer(type_right);
+ type_left = promote_integer(type_left);
+
+ if(type_left == type_right)
+ return type_left;
+
+ bool signed_left = is_type_signed(type_left);
+ bool signed_right = is_type_signed(type_right);
+ int rank_left = get_rank(type_left);
+ int rank_right = get_rank(type_right);
+ if(rank_left < rank_right) {
+ if(signed_left == signed_right || !signed_right) {
+ return type_right;
+ } else {
+ return type_left;
+ }
+ } else {
+ if(signed_left == signed_right || !signed_left) {
+ return type_left;
+ } else {
+ return type_right;
+ }
+ }
+}
+
+/**
+ * Check the semantic restrictions for a binary expression.
+ */
+static void semantic_binexpr_arithmetic(binary_expression_t *expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.datatype;
+ type_t *const orig_type_right = right->base.datatype;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+
+ if(!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) {
+ /* TODO: improve error message */
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(HERE, "operation needs arithmetic types");
+ }
+ return;
+ }
+
+ type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+ expression->left = create_implicit_cast(left, arithmetic_type);
+ expression->right = create_implicit_cast(right, arithmetic_type);
+ expression->expression.datatype = arithmetic_type;
+}
+
+static void semantic_shift_op(binary_expression_t *expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.datatype;
+ type_t *const orig_type_right = right->base.datatype;
+ type_t * type_left = skip_typeref(orig_type_left);
+ type_t * type_right = skip_typeref(orig_type_right);
+
+ if(!is_type_integer(type_left) || !is_type_integer(type_right)) {
+ /* TODO: improve error message */
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(HERE, "operation needs integer types");
+ }
+ return;
+ }
+
+ type_left = promote_integer(type_left);
+ type_right = promote_integer(type_right);
+
+ expression->left = create_implicit_cast(left, type_left);
+ expression->right = create_implicit_cast(right, type_right);
+ expression->expression.datatype = type_left;
+}
+
+static void semantic_add(binary_expression_t *expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.datatype;
+ type_t *const orig_type_right = right->base.datatype;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+
+ /* § 5.6.5 */
+ if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+ type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+ expression->left = create_implicit_cast(left, arithmetic_type);
+ expression->right = create_implicit_cast(right, arithmetic_type);
+ expression->expression.datatype = arithmetic_type;
+ return;
+ } else if(is_type_pointer(type_left) && is_type_integer(type_right)) {
+ expression->expression.datatype = type_left;
+ } else if(is_type_pointer(type_right) && is_type_integer(type_left)) {
+ expression->expression.datatype = type_right;
+ } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(HERE, "invalid operands to binary + ('%T', '%T')", orig_type_left, orig_type_right);
+ }
+}
+
+static void semantic_sub(binary_expression_t *expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.datatype;
+ type_t *const orig_type_right = right->base.datatype;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+
+ /* § 5.6.5 */
+ if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+ type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+ expression->left = create_implicit_cast(left, arithmetic_type);
+ expression->right = create_implicit_cast(right, arithmetic_type);
+ expression->expression.datatype = arithmetic_type;
+ return;
+ } else if(is_type_pointer(type_left) && is_type_integer(type_right)) {
+ expression->expression.datatype = type_left;
+ } else if(is_type_pointer(type_left) && is_type_pointer(type_right)) {
+ if(!pointers_compatible(type_left, type_right)) {
+ errorf(HERE, "pointers to incompatible objects to binary '-' ('%T', '%T')", orig_type_left, orig_type_right);
+ } else {
+ expression->expression.datatype = type_ptrdiff_t;
+ }
+ } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(HERE, "invalid operands to binary '-' ('%T', '%T')", orig_type_left, orig_type_right);
+ }
+}
+
+static void semantic_comparison(binary_expression_t *expression)
+{
+ expression_t *left = expression->left;
+ expression_t *right = expression->right;
+ type_t *orig_type_left = left->base.datatype;
+ type_t *orig_type_right = right->base.datatype;
+
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *type_right = skip_typeref(orig_type_right);
+
+ /* TODO non-arithmetic types */
+ if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+ type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+ expression->left = create_implicit_cast(left, arithmetic_type);
+ expression->right = create_implicit_cast(right, arithmetic_type);
+ expression->expression.datatype = arithmetic_type;
+ } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
+ /* TODO check compatibility */
+ } else if (is_type_pointer(type_left)) {
+ expression->right = create_implicit_cast(right, type_left);
+ } else if (is_type_pointer(type_right)) {
+ expression->left = create_implicit_cast(left, type_right);
+ } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ type_error_incompatible("invalid operands in comparison",
+ token.source_position, type_left, type_right);
+ }
+ expression->expression.datatype = type_int;
+}
+
+static void semantic_arithmetic_assign(binary_expression_t *expression)
+{
+ expression_t *left = expression->left;
+ expression_t *right = expression->right;
+ type_t *orig_type_left = left->base.datatype;
+ type_t *orig_type_right = right->base.datatype;
+
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *type_right = skip_typeref(orig_type_right);
+
+ if(!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) {
+ /* TODO: improve error message */
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(HERE, "operation needs arithmetic types");
+ }
+ return;
+ }
+
+ /* combined instructions are tricky. We can't create an implicit cast on
+ * the left side, because we need the uncasted form for the store.
+ * The ast2firm pass has to know that left_type must be right_type
+ * for the arithmetic operation and create a cast by itself */
+ type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+ expression->right = create_implicit_cast(right, arithmetic_type);
+ expression->expression.datatype = type_left;
+}
+
+static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.datatype;
+ type_t *const orig_type_right = right->base.datatype;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+
+ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+ /* combined instructions are tricky. We can't create an implicit cast on
+ * the left side, because we need the uncasted form for the store.
+ * The ast2firm pass has to know that left_type must be right_type
+ * for the arithmetic operation and create a cast by itself */
+ type_t *const arithmetic_type = semantic_arithmetic(type_left, type_right);
+ expression->right = create_implicit_cast(right, arithmetic_type);
+ expression->expression.datatype = type_left;
+ } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
+ expression->expression.datatype = type_left;
+ } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(HERE, "incompatible types '%T' and '%T' in assignment", orig_type_left, orig_type_right);
+ }
+}
+
+/**
+ * Check the semantic restrictions of a logical expression.
+ */
+static void semantic_logical_op(binary_expression_t *expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.datatype;
+ type_t *const orig_type_right = right->base.datatype;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+
+ if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
+ /* TODO: improve error message */
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(HERE, "operation needs scalar types");
+ }
+ return;
+ }
+
+ expression->expression.datatype = type_int;
+}
+
+/**
+ * Checks if a compound type has constant fields.
+ */
+static bool has_const_fields(const compound_type_t *type)
+{
+ const context_t *context = &type->declaration->context;
+ const declaration_t *declaration = context->declarations;
+
+ for (; declaration != NULL; declaration = declaration->next) {
+ if (declaration->namespc != NAMESPACE_NORMAL)
+ continue;
+
+ const type_t *decl_type = skip_typeref(declaration->type);
+ if (decl_type->base.qualifiers & TYPE_QUALIFIER_CONST)
+ return true;
+ }
+ /* TODO */
+ return false;
+}
+
+/**
+ * Check the semantic restrictions of a binary assign expression.
+ */
+static void semantic_binexpr_assign(binary_expression_t *expression)
+{
+ expression_t *left = expression->left;
+ type_t *orig_type_left = left->base.datatype;
+
+ type_t *type_left = revert_automatic_type_conversion(left);
+ type_left = skip_typeref(orig_type_left);
+
+ /* must be a modifiable lvalue */
+ if (is_type_array(type_left)) {
+ errorf(HERE, "cannot assign to arrays ('%E')", left);
+ return;
+ }
+ if(type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
+ errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
+ orig_type_left);
+ return;
+ }
+ if(is_type_incomplete(type_left)) {
+ errorf(HERE,
+ "left-hand side of assignment '%E' has incomplete type '%T'",
+ left, orig_type_left);
+ return;
+ }
+ if(is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
+ errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
+ left, orig_type_left);
+ return;
+ }
+
+ type_t *const res_type = semantic_assign(orig_type_left, expression->right,
+ "assignment");
+ if (res_type == NULL) {
+ errorf(expression->expression.source_position,
+ "cannot assign to '%T' from '%T'",
+ orig_type_left, expression->right->base.datatype);
+ } else {
+ expression->right = create_implicit_cast(expression->right, res_type);
+ }
+
+ expression->expression.datatype = orig_type_left;
+}
+
+static bool expression_has_effect(const expression_t *const expr)
+{
+ switch (expr->kind) {
+ case EXPR_UNKNOWN: break;
+ case EXPR_INVALID: break;
+ case EXPR_REFERENCE: return false;
+ case EXPR_CONST: return false;
+ case EXPR_STRING_LITERAL: return false;
+ case EXPR_WIDE_STRING_LITERAL: return false;
+ case EXPR_CALL: {
+ const call_expression_t *const call = &expr->call;
+ if (call->function->kind != EXPR_BUILTIN_SYMBOL)
+ return true;
+
+ switch (call->function->builtin_symbol.symbol->ID) {
+ case T___builtin_va_end: return true;
+ default: return false;
+ }
+ }
+ case EXPR_CONDITIONAL: {
+ const conditional_expression_t *const cond = &expr->conditional;
+ return
+ expression_has_effect(cond->true_expression) &&
+ expression_has_effect(cond->false_expression);
+ }
+ case EXPR_SELECT: return false;
+ case EXPR_ARRAY_ACCESS: return false;
+ case EXPR_SIZEOF: return false;
+ case EXPR_CLASSIFY_TYPE: return false;
+ case EXPR_ALIGNOF: return false;
+
+ case EXPR_FUNCTION: return false;
+ case EXPR_PRETTY_FUNCTION: return false;
+ case EXPR_BUILTIN_SYMBOL: break; /* handled in EXPR_CALL */
+ case EXPR_BUILTIN_CONSTANT_P: return false;
+ case EXPR_BUILTIN_PREFETCH: return true;
+ case EXPR_OFFSETOF: return false;
+ case EXPR_VA_START: return true;
+ case EXPR_VA_ARG: return true;
+ case EXPR_STATEMENT: return true; // TODO
+
+ case EXPR_UNARY_NEGATE: return false;
+ case EXPR_UNARY_PLUS: return false;
+ case EXPR_UNARY_BITWISE_NEGATE: return false;
+ case EXPR_UNARY_NOT: return false;
+ case EXPR_UNARY_DEREFERENCE: return false;
+ case EXPR_UNARY_TAKE_ADDRESS: return false;
+ case EXPR_UNARY_POSTFIX_INCREMENT: return true;
+ case EXPR_UNARY_POSTFIX_DECREMENT: return true;
+ case EXPR_UNARY_PREFIX_INCREMENT: return true;
+ case EXPR_UNARY_PREFIX_DECREMENT: return true;
+ case EXPR_UNARY_CAST:
+ return is_type_atomic(expr->base.datatype, ATOMIC_TYPE_VOID);
+ case EXPR_UNARY_CAST_IMPLICIT: return true;
+ case EXPR_UNARY_ASSUME: return true;
+ case EXPR_UNARY_BITFIELD_EXTRACT: return false;
+
+ case EXPR_BINARY_ADD: return false;
+ case EXPR_BINARY_SUB: return false;
+ case EXPR_BINARY_MUL: return false;
+ case EXPR_BINARY_DIV: return false;
+ case EXPR_BINARY_MOD: return false;
+ case EXPR_BINARY_EQUAL: return false;
+ case EXPR_BINARY_NOTEQUAL: return false;
+ case EXPR_BINARY_LESS: return false;
+ case EXPR_BINARY_LESSEQUAL: return false;
+ case EXPR_BINARY_GREATER: return false;
+ case EXPR_BINARY_GREATEREQUAL: return false;
+ case EXPR_BINARY_BITWISE_AND: return false;
+ case EXPR_BINARY_BITWISE_OR: return false;
+ case EXPR_BINARY_BITWISE_XOR: return false;
+ case EXPR_BINARY_SHIFTLEFT: return false;
+ case EXPR_BINARY_SHIFTRIGHT: return false;
+ case EXPR_BINARY_ASSIGN: return true;
+ case EXPR_BINARY_MUL_ASSIGN: return true;
+ case EXPR_BINARY_DIV_ASSIGN: return true;
+ case EXPR_BINARY_MOD_ASSIGN: return true;
+ case EXPR_BINARY_ADD_ASSIGN: return true;
+ case EXPR_BINARY_SUB_ASSIGN: return true;
+ case EXPR_BINARY_SHIFTLEFT_ASSIGN: return true;
+ case EXPR_BINARY_SHIFTRIGHT_ASSIGN: return true;
+ case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
+ case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
+ case EXPR_BINARY_BITWISE_OR_ASSIGN: return true;
+ case EXPR_BINARY_LOGICAL_AND:
+ case EXPR_BINARY_LOGICAL_OR:
+ case EXPR_BINARY_COMMA:
+ return expression_has_effect(expr->binary.right);
+
+ case EXPR_BINARY_BUILTIN_EXPECT: return true;
+ case EXPR_BINARY_ISGREATER: return false;
+ case EXPR_BINARY_ISGREATEREQUAL: return false;
+ case EXPR_BINARY_ISLESS: return false;
+ case EXPR_BINARY_ISLESSEQUAL: return false;
+ case EXPR_BINARY_ISLESSGREATER: return false;
+ case EXPR_BINARY_ISUNORDERED: return false;
+ }
+
+ panic("unexpected statement");
+}
+
+static void semantic_comma(binary_expression_t *expression)
+{
+ if (warning.unused_value) {
+ const expression_t *const left = expression->left;
+ if (!expression_has_effect(left)) {
+ warningf(left->base.source_position, "left-hand operand of comma expression has no effect");
+ }
+ }
+ expression->expression.datatype = expression->right->base.datatype;
+}
+
+#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, sfunc, lr) \
+static expression_t *parse_##binexpression_type(unsigned precedence, \
+ expression_t *left) \
+{ \
+ eat(token_type); \
+ \
+ expression_t *right = parse_sub_expression(precedence + lr); \
+ \
+ expression_t *binexpr = allocate_expression_zero(binexpression_type); \
+ binexpr->binary.left = left; \
+ binexpr->binary.right = right; \
+ sfunc(&binexpr->binary); \
+ \
+ return binexpr; \
+}
+
+CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, semantic_comma, 1)
+CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, semantic_binexpr_arithmetic, 1)
+CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, semantic_binexpr_arithmetic, 1)
+CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, semantic_binexpr_arithmetic, 1)
+CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, semantic_add, 1)
+CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, semantic_sub, 1)
+CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, semantic_comparison, 1)
+CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, semantic_comparison, 1)
+CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, semantic_binexpr_assign, 0)
+
+CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL,
+ semantic_comparison, 1)
+CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,
+ semantic_comparison, 1)
+CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL,
+ semantic_comparison, 1)
+CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL,
+ semantic_comparison, 1)
+
+CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND,
+ semantic_binexpr_arithmetic, 1)
+CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR,
+ semantic_binexpr_arithmetic, 1)
+CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR,
+ semantic_binexpr_arithmetic, 1)
+CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND,
+ semantic_logical_op, 1)
+CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR,
+ semantic_logical_op, 1)
+CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT,
+ semantic_shift_op, 1)
+CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT,
+ semantic_shift_op, 1)
+CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN,
+ semantic_arithmetic_addsubb_assign, 0)
+CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN,
+ semantic_arithmetic_addsubb_assign, 0)
+CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN,
+ semantic_arithmetic_assign, 0)
+CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN,
+ semantic_arithmetic_assign, 0)
+CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN,
+ semantic_arithmetic_assign, 0)
+CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN,
+ semantic_arithmetic_assign, 0)
+CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN,
+ semantic_arithmetic_assign, 0)
+CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN,
+ semantic_arithmetic_assign, 0)
+CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN,
+ semantic_arithmetic_assign, 0)
+CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN,
+ semantic_arithmetic_assign, 0)