+ switch(token.type) {
+ case T___builtin_isgreater:
+ expression = allocate_expression_zero(EXPR_BINARY_ISGREATER);
+ break;
+ case T___builtin_isgreaterequal:
+ expression = allocate_expression_zero(EXPR_BINARY_ISGREATEREQUAL);
+ break;
+ case T___builtin_isless:
+ expression = allocate_expression_zero(EXPR_BINARY_ISLESS);
+ break;
+ case T___builtin_islessequal:
+ expression = allocate_expression_zero(EXPR_BINARY_ISLESSEQUAL);
+ break;
+ case T___builtin_islessgreater:
+ expression = allocate_expression_zero(EXPR_BINARY_ISLESSGREATER);
+ break;
+ case T___builtin_isunordered:
+ expression = allocate_expression_zero(EXPR_BINARY_ISUNORDERED);
+ break;
+ default:
+ panic("invalid compare builtin found");
+ break;
+ }
+ next_token();
+
+ expect('(');
+ expression->binary.left = parse_assignment_expression();
+ expect(',');
+ expression->binary.right = parse_assignment_expression();
+ expect(')');
+
+ type_t *const orig_type_left = expression->binary.left->base.datatype;
+ type_t *const orig_type_right = expression->binary.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_floating(type_left) && !is_type_floating(type_right)) {
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ type_error_incompatible("invalid operands in comparison",
+ token.source_position, orig_type_left, orig_type_right);
+ }
+ } else {
+ semantic_comparison(&expression->binary);
+ }
+
+ return expression;
+}
+
+static expression_t *parse_builtin_expect(void)
+{
+ eat(T___builtin_expect);
+
+ expression_t *expression
+ = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT);
+
+ expect('(');
+ expression->binary.left = parse_assignment_expression();
+ expect(',');
+ expression->binary.right = parse_constant_expression();
+ expect(')');
+
+ expression->base.datatype = expression->binary.left->base.datatype;
+
+ return expression;
+}
+
+static expression_t *parse_assume(void) {
+ eat(T_assume);
+
+ expression_t *expression
+ = allocate_expression_zero(EXPR_UNARY_ASSUME);
+
+ expect('(');
+ expression->unary.value = parse_assignment_expression();
+ expect(')');
+
+ expression->base.datatype = type_void;
+ return expression;
+}
+
+static expression_t *parse_alignof(void) {
+ eat(T___alignof__);
+
+ expression_t *expression
+ = allocate_expression_zero(EXPR_ALIGNOF);
+
+ expect('(');
+ expression->alignofe.type = parse_typename();
+ expect(')');
+
+ expression->base.datatype = type_size_t;
+ return expression;
+}
+
+static expression_t *parse_primary_expression(void)
+{
+ switch(token.type) {
+ case T_INTEGER:
+ return parse_int_const();
+ case T_FLOATINGPOINT:
+ return parse_float_const();
+ case T_STRING_LITERAL:
+ return parse_string_const();
+ case T_WIDE_STRING_LITERAL:
+ return parse_wide_string_const();
+ case T_IDENTIFIER:
+ return parse_reference();
+ case T___FUNCTION__:
+ case T___func__:
+ return parse_function_keyword();
+ case T___PRETTY_FUNCTION__:
+ return parse_pretty_function_keyword();
+ case T___builtin_offsetof:
+ return parse_offsetof();
+ case T___builtin_va_start:
+ return parse_va_start();
+ case T___builtin_va_arg:
+ return parse_va_arg();
+ case T___builtin_expect:
+ return parse_builtin_expect();
+ case T___builtin_nanf:
+ case T___builtin_alloca:
+ case T___builtin_va_end:
+ return parse_builtin_symbol();
+ case T___builtin_isgreater:
+ case T___builtin_isgreaterequal:
+ case T___builtin_isless:
+ case T___builtin_islessequal:
+ case T___builtin_islessgreater:
+ case T___builtin_isunordered:
+ return parse_compare_builtin();
+ case T___builtin_constant_p:
+ return parse_builtin_constant();
+ case T___builtin_prefetch:
+ return parse_builtin_prefetch();
+ case T___alignof__:
+ return parse_alignof();
+ case T_assume:
+ return parse_assume();
+
+ case '(':
+ return parse_brace_expression();
+ }
+
+ errorf(HERE, "unexpected token '%K'", &token);
+ eat_statement();
+
+ return create_invalid_expression();
+}
+
+/**
+ * Check if the expression has the character type and issue a warning then.
+ */
+static void check_for_char_index_type(const expression_t *expression) {
+ type_t *const type = expression->base.datatype;
+ const type_t *const base_type = skip_typeref(type);
+
+ if (is_type_atomic(base_type, ATOMIC_TYPE_CHAR) &&
+ warning.char_subscripts) {
+ warningf(expression->base.source_position,
+ "array subscript has type '%T'", type);
+ }
+}
+
+static expression_t *parse_array_expression(unsigned precedence,
+ expression_t *left)
+{
+ (void) precedence;
+
+ eat('[');
+
+ expression_t *inside = parse_expression();
+
+ array_access_expression_t *array_access
+ = allocate_ast_zero(sizeof(array_access[0]));
+
+ array_access->expression.kind = EXPR_ARRAY_ACCESS;
+
+ type_t *const orig_type_left = left->base.datatype;
+ type_t *const orig_type_inside = inside->base.datatype;
+
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_inside = skip_typeref(orig_type_inside);
+
+ type_t *return_type;
+ if (is_type_pointer(type_left)) {
+ return_type = type_left->pointer.points_to;
+ array_access->array_ref = left;
+ array_access->index = inside;
+ check_for_char_index_type(inside);
+ } else if (is_type_pointer(type_inside)) {
+ return_type = type_inside->pointer.points_to;
+ array_access->array_ref = inside;
+ array_access->index = left;
+ array_access->flipped = true;
+ check_for_char_index_type(left);
+ } else {
+ if (is_type_valid(type_left) && is_type_valid(type_inside)) {
+ errorf(HERE,
+ "array access on object with non-pointer types '%T', '%T'",
+ orig_type_left, orig_type_inside);
+ }
+ return_type = type_error_type;
+ array_access->array_ref = create_invalid_expression();
+ }
+
+ if(token.type != ']') {
+ parse_error_expected("Problem while parsing array access", ']', 0);
+ return (expression_t*) array_access;
+ }
+ next_token();
+
+ return_type = automatic_type_conversion(return_type);
+ array_access->expression.datatype = return_type;
+
+ return (expression_t*) array_access;
+}
+
+static expression_t *parse_sizeof(unsigned precedence)
+{
+ eat(T_sizeof);
+
+ sizeof_expression_t *sizeof_expression
+ = allocate_ast_zero(sizeof(sizeof_expression[0]));
+ sizeof_expression->expression.kind = EXPR_SIZEOF;
+ sizeof_expression->expression.datatype = type_size_t;
+
+ if(token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
+ next_token();
+ sizeof_expression->type = parse_typename();
+ expect(')');