+ type_t *orig_type_left = left->datatype;
+ type_t *orig_type_right = right->datatype;
+
+ if(orig_type_left == NULL || orig_type_right == NULL)
+ return;
+
+ 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 */
+ parser_print_error_prefix();
+ fprintf(stderr, "operation needs integer types\n");
+ 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 *left = expression->left;
+ expression_t *right = expression->right;
+ type_t *orig_type_left = left->datatype;
+ type_t *orig_type_right = right->datatype;
+
+ if(orig_type_left == NULL || orig_type_right == NULL)
+ return;
+
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *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(type_left->type == TYPE_POINTER && is_type_integer(type_right)) {
+ expression->expression.datatype = type_left;
+ } else if(type_right->type == TYPE_POINTER && is_type_integer(type_left)) {
+ expression->expression.datatype = type_right;
+ } else if (type_left->type == TYPE_ARRAY && is_type_integer(type_right)) {
+ const array_type_t *const arr_type = (const array_type_t*)type_left;
+ expression->expression.datatype =
+ make_pointer_type(arr_type->element_type, TYPE_QUALIFIER_NONE);
+ } else if (type_right->type == TYPE_ARRAY && is_type_integer(type_left)) {
+ const array_type_t *const arr_type = (const array_type_t*)type_right;
+ expression->expression.datatype =
+ make_pointer_type(arr_type->element_type, TYPE_QUALIFIER_NONE);
+ } else {
+ parser_print_error_prefix();
+ fprintf(stderr, "invalid operands to binary + (");
+ print_type_quoted(orig_type_left);
+ fprintf(stderr, ", ");
+ print_type_quoted(orig_type_right);
+ fprintf(stderr, ")\n");
+ }
+}
+
+static void semantic_sub(binary_expression_t *expression)
+{
+ expression_t *left = expression->left;
+ expression_t *right = expression->right;
+ type_t *orig_type_left = left->datatype;
+ type_t *orig_type_right = right->datatype;
+
+ if(orig_type_left == NULL || orig_type_right == NULL)
+ return;
+
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *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(type_left->type == TYPE_POINTER && is_type_integer(type_right)) {
+ expression->expression.datatype = type_left;
+ } else if(type_left->type == TYPE_POINTER &&
+ type_right->type == TYPE_POINTER) {
+ if(!pointers_compatible(type_left, type_right)) {
+ parser_print_error_prefix();
+ fprintf(stderr, "pointers to incompatible objects to binary - (");
+ print_type_quoted(orig_type_left);
+ fprintf(stderr, ", ");
+ print_type_quoted(orig_type_right);
+ fprintf(stderr, ")\n");
+ } else {
+ expression->expression.datatype = type_ptrdiff_t;
+ }
+ } else {
+ parser_print_error_prefix();
+ fprintf(stderr, "invalid operands to binary - (");
+ print_type_quoted(orig_type_left);
+ fprintf(stderr, ", ");
+ print_type_quoted(orig_type_right);
+ fprintf(stderr, ")\n");
+ }
+}
+
+static void semantic_comparison(binary_expression_t *expression)
+{
+ expression_t *left = expression->left;
+ expression_t *right = expression->right;
+ type_t *orig_type_left = left->datatype;
+ type_t *orig_type_right = right->datatype;
+
+ if(orig_type_left == NULL || orig_type_right == NULL)
+ return;
+
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *type_right = skip_typeref(orig_type_right);