finished implementation of __func__ and _PRETTY_FUNC__
[cparser] / parser.c
index d7317ce..beedd11 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -55,6 +55,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 +74,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:          \
@@ -96,22 +99,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 +153,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 +177,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 +188,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 +245,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 +454,7 @@ static void eat_statement(void)
        eat(';');
 }
 
-static void eat_brace(void)
+static void eat_paren(void)
 {
        if(token.type == '(')
                next_token();
@@ -456,7 +466,7 @@ static void eat_brace(void)
                        return;
                }
                if(token.type == '(') {
-                       eat_brace();
+                       eat_paren();
                        continue;
                }
                if(token.type == '{') {
@@ -582,8 +592,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 +612,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);
@@ -739,6 +752,7 @@ static void label_pop_to(size_t new_top)
 
 static int get_rank(const type_t *type)
 {
+       assert(!is_typeref(type));
        /* The C-standard allows promoting to int or unsigned int (see § 7.2.2
         * and esp. footnote 108). However we can't fold constants (yet), so we
         * can't decide wether unsigned int is possible, while int always works.
@@ -764,9 +778,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;
 
@@ -776,12 +789,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
@@ -1019,7 +1029,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();
@@ -1092,32 +1102,53 @@ 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(type->type == TYPE_ARRAY && 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;
                        }
                }
        }
 
-       if(is_type_scalar(type)) {
+       type_t *expression_type = skip_typeref(expression->base.datatype);
+       if(is_type_scalar(type) || types_compatible(type, expression_type)) {
                semantic_assign(type, &expression, "initializer");
 
                initializer_t *result = allocate_initializer(INITIALIZER_VALUE);
@@ -1190,7 +1221,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
        /* descend into subtype */
        initializer_t  *result = NULL;
        initializer_t **elems;
-       if(type->type == TYPE_ARRAY) {
+       if(is_type_array(type)) {
                array_type_t *array_type   = &type->array;
                type_t       *element_type = array_type->element_type;
                element_type               = skip_typeref(element_type);
@@ -1230,8 +1261,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                        ARR_APP1(initializer_t*, elems, sub);
                }
        } else {
-               assert(type->type == TYPE_COMPOUND_STRUCT
-                               || type->type == TYPE_COMPOUND_UNION);
+               assert(is_type_compound(type));
                compound_type_t *compound_type = &type->compound;
                context_t       *context       = &compound_type->declaration->context;
 
@@ -1312,8 +1342,19 @@ static initializer_t *parse_initializer(type_t *type)
        type = skip_typeref(type);
 
        if(token.type != '{') {
-               expression_t *expression = parse_assignment_expression();
-               return initializer_from_expression(type, expression);
+               expression_t  *expression  = parse_assignment_expression();
+               initializer_t *initializer = initializer_from_expression(type, expression);
+               if(initializer == NULL) {
+                       parser_print_error_prefix();
+                       fprintf(stderr, "initializer expression '");
+                       print_expression(expression);
+                       fprintf(stderr, "', type ");
+                       print_type_quoted(expression->base.datatype);
+                       fprintf(stderr, " is incompatible with type ");
+                       print_type_quoted(type);
+                       fprintf(stderr, "\n");
+               }
+               return initializer;
        }
 
        if(is_type_scalar(type)) {
@@ -1579,14 +1620,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)
@@ -1729,7 +1775,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;
 
@@ -1948,7 +1994,7 @@ static void semantic_parameter(declaration_t *declaration)
 
        /* Array as last part of a paramter type is just syntactic sugar.  Turn it
         * into a pointer. § 6.7.5.3 (7) */
-       if (type->type == TYPE_ARRAY) {
+       if (is_type_array(type)) {
                const array_type_t *arr_type     = &type->array;
                type_t             *element_type = arr_type->element_type;
 
@@ -2407,7 +2453,7 @@ static void parse_init_declarator_rest(declaration_t *declaration)
 
        /* § 6.7.5 (22)  array intializers for arrays with unknown size determine
         * the array type size */
-       if(type != NULL && type->type == TYPE_ARRAY && initializer != NULL) {
+       if(type != NULL && is_type_array(type) && initializer != NULL) {
                array_type_t *array_type = &type->array;
 
                if(array_type->size == NULL) {
@@ -2415,20 +2461,34 @@ 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;
                }
        }
 
-       if(type != NULL && type->type == TYPE_FUNCTION) {
+       if(type != NULL && is_type_function(type)) {
                parser_print_error_prefix_pos(declaration->source_position);
                fprintf(stderr, "initializers not allowed for function types at "
                                "declator '%s' (type ", declaration->symbol->string);
@@ -2536,7 +2596,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(type->type == TYPE_FUNCTION);
+       if(!is_type_function(type))
+               return;
 
        if(!type->function.kr_style_parameters)
                return;
@@ -2587,6 +2648,7 @@ static void parse_kr_declaration_list(declaration_t *declaration)
                }
 
                semantic_parameter(parameter_declaration);
+               parameter_type = parameter_declaration->type;
 
                function_parameter_t *function_parameter
                        = obstack_alloc(type_obst, sizeof(function_parameter[0]));
@@ -2642,17 +2704,18 @@ static void parse_external_declaration(void)
                return;
        }
 
-       type_t *orig_type = ndeclaration->type;
-       if(orig_type == NULL) {
+       type_t *type = ndeclaration->type;
+       if(type == NULL) {
                eat_block();
                return;
        }
 
-       type_t *type = skip_typeref(orig_type);
+       /* note that we don't skip typerefs: the standard doesn't allow them here
+        * (so we can't use is_type_function here) */
        if(type->type != TYPE_FUNCTION) {
                parser_print_error_prefix();
                fprintf(stderr, "declarator '");
-               print_type_ext(orig_type, ndeclaration->symbol, NULL);
+               print_type_ext(type, ndeclaration->symbol, NULL);
                fprintf(stderr, "' has a body but is not a function type.\n");
                eat_block();
                return;
@@ -2790,7 +2853,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;
@@ -2806,7 +2869,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)
@@ -2915,6 +2978,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");
        }
@@ -2923,12 +2988,13 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
 /**
  * performs automatic type cast as described in § 6.3.2.1
  */
-static type_t *automatic_type_conversion(type_t *type)
+static type_t *automatic_type_conversion(type_t *orig_type)
 {
-       if(type == NULL)
+       if(orig_type == NULL)
                return NULL;
 
-       if(type->type == TYPE_ARRAY) {
+       type_t *type = skip_typeref(orig_type);
+       if(is_type_array(type)) {
                array_type_t *array_type   = &type->array;
                type_t       *element_type = array_type->element_type;
                unsigned      qualifiers   = array_type->type.qualifiers;
@@ -2936,11 +3002,11 @@ static type_t *automatic_type_conversion(type_t *type)
                return make_pointer_type(element_type, qualifiers);
        }
 
-       if(type->type == TYPE_FUNCTION) {
-               return make_pointer_type(type, TYPE_QUALIFIER_NONE);
+       if(is_type_function(type)) {
+               return make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
        }
 
-       return type;
+       return orig_type;
 }
 
 /**
@@ -2961,16 +3027,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
@@ -3045,9 +3107,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();
@@ -3136,7 +3197,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;
 }
@@ -3146,12 +3207,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;
 }
@@ -3163,7 +3228,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;
@@ -3176,7 +3241,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]));
@@ -3192,7 +3257,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(']');
@@ -3223,6 +3288,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);
@@ -3230,7 +3321,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(')');
@@ -3254,6 +3345,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) {
@@ -3274,14 +3417,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();
@@ -3293,7 +3444,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,
@@ -3400,7 +3551,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);
 
@@ -3411,7 +3562,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;
@@ -3425,7 +3576,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;
@@ -3437,7 +3588,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;
@@ -3450,7 +3601,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
@@ -3481,7 +3632,7 @@ static expression_t *parse_call_expression(unsigned precedence,
 
                        type = skip_typeref(pointer_type->points_to);
 
-                       if (type->type == TYPE_FUNCTION) {
+                       if (is_type_function(type)) {
                                function_type             = &type->function;
                                call->expression.datatype = function_type->return_type;
                        }
@@ -3788,27 +3939,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, \
@@ -3819,20 +3973,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)
@@ -3981,10 +4135,9 @@ static void semantic_sub(binary_expression_t *expression)
                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)) {
+       } else if(is_type_pointer(type_left) && is_type_integer(type_right)) {
                expression->expression.datatype = type_left;
-       } else if(type_left->type == TYPE_POINTER &&
-                       type_right->type == TYPE_POINTER) {
+       } else if(is_type_pointer(type_left) && is_type_pointer(type_right)) {
                if(!pointers_compatible(type_left, type_right)) {
                        parser_print_error_prefix();
                        fprintf(stderr, "pointers to incompatible objects to binary - (");
@@ -4024,12 +4177,11 @@ static void semantic_comparison(binary_expression_t *expression)
                expression->left  = create_implicit_cast(left, arithmetic_type);
                expression->right = create_implicit_cast(right, arithmetic_type);
                expression->expression.datatype = arithmetic_type;
-       } else if (type_left->type  == TYPE_POINTER &&
-                  type_right->type == TYPE_POINTER) {
+       } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
                /* TODO check compatibility */
-       } else if (type_left->type == TYPE_POINTER) {
+       } else if (is_type_pointer(type_left)) {
                expression->right = create_implicit_cast(right, type_left);
-       } else if (type_right->type == TYPE_POINTER) {
+       } else if (is_type_pointer(type_right)) {
                expression->left = create_implicit_cast(left, type_right);
        } else {
                type_error_incompatible("invalid operands in comparison",
@@ -4088,7 +4240,7 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
                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 (type_left->type == TYPE_POINTER && is_type_integer(type_right)) {
+       } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
                expression->expression.datatype = type_left;
        } else {
                parser_print_error_prefix();
@@ -4140,10 +4292,10 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
                return;
 
        type_t *type_left = revert_automatic_type_conversion(left);
-       type_left = skip_typeref(orig_type_left);
+       type_left         = skip_typeref(orig_type_left);
 
        /* must be a modifiable lvalue */
-       if (type_left->type == TYPE_ARRAY) {
+       if (is_type_array(type_left)) {
                parser_print_error_prefix();
                fprintf(stderr, "Cannot assign to arrays ('");
                print_expression(left);
@@ -4188,68 +4340,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)
@@ -4314,9 +4472,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];
 
@@ -4335,67 +4492,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,
@@ -4766,7 +4920,7 @@ static statement_t *parse_return(void)
        statement->statement.type            = STATEMENT_RETURN;
        statement->statement.source_position = token.source_position;
 
-       assert(current_function->type->type == TYPE_FUNCTION);
+       assert(is_type_function(current_function->type));
        function_type_t *function_type = &current_function->type->function;
        type_t          *return_type   = function_type->return_type;
 
@@ -4778,6 +4932,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);
 
@@ -5057,6 +5213,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)