add an is_constant_expression, only try to fold expressions that are really constant...
[cparser] / parser.c
index fd91636..48ca810 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -30,6 +30,7 @@ struct declaration_specifiers_t {
        source_position_t  source_position;
        unsigned char      storage_class;
        bool               is_inline;
+       decl_modifiers_t   decl_modifiers;
        type_t            *type;
 };
 
@@ -55,6 +56,7 @@ static type_t         *type_char        = NULL;
 static type_t         *type_string      = NULL;
 static type_t         *type_void        = NULL;
 static type_t         *type_void_ptr    = NULL;
+static type_t         *type_valist      = NULL;
 
 type_t *type_size_t      = NULL;
 type_t *type_ptrdiff_t   = NULL;
@@ -73,6 +75,8 @@ static declaration_t *parse_declarator(
                const declaration_specifiers_t *specifiers, bool may_be_abstract);
 static declaration_t *record_declaration(declaration_t *declaration);
 
+static void semantic_comparison(binary_expression_t *expression);
+
 #define STORAGE_CLASSES     \
        case T_typedef:         \
        case T_extern:          \
@@ -84,7 +88,8 @@ static declaration_t *record_declaration(declaration_t *declaration);
        case T_const:           \
        case T_restrict:        \
        case T_volatile:        \
-       case T_inline:
+       case T_inline:          \
+       case T_forceinline:
 
 #ifdef PROVIDE_COMPLEX
 #define COMPLEX_SPECIFIERS  \
@@ -96,22 +101,23 @@ static declaration_t *record_declaration(declaration_t *declaration);
 #define IMAGINARY_SPECIFIERS
 #endif
 
-#define TYPE_SPECIFIERS     \
-       case T_void:            \
-       case T_char:            \
-       case T_short:           \
-       case T_int:             \
-       case T_long:            \
-       case T_float:           \
-       case T_double:          \
-       case T_signed:          \
-       case T_unsigned:        \
-       case T__Bool:           \
-       case T_struct:          \
-       case T_union:           \
-       case T_enum:            \
-       case T___typeof__:      \
-       COMPLEX_SPECIFIERS      \
+#define TYPE_SPECIFIERS       \
+       case T_void:              \
+       case T_char:              \
+       case T_short:             \
+       case T_int:               \
+       case T_long:              \
+       case T_float:             \
+       case T_double:            \
+       case T_signed:            \
+       case T_unsigned:          \
+       case T__Bool:             \
+       case T_struct:            \
+       case T_union:             \
+       case T_enum:              \
+       case T___typeof__:        \
+       case T___builtin_va_list: \
+       COMPLEX_SPECIFIERS        \
        IMAGINARY_SPECIFIERS
 
 #define DECLARATION_START   \
@@ -149,8 +155,7 @@ static size_t get_statement_struct_size(statement_type_t type)
                [STATEMENT_FOR]         = sizeof(for_statement_t),
                [STATEMENT_ASM]         = sizeof(asm_statement_t)
        };
-       assert(sizeof(sizes) / sizeof(sizes[0]) == STATEMENT_ASM + 1);
-       assert(type <= STATEMENT_ASM);
+       assert(type <= sizeof(sizes) / sizeof(sizes[0]));
        assert(sizes[type] != 0);
        return sizes[type];
 }
@@ -174,8 +179,8 @@ static size_t get_expression_struct_size(expression_type_t type)
                [EXPR_STRING_LITERAL]      = sizeof(string_literal_expression_t),
                [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t),
                [EXPR_CALL]                = sizeof(call_expression_t),
-               [EXPR_UNARY]               = sizeof(unary_expression_t),
-               [EXPR_BINARY]              = sizeof(binary_expression_t),
+               [EXPR_UNARY_FIRST]         = sizeof(unary_expression_t),
+               [EXPR_BINARY_FIRST]        = sizeof(binary_expression_t),
                [EXPR_CONDITIONAL]         = sizeof(conditional_expression_t),
                [EXPR_SELECT]              = sizeof(select_expression_t),
                [EXPR_ARRAY_ACCESS]        = sizeof(array_access_expression_t),
@@ -185,11 +190,17 @@ static size_t get_expression_struct_size(expression_type_t type)
                [EXPR_PRETTY_FUNCTION]     = sizeof(string_literal_expression_t),
                [EXPR_BUILTIN_SYMBOL]      = sizeof(builtin_symbol_expression_t),
                [EXPR_OFFSETOF]            = sizeof(offsetof_expression_t),
+               [EXPR_VA_START]            = sizeof(va_start_expression_t),
                [EXPR_VA_ARG]              = sizeof(va_arg_expression_t),
-               [EXPR_STATEMENT]           = sizeof(statement_expression_t)
+               [EXPR_STATEMENT]           = sizeof(statement_expression_t),
        };
-       assert(sizeof(sizes) / sizeof(sizes[0]) == EXPR_STATEMENT + 1);
-       assert(type <= EXPR_STATEMENT);
+       if(type >= EXPR_UNARY_FIRST && type <= EXPR_UNARY_LAST) {
+               return sizes[EXPR_UNARY_FIRST];
+       }
+       if(type >= EXPR_BINARY_FIRST && type <= EXPR_BINARY_LAST) {
+               return sizes[EXPR_BINARY_FIRST];
+       }
+       assert(type <= sizeof(sizes) / sizeof(sizes[0]));
        assert(sizes[type] != 0);
        return sizes[type];
 }
@@ -236,11 +247,12 @@ static type_t *allocate_type_zero(type_type_t type)
 static size_t get_initializer_size(initializer_type_t type)
 {
        static const size_t sizes[] = {
-               [INITIALIZER_VALUE]  = sizeof(initializer_value_t),
-               [INITIALIZER_STRING] = sizeof(initializer_string_t),
-               [INITIALIZER_LIST]   = sizeof(initializer_list_t)
+               [INITIALIZER_VALUE]       = sizeof(initializer_value_t),
+               [INITIALIZER_STRING]      = sizeof(initializer_string_t),
+               [INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t),
+               [INITIALIZER_LIST]        = sizeof(initializer_list_t)
        };
-       assert(type < INITIALIZER_COUNT);
+       assert(type < sizeof(sizes) / sizeof(*sizes));
        assert(sizes[type] != 0);
        return sizes[type];
 }
@@ -444,7 +456,7 @@ static void eat_statement(void)
        eat(';');
 }
 
-static void eat_brace(void)
+static void eat_paren(void)
 {
        if(token.type == '(')
                next_token();
@@ -456,7 +468,7 @@ static void eat_brace(void)
                        return;
                }
                if(token.type == '(') {
-                       eat_brace();
+                       eat_paren();
                        continue;
                }
                if(token.type == '{') {
@@ -582,8 +594,11 @@ static declaration_t *stack_push(stack_entry_t **stack_ptr,
                        print_type_quoted(previous_declaration->type);
                        fputc('\n', stderr);
                } else {
-                       unsigned old_storage_class = previous_declaration->storage_class;
-                       unsigned new_storage_class = declaration->storage_class;
+                       unsigned  old_storage_class = previous_declaration->storage_class;
+                       unsigned  new_storage_class = declaration->storage_class;
+                       type_t   *type              = previous_declaration->type;
+                       type = skip_typeref(type);
+
                        if (current_function == NULL) {
                                if (old_storage_class != STORAGE_CLASS_STATIC &&
                                    new_storage_class == STORAGE_CLASS_STATIC) {
@@ -599,7 +614,7 @@ static declaration_t *stack_push(stack_entry_t **stack_ptr,
                                                if (new_storage_class == STORAGE_CLASS_NONE) {
                                                        previous_declaration->storage_class = STORAGE_CLASS_NONE;
                                                }
-                                       } else {
+                                       } else if(!is_type_function(type)) {
                                                parser_print_warning_prefix_pos(declaration->source_position);
                                                fprintf(stderr, "redundant declaration for '%s'\n",
                                                                                symbol->string);
@@ -765,9 +780,8 @@ static type_t *promote_integer(type_t *type)
 static expression_t *create_cast_expression(expression_t *expression,
                                             type_t *dest_type)
 {
-       expression_t *cast = allocate_expression_zero(EXPR_UNARY);
+       expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST_IMPLICIT);
 
-       cast->unary.type    = UNEXPR_CAST_IMPLICIT;
        cast->unary.value   = expression;
        cast->base.datatype = dest_type;
 
@@ -777,12 +791,9 @@ static expression_t *create_cast_expression(expression_t *expression,
 static bool is_null_pointer_constant(const expression_t *expression)
 {
        /* skip void* cast */
-       if(expression->type == EXPR_UNARY) {
-               const unary_expression_t *unary = &expression->unary;
-               if(unary->type == UNEXPR_CAST
-                               && expression->base.datatype == type_void_ptr) {
-                       expression = unary->value;
-               }
+       if(expression->type == EXPR_UNARY_CAST
+                       || expression->type == EXPR_UNARY_CAST_IMPLICIT) {
+               expression = expression->unary.value;
        }
 
        /* TODO: not correct yet, should be any constant integer expression
@@ -943,7 +954,16 @@ incompatible_assign_types:
 static expression_t *parse_constant_expression(void)
 {
        /* start parsing at precedence 7 (conditional expression) */
-       return parse_sub_expression(7);
+       expression_t *result = parse_sub_expression(7);
+
+       if(!is_constant_expression(result)) {
+               parser_print_error_prefix_pos(result->base.source_position);
+               fprintf(stderr, "expression '");
+               print_expression(result);
+               fprintf(stderr, "' is not constant\n");
+       }
+
+       return result;
 }
 
 static expression_t *parse_assignment_expression(void)
@@ -1020,7 +1040,7 @@ static void parse_attributes(void)
                        if(token.type != T_STRING_LITERAL) {
                                parse_error_expected("while parsing assembler attribute",
                                                     T_STRING_LITERAL);
-                               eat_brace();
+                               eat_paren();
                                break;
                        } else {
                                parse_string_literals();
@@ -1093,27 +1113,47 @@ static initializer_t *initializer_from_string(array_type_t *type,
        return initializer;
 }
 
+static initializer_t *initializer_from_wide_string(array_type_t *const type,
+                                                   wide_string_t *const string)
+{
+       /* TODO: check len vs. size of array type */
+       (void) type;
+
+       initializer_t *const initializer =
+               allocate_initializer(INITIALIZER_WIDE_STRING);
+       initializer->wide_string.string = *string;
+
+       return initializer;
+}
+
 static initializer_t *initializer_from_expression(type_t *type,
                                                   expression_t *expression)
 {
        /* TODO check that expression is a constant expression */
 
        /* ยง 6.7.8.14/15 char array may be initialized by string literals */
-       if(is_type_array(type) && expression->type == EXPR_STRING_LITERAL) {
-               array_type_t *array_type   = &type->array;
-               type_t       *element_type = array_type->element_type;
-
-               if(element_type->type == TYPE_ATOMIC) {
-                       atomic_type_t      *atomic_type = &element_type->atomic;
-                       atomic_type_type_t  atype       = atomic_type->atype;
+       type_t *const expr_type = expression->base.datatype;
+       if (is_type_array(type) && expr_type->type == TYPE_POINTER) {
+               array_type_t *const array_type     = &type->array;
+               type_t       *const element_type   = skip_typeref(array_type->element_type);
+
+               if (element_type->type == TYPE_ATOMIC) {
+                       switch (expression->type) {
+                               case EXPR_STRING_LITERAL:
+                                       if (element_type->atomic.atype == ATOMIC_TYPE_CHAR) {
+                                               return initializer_from_string(array_type,
+                                                       expression->string.value);
+                                       }
 
-                       /* TODO handle wide strings */
-                       if(atype == ATOMIC_TYPE_CHAR
-                                       || atype == ATOMIC_TYPE_SCHAR
-                                       || atype == ATOMIC_TYPE_UCHAR) {
+                               case EXPR_WIDE_STRING_LITERAL: {
+                                       type_t *bare_wchar_type = skip_typeref(type_wchar_t);
+                                       if (get_unqualified_type(element_type) == bare_wchar_type) {
+                                               return initializer_from_wide_string(array_type,
+                                                       &expression->wide_string.value);
+                                       }
+                               }
 
-                               string_literal_expression_t *literal = &expression->string;
-                               return initializer_from_string(array_type, literal->value);
+                               default: break;
                        }
                }
        }
@@ -1591,14 +1631,19 @@ typedef enum {
 #endif
 } specifiers_t;
 
-static type_t *create_builtin_type(symbol_t *symbol)
+static type_t *create_builtin_type(symbol_t *const symbol,
+                                   type_t *const real_type)
 {
        type_t *type            = allocate_type_zero(TYPE_BUILTIN);
        type->builtin.symbol    = symbol;
-       /* TODO... */
-       type->builtin.real_type = type_int;
+       type->builtin.real_type = real_type;
 
-       return type;
+       type_t *result = typehash_insert(type);
+       if (type != result) {
+               free_type(type);
+       }
+
+       return result;
 }
 
 static type_t *get_typedef_type(symbol_t *symbol)
@@ -1704,6 +1749,10 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_SPECIFIER(T__Complex,   SPECIFIER_COMPLEX,   "_Complex")
                MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary")
 #endif
+               case T_forceinline:
+                       /* only in microsoft mode */
+                       specifiers->decl_modifiers |= DM_FORCEINLINE;
+
                case T_inline:
                        next_token();
                        specifiers->is_inline = true;
@@ -1741,7 +1790,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        type = parse_typeof();
                        break;
                case T___builtin_va_list:
-                       type = create_builtin_type(token.v.symbol);
+                       type = duplicate_type(type_valist);
                        next_token();
                        break;
 
@@ -1985,7 +2034,7 @@ static declaration_t *parse_parameter(void)
 
        parse_declaration_specifiers(&specifiers);
 
-       declaration_t *declaration = parse_declarator(&specifiers, true);
+       declaration_t *declaration = parse_declarator(&specifiers, /*may_be_abstract=*/true);
 
        semantic_parameter(declaration);
 
@@ -2321,10 +2370,11 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 static declaration_t *parse_declarator(
                const declaration_specifiers_t *specifiers, bool may_be_abstract)
 {
-       type_t        *type        = specifiers->type;
-       declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
-       declaration->storage_class = specifiers->storage_class;
-       declaration->is_inline     = specifiers->is_inline;
+       type_t        *type         = specifiers->type;
+       declaration_t *declaration  = allocate_ast_zero(sizeof(declaration[0]));
+       declaration->storage_class  = specifiers->storage_class;
+       declaration->decl_modifiers = specifiers->decl_modifiers;
+       declaration->is_inline      = specifiers->is_inline;
 
        construct_type_t *construct_type
                = parse_inner_declarator(declaration, may_be_abstract);
@@ -2427,13 +2477,27 @@ static void parse_init_declarator_rest(declaration_t *declaration)
 
                        cnst->base.datatype = type_size_t;
 
-                       if(initializer->type == INITIALIZER_LIST) {
-                               initializer_list_t *list = &initializer->list;
-                               cnst->conste.v.int_value = list->len;
-                       } else {
-                               assert(initializer->type == INITIALIZER_STRING);
-                               initializer_string_t *string = &initializer->string;
-                               cnst->conste.v.int_value = strlen(string->string) + 1;
+                       switch (initializer->type) {
+                               case INITIALIZER_LIST: {
+                                       initializer_list_t *const list = &initializer->list;
+                                       cnst->conste.v.int_value = list->len;
+                                       break;
+                               }
+
+                               case INITIALIZER_STRING: {
+                                       initializer_string_t *const string = &initializer->string;
+                                       cnst->conste.v.int_value = strlen(string->string) + 1;
+                                       break;
+                               }
+
+                               case INITIALIZER_WIDE_STRING: {
+                                       initializer_wide_string_t *const string = &initializer->wide_string;
+                                       cnst->conste.v.int_value = string->string.size;
+                                       break;
+                               }
+
+                               default:
+                                       panic("invalid initializer type");
                        }
 
                        array_type->size = cnst;
@@ -2517,7 +2581,7 @@ static void parse_declaration_rest(declaration_t *ndeclaration,
                        break;
                eat(',');
 
-               ndeclaration = parse_declarator(specifiers, false);
+               ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false);
        }
        expect_void(';');
 }
@@ -2540,7 +2604,7 @@ static void parse_declaration(parsed_declaration_func finished_declaration)
        if(token.type == ';') {
                parse_anonymous_declaration_rest(&specifiers, finished_declaration);
        } else {
-               declaration_t *declaration = parse_declarator(&specifiers, false);
+               declaration_t *declaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
                parse_declaration_rest(declaration, &specifiers, finished_declaration);
        }
 }
@@ -2548,7 +2612,8 @@ static void parse_declaration(parsed_declaration_func finished_declaration)
 static void parse_kr_declaration_list(declaration_t *declaration)
 {
        type_t *type = skip_typeref(declaration->type);
-       assert(is_type_function(type));
+       if(!is_type_function(type))
+               return;
 
        if(!type->function.kr_style_parameters)
                return;
@@ -2638,7 +2703,7 @@ static void parse_external_declaration(void)
        }
 
        /* declarator is common to both function-definitions and declarations */
-       declaration_t *ndeclaration = parse_declarator(&specifiers, false);
+       declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
 
        /* must be a declaration */
        if(token.type == ',' || token.type == '=' || token.type == ';') {
@@ -2733,7 +2798,7 @@ static void parse_struct_declarators(const declaration_specifiers_t *specifiers)
                        parse_constant_expression();
                        /* TODO (bitfields) */
                } else {
-                       declaration_t *declaration = parse_declarator(specifiers, true);
+                       declaration_t *declaration = parse_declarator(specifiers, /*may_be_abstract=*/true);
 
                        /* TODO: check constraints for struct declarations */
                        /* TODO: check for doubled fields */
@@ -2804,7 +2869,7 @@ struct expression_parser_function_t {
 
 expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
-static expression_t *make_invalid_expression(void)
+static expression_t *create_invalid_expression(void)
 {
        expression_t *expression         = allocate_expression_zero(EXPR_INVALID);
        expression->base.source_position = token.source_position;
@@ -2820,7 +2885,7 @@ static expression_t *expected_expression_error(void)
 
        next_token();
 
-       return make_invalid_expression();
+       return create_invalid_expression();
 }
 
 static expression_t *parse_string_const(void)
@@ -2929,6 +2994,8 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
                return make_function_1_type(type_float, type_string);
        case T___builtin_nand:
                return make_function_1_type(type_long_double, type_string);
+       case T___builtin_va_end:
+               return make_function_1_type(type_void, type_valist);
        default:
                panic("not implemented builtin symbol found");
        }
@@ -2976,16 +3043,12 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
                const select_expression_t *select = &expression->select;
                return select->compound_entry->type;
        }
-       case EXPR_UNARY: {
-               const unary_expression_t *unary = &expression->unary;
-               if(unary->type == UNEXPR_DEREFERENCE) {
-                       expression_t   *value        = unary->value;
-                       type_t         *type         = skip_typeref(value->base.datatype);
-                       pointer_type_t *pointer_type = &type->pointer;
+       case EXPR_UNARY_DEREFERENCE: {
+               expression_t   *value        = expression->unary.value;
+               type_t         *type         = skip_typeref(value->base.datatype);
+               pointer_type_t *pointer_type = &type->pointer;
 
-                       return pointer_type->points_to;
-               }
-               break;
+               return pointer_type->points_to;
        }
        case EXPR_BUILTIN_SYMBOL: {
                const builtin_symbol_expression_t *builtin
@@ -3060,9 +3123,8 @@ static void check_cast_allowed(expression_t *expression, type_t *dest_type)
 
 static expression_t *parse_cast(void)
 {
-       expression_t *cast = allocate_expression_zero(EXPR_UNARY);
+       expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
 
-       cast->unary.type           = UNEXPR_CAST;
        cast->base.source_position = token.source_position;
 
        type_t *type  = parse_typename();
@@ -3151,7 +3213,7 @@ static expression_t *parse_function_keyword(void)
 
        expression->expression.type     = EXPR_FUNCTION;
        expression->expression.datatype = type_string;
-       expression->value               = "TODO: FUNCTION";
+       expression->value               = current_function->symbol->string;
 
        return (expression_t*) expression;
 }
@@ -3161,12 +3223,16 @@ static expression_t *parse_pretty_function_keyword(void)
        eat(T___PRETTY_FUNCTION__);
        /* TODO */
 
+       if (current_function == NULL) {
+               parse_error("'__PRETTY_FUNCTION__' used outside of a function");
+       }
+
        string_literal_expression_t *expression
                = allocate_ast_zero(sizeof(expression[0]));
 
        expression->expression.type     = EXPR_PRETTY_FUNCTION;
        expression->expression.datatype = type_string;
-       expression->value               = "TODO: PRETTY FUNCTION";
+       expression->value               = current_function->symbol->string;
 
        return (expression_t*) expression;
 }
@@ -3178,7 +3244,7 @@ static designator_t *parse_designator(void)
        if(token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing member designator",
                                     T_IDENTIFIER, 0);
-               eat_brace();
+               eat_paren();
                return NULL;
        }
        result->symbol = token.v.symbol;
@@ -3191,7 +3257,7 @@ static designator_t *parse_designator(void)
                        if(token.type != T_IDENTIFIER) {
                                parse_error_expected("while parsing member designator",
                                                     T_IDENTIFIER, 0);
-                               eat_brace();
+                               eat_paren();
                                return NULL;
                        }
                        designator_t *designator = allocate_ast_zero(sizeof(result[0]));
@@ -3207,7 +3273,7 @@ static designator_t *parse_designator(void)
                        designator_t *designator = allocate_ast_zero(sizeof(result[0]));
                        designator->array_access = parse_expression();
                        if(designator->array_access == NULL) {
-                               eat_brace();
+                               eat_paren();
                                return NULL;
                        }
                        expect(']');
@@ -3238,6 +3304,32 @@ static expression_t *parse_offsetof(void)
        return expression;
 }
 
+static expression_t *parse_va_start(void)
+{
+       eat(T___builtin_va_start);
+
+       expression_t *expression = allocate_expression_zero(EXPR_VA_START);
+
+       expect('(');
+       expression->va_starte.ap = parse_assignment_expression();
+       expect(',');
+       expression_t *const expr = parse_assignment_expression();
+       if (expr->type == EXPR_REFERENCE) {
+               declaration_t *const decl = expr->reference.declaration;
+               if (decl->parent_context == &current_function->context &&
+                   decl->next == NULL) {
+                       expression->va_starte.parameter = decl;
+                       expect(')');
+                       return expression;
+               }
+       }
+       parser_print_error_prefix_pos(expr->base.source_position);
+       fprintf(stderr, "second argument of 'va_start' must be last parameter "
+                       "of the current function\n");
+
+       return create_invalid_expression();
+}
+
 static expression_t *parse_va_arg(void)
 {
        eat(T___builtin_va_arg);
@@ -3245,7 +3337,7 @@ static expression_t *parse_va_arg(void)
        expression_t *expression = allocate_expression_zero(EXPR_VA_ARG);
 
        expect('(');
-       expression->va_arge.arg = parse_assignment_expression();
+       expression->va_arge.ap = parse_assignment_expression();
        expect(',');
        expression->base.datatype = parse_typename();
        expect(')');
@@ -3269,6 +3361,58 @@ static expression_t *parse_builtin_symbol(void)
        return expression;
 }
 
+static expression_t *parse_compare_builtin(void)
+{
+       expression_t *expression;
+
+       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 *orig_type_left  = expression->binary.left->base.datatype;
+       type_t *orig_type_right = expression->binary.right->base.datatype;
+       if(orig_type_left == NULL || orig_type_right == NULL)
+               return expression;
+
+       type_t *type_left  = skip_typeref(orig_type_left);
+       type_t *type_right = skip_typeref(orig_type_right);
+       if(!is_type_floating(type_left) && !is_type_floating(type_right)) {
+               type_error_incompatible("invalid operands in comparison",
+                                       token.source_position, type_left, type_right);
+       } else {
+               semantic_comparison(&expression->binary);
+       }
+
+       return expression;
+}
+
 static expression_t *parse_primary_expression(void)
 {
        switch(token.type) {
@@ -3289,14 +3433,22 @@ static expression_t *parse_primary_expression(void)
                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_nanf:
        case T___builtin_alloca:
        case T___builtin_expect:
-       case T___builtin_va_start:
        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 '(':
                return parse_brace_expression();
@@ -3308,7 +3460,7 @@ static expression_t *parse_primary_expression(void)
        fprintf(stderr, "\n");
        eat_statement();
 
-       return make_invalid_expression();
+       return create_invalid_expression();
 }
 
 static expression_t *parse_array_expression(unsigned precedence,
@@ -3415,7 +3567,7 @@ static expression_t *parse_select_expression(unsigned precedence,
 
        type_t *orig_type = compound->base.datatype;
        if(orig_type == NULL)
-               return make_invalid_expression();
+               return create_invalid_expression();
 
        type_t *type = skip_typeref(orig_type);
 
@@ -3426,7 +3578,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                        fprintf(stderr, "left hand side of '->' is not a pointer, but ");
                        print_type_quoted(orig_type);
                        fputc('\n', stderr);
-                       return make_invalid_expression();
+                       return create_invalid_expression();
                }
                pointer_type_t *pointer_type = &type->pointer;
                type_left                    = pointer_type->points_to;
@@ -3440,7 +3592,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                        "union, but ", symbol->string);
                print_type_quoted(type_left);
                fputc('\n', stderr);
-               return make_invalid_expression();
+               return create_invalid_expression();
        }
 
        compound_type_t *compound_type = &type_left->compound;
@@ -3452,7 +3604,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                        symbol->string);
                print_type_quoted(type_left);
                fputc('\n', stderr);
-               return make_invalid_expression();
+               return create_invalid_expression();
        }
 
        declaration_t *iter = declaration->context.declarations;
@@ -3465,7 +3617,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                parser_print_error_prefix();
                print_type_quoted(type_left);
                fprintf(stderr, " has no member named '%s'\n", symbol->string);
-               return make_invalid_expression();
+               return create_invalid_expression();
        }
 
        /* we always do the auto-type conversions; the & and sizeof parser contains
@@ -3803,27 +3955,30 @@ static expression_t *parse_##unexpression_type(unsigned precedence)            \
 {                                                                              \
        eat(token_type);                                                           \
                                                                                \
-       unary_expression_t *unary_expression                                       \
-               = allocate_ast_zero(sizeof(unary_expression[0]));                      \
-       unary_expression->expression.type     = EXPR_UNARY;                        \
-       unary_expression->type                = unexpression_type;                 \
-       unary_expression->value               = parse_sub_expression(precedence);  \
+       expression_t *unary_expression                                             \
+               = allocate_expression_zero(unexpression_type);                         \
+       unary_expression->unary.value = parse_sub_expression(precedence);          \
                                                                                   \
-       sfunc(unary_expression);                                                   \
+       sfunc(&unary_expression->unary);                                           \
                                                                                \
-       return (expression_t*) unary_expression;                                   \
-}
-
-CREATE_UNARY_EXPRESSION_PARSER('-', UNEXPR_NEGATE, semantic_unexpr_arithmetic)
-CREATE_UNARY_EXPRESSION_PARSER('+', UNEXPR_PLUS,   semantic_unexpr_arithmetic)
-CREATE_UNARY_EXPRESSION_PARSER('!', UNEXPR_NOT,    semantic_unexpr_scalar)
-CREATE_UNARY_EXPRESSION_PARSER('*', UNEXPR_DEREFERENCE, semantic_dereference)
-CREATE_UNARY_EXPRESSION_PARSER('&', UNEXPR_TAKE_ADDRESS, semantic_take_addr)
-CREATE_UNARY_EXPRESSION_PARSER('~', UNEXPR_BITWISE_NEGATE,
+       return unary_expression;                                                   \
+}
+
+CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE,
+                               semantic_unexpr_arithmetic)
+CREATE_UNARY_EXPRESSION_PARSER('+', EXPR_UNARY_PLUS,
+                               semantic_unexpr_arithmetic)
+CREATE_UNARY_EXPRESSION_PARSER('!', EXPR_UNARY_NOT,
+                               semantic_unexpr_scalar)
+CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE,
+                               semantic_dereference)
+CREATE_UNARY_EXPRESSION_PARSER('&', EXPR_UNARY_TAKE_ADDRESS,
+                               semantic_take_addr)
+CREATE_UNARY_EXPRESSION_PARSER('~', EXPR_UNARY_BITWISE_NEGATE,
                                semantic_unexpr_integer)
-CREATE_UNARY_EXPRESSION_PARSER(T_PLUSPLUS,   UNEXPR_PREFIX_INCREMENT,
+CREATE_UNARY_EXPRESSION_PARSER(T_PLUSPLUS,   EXPR_UNARY_PREFIX_INCREMENT,
                                semantic_incdec)
-CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, UNEXPR_PREFIX_DECREMENT,
+CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT,
                                semantic_incdec)
 
 #define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \
@@ -3834,20 +3989,20 @@ static expression_t *parse_##unexpression_type(unsigned precedence,           \
        (void) precedence;                                                        \
        eat(token_type);                                                          \
                                                                               \
-       unary_expression_t *unary_expression                                      \
-               = allocate_ast_zero(sizeof(unary_expression[0]));                     \
-       unary_expression->expression.type     = EXPR_UNARY;                       \
-       unary_expression->type                = unexpression_type;                \
-       unary_expression->value               = left;                             \
+       expression_t *unary_expression                                            \
+               = allocate_expression_zero(unexpression_type);                        \
+       unary_expression->unary.value = left;                                     \
                                                                                  \
-       sfunc(unary_expression);                                                  \
+       sfunc(&unary_expression->unary);                                          \
                                                                               \
-       return (expression_t*) unary_expression;                                  \
+       return unary_expression;                                                  \
 }
 
-CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_PLUSPLUS,   UNEXPR_POSTFIX_INCREMENT,
+CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_PLUSPLUS,
+                                       EXPR_UNARY_POSTFIX_INCREMENT,
                                        semantic_incdec)
-CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_MINUSMINUS, UNEXPR_POSTFIX_DECREMENT,
+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)
@@ -4201,68 +4356,74 @@ static void semantic_comma(binary_expression_t *expression)
        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);         \
-                                                                         \
-       binary_expression_t *binexpr                                         \
-               = allocate_ast_zero(sizeof(binexpr[0]));                         \
-       binexpr->expression.type     = EXPR_BINARY;                          \
-       binexpr->type                = binexpression_type;                   \
-       binexpr->left                = left;                                 \
-       binexpr->right               = right;                                \
-       sfunc(binexpr);                                                      \
-                                                                         \
-       return (expression_t*) binexpr;                                      \
-}
-
-CREATE_BINEXPR_PARSER(',', BINEXPR_COMMA,          semantic_comma, 1)
-CREATE_BINEXPR_PARSER('*', BINEXPR_MUL,            semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('/', BINEXPR_DIV,            semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('%', BINEXPR_MOD,            semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('+', BINEXPR_ADD,            semantic_add, 1)
-CREATE_BINEXPR_PARSER('-', BINEXPR_SUB,            semantic_sub, 1)
-CREATE_BINEXPR_PARSER('<', BINEXPR_LESS,           semantic_comparison, 1)
-CREATE_BINEXPR_PARSER('>', BINEXPR_GREATER,        semantic_comparison, 1)
-CREATE_BINEXPR_PARSER('=', BINEXPR_ASSIGN,         semantic_binexpr_assign, 0)
-CREATE_BINEXPR_PARSER(T_EQUALEQUAL, BINEXPR_EQUAL, semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, BINEXPR_NOTEQUAL,
+#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_LESSEQUAL, BINEXPR_LESSEQUAL, semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_GREATEREQUAL, BINEXPR_GREATEREQUAL,
+CREATE_BINEXPR_PARSER(T_GREATEREQUAL,         EXPR_BINARY_GREATEREQUAL,
                       semantic_comparison, 1)
-CREATE_BINEXPR_PARSER('&', BINEXPR_BITWISE_AND,    semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('|', BINEXPR_BITWISE_OR,     semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('^', BINEXPR_BITWISE_XOR,    semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER(T_ANDAND, BINEXPR_LOGICAL_AND,  semantic_logical_op, 1)
-CREATE_BINEXPR_PARSER(T_PIPEPIPE, BINEXPR_LOGICAL_OR, semantic_logical_op, 1)
-CREATE_BINEXPR_PARSER(T_LESSLESS, BINEXPR_SHIFTLEFT,
+
+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, BINEXPR_SHIFTRIGHT,
+CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT,
                       semantic_shift_op, 1)
-CREATE_BINEXPR_PARSER(T_PLUSEQUAL, BINEXPR_ADD_ASSIGN,
+CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN,
                       semantic_arithmetic_addsubb_assign, 0)
-CREATE_BINEXPR_PARSER(T_MINUSEQUAL, BINEXPR_SUB_ASSIGN,
+CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN,
                       semantic_arithmetic_addsubb_assign, 0)
-CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, BINEXPR_MUL_ASSIGN,
+CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN,
                       semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_SLASHEQUAL, BINEXPR_DIV_ASSIGN,
+CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN,
                       semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, BINEXPR_MOD_ASSIGN,
+CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN,
                       semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, BINEXPR_SHIFTLEFT_ASSIGN,
+CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN,
                       semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, BINEXPR_SHIFTRIGHT_ASSIGN,
+CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN,
                       semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_ANDEQUAL, BINEXPR_BITWISE_AND_ASSIGN,
+CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN,
                       semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_PIPEEQUAL, BINEXPR_BITWISE_OR_ASSIGN,
+CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN,
                       semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_CARETEQUAL, BINEXPR_BITWISE_XOR_ASSIGN,
+CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN,
                       semantic_arithmetic_assign, 0)
 
 static expression_t *parse_sub_expression(unsigned precedence)
@@ -4327,9 +4488,8 @@ static void register_expression_parser(parse_expression_function parser,
        entry->precedence = precedence;
 }
 
-static void register_expression_infix_parser(
-               parse_expression_infix_function parser, int token_type,
-               unsigned precedence)
+static void register_infix_parser(parse_expression_infix_function parser,
+               int token_type, unsigned precedence)
 {
        expression_parser_function_t *entry = &expression_parsers[token_type];
 
@@ -4348,67 +4508,64 @@ static void init_expression_parsers(void)
 {
        memset(&expression_parsers, 0, sizeof(expression_parsers));
 
-       register_expression_infix_parser(parse_BINEXPR_MUL,         '*',        16);
-       register_expression_infix_parser(parse_BINEXPR_DIV,         '/',        16);
-       register_expression_infix_parser(parse_BINEXPR_MOD,         '%',        16);
-       register_expression_infix_parser(parse_BINEXPR_SHIFTLEFT,   T_LESSLESS, 16);
-       register_expression_infix_parser(parse_BINEXPR_SHIFTRIGHT,
-                                                             T_GREATERGREATER, 16);
-       register_expression_infix_parser(parse_BINEXPR_ADD,         '+',        15);
-       register_expression_infix_parser(parse_BINEXPR_SUB,         '-',        15);
-       register_expression_infix_parser(parse_BINEXPR_LESS,        '<',        14);
-       register_expression_infix_parser(parse_BINEXPR_GREATER,     '>',        14);
-       register_expression_infix_parser(parse_BINEXPR_LESSEQUAL, T_LESSEQUAL,  14);
-       register_expression_infix_parser(parse_BINEXPR_GREATEREQUAL,
-                                                               T_GREATEREQUAL, 14);
-       register_expression_infix_parser(parse_BINEXPR_EQUAL,     T_EQUALEQUAL, 13);
-       register_expression_infix_parser(parse_BINEXPR_NOTEQUAL,
-                                                       T_EXCLAMATIONMARKEQUAL, 13);
-       register_expression_infix_parser(parse_BINEXPR_BITWISE_AND, '&',        12);
-       register_expression_infix_parser(parse_BINEXPR_BITWISE_XOR, '^',        11);
-       register_expression_infix_parser(parse_BINEXPR_BITWISE_OR,  '|',        10);
-       register_expression_infix_parser(parse_BINEXPR_LOGICAL_AND, T_ANDAND,    9);
-       register_expression_infix_parser(parse_BINEXPR_LOGICAL_OR,  T_PIPEPIPE,  8);
-       register_expression_infix_parser(parse_conditional_expression, '?',      7);
-       register_expression_infix_parser(parse_BINEXPR_ASSIGN,      '=',         2);
-       register_expression_infix_parser(parse_BINEXPR_ADD_ASSIGN, T_PLUSEQUAL,  2);
-       register_expression_infix_parser(parse_BINEXPR_SUB_ASSIGN, T_MINUSEQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_MUL_ASSIGN,
-                                                               T_ASTERISKEQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_DIV_ASSIGN, T_SLASHEQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_MOD_ASSIGN,
-                                                                T_PERCENTEQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_SHIFTLEFT_ASSIGN,
+       register_infix_parser(parse_array_expression,         '[',              30);
+       register_infix_parser(parse_call_expression,          '(',              30);
+       register_infix_parser(parse_select_expression,        '.',              30);
+       register_infix_parser(parse_select_expression,        T_MINUSGREATER,   30);
+       register_infix_parser(parse_EXPR_UNARY_POSTFIX_INCREMENT,
+                                                             T_PLUSPLUS,       30);
+       register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT,
+                                                             T_MINUSMINUS,     30);
+
+       register_infix_parser(parse_EXPR_BINARY_MUL,          '*',              16);
+       register_infix_parser(parse_EXPR_BINARY_DIV,          '/',              16);
+       register_infix_parser(parse_EXPR_BINARY_MOD,          '%',              16);
+       register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT,    T_LESSLESS,       16);
+       register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT,   T_GREATERGREATER, 16);
+       register_infix_parser(parse_EXPR_BINARY_ADD,          '+',              15);
+       register_infix_parser(parse_EXPR_BINARY_SUB,          '-',              15);
+       register_infix_parser(parse_EXPR_BINARY_LESS,         '<',              14);
+       register_infix_parser(parse_EXPR_BINARY_GREATER,      '>',              14);
+       register_infix_parser(parse_EXPR_BINARY_LESSEQUAL,    T_LESSEQUAL,      14);
+       register_infix_parser(parse_EXPR_BINARY_GREATEREQUAL, T_GREATEREQUAL,   14);
+       register_infix_parser(parse_EXPR_BINARY_EQUAL,        T_EQUALEQUAL,     13);
+       register_infix_parser(parse_EXPR_BINARY_NOTEQUAL,
+                                                    T_EXCLAMATIONMARKEQUAL, 13);
+       register_infix_parser(parse_EXPR_BINARY_BITWISE_AND,  '&',              12);
+       register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR,  '^',              11);
+       register_infix_parser(parse_EXPR_BINARY_BITWISE_OR,   '|',              10);
+       register_infix_parser(parse_EXPR_BINARY_LOGICAL_AND,  T_ANDAND,          9);
+       register_infix_parser(parse_EXPR_BINARY_LOGICAL_OR,   T_PIPEPIPE,        8);
+       register_infix_parser(parse_conditional_expression,   '?',               7);
+       register_infix_parser(parse_EXPR_BINARY_ASSIGN,       '=',               2);
+       register_infix_parser(parse_EXPR_BINARY_ADD_ASSIGN,   T_PLUSEQUAL,       2);
+       register_infix_parser(parse_EXPR_BINARY_SUB_ASSIGN,   T_MINUSEQUAL,      2);
+       register_infix_parser(parse_EXPR_BINARY_MUL_ASSIGN,   T_ASTERISKEQUAL,   2);
+       register_infix_parser(parse_EXPR_BINARY_DIV_ASSIGN,   T_SLASHEQUAL,      2);
+       register_infix_parser(parse_EXPR_BINARY_MOD_ASSIGN,   T_PERCENTEQUAL,    2);
+       register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT_ASSIGN,
                                                                T_LESSLESSEQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_SHIFTRIGHT_ASSIGN,
+       register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT_ASSIGN,
                                                          T_GREATERGREATEREQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_BITWISE_AND_ASSIGN,
+       register_infix_parser(parse_EXPR_BINARY_BITWISE_AND_ASSIGN,
                                                                     T_ANDEQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_BITWISE_OR_ASSIGN,
+       register_infix_parser(parse_EXPR_BINARY_BITWISE_OR_ASSIGN,
                                                                    T_PIPEEQUAL, 2);
-       register_expression_infix_parser(parse_BINEXPR_BITWISE_XOR_ASSIGN,
+       register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR_ASSIGN,
                                                                   T_CARETEQUAL, 2);
 
-       register_expression_infix_parser(parse_BINEXPR_COMMA,       ',',         1);
-
-       register_expression_infix_parser(parse_array_expression,        '[',    30);
-       register_expression_infix_parser(parse_call_expression,         '(',    30);
-       register_expression_infix_parser(parse_select_expression,       '.',    30);
-       register_expression_infix_parser(parse_select_expression,
-                                                               T_MINUSGREATER, 30);
-       register_expression_infix_parser(parse_UNEXPR_POSTFIX_INCREMENT,
-                                        T_PLUSPLUS, 30);
-       register_expression_infix_parser(parse_UNEXPR_POSTFIX_DECREMENT,
-                                        T_MINUSMINUS, 30);
-
-       register_expression_parser(parse_UNEXPR_NEGATE,           '-',          25);
-       register_expression_parser(parse_UNEXPR_PLUS,             '+',          25);
-       register_expression_parser(parse_UNEXPR_NOT,              '!',          25);
-       register_expression_parser(parse_UNEXPR_BITWISE_NEGATE,   '~',          25);
-       register_expression_parser(parse_UNEXPR_DEREFERENCE,      '*',          25);
-       register_expression_parser(parse_UNEXPR_TAKE_ADDRESS,     '&',          25);
-       register_expression_parser(parse_UNEXPR_PREFIX_INCREMENT, T_PLUSPLUS,   25);
-       register_expression_parser(parse_UNEXPR_PREFIX_DECREMENT, T_MINUSMINUS, 25);
+       register_infix_parser(parse_EXPR_BINARY_COMMA,        ',',               1);
+
+       register_expression_parser(parse_EXPR_UNARY_NEGATE,           '-',      25);
+       register_expression_parser(parse_EXPR_UNARY_PLUS,             '+',      25);
+       register_expression_parser(parse_EXPR_UNARY_NOT,              '!',      25);
+       register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE,   '~',      25);
+       register_expression_parser(parse_EXPR_UNARY_DEREFERENCE,      '*',      25);
+       register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS,     '&',      25);
+       register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT,
+                                                                 T_PLUSPLUS,   25);
+       register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT,
+                                                                 T_MINUSMINUS, 25);
        register_expression_parser(parse_sizeof,                  T_sizeof,     25);
        register_expression_parser(parse_extension,            T___extension__, 25);
        register_expression_parser(parse_builtin_classify_type,
@@ -4791,6 +4948,8 @@ static statement_t *parse_return(void)
 
        if(return_type == NULL)
                return (statement_t*) statement;
+       if(return_value != NULL && return_value->base.datatype == NULL)
+               return (statement_t*) statement;
 
        return_type = skip_typeref(return_type);
 
@@ -5070,6 +5229,9 @@ void init_parser(void)
        type_void        = make_atomic_type(ATOMIC_TYPE_VOID, TYPE_QUALIFIER_NONE);
        type_void_ptr    = make_pointer_type(type_void, TYPE_QUALIFIER_NONE);
        type_string      = make_pointer_type(type_char, TYPE_QUALIFIER_NONE);
+
+       symbol_t *const va_list_sym = symbol_table_insert("__builtin_va_list");
+       type_valist = create_builtin_type(va_list_sym, type_void_ptr);
 }
 
 void exit_parser(void)