Add the helper function create_Const_from_bool() to create 0/1 constant from a boolea...
[cparser] / parser.c
index 285e9a4..205aed1 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -38,6 +38,7 @@
 #include "lang_features.h"
 #include "walk_statements.h"
 #include "warning.h"
+#include "printer.h"
 #include "adt/bitfiddle.h"
 #include "adt/error.h"
 #include "adt/array.h"
@@ -87,6 +88,7 @@ static scope_t             *file_scope        = NULL;
 static scope_t             *current_scope     = NULL;
 /** Point to the current function declaration if inside a function. */
 static function_t          *current_function  = NULL;
+static entity_t            *current_entity    = NULL;
 static entity_t            *current_init_decl = NULL;
 static switch_statement_t  *current_switch    = NULL;
 static statement_t         *current_loop      = NULL;
@@ -99,9 +101,9 @@ static label_statement_t   *label_first       = NULL;
 static label_statement_t  **label_anchor      = NULL;
 /** current translation unit. */
 static translation_unit_t  *unit              = NULL;
-/** true if we are in a type property context (evaluation only for type. */
+/** true if we are in a type property context (evaluation only for type) */
 static bool                 in_type_prop      = false;
-/** true in we are in a __extension__ context. */
+/** true if we are in an __extension__ context. */
 static bool                 in_gcc_extension  = false;
 static struct obstack       temp_obst;
 static entity_t            *anonymous_entity;
@@ -128,7 +130,7 @@ static unsigned char token_anchor_set[T_LAST_TOKEN];
 static statement_t *parse_compound_statement(bool inside_expression_statement);
 static statement_t *parse_statement(void);
 
-static expression_t *parse_sub_expression(precedence_t);
+static expression_t *parse_subexpression(precedence_t);
 static expression_t *parse_expression(void);
 static type_t       *parse_typename(void);
 static void          parse_externals(void);
@@ -149,13 +151,8 @@ typedef enum declarator_flags_t {
 static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                   declarator_flags_t flags);
 
-static entity_t *record_entity(entity_t *entity, bool is_definition);
-
 static void semantic_comparison(binary_expression_t *expression);
 
-static void create_gnu_builtins(void);
-static void create_microsoft_intrinsics(void);
-
 #define STORAGE_CLASSES       \
        STORAGE_CLASSES_NO_EXTERN \
        case T_extern:
@@ -221,100 +218,52 @@ static void create_microsoft_intrinsics(void);
        TYPE_QUALIFIERS         \
        TYPE_SPECIFIERS
 
-#define EXPRESSION_START           \
-       case '!':                        \
-       case '&':                        \
-       case '(':                        \
-       case '*':                        \
-       case '+':                        \
-       case '-':                        \
-       case '~':                        \
-       case T_ANDAND:                   \
-       case T_CHARACTER_CONSTANT:       \
-       case T_FLOATINGPOINT:            \
-       case T_INTEGER:                  \
-       case T_MINUSMINUS:               \
-       case T_PLUSPLUS:                 \
-       case T_STRING_LITERAL:           \
-       case T_WIDE_CHARACTER_CONSTANT:  \
-       case T_WIDE_STRING_LITERAL:      \
-       case T___FUNCDNAME__:            \
-       case T___FUNCSIG__:              \
-       case T___FUNCTION__:             \
-       case T___PRETTY_FUNCTION__:      \
-       case T___alignof__:              \
-       case T___builtin_classify_type:  \
-       case T___builtin_constant_p:     \
-       case T___builtin_isgreater:      \
-       case T___builtin_isgreaterequal: \
-       case T___builtin_isless:         \
-       case T___builtin_islessequal:    \
-       case T___builtin_islessgreater:  \
-       case T___builtin_isunordered:    \
-       case T___builtin_offsetof:       \
-       case T___builtin_va_arg:         \
-       case T___builtin_va_start:       \
-       case T___builtin_va_copy:        \
-       case T___func__:                 \
-       case T___noop:                   \
-       case T__assume:                  \
-       case T_delete:                   \
-       case T_false:                    \
-       case T_sizeof:                   \
-       case T_throw:                    \
+#define EXPRESSION_START              \
+       case '!':                         \
+       case '&':                         \
+       case '(':                         \
+       case '*':                         \
+       case '+':                         \
+       case '-':                         \
+       case '~':                         \
+       case T_ANDAND:                    \
+       case T_CHARACTER_CONSTANT:        \
+       case T_FLOATINGPOINT:             \
+       case T_FLOATINGPOINT_HEXADECIMAL: \
+       case T_INTEGER:                   \
+       case T_INTEGER_HEXADECIMAL:       \
+       case T_INTEGER_OCTAL:             \
+       case T_MINUSMINUS:                \
+       case T_PLUSPLUS:                  \
+       case T_STRING_LITERAL:            \
+       case T_WIDE_CHARACTER_CONSTANT:   \
+       case T_WIDE_STRING_LITERAL:       \
+       case T___FUNCDNAME__:             \
+       case T___FUNCSIG__:               \
+       case T___FUNCTION__:              \
+       case T___PRETTY_FUNCTION__:       \
+       case T___alignof__:               \
+       case T___builtin_classify_type:   \
+       case T___builtin_constant_p:      \
+       case T___builtin_isgreater:       \
+       case T___builtin_isgreaterequal:  \
+       case T___builtin_isless:          \
+       case T___builtin_islessequal:     \
+       case T___builtin_islessgreater:   \
+       case T___builtin_isunordered:     \
+       case T___builtin_offsetof:        \
+       case T___builtin_va_arg:          \
+       case T___builtin_va_copy:         \
+       case T___builtin_va_start:        \
+       case T___func__:                  \
+       case T___noop:                    \
+       case T__assume:                   \
+       case T_delete:                    \
+       case T_false:                     \
+       case T_sizeof:                    \
+       case T_throw:                     \
        case T_true:
 
-/**
- * Allocate an AST node with given size and
- * initialize all fields with zero.
- */
-static void *allocate_ast_zero(size_t size)
-{
-       void *res = allocate_ast(size);
-       memset(res, 0, size);
-       return res;
-}
-
-/**
- * Returns the size of an entity node.
- *
- * @param kind  the entity kind
- */
-static size_t get_entity_struct_size(entity_kind_t kind)
-{
-       static const size_t sizes[] = {
-               [ENTITY_VARIABLE]        = sizeof(variable_t),
-               [ENTITY_PARAMETER]       = sizeof(parameter_t),
-               [ENTITY_COMPOUND_MEMBER] = sizeof(compound_member_t),
-               [ENTITY_FUNCTION]        = sizeof(function_t),
-               [ENTITY_TYPEDEF]         = sizeof(typedef_t),
-               [ENTITY_STRUCT]          = sizeof(compound_t),
-               [ENTITY_UNION]           = sizeof(compound_t),
-               [ENTITY_ENUM]            = sizeof(enum_t),
-               [ENTITY_ENUM_VALUE]      = sizeof(enum_value_t),
-               [ENTITY_LABEL]           = sizeof(label_t),
-               [ENTITY_LOCAL_LABEL]     = sizeof(label_t),
-               [ENTITY_NAMESPACE]       = sizeof(namespace_t)
-       };
-       assert(kind < lengthof(sizes));
-       assert(sizes[kind] != 0);
-       return sizes[kind];
-}
-
-/**
- * Allocate an entity of given kind and initialize all
- * fields with zero.
- *
- * @param kind   the kind of the entity to allocate
- */
-static entity_t *allocate_entity_zero(entity_kind_t kind)
-{
-       size_t    size   = get_entity_struct_size(kind);
-       entity_t *entity = allocate_ast_zero(size);
-       entity->kind     = kind;
-       return entity;
-}
-
 /**
  * Returns the size of a statement node.
  *
@@ -359,11 +308,15 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_INVALID]                    = sizeof(expression_base_t),
                [EXPR_REFERENCE]                  = sizeof(reference_expression_t),
                [EXPR_REFERENCE_ENUM_VALUE]       = sizeof(reference_expression_t),
-               [EXPR_CONST]                      = sizeof(const_expression_t),
-               [EXPR_CHARACTER_CONSTANT]         = sizeof(const_expression_t),
-               [EXPR_WIDE_CHARACTER_CONSTANT]    = sizeof(const_expression_t),
+               [EXPR_LITERAL_INTEGER]            = sizeof(literal_expression_t),
+               [EXPR_LITERAL_INTEGER_OCTAL]      = sizeof(literal_expression_t),
+               [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t),
+               [EXPR_LITERAL_FLOATINGPOINT]      = sizeof(literal_expression_t),
+               [EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL] = sizeof(literal_expression_t),
+               [EXPR_LITERAL_CHARACTER]          = sizeof(literal_expression_t),
+               [EXPR_LITERAL_WIDE_CHARACTER]     = sizeof(literal_expression_t),
                [EXPR_STRING_LITERAL]             = sizeof(string_literal_expression_t),
-               [EXPR_WIDE_STRING_LITERAL]        = sizeof(wide_string_literal_expression_t),
+               [EXPR_WIDE_STRING_LITERAL]        = sizeof(string_literal_expression_t),
                [EXPR_COMPOUND_LITERAL]           = sizeof(compound_literal_expression_t),
                [EXPR_CALL]                       = sizeof(call_expression_t),
                [EXPR_UNARY_FIRST]                = sizeof(unary_expression_t),
@@ -453,53 +406,10 @@ static statement_t *create_empty_statement(void)
        return allocate_statement_zero(STATEMENT_EMPTY);
 }
 
-/**
- * Returns the size of a type node.
- *
- * @param kind  the type kind
- */
-static size_t get_type_struct_size(type_kind_t kind)
-{
-       static const size_t sizes[] = {
-               [TYPE_ATOMIC]          = sizeof(atomic_type_t),
-               [TYPE_COMPLEX]         = sizeof(complex_type_t),
-               [TYPE_IMAGINARY]       = sizeof(imaginary_type_t),
-               [TYPE_BITFIELD]        = sizeof(bitfield_type_t),
-               [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t),
-               [TYPE_COMPOUND_UNION]  = sizeof(compound_type_t),
-               [TYPE_ENUM]            = sizeof(enum_type_t),
-               [TYPE_FUNCTION]        = sizeof(function_type_t),
-               [TYPE_POINTER]         = sizeof(pointer_type_t),
-               [TYPE_ARRAY]           = sizeof(array_type_t),
-               [TYPE_BUILTIN]         = sizeof(builtin_type_t),
-               [TYPE_TYPEDEF]         = sizeof(typedef_type_t),
-               [TYPE_TYPEOF]          = sizeof(typeof_type_t),
-       };
-       assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1);
-       assert(kind <= TYPE_TYPEOF);
-       assert(sizes[kind] != 0);
-       return sizes[kind];
-}
-
-/**
- * Allocate a type node of given kind and initialize all
- * fields with zero.
- *
- * @param kind             type kind to allocate
- */
-static type_t *allocate_type_zero(type_kind_t kind)
-{
-       size_t  size = get_type_struct_size(kind);
-       type_t *res  = obstack_alloc(type_obst, size);
-       memset(res, 0, size);
-       res->base.kind = kind;
-
-       return res;
-}
-
 static function_parameter_t *allocate_parameter(type_t *const type)
 {
-       function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param));
+       function_parameter_t *const param
+               = obstack_alloc(type_obst, sizeof(*param));
        memset(param, 0, sizeof(*param));
        param->type = type;
        return param;
@@ -569,6 +479,16 @@ static inline void next_token(void)
 #endif
 }
 
+static inline bool next_if(int const type)
+{
+       if (token.type == type) {
+               next_token();
+               return true;
+       } else {
+               return false;
+       }
+}
+
 /**
  * Return the next token with a given lookahead.
  */
@@ -702,8 +622,7 @@ static void eat_until_anchor(void)
 static void eat_block(void)
 {
        eat_until_matching_token('{');
-       if (token.type == '}')
-               next_token();
+       next_if('}');
 }
 
 #define eat(token_type) (assert(token.type == (token_type)), next_token())
@@ -739,7 +658,7 @@ static void type_error_incompatible(const char *msg,
 /**
  * Expect the current token is the expected token.
  * If not, generate an error, eat the current statement,
- * and goto the end_error label.
+ * and goto the error_label label.
  */
 #define expect(expected, error_label)                     \
        do {                                                  \
@@ -747,8 +666,7 @@ static void type_error_incompatible(const char *msg,
                        parse_error_expected(NULL, (expected), NULL); \
                        add_anchor_token(expected);                   \
                        eat_until_anchor();                           \
-                       if (token.type == expected)                   \
-                               next_token();                             \
+                       next_if((expected));                          \
                        rem_anchor_token(expected);                   \
                        goto error_label;                             \
                }                                                 \
@@ -905,7 +823,7 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
                }
        }
 
-       ARR_SHRINKLEN(*stack_ptr, (int) new_top);
+       ARR_SHRINKLEN(*stack_ptr, new_top);
 }
 
 /**
@@ -998,10 +916,13 @@ static bool is_null_pointer_constant(const expression_t *expression)
        }
 
        type_t *const type = skip_typeref(expression->base.type);
-       return
-               is_type_integer(type)              &&
-               is_constant_expression(expression) &&
-               !fold_constant_to_bool(expression);
+       if (!is_type_integer(type))
+               return false;
+       switch (is_constant_expression(expression)) {
+               case EXPR_CLASS_ERROR:    return true;
+               case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression);
+               default:                  return false;
+       }
 }
 
 /**
@@ -1137,8 +1058,8 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
                        return ASSIGN_WARNING_POINTER_FROM_INT;
                }
        } else if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
-           (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
-               && is_type_pointer(type_right))) {
+                       (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
+                               && is_type_pointer(type_right))) {
                return ASSIGN_SUCCESS;
        } else if ((is_type_compound(type_left)  && is_type_compound(type_right))
                        || (is_type_builtin(type_left) && is_type_builtin(type_right))) {
@@ -1159,9 +1080,9 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
 
 static expression_t *parse_constant_expression(void)
 {
-       expression_t *result = parse_sub_expression(PREC_CONDITIONAL);
+       expression_t *result = parse_subexpression(PREC_CONDITIONAL);
 
-       if (!is_constant_expression(result)) {
+       if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
                errorf(&result->base.source_position,
                       "expression '%E' is not constant", result);
        }
@@ -1171,18 +1092,26 @@ static expression_t *parse_constant_expression(void)
 
 static expression_t *parse_assignment_expression(void)
 {
-       return parse_sub_expression(PREC_ASSIGNMENT);
+       return parse_subexpression(PREC_ASSIGNMENT);
+}
+
+static void warn_string_concat(const source_position_t *pos)
+{
+       if (warning.traditional) {
+               warningf(pos, "traditional C rejects string constant concatenation");
+       }
 }
 
 static string_t parse_string_literals(void)
 {
        assert(token.type == T_STRING_LITERAL);
-       string_t result = token.v.string;
+       string_t result = token.literal;
 
        next_token();
 
        while (token.type == T_STRING_LITERAL) {
-               result = concat_strings(&result, &token.v.string);
+               warn_string_concat(&token.source_position);
+               result = concat_strings(&result, &token.literal);
                next_token();
        }
 
@@ -1242,18 +1171,15 @@ static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
  */
 static attribute_argument_t *parse_attribute_arguments(void)
 {
-       if (token.type == ')')
-               return NULL;
-
-       attribute_argument_t *first = NULL;
-       attribute_argument_t *last  = NULL;
-       while (true) {
+       attribute_argument_t  *first  = NULL;
+       attribute_argument_t **anchor = &first;
+       if (token.type != ')') do {
                attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument));
 
                /* is it an identifier */
                if (token.type == T_IDENTIFIER
                                && (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) {
-                       symbol_t *symbol   = token.v.symbol;
+                       symbol_t *symbol   = token.symbol;
                        argument->kind     = ATTRIBUTE_ARGUMENT_SYMBOL;
                        argument->v.symbol = symbol;
                        next_token();
@@ -1266,20 +1192,10 @@ static attribute_argument_t *parse_attribute_arguments(void)
                }
 
                /* append argument */
-               if (last == NULL) {
-                       first = argument;
-               } else {
-                       last->next = argument;
-               }
-               last = argument;
-
-               if (token.type == ',') {
-                       next_token();
-                       continue;
-               }
-               expect(')', end_error);
-               break;
-       }
+               *anchor = argument;
+               anchor  = &argument->next;
+       } while (next_if(','));
+       expect(')', end_error);
 
        return first;
 
@@ -1306,7 +1222,7 @@ static symbol_t *get_symbol_from_token(void)
 {
        switch(token.type) {
        case T_IDENTIFIER:
-               return token.v.symbol;
+               return token.symbol;
        case T_auto:
        case T_char:
        case T_double:
@@ -1348,7 +1264,7 @@ static attribute_t *parse_attribute_gnu_single(void)
        symbol_t *symbol = get_symbol_from_token();
        if (symbol == NULL) {
                parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
-               goto end_error;
+               return NULL;
        }
 
        const char *name = symbol->string;
@@ -1373,50 +1289,30 @@ static attribute_t *parse_attribute_gnu_single(void)
        attribute_t *attribute = allocate_attribute_zero(kind);
 
        /* parse arguments */
-       if (token.type == '(') {
-               next_token();
+       if (next_if('('))
                attribute->a.arguments = parse_attribute_arguments();
-       }
 
        return attribute;
-
-end_error:
-       return NULL;
 }
 
 static attribute_t *parse_attribute_gnu(void)
 {
-       attribute_t *first = NULL;
-       attribute_t *last  = NULL;
+       attribute_t  *first  = NULL;
+       attribute_t **anchor = &first;
 
        eat(T___attribute__);
        expect('(', end_error);
        expect('(', end_error);
 
-       if (token.type == ')') {
-               next_token();
-               expect(')', end_error);
-               return first;
-       }
-
-       while (true) {
+       if (token.type != ')') do {
                attribute_t *attribute = parse_attribute_gnu_single();
                if (attribute == NULL)
                        goto end_error;
 
-               if (last == NULL) {
-                       first = attribute;
-               } else {
-                       last->next = attribute;
-               }
-               last = attribute;
-
-               if (token.type == ')') {
-                       next_token();
-                       break;
-               }
-               expect(',', end_error);
-       }
+               *anchor = attribute;
+               anchor  = &attribute->next;
+       } while (next_if(','));
+       expect(')', end_error);
        expect(')', end_error);
 
 end_error:
@@ -1426,12 +1322,10 @@ end_error:
 /** Parse attributes. */
 static attribute_t *parse_attributes(attribute_t *first)
 {
-       attribute_t *last = first;
-       while (true) {
-               if (last != NULL) {
-                       while (last->next != NULL)
-                               last = last->next;
-               }
+       attribute_t **anchor = &first;
+       for (;;) {
+               while (*anchor != NULL)
+                       anchor = &(*anchor)->next;
 
                attribute_t *attribute;
                switch (token.type) {
@@ -1475,12 +1369,8 @@ static attribute_t *parse_attributes(attribute_t *first)
                        return first;
                }
 
-               if (last == NULL) {
-                       first = attribute;
-               } else {
-                       last->next = attribute;
-               }
-               last = attribute;
+               *anchor = attribute;
+               anchor  = &attribute->next;
        }
 }
 
@@ -1695,11 +1585,9 @@ unary:
                        determine_lhs_ent(expr->va_starte.ap, lhs_ent);
                        return;
 
+               EXPR_LITERAL_CASES
                case EXPR_UNKNOWN:
                case EXPR_INVALID:
-               case EXPR_CONST:
-               case EXPR_CHARACTER_CONSTANT:
-               case EXPR_WIDE_CHARACTER_CONSTANT:
                case EXPR_STRING_LITERAL:
                case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO init?
@@ -1721,10 +1609,10 @@ unary:
 
 static designator_t *parse_designation(void)
 {
-       designator_t *result = NULL;
-       designator_t *last   = NULL;
+       designator_t  *result = NULL;
+       designator_t **anchor = &result;
 
-       while (true) {
+       for (;;) {
                designator_t *designator;
                switch (token.type) {
                case '[':
@@ -1745,7 +1633,7 @@ static designator_t *parse_designation(void)
                                                     T_IDENTIFIER, NULL);
                                return NULL;
                        }
-                       designator->symbol = token.v.symbol;
+                       designator->symbol = token.symbol;
                        next_token();
                        break;
                default:
@@ -1754,18 +1642,14 @@ static designator_t *parse_designation(void)
                }
 
                assert(designator != NULL);
-               if (last != NULL) {
-                       last->next = designator;
-               } else {
-                       result = designator;
-               }
-               last = designator;
+               *anchor = designator;
+               anchor  = &designator->next;
        }
 end_error:
        return NULL;
 }
 
-static initializer_t *initializer_from_string(array_type_t *type,
+static initializer_t *initializer_from_string(array_type_t *const type,
                                               const string_t *const string)
 {
        /* TODO: check len vs. size of array type */
@@ -1778,7 +1662,7 @@ static initializer_t *initializer_from_string(array_type_t *type,
 }
 
 static initializer_t *initializer_from_wide_string(array_type_t *const type,
-                                                   wide_string_t *const string)
+                                                   const string_t *const string)
 {
        /* TODO: check len vs. size of array type */
        (void) type;
@@ -1802,6 +1686,7 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
        type_t *type           = skip_typeref(orig_type);
        type_t *expr_type_orig = expression->base.type;
        type_t *expr_type      = skip_typeref(expr_type_orig);
+
        if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
                array_type_t *const array_type   = &type->array;
                type_t       *const element_type = skip_typeref(array_type->element_type);
@@ -1809,26 +1694,26 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                if (element_type->kind == TYPE_ATOMIC) {
                        atomic_type_kind_t akind = element_type->atomic.akind;
                        switch (expression->kind) {
-                               case EXPR_STRING_LITERAL:
-                                       if (akind == ATOMIC_TYPE_CHAR
-                                                       || akind == ATOMIC_TYPE_SCHAR
-                                                       || akind == ATOMIC_TYPE_UCHAR) {
-                                               return initializer_from_string(array_type,
-                                                       &expression->string.value);
-                                       }
-                                       break;
+                       case EXPR_STRING_LITERAL:
+                               if (akind == ATOMIC_TYPE_CHAR
+                                               || akind == ATOMIC_TYPE_SCHAR
+                                               || akind == ATOMIC_TYPE_UCHAR) {
+                                       return initializer_from_string(array_type,
+                                                       &expression->string_literal.value);
+                               }
+                               break;
 
-                               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);
-                                       }
-                                       break;
+                       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->string_literal.value);
                                }
+                               break;
+                       }
 
-                               default:
-                                       break;
+                       default:
+                               break;
                        }
                }
        }
@@ -1850,8 +1735,9 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
  */
 static bool is_initializer_constant(const expression_t *expression)
 {
-       return is_constant_expression(expression)
-               || is_address_constant(expression);
+       return
+               is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+               is_address_constant(expression)    != EXPR_CLASS_VARIABLE;
 }
 
 /**
@@ -1864,20 +1750,19 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 {
        /* there might be extra {} hierarchies */
        int braces = 0;
-       if (token.type == '{') {
+       if (next_if('{')) {
                if (warning.other)
                        warningf(HERE, "extra curly braces around scalar initializer");
                do {
                        ++braces;
-                       next_token();
-               } while (token.type == '{');
+               } while (next_if('{'));
        }
 
        expression_t *expression = parse_assignment_expression();
        mark_vars_read(expression, NULL);
        if (must_be_constant && !is_initializer_constant(expression)) {
                errorf(&expression->base.source_position,
-                      "Initialisation expression '%E' is not constant",
+                      "initialisation expression '%E' is not constant",
                       expression);
        }
 
@@ -1893,9 +1778,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 
        bool additional_warning_displayed = false;
        while (braces > 0) {
-               if (token.type == ',') {
-                       next_token();
-               }
+               next_if(',');
                if (token.type != '}') {
                        if (!additional_warning_displayed && warning.other) {
                                warningf(HERE, "additional elements in scalar initializer");
@@ -2085,7 +1968,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                        type_t *real_type = skip_typeref(iter->declaration.type);
                                        if (real_type->kind == TYPE_BITFIELD) {
                                                errorf(&designator->source_position,
-                                                      "offsetof designator '%Y' may not specify bitfield",
+                                                      "offsetof designator '%Y' must not specify bitfield",
                                                       symbol);
                                                goto failed;
                                        }
@@ -2117,8 +2000,8 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                        long array_size = type->array.size;
                                        if (index >= array_size) {
                                                errorf(&designator->source_position,
-                                                      "designator [%E] (%d) exceeds array size %d",
-                                                      array_index, index, array_size);
+                                                      "designator [%E] (%d) exceeds array size %d",
+                                                      array_index, index, array_size);
                                        }
                                }
                        }
@@ -2193,8 +2076,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
  */
 static void skip_initializers(void)
 {
-       if (token.type == '{')
-               next_token();
+       next_if('{');
 
        while (token.type != '}') {
                if (token.type == T_EOF)
@@ -2246,7 +2128,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                        /* GNU-style designator ("identifier: value") */
                        designator = allocate_ast_zero(sizeof(designator[0]));
                        designator->source_position = token.source_position;
-                       designator->symbol          = token.v.symbol;
+                       designator->symbol          = token.symbol;
                        eat(T_IDENTIFIER);
                        eat(':');
 
@@ -2311,6 +2193,8 @@ finish_designator:
 
                        if (type == NULL) {
                                /* we are already outside, ... */
+                               if (outer_type == NULL)
+                                       goto error_parse_next;
                                type_t *const outer_type_skip = skip_typeref(outer_type);
                                if (is_type_compound(outer_type_skip) &&
                                    !outer_type_skip->compound.compound->complete) {
@@ -2325,9 +2209,7 @@ finish_designator:
                                        && outer_type != NULL) {
                                sub = initializer_from_expression(outer_type, expression);
                                if (sub != NULL) {
-                                       if (token.type == ',') {
-                                               next_token();
-                                       }
+                                       next_if(',');
                                        if (token.type != '}' && warning.other) {
                                                warningf(HERE, "excessive elements in initializer for type '%T'",
                                                                 orig_type);
@@ -2425,6 +2307,18 @@ end_error:
        return NULL;
 }
 
+static expression_t *make_size_literal(size_t value)
+{
+       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_INTEGER);
+       literal->base.type    = type_size_t;
+
+       char buf[128];
+       snprintf(buf, sizeof(buf), "%u", (unsigned) value);
+       literal->literal.value = make_string(buf);
+
+       return literal;
+}
+
 /**
  * Parses an initializer. Parsers either a compound literal
  * (env->declaration == NULL) or an initializer of a declaration.
@@ -2432,7 +2326,7 @@ end_error:
 static initializer_t *parse_initializer(parse_initializer_env_t *env)
 {
        type_t        *type      = skip_typeref(env->type);
-       size_t         max_index = 0xdeadbeaf;   // TODO: Resolve this uninitialized variable problem
+       size_t         max_index = 0;
        initializer_t *result;
 
        if (is_type_scalar(type)) {
@@ -2490,13 +2384,9 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                        internal_errorf(HERE, "invalid initializer type");
                }
 
-               expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
-               cnst->base.type          = type_size_t;
-               cnst->conste.v.int_value = size;
-
                type_t *new_type = duplicate_type(type);
 
-               new_type->array.size_expression   = cnst;
+               new_type->array.size_expression   = make_size_literal(size);
                new_type->array.size_constant     = true;
                new_type->array.has_implicit_size = true;
                new_type->array.size              = size;
@@ -2515,17 +2405,14 @@ static void append_entity(scope_t *scope, entity_t *entity)
        } else {
                scope->entities = entity;
        }
-       scope->last_entity = entity;
+       entity->base.parent_entity = current_entity;
+       scope->last_entity         = entity;
 }
 
 
 static compound_t *parse_compound_type_specifier(bool is_struct)
 {
-       if (is_struct) {
-               eat(T_struct);
-       } else {
-               eat(T_union);
-       }
+       eat(is_struct ? T_struct : T_union);
 
        symbol_t    *symbol   = NULL;
        compound_t  *compound = NULL;
@@ -2538,7 +2425,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
        if (token.type == T_IDENTIFIER) {
                /* the compound has a name, check if we have seen it already */
-               symbol = token.v.symbol;
+               symbol = token.symbol;
                next_token();
 
                entity_t *entity = get_tag(symbol, kind);
@@ -2623,12 +2510,11 @@ static void parse_enum_entries(type_t *const enum_type)
 
                entity_t *entity             = allocate_entity_zero(ENTITY_ENUM_VALUE);
                entity->enum_value.enum_type = enum_type;
-               entity->base.symbol          = token.v.symbol;
+               entity->base.symbol          = token.symbol;
                entity->base.source_position = token.source_position;
                next_token();
 
-               if (token.type == '=') {
-                       next_token();
+               if (next_if('=')) {
                        expression_t *value = parse_constant_expression();
 
                        value = create_implicit_cast(value, enum_type);
@@ -2638,11 +2524,7 @@ static void parse_enum_entries(type_t *const enum_type)
                }
 
                record_entity(entity, false);
-
-               if (token.type != ',')
-                       break;
-               next_token();
-       } while (token.type != '}');
+       } while (next_if(',') && token.type != '}');
        rem_anchor_token('}');
 
        expect('}', end_error);
@@ -2653,33 +2535,38 @@ end_error:
 
 static type_t *parse_enum_specifier(void)
 {
-       entity_t        *entity;
-       symbol_t        *symbol;
+       entity_t *entity;
+       symbol_t *symbol;
 
        eat(T_enum);
-       if (token.type == T_IDENTIFIER) {
-               symbol = token.v.symbol;
-               next_token();
+       switch (token.type) {
+               case T_IDENTIFIER:
+                       symbol = token.symbol;
+                       next_token();
 
-               entity = get_tag(symbol, ENTITY_ENUM);
-               if (entity != NULL) {
-                       if (entity->base.parent_scope != current_scope &&
-                                       (token.type == '{' || token.type == ';')) {
-                               /* we're in an inner scope and have a definition. Shadow
-                                * existing definition in outer scope */
-                               entity = NULL;
-                       } else if (entity->enume.complete && token.type == '{') {
-                               errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
-                                               symbol, &entity->base.source_position);
+                       entity = get_tag(symbol, ENTITY_ENUM);
+                       if (entity != NULL) {
+                               if (entity->base.parent_scope != current_scope &&
+                                               (token.type == '{' || token.type == ';')) {
+                                       /* we're in an inner scope and have a definition. Shadow
+                                        * existing definition in outer scope */
+                                       entity = NULL;
+                               } else if (entity->enume.complete && token.type == '{') {
+                                       errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
+                                                       symbol, &entity->base.source_position);
+                               }
                        }
-               }
-       } else if (token.type != '{') {
-               parse_error_expected("while parsing enum type specifier",
-                                    T_IDENTIFIER, '{', NULL);
-               return NULL;
-       } else {
-               entity  = NULL;
-               symbol  = NULL;
+                       break;
+
+               case '{':
+                       entity = NULL;
+                       symbol = NULL;
+                       break;
+
+               default:
+                       parse_error_expected("while parsing enum type specifier",
+                                       T_IDENTIFIER, '{', NULL);
+                       return NULL;
        }
 
        if (entity == NULL) {
@@ -2741,29 +2628,21 @@ static type_t *parse_typeof(void)
        bool old_gcc_extension = in_gcc_extension;
        in_type_prop           = true;
 
-       while (token.type == T___extension__) {
+       while (next_if(T___extension__)) {
                /* This can be a prefix to a typename or an expression. */
-               next_token();
                in_gcc_extension = true;
        }
        switch (token.type) {
        case T_IDENTIFIER:
-               if (is_typedef_symbol(token.v.symbol)) {
+               if (is_typedef_symbol(token.symbol)) {
+       TYPENAME_START
                        type = parse_typename();
                } else {
+       default:
                        expression = parse_expression();
                        type       = revert_automatic_type_conversion(expression);
                }
                break;
-
-       TYPENAME_START
-               type = parse_typename();
-               break;
-
-       default:
-               expression = parse_expression();
-               type       = expression->base.type;
-               break;
        }
        in_type_prop     = old_type_prop;
        in_gcc_extension = old_gcc_extension;
@@ -2830,7 +2709,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
        attribute_property_argument_t *property
                = allocate_ast_zero(sizeof(*property));
 
-       while (true) {
+       do {
                if (token.type != T_IDENTIFIER) {
                        parse_error_expected("while parsing property declspec",
                                             T_IDENTIFIER, NULL);
@@ -2838,7 +2717,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
                }
 
                bool is_put;
-               symbol_t *symbol = token.v.symbol;
+               symbol_t *symbol = token.symbol;
                next_token();
                if (strcmp(symbol->string, "put") == 0) {
                        is_put = true;
@@ -2855,15 +2734,12 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
                        goto end_error;
                }
                if (is_put) {
-                       property->put_symbol = token.v.symbol;
+                       property->put_symbol = token.symbol;
                } else {
-                       property->get_symbol = token.v.symbol;
+                       property->get_symbol = token.symbol;
                }
                next_token();
-               if (token.type == ')')
-                       break;
-               expect(',', end_error);
-       }
+       } while (next_if(','));
 
        attribute->a.property = property;
 
@@ -2876,11 +2752,10 @@ end_error:
 static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
 {
        attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
-       if (token.type == T_restrict) {
+       if (next_if(T_restrict)) {
                kind = ATTRIBUTE_MS_RESTRICT;
-               next_token();
        } else if (token.type == T_IDENTIFIER) {
-               const char *name = token.v.symbol->string;
+               const char *name = token.symbol->string;
                next_token();
                for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
                     ++k) {
@@ -2906,10 +2781,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
        }
 
        /* parse arguments */
-       if (token.type == '(') {
-               next_token();
+       if (next_if('('))
                attribute->a.arguments = parse_attribute_arguments();
-       }
 
        return attribute;
 }
@@ -2920,37 +2793,24 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 
        expect('(', end_error);
 
-       if (token.type == ')') {
-               next_token();
+       if (next_if(')'))
                return NULL;
-       }
 
        add_anchor_token(')');
 
-       attribute_t *last = first;
-       while (true) {
-               if (last != NULL) {
-                       while (last->next != NULL)
-                               last = last->next;
-               }
+       attribute_t **anchor = &first;
+       do {
+               while (*anchor != NULL)
+                       anchor = &(*anchor)->next;
 
                attribute_t *attribute
                        = parse_microsoft_extended_decl_modifier_single();
                if (attribute == NULL)
                        goto end_error;
 
-               if (last == NULL) {
-                       first = attribute;
-               } else {
-                       last->next = attribute;
-               }
-               last = attribute;
-
-               if (token.type == ')') {
-                       break;
-               }
-               expect(',', end_error);
-       }
+               *anchor = attribute;
+               anchor  = &attribute->next;
+       } while (next_if(','));
 
        rem_anchor_token(')');
        expect(')', end_error);
@@ -3029,10 +2889,10 @@ check_thread_storage_class:
                                                break;
 
                                                char const* wrong;
-                                       case STORAGE_CLASS_AUTO:     wrong = "auto";     goto wrong_thread_stoarge_class;
-                                       case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class;
-                                       case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_stoarge_class;
-wrong_thread_stoarge_class:
+                                       case STORAGE_CLASS_AUTO:     wrong = "auto";     goto wrong_thread_storage_class;
+                                       case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class;
+                                       case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_storage_class;
+wrong_thread_storage_class:
                                                errorf(HERE, "'__thread' used with '%s'", wrong);
                                                break;
                                }
@@ -3169,7 +3029,7 @@ wrong_thread_stoarge_class:
                                }
                        }
 
-                       type_t *const typedef_type = get_typedef_type(token.v.symbol);
+                       type_t *const typedef_type = get_typedef_type(token.symbol);
                        if (typedef_type == NULL) {
                                /* Be somewhat resilient to typos like 'vodi f()' at the beginning of a
                                 * declaration, so it doesn't generate 'implicit int' followed by more
@@ -3183,7 +3043,7 @@ wrong_thread_stoarge_class:
                                                errorf(HERE, "%K does not name a type", &token);
 
                                                entity_t *entity =
-                                                       create_error_entity(token.v.symbol, ENTITY_TYPEDEF);
+                                                       create_error_entity(token.symbol, ENTITY_TYPEDEF);
 
                                                type = allocate_type_zero(TYPE_TYPEDEF);
                                                type->typedeft.typedefe = &entity->typedefe;
@@ -3412,7 +3272,6 @@ warn_about_long_long:
 
 end_error:
        specifiers->type = type_error_type;
-       return;
 }
 
 static type_qualifiers_t parse_type_qualifiers(void)
@@ -3447,18 +3306,13 @@ static void parse_identifier_list(scope_t *scope)
                entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER);
                entity->base.source_position = token.source_position;
                entity->base.namespc         = NAMESPACE_NORMAL;
-               entity->base.symbol          = token.v.symbol;
+               entity->base.symbol          = token.symbol;
                /* a K&R parameter has no type, yet */
                next_token();
 
                if (scope != NULL)
                        append_entity(scope, entity);
-
-               if (token.type != ',') {
-                       break;
-               }
-               next_token();
-       } while (token.type == T_IDENTIFIER);
+       } while (next_if(',') && token.type == T_IDENTIFIER);
 }
 
 static entity_t *parse_parameter(void)
@@ -3494,7 +3348,7 @@ static bool has_parameters(void)
 {
        /* func(void) is not a parameter */
        if (token.type == T_IDENTIFIER) {
-               entity_t const *const entity = get_entity(token.v.symbol, NAMESPACE_NORMAL);
+               entity_t const *const entity = get_entity(token.symbol, NAMESPACE_NORMAL);
                if (entity == NULL)
                        return true;
                if (entity->kind != ENTITY_TYPEDEF)
@@ -3521,7 +3375,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
        int saved_comma_state = save_and_reset_anchor_state(',');
 
        if (token.type == T_IDENTIFIER &&
-           !is_typedef_symbol(token.v.symbol)) {
+           !is_typedef_symbol(token.symbol)) {
                token_type_t la1_type = (token_type_t)look_ahead(1)->type;
                if (la1_type == ',' || la1_type == ')') {
                        type->kr_style_parameters = true;
@@ -3539,7 +3393,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
 
        if (has_parameters()) {
                function_parameter_t **anchor = &type->parameters;
-               for (;;) {
+               do {
                        switch (token.type) {
                        case T_DOTDOTDOT:
                                next_token();
@@ -3575,11 +3429,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                        default:
                                goto parameters_finished;
                        }
-                       if (token.type != ',') {
-                               goto parameters_finished;
-                       }
-                       next_token();
-               }
+               } while (next_if(','));
        }
 
 
@@ -3638,60 +3488,64 @@ union construct_type_t {
        parsed_array_t            array;
 };
 
+static construct_type_t *allocate_declarator_zero(construct_type_kind_t const kind, size_t const size)
+{
+       construct_type_t *const cons = obstack_alloc(&temp_obst, size);
+       memset(cons, 0, size);
+       cons->kind = kind;
+       return cons;
+}
+
+/* Â§6.7.5.1 */
 static construct_type_t *parse_pointer_declarator(void)
 {
        eat('*');
 
-       parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
-       memset(pointer, 0, sizeof(pointer[0]));
-       pointer->base.kind       = CONSTRUCT_POINTER;
-       pointer->type_qualifiers = parse_type_qualifiers();
-       //pointer->base_variable       = base_variable;
+       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t));
+       cons->pointer.type_qualifiers = parse_type_qualifiers();
+       //cons->pointer.base_variable   = base_variable;
 
-       return (construct_type_t*) pointer;
+       return cons;
 }
 
+/* ISO/IEC 14882:1998(E) Â§8.3.2 */
 static construct_type_t *parse_reference_declarator(void)
 {
        eat('&');
 
-       construct_type_t   *cons      = obstack_alloc(&temp_obst, sizeof(cons->reference));
-       parsed_reference_t *reference = &cons->reference;
-       memset(reference, 0, sizeof(*reference));
-       cons->kind = CONSTRUCT_REFERENCE;
+       if (!(c_mode & _CXX))
+               errorf(HERE, "references are only available for C++");
+
+       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t));
 
        return cons;
 }
 
+/* Â§6.7.5.2 */
 static construct_type_t *parse_array_declarator(void)
 {
        eat('[');
        add_anchor_token(']');
 
-       construct_type_t *cons  = obstack_alloc(&temp_obst, sizeof(cons->array));
-       parsed_array_t   *array = &cons->array;
-       memset(array, 0, sizeof(*array));
-       cons->kind = CONSTRUCT_ARRAY;
+       construct_type_t *const cons  = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t));
+       parsed_array_t   *const array = &cons->array;
 
-       if (token.type == T_static) {
-               array->is_static = true;
-               next_token();
-       }
+       bool is_static = next_if(T_static);
 
        type_qualifiers_t type_qualifiers = parse_type_qualifiers();
-       if (type_qualifiers != 0) {
-               if (token.type == T_static) {
-                       array->is_static = true;
-                       next_token();
-               }
-       }
+
+       if (!is_static)
+               is_static = next_if(T_static);
+
        array->type_qualifiers = type_qualifiers;
+       array->is_static       = is_static;
 
+       expression_t *size = NULL;
        if (token.type == '*' && look_ahead(1)->type == ']') {
                array->is_variable = true;
                next_token();
        } else if (token.type != ']') {
-               expression_t *const size = parse_assignment_expression();
+               size = parse_assignment_expression();
 
                /* Â§6.7.5.2:1  Array size must have integer type */
                type_t *const orig_type = size->base.type;
@@ -3706,6 +3560,9 @@ static construct_type_t *parse_array_declarator(void)
                mark_vars_read(size, NULL);
        }
 
+       if (is_static && size == NULL)
+               errorf(HERE, "static array parameters require a size");
+
        rem_anchor_token(']');
        expect(']', end_error);
 
@@ -3713,6 +3570,7 @@ end_error:
        return cons;
 }
 
+/* Â§6.7.5.3 */
 static construct_type_t *parse_function_declarator(scope_t *scope)
 {
        type_t          *type  = allocate_type_zero(TYPE_FUNCTION);
@@ -3723,11 +3581,8 @@ static construct_type_t *parse_function_declarator(scope_t *scope)
 
        parse_parameters(ftype, scope);
 
-       construct_type_t          *cons     = obstack_alloc(&temp_obst, sizeof(cons->function));
-       construct_function_type_t *function = &cons->function;
-       memset(function, 0, sizeof(*function));
-       cons->kind              = CONSTRUCT_FUNCTION;
-       function->function_type = type;
+       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
+       cons->function.function_type = type;
 
        return cons;
 }
@@ -3742,6 +3597,7 @@ typedef struct parse_declarator_env_t {
        attribute_t       *attributes;
 } parse_declarator_env_t;
 
+/* Â§6.7.5 */
 static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
 {
        /* construct a single linked list of construct_type_t's which describe
@@ -3756,32 +3612,11 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
                //variable_t       *based = NULL; /* MS __based extension */
                switch (token.type) {
                        case '&':
-                               if (!(c_mode & _CXX))
-                                       errorf(HERE, "references are only available for C++");
                                type = parse_reference_declarator();
                                break;
 
                        case T__based: {
-#if 0
-                               source_position_t const pos = *HERE;
-                               next_token();
-                               expect('(', end_error);
-                               add_anchor_token(')');
-                               based = parse_microsoft_based();
-                               rem_anchor_token(')');
-                               expect(')', end_error);
-                               if (token.type != '*') {
-                                       if (token.type == T__based) {
-                                               errorf(&pos, "__based type modifier specified more than once");
-                                       } else if (warning.other) {
-                                               warningf(&pos,
-                                                               "__based does not precede a pointer declarator, ignored");
-                                       }
-                                       continue;
-                               }
-#else
-                               panic("based currently disabled");
-#endif
+                               panic("based not supported anymore");
                                /* FALLTHROUGH */
                        }
 
@@ -3801,11 +3636,6 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
        }
 
 ptr_operator_end: ;
-#if 0
-       modifiers      |= env->modifiers;
-       env->modifiers  = modifiers;
-#endif
-
        construct_type_t *inner_types = NULL;
 
        switch (token.type) {
@@ -3813,7 +3643,7 @@ ptr_operator_end: ;
                if (env->must_be_abstract) {
                        errorf(HERE, "no identifier expected in typename");
                } else {
-                       env->symbol          = token.v.symbol;
+                       env->symbol          = token.symbol;
                        env->source_position = token.source_position;
                }
                next_token();
@@ -3832,12 +3662,16 @@ ptr_operator_end: ;
                        }
                        rem_anchor_token(')');
                        expect(')', end_error);
+               } else if (!env->may_be_abstract) {
+                       errorf(HERE, "declarator must have a name");
+                       goto error_out;
                }
                break;
        default:
                if (env->may_be_abstract)
                        break;
                parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
+error_out:
                eat_until_anchor();
                return NULL;
        }
@@ -3880,7 +3714,8 @@ end_error:
        return NULL;
 }
 
-static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
+static type_t *construct_declarator_type(construct_type_t *construct_list,
+                                         type_t *type)
 {
        construct_type_t *iter = construct_list;
        for (; iter != NULL; iter = iter->base.next) {
@@ -3948,24 +3783,31 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_
                        array_type->array.size_expression = size_expression;
 
                        if (size_expression != NULL) {
-                               if (is_constant_expression(size_expression)) {
-                                       long const size
-                                               = fold_constant_to_int(size_expression);
-                                       array_type->array.size          = size;
-                                       array_type->array.size_constant = true;
-                                       /* Â§6.7.5.2:1  If the expression is a constant expression, it shall
-                                        * have a value greater than zero. */
-                                       if (size <= 0) {
-                                               if (size < 0 || !GNU_MODE) {
-                                                       errorf(&size_expression->base.source_position,
-                                                                       "size of array must be greater than zero");
-                                               } else if (warning.other) {
-                                                       warningf(&size_expression->base.source_position,
-                                                                       "zero length arrays are a GCC extension");
+                               switch (is_constant_expression(size_expression)) {
+                                       case EXPR_CLASS_CONSTANT: {
+                                               long const size = fold_constant_to_int(size_expression);
+                                               array_type->array.size          = size;
+                                               array_type->array.size_constant = true;
+                                               /* Â§6.7.5.2:1  If the expression is a constant expression, it shall
+                                                * have a value greater than zero. */
+                                               if (size <= 0) {
+                                                       if (size < 0 || !GNU_MODE) {
+                                                               errorf(&size_expression->base.source_position,
+                                                                               "size of array must be greater than zero");
+                                                       } else if (warning.other) {
+                                                               warningf(&size_expression->base.source_position,
+                                                                               "zero length arrays are a GCC extension");
+                                                       }
                                                }
+                                               break;
                                        }
-                               } else {
-                                       array_type->array.is_vla = true;
+
+                                       case EXPR_CLASS_VARIABLE:
+                                               array_type->array.is_vla = true;
+                                               break;
+
+                                       case EXPR_CLASS_ERROR:
+                                               break;
                                }
                        }
 
@@ -4039,15 +3881,11 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        attribute_t *attributes = parse_attributes(env.attributes);
        /* append (shared) specifier attribute behind attributes of this
-          declarator */
-       if (attributes != NULL) {
-               attribute_t *last = attributes;
-               while (last->next != NULL)
-                       last = last->next;
-               last->next = specifiers->attributes;
-       } else {
-               attributes = specifiers->attributes;
-       }
+        * declarator */
+       attribute_t **anchor = &attributes;
+       while (*anchor != NULL)
+               anchor = &(*anchor)->next;
+       *anchor = specifiers->attributes;
 
        entity_t *entity;
        if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
@@ -4104,10 +3942,10 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                bool in_function_scope = current_function != NULL;
 
                                if (specifiers->thread_local || (
-                                     specifiers->storage_class != STORAGE_CLASS_EXTERN &&
-                                         specifiers->storage_class != STORAGE_CLASS_NONE   &&
-                                         (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
-                                  )) {
+                                                       specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+                                                       specifiers->storage_class != STORAGE_CLASS_NONE   &&
+                                                       (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
+                                               )) {
                                        errorf(&env.source_position,
                                                        "invalid storage class for function '%Y'", env.symbol);
                                }
@@ -4275,11 +4113,52 @@ static bool is_error_entity(entity_t *const ent)
        return false;
 }
 
+static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
+{
+       for (const attribute_t *tattr = list; tattr != NULL; tattr = tattr->next) {
+               if (attributes_equal(tattr, attr))
+                       return true;
+       }
+       return false;
+}
+
+/**
+ * test wether new_list contains any attributes not included in old_list
+ */
+static bool has_new_attributes(const attribute_t *old_list,
+                               const attribute_t *new_list)
+{
+       for (const attribute_t *attr = new_list; attr != NULL; attr = attr->next) {
+               if (!contains_attribute(old_list, attr))
+                       return true;
+       }
+       return false;
+}
+
+/**
+ * Merge in attributes from an attribute list (probably from a previous
+ * declaration with the same name). Warning: destroys the old structure
+ * of the attribute list - don't reuse attributes after this call.
+ */
+static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
+{
+       attribute_t *next;
+       for (attribute_t *attr = attributes; attr != NULL; attr = next) {
+               next = attr->next;
+               if (contains_attribute(decl->attributes, attr))
+                       continue;
+
+               /* move attribute to new declarations attributes list */
+               attr->next       = decl->attributes;
+               decl->attributes = attr;
+       }
+}
+
 /**
  * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
  * for various problems that occur for multiple definitions
  */
-static entity_t *record_entity(entity_t *entity, const bool is_definition)
+entity_t *record_entity(entity_t *entity, const bool is_definition)
 {
        const symbol_t *const    symbol  = entity->base.symbol;
        const namespace_tag_t    namespc = (namespace_tag_t)entity->base.namespc;
@@ -4429,22 +4308,28 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                                if (old_storage_class == STORAGE_CLASS_EXTERN &&
                                                new_storage_class == STORAGE_CLASS_EXTERN) {
-warn_redundant_declaration:
-                                       if (!is_definition           &&
+
+warn_redundant_declaration: ;
+                                       bool has_new_attrs
+                                               = has_new_attributes(prev_decl->attributes,
+                                                                    decl->attributes);
+                                       if (has_new_attrs) {
+                                               merge_in_attributes(decl, prev_decl->attributes);
+                                       } else if (!is_definition        &&
                                                        warning.redundant_decls  &&
                                                        is_type_valid(prev_type) &&
                                                        strcmp(previous_entity->base.source_position.input_name,
                                                                "<builtin>") != 0) {
                                                warningf(pos,
-                                                               "redundant declaration for '%Y' (declared %P)",
-                                                               symbol, &previous_entity->base.source_position);
+                                                        "redundant declaration for '%Y' (declared %P)",
+                                                        symbol, &previous_entity->base.source_position);
                                        }
                                } else if (current_function == NULL) {
                                        if (old_storage_class != STORAGE_CLASS_STATIC &&
                                                        new_storage_class == STORAGE_CLASS_STATIC) {
                                                errorf(pos,
-                                                               "static declaration of '%Y' follows non-static declaration (declared %P)",
-                                                               symbol, &previous_entity->base.source_position);
+                                                      "static declaration of '%Y' follows non-static declaration (declared %P)",
+                                                      symbol, &previous_entity->base.source_position);
                                        } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
                                                prev_decl->storage_class          = STORAGE_CLASS_NONE;
                                                prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
@@ -4530,7 +4415,7 @@ static bool is_declaration_specifier(const token_t *token,
                TYPE_QUALIFIERS
                        return true;
                case T_IDENTIFIER:
-                       return is_typedef_symbol(token->v.symbol);
+                       return is_typedef_symbol(token->symbol);
 
                case T___extension__:
                STORAGE_CLASSES
@@ -4678,9 +4563,8 @@ static void parse_declaration_rest(entity_t *ndeclaration,
 
                check_variable_type_complete(entity);
 
-               if (token.type != ',')
+               if (!next_if(','))
                        break;
-               eat(',');
 
                add_anchor_token('=');
                ndeclaration = parse_declarator(specifiers, flags);
@@ -5010,8 +4894,8 @@ static void check_declarations(void)
 static int determine_truth(expression_t const* const cond)
 {
        return
-               !is_constant_expression(cond) ? 0 :
-               fold_constant_to_bool(cond)   ? 1 :
+               is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
+               fold_constant_to_bool(cond)                         ? 1 :
                -1;
 }
 
@@ -5043,9 +4927,7 @@ static bool expression_returns(expression_t const *const expr)
 
                case EXPR_REFERENCE:
                case EXPR_REFERENCE_ENUM_VALUE:
-               case EXPR_CONST:
-               case EXPR_CHARACTER_CONSTANT:
-               case EXPR_WIDE_CHARACTER_CONSTANT:
+               EXPR_LITERAL_CASES
                case EXPR_STRING_LITERAL:
                case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
@@ -5223,7 +5105,7 @@ static void check_reachable(statement_t *const stmt)
                        if (!expression_returns(expr))
                                return;
 
-                       if (is_constant_expression(expr)) {
+                       if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
                                long                    const val      = fold_constant_to_int(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
@@ -5269,9 +5151,8 @@ static void check_reachable(statement_t *const stmt)
                        break;
                }
 
-               case STATEMENT_CONTINUE: {
-                       statement_t *parent = stmt;
-                       for (;;) {
+               case STATEMENT_CONTINUE:
+                       for (statement_t *parent = stmt;;) {
                                parent = parent->base.parent;
                                if (parent == NULL) /* continue not within loop */
                                        return;
@@ -5285,11 +5166,9 @@ static void check_reachable(statement_t *const stmt)
                                        default: break;
                                }
                        }
-               }
 
-               case STATEMENT_BREAK: {
-                       statement_t *parent = stmt;
-                       for (;;) {
+               case STATEMENT_BREAK:
+                       for (statement_t *parent = stmt;;) {
                                parent = parent->base.parent;
                                if (parent == NULL) /* break not within loop/switch */
                                        return;
@@ -5308,7 +5187,6 @@ static void check_reachable(statement_t *const stmt)
                        }
 found_break_parent:
                        break;
-               }
 
                case STATEMENT_GOTO:
                        if (stmt->gotos.expression) {
@@ -5749,7 +5627,9 @@ static void parse_external_declaration(void)
                /* parse function body */
                int         label_stack_top      = label_top();
                function_t *old_current_function = current_function;
+               entity_t   *old_current_entity   = current_entity;
                current_function                 = function;
+               current_entity                   = (entity_t*) function;
                current_parent                   = NULL;
 
                goto_first   = NULL;
@@ -5781,6 +5661,8 @@ static void parse_external_declaration(void)
 
                assert(current_parent   == NULL);
                assert(current_function == function);
+               assert(current_entity   == (entity_t*) function);
+               current_entity   = old_current_entity;
                current_function = old_current_function;
                label_pop_to(label_stack_top);
        }
@@ -5803,13 +5685,13 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
        type_t *skipped_type = skip_typeref(base_type);
        if (!is_type_integer(skipped_type)) {
                errorf(HERE, "bitfield base type '%T' is not an integer type",
-                       base_type);
+                      base_type);
                bit_size = 0;
        } else {
                bit_size = get_type_size(base_type) * 8;
        }
 
-       if (is_constant_expression(size)) {
+       if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
                long v = fold_constant_to_int(size);
                const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
 
@@ -5949,7 +5831,7 @@ static expression_t *find_create_select(const source_position_t *pos,
 static void parse_compound_declarators(compound_t *compound,
                const declaration_specifiers_t *specifiers)
 {
-       while (true) {
+       do {
                entity_t *entity;
 
                if (token.type == ':') {
@@ -5962,15 +5844,11 @@ static void parse_compound_declarators(compound_t *compound,
                        type_t *type = make_bitfield_type(base_type, size,
                                        &source_position, NULL);
 
-                       attribute_t *attributes = parse_attributes(NULL);
-                       if (attributes != NULL) {
-                               attribute_t *last = attributes;
-                               while (last->next != NULL)
-                                       last = last->next;
-                               last->next = specifiers->attributes;
-                       } else {
-                               attributes = specifiers->attributes;
-                       }
+                       attribute_t  *attributes = parse_attributes(NULL);
+                       attribute_t **anchor     = &attributes;
+                       while (*anchor != NULL)
+                               anchor = &(*anchor)->next;
+                       *anchor = specifiers->attributes;
 
                        entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
                        entity->base.namespc                       = NAMESPACE_NORMAL;
@@ -6021,7 +5899,7 @@ static void parse_compound_declarators(compound_t *compound,
                                        type_t *type      = skip_typeref(orig_type);
                                        if (is_type_function(type)) {
                                                errorf(&entity->base.source_position,
-                                                               "compound member '%Y' must not have function type '%T'",
+                                                      "compound member '%Y' must not have function type '%T'",
                                                                entity->base.symbol, orig_type);
                                        } else if (is_type_incomplete(type)) {
                                                /* Â§6.7.2.1:16 flexible array member */
@@ -6029,7 +5907,7 @@ static void parse_compound_declarators(compound_t *compound,
                                                                token.type          != ';' ||
                                                                look_ahead(1)->type != '}') {
                                                        errorf(&entity->base.source_position,
-                                                                       "compound member '%Y' has incomplete type '%T'",
+                                                              "compound member '%Y' has incomplete type '%T'",
                                                                        entity->base.symbol, orig_type);
                                                }
                                        }
@@ -6038,11 +5916,7 @@ static void parse_compound_declarators(compound_t *compound,
                                append_entity(&compound->members, entity);
                        }
                }
-
-               if (token.type != ',')
-                       break;
-               next_token();
-       }
+       } while (next_if(','));
        expect(';', end_error);
 
 end_error:
@@ -6077,12 +5951,12 @@ static type_t *parse_typename(void)
        declaration_specifiers_t specifiers;
        memset(&specifiers, 0, sizeof(specifiers));
        parse_declaration_specifiers(&specifiers);
-       if (specifiers.storage_class != STORAGE_CLASS_NONE ||
-                       specifiers.thread_local) {
+       if (specifiers.storage_class != STORAGE_CLASS_NONE
+                       || specifiers.thread_local) {
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
-               errorf(HERE, "typename may not have a storage class");
+               errorf(HERE, "typename must not have a storage class");
        }
 
        type_t *result = parse_abstract_declarator(specifiers.type);
@@ -6119,82 +5993,184 @@ static expression_t *expected_expression_error(void)
        return create_invalid_expression();
 }
 
+static type_t *get_string_type(void)
+{
+       return warning.write_strings ? type_const_char_ptr : type_char_ptr;
+}
+
+static type_t *get_wide_string_type(void)
+{
+       return warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+}
+
 /**
  * Parse a string constant.
  */
-static expression_t *parse_string_const(void)
+static expression_t *parse_string_literal(void)
 {
-       wide_string_t wres;
-       if (token.type == T_STRING_LITERAL) {
-               string_t res = token.v.string;
+       source_position_t begin   = token.source_position;
+       string_t          res     = token.literal;
+       bool              is_wide = (token.type == T_WIDE_STRING_LITERAL);
+
+       next_token();
+       while (token.type == T_STRING_LITERAL
+                       || token.type == T_WIDE_STRING_LITERAL) {
+               warn_string_concat(&token.source_position);
+               res = concat_strings(&res, &token.literal);
                next_token();
-               while (token.type == T_STRING_LITERAL) {
-                       res = concat_strings(&res, &token.v.string);
-                       next_token();
-               }
-               if (token.type != T_WIDE_STRING_LITERAL) {
-                       expression_t *const cnst = allocate_expression_zero(EXPR_STRING_LITERAL);
-                       /* note: that we use type_char_ptr here, which is already the
-                        * automatic converted type. revert_automatic_type_conversion
-                        * will construct the array type */
-                       cnst->base.type    = warning.write_strings ? type_const_char_ptr : type_char_ptr;
-                       cnst->string.value = res;
-                       return cnst;
-               }
+               is_wide |= token.type == T_WIDE_STRING_LITERAL;
+       }
 
-               wres = concat_string_wide_string(&res, &token.v.wide_string);
+       expression_t *literal;
+       if (is_wide) {
+               literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
+               literal->base.type = get_wide_string_type();
        } else {
-               wres = token.v.wide_string;
+               literal = allocate_expression_zero(EXPR_STRING_LITERAL);
+               literal->base.type = get_string_type();
        }
-       next_token();
+       literal->base.source_position = begin;
+       literal->literal.value        = res;
 
-       for (;;) {
-               switch (token.type) {
-                       case T_WIDE_STRING_LITERAL:
-                               wres = concat_wide_strings(&wres, &token.v.wide_string);
-                               break;
+       return literal;
+}
+
+/**
+ * Parse a boolean constant.
+ */
+static expression_t *parse_boolean_literal(bool value)
+{
+       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_BOOLEAN);
+       literal->base.source_position = token.source_position;
+       literal->base.type            = type_bool;
+       literal->literal.value.begin  = value ? "true" : "false";
+       literal->literal.value.size   = value ? 4 : 5;
+
+       next_token();
+       return literal;
+}
 
-                       case T_STRING_LITERAL:
-                               wres = concat_wide_string_string(&wres, &token.v.string);
-                               break;
+static void warn_traditional_suffix(void)
+{
+       if (!warning.traditional)
+               return;
+       warningf(&token.source_position, "traditional C rejects the '%Y' suffix",
+                token.symbol);
+}
+
+static void check_integer_suffix(void)
+{
+       symbol_t *suffix = token.symbol;
+       if (suffix == NULL)
+               return;
 
-                       default: {
-                               expression_t *const cnst = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
-                               cnst->base.type         = warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr;
-                               cnst->wide_string.value = wres;
-                               return cnst;
+       bool not_traditional = false;
+       const char *c = suffix->string;
+       if (*c == 'l' || *c == 'L') {
+               ++c;
+               if (*c == *(c-1)) {
+                       not_traditional = true;
+                       ++c;
+                       if (*c == 'u' || *c == 'U') {
+                               ++c;
+                       }
+               } else if (*c == 'u' || *c == 'U') {
+                       not_traditional = true;
+                       ++c;
+               }
+       } else if (*c == 'u' || *c == 'U') {
+               not_traditional = true;
+               ++c;
+               if (*c == 'l' || *c == 'L') {
+                       ++c;
+                       if (*c == *(c-1)) {
+                               ++c;
                        }
                }
-               next_token();
+       }
+       if (*c != '\0') {
+               errorf(&token.source_position,
+                      "invalid suffix '%s' on integer constant", suffix->string);
+       } else if (not_traditional) {
+               warn_traditional_suffix();
        }
 }
 
-/**
- * Parse a boolean constant.
- */
-static expression_t *parse_bool_const(bool value)
+static type_t *check_floatingpoint_suffix(void)
 {
-       expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
-       cnst->base.type          = type_bool;
-       cnst->conste.v.int_value = value;
+       symbol_t *suffix = token.symbol;
+       type_t   *type   = type_double;
+       if (suffix == NULL)
+               return type;
 
-       next_token();
+       bool not_traditional = false;
+       const char *c = suffix->string;
+       if (*c == 'f' || *c == 'F') {
+               ++c;
+               type = type_float;
+       } else if (*c == 'l' || *c == 'L') {
+               ++c;
+               type = type_long_double;
+       }
+       if (*c != '\0') {
+               errorf(&token.source_position,
+                      "invalid suffix '%s' on floatingpoint constant", suffix->string);
+       } else if (not_traditional) {
+               warn_traditional_suffix();
+       }
 
-       return cnst;
+       return type;
 }
 
 /**
  * Parse an integer constant.
  */
-static expression_t *parse_int_const(void)
+static expression_t *parse_number_literal(void)
 {
-       expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
-       cnst->base.type          = token.datatype;
-       cnst->conste.v.int_value = token.v.intvalue;
+       expression_kind_t  kind;
+       type_t            *type;
+
+       switch (token.type) {
+       case T_INTEGER:
+               kind = EXPR_LITERAL_INTEGER;
+               check_integer_suffix();
+               type = type_int;
+               break;
+       case T_INTEGER_OCTAL:
+               kind = EXPR_LITERAL_INTEGER_OCTAL;
+               check_integer_suffix();
+               type = type_int;
+               break;
+       case T_INTEGER_HEXADECIMAL:
+               kind = EXPR_LITERAL_INTEGER_HEXADECIMAL;
+               check_integer_suffix();
+               type = type_int;
+               break;
+       case T_FLOATINGPOINT:
+               kind = EXPR_LITERAL_FLOATINGPOINT;
+               type = check_floatingpoint_suffix();
+               break;
+       case T_FLOATINGPOINT_HEXADECIMAL:
+               kind = EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL;
+               type = check_floatingpoint_suffix();
+               break;
+       default:
+               panic("unexpected token type in parse_number_literal");
+       }
 
+       expression_t *literal = allocate_expression_zero(kind);
+       literal->base.source_position = token.source_position;
+       literal->base.type            = type;
+       literal->literal.value        = token.literal;
+       literal->literal.suffix       = token.symbol;
        next_token();
 
-       return cnst;
+       /* integer type depends on the size of the number and the size
+        * representable by the types. The backend/codegeneration has to determine
+        * that
+        */
+       determine_literal_type(&literal->literal);
+       return literal;
 }
 
 /**
@@ -6202,20 +6178,23 @@ static expression_t *parse_int_const(void)
  */
 static expression_t *parse_character_constant(void)
 {
-       expression_t *cnst = allocate_expression_zero(EXPR_CHARACTER_CONSTANT);
-       cnst->base.type          = token.datatype;
-       cnst->conste.v.character = token.v.string;
+       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
+       literal->base.source_position = token.source_position;
+       literal->base.type            = c_mode & _CXX ? type_char : type_int;
+       literal->literal.value        = token.literal;
 
-       if (cnst->conste.v.character.size != 1) {
-               if (!GNU_MODE) {
+       size_t len = literal->literal.value.size;
+       if (len != 1) {
+               if (!GNU_MODE && !(c_mode & _C99)) {
                        errorf(HERE, "more than 1 character in character constant");
                } else if (warning.multichar) {
+                       literal->base.type = type_int;
                        warningf(HERE, "multi-character character constant");
                }
        }
-       next_token();
 
-       return cnst;
+       next_token();
+       return literal;
 }
 
 /**
@@ -6223,34 +6202,18 @@ static expression_t *parse_character_constant(void)
  */
 static expression_t *parse_wide_character_constant(void)
 {
-       expression_t *cnst = allocate_expression_zero(EXPR_WIDE_CHARACTER_CONSTANT);
-       cnst->base.type               = token.datatype;
-       cnst->conste.v.wide_character = token.v.wide_string;
+       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
+       literal->base.source_position = token.source_position;
+       literal->base.type            = type_int;
+       literal->literal.value        = token.literal;
 
-       if (cnst->conste.v.wide_character.size != 1) {
-               if (!GNU_MODE) {
-                       errorf(HERE, "more than 1 character in character constant");
-               } else if (warning.multichar) {
-                       warningf(HERE, "multi-character character constant");
-               }
+       size_t len = wstrlen(&literal->literal.value);
+       if (len != 1) {
+               warningf(HERE, "multi-character character constant");
        }
-       next_token();
-
-       return cnst;
-}
-
-/**
- * Parse a float constant.
- */
-static expression_t *parse_float_const(void)
-{
-       expression_t *cnst         = allocate_expression_zero(EXPR_CONST);
-       cnst->base.type            = token.datatype;
-       cnst->conste.v.float_value = token.v.floatvalue;
 
        next_token();
-
-       return cnst;
+       return literal;
 }
 
 static entity_t *create_implicit_function(symbol_t *symbol,
@@ -6280,91 +6243,6 @@ static entity_t *create_implicit_function(symbol_t *symbol,
        return entity;
 }
 
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- */
-static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1,
-                                    type_t *argument_type2)
-{
-       function_parameter_t *const parameter2 = allocate_parameter(argument_type2);
-       function_parameter_t *const parameter1 = allocate_parameter(argument_type1);
-       parameter1->next = parameter2;
-
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = parameter1;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- *
- * @param return_type    the return type
- * @param argument_type  the argument type
- */
-static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
-{
-       function_parameter_t *const parameter = allocate_parameter(argument_type);
-
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = parameter;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type, ...) function type if not
- * already exists.
- *
- * @param return_type    the return type
- * @param argument_type  the argument type
- */
-static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type)
-{
-       function_parameter_t *const parameter = allocate_parameter(argument_type);
-
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = parameter;
-       type->function.variadic    = true;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type    the return type
- */
-static type_t *make_function_0_type(type_t *return_type)
-{
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = NULL;
-
-       return identify_new_type(type);
-}
-
-/**
- * Creates a NO_RETURN return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type    the return type
- */
-static type_t *make_function_0_type_noreturn(type_t *return_type)
-{
-       type_t *type               = allocate_type_zero(TYPE_FUNCTION);
-       type->function.return_type = return_type;
-       type->function.parameters  = NULL;
-       type->function.modifiers  |= DM_NORETURN;
-       return identify_new_type(type);
-}
-
 /**
  * Performs automatic type cast as described in Â§6.3.2.1.
  *
@@ -6395,57 +6273,58 @@ static type_t *automatic_type_conversion(type_t *orig_type)
 type_t *revert_automatic_type_conversion(const expression_t *expression)
 {
        switch (expression->kind) {
-               case EXPR_REFERENCE: {
-                       entity_t *entity = expression->reference.entity;
-                       if (is_declaration(entity)) {
-                               return entity->declaration.type;
-                       } else if (entity->kind == ENTITY_ENUM_VALUE) {
-                               return entity->enum_value.enum_type;
-                       } else {
-                               panic("no declaration or enum in reference");
-                       }
+       case EXPR_REFERENCE: {
+               entity_t *entity = expression->reference.entity;
+               if (is_declaration(entity)) {
+                       return entity->declaration.type;
+               } else if (entity->kind == ENTITY_ENUM_VALUE) {
+                       return entity->enum_value.enum_type;
+               } else {
+                       panic("no declaration or enum in reference");
                }
+       }
 
-               case EXPR_SELECT: {
-                       entity_t *entity = expression->select.compound_entry;
-                       assert(is_declaration(entity));
-                       type_t   *type   = entity->declaration.type;
-                       return get_qualified_type(type,
-                                       expression->base.type->base.qualifiers);
-               }
+       case EXPR_SELECT: {
+               entity_t *entity = expression->select.compound_entry;
+               assert(is_declaration(entity));
+               type_t   *type   = entity->declaration.type;
+               return get_qualified_type(type,
+                               expression->base.type->base.qualifiers);
+       }
 
-               case EXPR_UNARY_DEREFERENCE: {
-                       const expression_t *const value = expression->unary.value;
-                       type_t             *const type  = skip_typeref(value->base.type);
-                       if (!is_type_pointer(type))
-                               return type_error_type;
-                       return type->pointer.points_to;
-               }
+       case EXPR_UNARY_DEREFERENCE: {
+               const expression_t *const value = expression->unary.value;
+               type_t             *const type  = skip_typeref(value->base.type);
+               if (!is_type_pointer(type))
+                       return type_error_type;
+               return type->pointer.points_to;
+       }
 
-               case EXPR_ARRAY_ACCESS: {
-                       const expression_t *array_ref = expression->array_access.array_ref;
-                       type_t             *type_left = skip_typeref(array_ref->base.type);
-                       if (!is_type_pointer(type_left))
-                               return type_error_type;
-                       return type_left->pointer.points_to;
-               }
+       case EXPR_ARRAY_ACCESS: {
+               const expression_t *array_ref = expression->array_access.array_ref;
+               type_t             *type_left = skip_typeref(array_ref->base.type);
+               if (!is_type_pointer(type_left))
+                       return type_error_type;
+               return type_left->pointer.points_to;
+       }
 
-               case EXPR_STRING_LITERAL: {
-                       size_t size = expression->string.value.size;
-                       return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
-               }
+       case EXPR_STRING_LITERAL: {
+               size_t size = expression->string_literal.value.size;
+               return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
+       }
 
-               case EXPR_WIDE_STRING_LITERAL: {
-                       size_t size = expression->wide_string.value.size;
-                       return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
-               }
+       case EXPR_WIDE_STRING_LITERAL: {
+               size_t size = wstrlen(&expression->string_literal.value);
+               return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+       }
 
-               case EXPR_COMPOUND_LITERAL:
-                       return expression->compound_literal.type;
+       case EXPR_COMPOUND_LITERAL:
+               return expression->compound_literal.type;
 
-               default:
-                       return expression->base.type;
+       default:
+               break;
        }
+       return expression->base.type;
 }
 
 /**
@@ -6473,13 +6352,12 @@ static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol,
 static entity_t *parse_qualified_identifier(void)
 {
        /* namespace containing the symbol */
-       symbol_t      *symbol;
-       const scope_t *lookup_scope = NULL;
+       symbol_t          *symbol;
+       source_position_t  pos;
+       const scope_t     *lookup_scope = NULL;
 
-       if (token.type == T_COLONCOLON) {
-               next_token();
+       if (next_if(T_COLONCOLON))
                lookup_scope = &unit->scope;
-       }
 
        entity_t *entity;
        while (true) {
@@ -6487,15 +6365,15 @@ static entity_t *parse_qualified_identifier(void)
                        parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
                        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
                }
-               symbol = token.v.symbol;
+               symbol = token.symbol;
+               pos    = *HERE;
                next_token();
 
                /* lookup entity */
                entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
 
-               if (token.type != T_COLONCOLON)
+               if (!next_if(T_COLONCOLON))
                        break;
-               next_token();
 
                switch (entity->kind) {
                case ENTITY_NAMESPACE:
@@ -6507,7 +6385,7 @@ static entity_t *parse_qualified_identifier(void)
                        lookup_scope = &entity->compound.members;
                        break;
                default:
-                       errorf(HERE, "'%Y' must be a namespace, class, struct or union (but is a %s)",
+                       errorf(&pos, "'%Y' must be a namespace, class, struct or union (but is a %s)",
                               symbol, get_entity_kind_name(entity->kind));
                        goto end_error;
                }
@@ -6517,14 +6395,14 @@ static entity_t *parse_qualified_identifier(void)
                if (!strict_mode && token.type == '(') {
                        /* an implicitly declared function */
                        if (warning.error_implicit_function_declaration) {
-                               errorf(HERE, "implicit declaration of function '%Y'", symbol);
+                               errorf(&pos, "implicit declaration of function '%Y'", symbol);
                        } else if (warning.implicit_function_declaration) {
-                               warningf(HERE, "implicit declaration of function '%Y'", symbol);
+                               warningf(&pos, "implicit declaration of function '%Y'", symbol);
                        }
 
-                       entity = create_implicit_function(symbol, HERE);
+                       entity = create_implicit_function(symbol, &pos);
                } else {
-                       errorf(HERE, "unknown identifier '%Y' found.", symbol);
+                       errorf(&pos, "unknown identifier '%Y' found.", symbol);
                        entity = create_error_entity(symbol, ENTITY_VARIABLE);
                }
        }
@@ -6533,12 +6411,7 @@ static entity_t *parse_qualified_identifier(void)
 
 end_error:
        /* skip further qualifications */
-       while (token.type == T_IDENTIFIER) {
-               next_token();
-               if (token.type != T_COLONCOLON)
-                       break;
-               next_token();
-       }
+       while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
 
        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
 }
@@ -6574,8 +6447,9 @@ static expression_t *parse_reference(void)
        }
 
        if (entity->base.parent_scope != file_scope
-               && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth)
-               && is_type_valid(orig_type) && !is_type_function(orig_type)) {
+               && (current_function != NULL
+                       && entity->base.parent_scope->depth < current_function->parameters.depth)
+               && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) {
                if (entity->kind == ENTITY_VARIABLE) {
                        /* access of a variable from an outer function */
                        entity->variable.address_taken = true;
@@ -6684,7 +6558,7 @@ static expression_t *parse_cast(void)
        expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
        cast->base.source_position = source_position;
 
-       expression_t *value = parse_sub_expression(PREC_CAST);
+       expression_t *value = parse_subexpression(PREC_CAST);
        cast->base.type   = type;
        cast->unary.value = value;
 
@@ -6748,7 +6622,7 @@ static expression_t *parse_parenthesized_expression(void)
        TYPE_SPECIFIERS
                return parse_cast();
        case T_IDENTIFIER:
-               if (is_typedef_symbol(token.v.symbol)) {
+               if (is_typedef_symbol(token.symbol)) {
                        return parse_cast();
                }
        }
@@ -6835,13 +6709,12 @@ static designator_t *parse_designator(void)
                                     T_IDENTIFIER, NULL);
                return NULL;
        }
-       result->symbol = token.v.symbol;
+       result->symbol = token.symbol;
        next_token();
 
        designator_t *last_designator = result;
        while (true) {
-               if (token.type == '.') {
-                       next_token();
+               if (next_if('.')) {
                        if (token.type != T_IDENTIFIER) {
                                parse_error_expected("while parsing member designator",
                                                     T_IDENTIFIER, NULL);
@@ -6849,15 +6722,14 @@ static designator_t *parse_designator(void)
                        }
                        designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
                        designator->source_position = *HERE;
-                       designator->symbol          = token.v.symbol;
+                       designator->symbol          = token.symbol;
                        next_token();
 
                        last_designator->next = designator;
                        last_designator       = designator;
                        continue;
                }
-               if (token.type == '[') {
-                       next_token();
+               if (next_if('[')) {
                        add_anchor_token(']');
                        designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
                        designator->source_position = *HERE;
@@ -7183,7 +7055,7 @@ static expression_t *parse_label_address(void)
                parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
                goto end_error;
        }
-       symbol_t *symbol = token.v.symbol;
+       symbol_t *symbol = token.symbol;
        next_token();
 
        label_t *label       = get_label(symbol);
@@ -7207,10 +7079,11 @@ end_error:
 static expression_t *parse_noop_expression(void)
 {
        /* the result is a (int)0 */
-       expression_t *cnst         = allocate_expression_zero(EXPR_CONST);
-       cnst->base.type            = type_int;
-       cnst->conste.v.int_value   = 0;
-       cnst->conste.is_ms_noop    = true;
+       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_MS_NOOP);
+       literal->base.type            = type_int;
+       literal->base.source_position = token.source_position;
+       literal->literal.value.begin  = "__noop";
+       literal->literal.value.size   = 6;
 
        eat(T___noop);
 
@@ -7220,21 +7093,16 @@ static expression_t *parse_noop_expression(void)
                add_anchor_token(')');
                add_anchor_token(',');
 
-               if (token.type != ')') {
-                       while (true) {
-                               (void)parse_assignment_expression();
-                               if (token.type != ',')
-                                       break;
-                               next_token();
-                       }
-               }
+               if (token.type != ')') do {
+                       (void)parse_assignment_expression();
+               } while (next_if(','));
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
        expect(')', end_error);
 
 end_error:
-       return cnst;
+       return literal;
 }
 
 /**
@@ -7243,57 +7111,61 @@ end_error:
 static expression_t *parse_primary_expression(void)
 {
        switch (token.type) {
-               case T_false:                        return parse_bool_const(false);
-               case T_true:                         return parse_bool_const(true);
-               case T_INTEGER:                      return parse_int_const();
-               case T_CHARACTER_CONSTANT:           return parse_character_constant();
-               case T_WIDE_CHARACTER_CONSTANT:      return parse_wide_character_constant();
-               case T_FLOATINGPOINT:                return parse_float_const();
-               case T_STRING_LITERAL:
-               case T_WIDE_STRING_LITERAL:          return parse_string_const();
-               case T___FUNCTION__:
-               case T___func__:                     return parse_function_keyword();
-               case T___PRETTY_FUNCTION__:          return parse_pretty_function_keyword();
-               case T___FUNCSIG__:                  return parse_funcsig_keyword();
-               case T___FUNCDNAME__:                return parse_funcdname_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_va_copy:            return parse_va_copy();
-               case T___builtin_isgreater:
-               case T___builtin_isgreaterequal:
-               case T___builtin_isless:
-               case T___builtin_islessequal:
-               case T___builtin_islessgreater:
-               case T___builtin_isunordered:        return parse_compare_builtin();
-               case T___builtin_constant_p:         return parse_builtin_constant();
-               case T___builtin_types_compatible_p: return parse_builtin_types_compatible();
-               case T__assume:                      return parse_assume();
-               case T_ANDAND:
-                       if (GNU_MODE)
-                               return parse_label_address();
-                       break;
+       case T_false:                        return parse_boolean_literal(false);
+       case T_true:                         return parse_boolean_literal(true);
+       case T_INTEGER:
+       case T_INTEGER_OCTAL:
+       case T_INTEGER_HEXADECIMAL:
+       case T_FLOATINGPOINT:
+       case T_FLOATINGPOINT_HEXADECIMAL:    return parse_number_literal();
+       case T_CHARACTER_CONSTANT:           return parse_character_constant();
+       case T_WIDE_CHARACTER_CONSTANT:      return parse_wide_character_constant();
+       case T_STRING_LITERAL:
+       case T_WIDE_STRING_LITERAL:          return parse_string_literal();
+       case T___FUNCTION__:
+       case T___func__:                     return parse_function_keyword();
+       case T___PRETTY_FUNCTION__:          return parse_pretty_function_keyword();
+       case T___FUNCSIG__:                  return parse_funcsig_keyword();
+       case T___FUNCDNAME__:                return parse_funcdname_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_va_copy:            return parse_va_copy();
+       case T___builtin_isgreater:
+       case T___builtin_isgreaterequal:
+       case T___builtin_isless:
+       case T___builtin_islessequal:
+       case T___builtin_islessgreater:
+       case T___builtin_isunordered:        return parse_compare_builtin();
+       case T___builtin_constant_p:         return parse_builtin_constant();
+       case T___builtin_types_compatible_p: return parse_builtin_types_compatible();
+       case T__assume:                      return parse_assume();
+       case T_ANDAND:
+               if (GNU_MODE)
+                       return parse_label_address();
+               break;
 
-               case '(':                            return parse_parenthesized_expression();
-               case T___noop:                       return parse_noop_expression();
+       case '(':                            return parse_parenthesized_expression();
+       case T___noop:                       return parse_noop_expression();
 
-               /* Gracefully handle type names while parsing expressions. */
-               case T_COLONCOLON:
+       /* Gracefully handle type names while parsing expressions. */
+       case T_COLONCOLON:
+               return parse_reference();
+       case T_IDENTIFIER:
+               if (!is_typedef_symbol(token.symbol)) {
                        return parse_reference();
-               case T_IDENTIFIER:
-                       if (!is_typedef_symbol(token.v.symbol)) {
-                               return parse_reference();
-                       }
-                       /* FALLTHROUGH */
-               TYPENAME_START {
-                       source_position_t  const pos  = *HERE;
-                       type_t const      *const type = parse_typename();
-                       errorf(&pos, "encountered type '%T' while parsing expression", type);
-                       return create_invalid_expression();
                }
+               /* FALLTHROUGH */
+       TYPENAME_START {
+               source_position_t  const pos  = *HERE;
+               type_t const      *const type = parse_typename();
+               errorf(&pos, "encountered type '%T' while parsing expression", type);
+               return create_invalid_expression();
+       }
        }
 
        errorf(HERE, "unexpected token %K, expected an expression", &token);
+       eat_until_anchor();
        return create_invalid_expression();
 }
 
@@ -7386,7 +7258,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
                        goto typeprop_expression;
                }
        } else {
-               expression = parse_sub_expression(PREC_UNARY);
+               expression = parse_subexpression(PREC_UNARY);
 
 typeprop_expression:
                tp_expression->typeprop.tp_expression = expression;
@@ -7435,7 +7307,7 @@ static expression_t *parse_select_expression(expression_t *addr)
                parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
                return create_invalid_expression();
        }
-       symbol_t *symbol = token.v.symbol;
+       symbol_t *symbol = token.symbol;
        next_token();
 
        type_t *const orig_type = addr->base.type;
@@ -7555,20 +7427,33 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                        /* argument must be constant */
                        call_argument_t *argument = call->arguments;
 
-                       if (! is_constant_expression(argument->expression)) {
+                       if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
                                errorf(&call->base.source_position,
                                       "argument of '%Y' must be a constant expression",
                                       call->function->reference.entity->base.symbol);
                        }
                        break;
                }
-               case bk_gnu_builtin_prefetch: {
+               case bk_gnu_builtin_object_size:
+                       if (call->arguments == NULL)
+                               break;
+
+                       call_argument_t *arg = call->arguments->next;
+                       if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
+                               errorf(&call->base.source_position,
+                                          "second argument of '%Y' must be a constant expression",
+                                          call->function->reference.entity->base.symbol);
+                       }
+                       break;
+               case bk_gnu_builtin_prefetch:
                        /* second and third argument must be constant if existent */
+                       if (call->arguments == NULL)
+                               break;
                        call_argument_t *rw = call->arguments->next;
                        call_argument_t *locality = NULL;
 
                        if (rw != NULL) {
-                               if (! is_constant_expression(rw->expression)) {
+                               if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
                                        errorf(&call->base.source_position,
                                               "second argument of '%Y' must be a constant expression",
                                               call->function->reference.entity->base.symbol);
@@ -7576,7 +7461,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                                locality = rw->next;
                        }
                        if (locality != NULL) {
-                               if (! is_constant_expression(locality->expression)) {
+                               if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
                                        errorf(&call->base.source_position,
                                               "third argument of '%Y' must be a constant expression",
                                               call->function->reference.entity->base.symbol);
@@ -7584,7 +7469,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                                locality = rw->next;
                        }
                        break;
-               }
                default:
                        break;
        }
@@ -7627,17 +7511,13 @@ static expression_t *parse_call_expression(expression_t *expression)
 
        if (token.type != ')') {
                call_argument_t **anchor = &call->arguments;
-               for (;;) {
+               do {
                        call_argument_t *argument = allocate_ast_zero(sizeof(*argument));
                        argument->expression = parse_assignment_expression();
 
                        *anchor = argument;
                        anchor  = &argument->next;
-
-                       if (token.type != ',')
-                               break;
-                       next_token();
-               }
+               } while (next_if(','));
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
@@ -7665,6 +7545,10 @@ static expression_t *parse_call_expression(expression_t *expression)
        /* do default promotion for other arguments */
        for (; argument != NULL; argument = argument->next) {
                type_t *type = argument->expression->base.type;
+               if (!is_type_object(skip_typeref(type))) {
+                       errorf(&argument->expression->base.source_position,
+                              "call argument '%E' must not be void", argument->expression);
+               }
 
                type = get_default_promoted_type(type);
 
@@ -7797,7 +7681,7 @@ static expression_t *parse_conditional_expression(expression_t *expression)
        expect(':', end_error);
 end_error:;
        expression_t *false_expression =
-               parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
+               parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
 
        type_t *const orig_true_type  = true_expression->base.type;
        type_t *const orig_false_type = false_expression->base.type;
@@ -7826,13 +7710,6 @@ end_error:;
        } else if (is_type_arithmetic(true_type)
                   && is_type_arithmetic(false_type)) {
                result_type = semantic_arithmetic(true_type, false_type);
-
-               true_expression  = create_implicit_cast(true_expression, result_type);
-               false_expression = create_implicit_cast(false_expression, result_type);
-
-               conditional->true_expression  = true_expression;
-               conditional->false_expression = false_expression;
-               conditional->base.type        = result_type;
        } else if (same_compound_type(true_type, false_type)) {
                /* just take 1 of the 2 types */
                result_type = true_type;
@@ -7884,7 +7761,7 @@ end_error:;
                        result_type = pointer_type;
                } else {
                        if (is_type_valid(other_type)) {
-                               type_error_incompatible("while parsing conditional",
+                               type_error_incompatible("while parsing conditional",
                                                &expression->base.source_position, true_type, false_type);
                        }
                        result_type = type_error_type;
@@ -7915,7 +7792,7 @@ static expression_t *parse_extension(void)
 
        bool old_gcc_extension   = in_gcc_extension;
        in_gcc_extension         = true;
-       expression_t *expression = parse_sub_expression(PREC_UNARY);
+       expression_t *expression = parse_subexpression(PREC_UNARY);
        in_gcc_extension         = old_gcc_extension;
        return expression;
 }
@@ -7953,14 +7830,13 @@ static expression_t *parse_delete(void)
 
        eat(T_delete);
 
-       if (token.type == '[') {
-               next_token();
+       if (next_if('[')) {
                result->kind = EXPR_UNARY_DELETE_ARRAY;
                expect(']', end_error);
 end_error:;
        }
 
-       expression_t *const value = parse_sub_expression(PREC_CAST);
+       expression_t *const value = parse_subexpression(PREC_CAST);
        result->unary.value = value;
 
        type_t *const type = skip_typeref(value->base.type);
@@ -8062,14 +7938,14 @@ static bool is_lvalue(const expression_t *expression)
                return true;
 
        default: {
-         type_t *type = skip_typeref(expression->base.type);
-         return
-               /* ISO/IEC 14882:1998(E) Â§3.10:3 */
-               is_type_reference(type) ||
-               /* Claim it is an lvalue, if the type is invalid.  There was a parse
-                * error before, which maybe prevented properly recognizing it as
-                * lvalue. */
-               !is_type_valid(type);
+               type_t *type = skip_typeref(expression->base.type);
+               return
+                       /* ISO/IEC 14882:1998(E) Â§3.10:3 */
+                       is_type_reference(type) ||
+                       /* Claim it is an lvalue, if the type is invalid.  There was a parse
+                        * error before, which maybe prevented properly recognizing it as
+                        * lvalue. */
+                       !is_type_valid(type);
        }
        }
 }
@@ -8224,7 +8100,7 @@ static expression_t *parse_##unexpression_type(void)                         \
        expression_t *unary_expression                                           \
                = allocate_expression_zero(unexpression_type);                       \
        eat(token_type);                                                         \
-       unary_expression->unary.value = parse_sub_expression(PREC_UNARY);        \
+       unary_expression->unary.value = parse_subexpression(PREC_UNARY);         \
                                                                                 \
        sfunc(&unary_expression->unary);                                         \
                                                                                 \
@@ -8368,8 +8244,8 @@ static void warn_div_by_zero(binary_expression_t const *const expression)
 
        expression_t const *const right = expression->right;
        /* The type of the right operand can be different for /= */
-       if (is_type_integer(right->base.type) &&
-           is_constant_expression(right)     &&
+       if (is_type_integer(right->base.type)                    &&
+           is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
            !fold_constant_to_bool(right)) {
                warningf(&expression->base.source_position, "division by zero");
        }
@@ -8420,7 +8296,7 @@ static bool semantic_shift(binary_expression_t *expression)
 
        type_left = promote_integer(type_left);
 
-       if (is_constant_expression(right)) {
+       if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
                long count = fold_constant_to_int(right);
                if (count < 0) {
                        warningf(&right->base.source_position,
@@ -8540,8 +8416,8 @@ static void warn_string_literal_address(expression_t const* expr)
                expr = expr->unary.value;
        }
 
-       if (expr->kind == EXPR_STRING_LITERAL ||
-           expr->kind == EXPR_WIDE_STRING_LITERAL) {
+       if (expr->kind == EXPR_STRING_LITERAL
+                       || expr->kind == EXPR_WIDE_STRING_LITERAL) {
                warningf(&expr->base.source_position,
                        "comparison with string literal results in unspecified behaviour");
        }
@@ -8568,9 +8444,11 @@ static void warn_comparison_in_comparison(const expression_t *const expr)
 
 static bool maybe_negative(expression_t const *const expr)
 {
-       return
-               !is_constant_expression(expr) ||
-               fold_constant_to_int(expr) < 0;
+       switch (is_constant_expression(expr)) {
+               case EXPR_CLASS_ERROR:    return false;
+               case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+               default:                  return true;
+       }
 }
 
 /**
@@ -8891,13 +8769,20 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_INVALID:                    return true; /* do NOT warn */
                case EXPR_REFERENCE:                  return false;
                case EXPR_REFERENCE_ENUM_VALUE:       return false;
+               case EXPR_LABEL_ADDRESS:              return false;
+
                /* suppress the warning for microsoft __noop operations */
-               case EXPR_CONST:                      return expr->conste.is_ms_noop;
-               case EXPR_CHARACTER_CONSTANT:         return false;
-               case EXPR_WIDE_CHARACTER_CONSTANT:    return false;
+               case EXPR_LITERAL_MS_NOOP:            return true;
+               case EXPR_LITERAL_BOOLEAN:
+               case EXPR_LITERAL_CHARACTER:
+               case EXPR_LITERAL_WIDE_CHARACTER:
+               case EXPR_LITERAL_INTEGER:
+               case EXPR_LITERAL_INTEGER_OCTAL:
+               case EXPR_LITERAL_INTEGER_HEXADECIMAL:
+               case EXPR_LITERAL_FLOATINGPOINT:
+               case EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL: return false;
                case EXPR_STRING_LITERAL:             return false;
                case EXPR_WIDE_STRING_LITERAL:        return false;
-               case EXPR_LABEL_ADDRESS:              return false;
 
                case EXPR_CALL: {
                        const call_expression_t *const call = &expr->call;
@@ -9031,7 +8916,7 @@ static expression_t *parse_##binexpression_type(expression_t *left)          \
        binexpr->binary.left  = left;                                            \
        eat(token_type);                                                         \
                                                                              \
-       expression_t *right = parse_sub_expression(prec_r);                      \
+       expression_t *right = parse_subexpression(prec_r);                       \
                                                                              \
        binexpr->binary.right = right;                                           \
        sfunc(&binexpr->binary);                                                 \
@@ -9071,7 +8956,7 @@ CREATE_BINEXPR_PARSER(T_CARETEQUAL,           EXPR_BINARY_BITWISE_XOR_ASSIGN, PR
 CREATE_BINEXPR_PARSER(',',                    EXPR_BINARY_COMMA,              PREC_ASSIGNMENT,     semantic_comma)
 
 
-static expression_t *parse_sub_expression(precedence_t precedence)
+static expression_t *parse_subexpression(precedence_t precedence)
 {
        if (token.type < 0) {
                return expected_expression_error();
@@ -9116,7 +9001,7 @@ static expression_t *parse_sub_expression(precedence_t precedence)
  */
 static expression_t *parse_expression(void)
 {
-       return parse_sub_expression(PREC_EXPRESSION);
+       return parse_subexpression(PREC_EXPRESSION);
 }
 
 /**
@@ -9231,14 +9116,13 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
                memset(argument, 0, sizeof(argument[0]));
 
-               if (token.type == '[') {
-                       eat('[');
+               if (next_if('[')) {
                        if (token.type != T_IDENTIFIER) {
                                parse_error_expected("while parsing asm argument",
                                                     T_IDENTIFIER, NULL);
                                return NULL;
                        }
-                       argument->symbol = token.v.symbol;
+                       argument->symbol = token.symbol;
 
                        expect(']', end_error);
                }
@@ -9298,7 +9182,9 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                       "asm output argument is not an lvalue");
                        }
 
-                       if (argument->constraints.begin[0] == '+')
+                       if (argument->constraints.begin[0] == '=')
+                               determine_lhs_ent(expression, NULL);
+                       else
                                mark_vars_read(expression, NULL);
                } else {
                        mark_vars_read(expression, NULL);
@@ -9311,9 +9197,8 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                *anchor = argument;
                anchor  = &argument->next;
 
-               if (token.type != ',')
+               if (!next_if(','))
                        break;
-               eat(',');
        }
 
        return result;
@@ -9326,23 +9211,18 @@ end_error:
  */
 static asm_clobber_t *parse_asm_clobbers(void)
 {
-       asm_clobber_t *result = NULL;
-       asm_clobber_t *last   = NULL;
+       asm_clobber_t *result  = NULL;
+       asm_clobber_t **anchor = &result;
 
        while (token.type == T_STRING_LITERAL) {
                asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
                clobber->clobber       = parse_string_literals();
 
-               if (last != NULL) {
-                       last->next = clobber;
-               } else {
-                       result = clobber;
-               }
-               last = clobber;
+               *anchor = clobber;
+               anchor  = &clobber->next;
 
-               if (token.type != ',')
+               if (!next_if(','))
                        break;
-               eat(',');
        }
 
        return result;
@@ -9358,36 +9238,35 @@ static statement_t *parse_asm_statement(void)
 
        eat(T_asm);
 
-       if (token.type == T_volatile) {
-               next_token();
+       if (next_if(T_volatile))
                asm_statement->is_volatile = true;
-       }
 
        expect('(', end_error);
        add_anchor_token(')');
-       add_anchor_token(':');
+       if (token.type != T_STRING_LITERAL) {
+               parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
+               goto end_of_asm;
+       }
        asm_statement->asm_text = parse_string_literals();
 
-       if (token.type != ':') {
+       add_anchor_token(':');
+       if (!next_if(':')) {
                rem_anchor_token(':');
                goto end_of_asm;
        }
-       eat(':');
 
        asm_statement->outputs = parse_asm_arguments(true);
-       if (token.type != ':') {
+       if (!next_if(':')) {
                rem_anchor_token(':');
                goto end_of_asm;
        }
-       eat(':');
 
        asm_statement->inputs = parse_asm_arguments(false);
-       if (token.type != ':') {
+       if (!next_if(':')) {
                rem_anchor_token(':');
                goto end_of_asm;
        }
        rem_anchor_token(':');
-       eat(':');
 
        asm_statement->clobbers = parse_asm_clobbers();
 
@@ -9407,6 +9286,36 @@ end_error:
        return create_invalid_statement();
 }
 
+static statement_t *parse_label_inner_statement(char const *const label, bool const eat_empty_stmt)
+{
+       statement_t *inner_stmt;
+       switch (token.type) {
+               case '}':
+                       errorf(HERE, "%s at end of compound statement", label);
+                       inner_stmt = create_invalid_statement();
+                       break;
+
+               case ';':
+                       if (eat_empty_stmt) {
+                               /* Eat an empty statement here, to avoid the warning about an empty
+                                * statement after a label.  label:; is commonly used to have a label
+                                * before a closing brace. */
+                               inner_stmt = create_empty_statement();
+                               next_token();
+                               break;
+                       }
+                       /* FALLTHROUGH */
+
+               default:
+                       inner_stmt = parse_statement();
+                       if (inner_stmt->kind == STATEMENT_DECLARATION) {
+                               errorf(&inner_stmt->base.source_position, "declaration after %s", label);
+                       }
+                       break;
+       }
+       return inner_stmt;
+}
+
 /**
  * Parse a case statement.
  */
@@ -9419,11 +9328,9 @@ static statement_t *parse_case_statement(void)
 
        expression_t *const expression   = parse_expression();
        statement->case_label.expression = expression;
-       if (!is_constant_expression(expression)) {
-               /* This check does not prevent the error message in all cases of an
-                * prior error while parsing the expression.  At least it catches the
-                * common case of a mistyped enum entry. */
-               if (is_type_valid(skip_typeref(expression->base.type))) {
+       expression_classification_t const expr_class = is_constant_expression(expression);
+       if (expr_class != EXPR_CLASS_CONSTANT) {
+               if (expr_class != EXPR_CLASS_ERROR) {
                        errorf(pos, "case label does not reduce to an integer constant");
                }
                statement->case_label.is_bad = true;
@@ -9434,15 +9341,12 @@ static statement_t *parse_case_statement(void)
        }
 
        if (GNU_MODE) {
-               if (token.type == T_DOTDOTDOT) {
-                       next_token();
+               if (next_if(T_DOTDOTDOT)) {
                        expression_t *const end_range   = parse_expression();
                        statement->case_label.end_range = end_range;
-                       if (!is_constant_expression(end_range)) {
-                               /* This check does not prevent the error message in all cases of an
-                                * prior error while parsing the expression.  At least it catches the
-                                * common case of a mistyped enum entry. */
-                               if (is_type_valid(skip_typeref(end_range->base.type))) {
+                       expression_classification_t const end_class = is_constant_expression(end_range);
+                       if (end_class != EXPR_CLASS_CONSTANT) {
+                               if (end_class != EXPR_CLASS_ERROR) {
                                        errorf(pos, "case range does not reduce to an integer constant");
                                }
                                statement->case_label.is_bad = true;
@@ -9490,11 +9394,7 @@ end_error:
                errorf(pos, "case label not within a switch statement");
        }
 
-       statement_t *const inner_stmt = parse_statement();
-       statement->case_label.statement = inner_stmt;
-       if (inner_stmt->kind == STATEMENT_DECLARATION) {
-               errorf(&inner_stmt->base.source_position, "declaration after case label");
-       }
+       statement->case_label.statement = parse_label_inner_statement("case label", false);
 
        POP_PARENT;
        return statement;
@@ -9512,6 +9412,8 @@ static statement_t *parse_default_statement(void)
        PUSH_PARENT(statement);
 
        expect(':', end_error);
+end_error:
+
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
                if (def_label != NULL) {
@@ -9533,17 +9435,10 @@ static statement_t *parse_default_statement(void)
                        "'default' label not within a switch statement");
        }
 
-       statement_t *const inner_stmt = parse_statement();
-       statement->case_label.statement = inner_stmt;
-       if (inner_stmt->kind == STATEMENT_DECLARATION) {
-               errorf(&inner_stmt->base.source_position, "declaration after default label");
-       }
+       statement->case_label.statement = parse_label_inner_statement("default label", false);
 
        POP_PARENT;
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 /**
@@ -9552,7 +9447,7 @@ end_error:
 static statement_t *parse_label_statement(void)
 {
        assert(token.type == T_IDENTIFIER);
-       symbol_t *symbol = token.v.symbol;
+       symbol_t *symbol = token.symbol;
        label_t  *label  = get_label(symbol);
 
        statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
@@ -9575,28 +9470,7 @@ static statement_t *parse_label_statement(void)
 
        eat(':');
 
-       if (token.type == '}') {
-               /* TODO only warn? */
-               if (warning.other && false) {
-                       warningf(HERE, "label at end of compound statement");
-                       statement->label.statement = create_empty_statement();
-               } else {
-                       errorf(HERE, "label at end of compound statement");
-                       statement->label.statement = create_invalid_statement();
-               }
-       } else if (token.type == ';') {
-               /* Eat an empty statement here, to avoid the warning about an empty
-                * statement after a label.  label:; is commonly used to have a label
-                * before a closing brace. */
-               statement->label.statement = create_empty_statement();
-               next_token();
-       } else {
-               statement_t *const inner_stmt = parse_statement();
-               statement->label.statement = inner_stmt;
-               if (inner_stmt->kind == STATEMENT_DECLARATION) {
-                       errorf(&inner_stmt->base.source_position, "declaration after label");
-               }
-       }
+       statement->label.statement = parse_label_inner_statement("label", true);
 
        /* remember the labels in a list for later checking */
        *label_anchor = &statement->label;
@@ -9638,8 +9512,7 @@ end_error:
        statement->ifs.true_statement = true_stmt;
        rem_anchor_token(T_else);
 
-       if (token.type == T_else) {
-               next_token();
+       if (next_if(T_else)) {
                statement->ifs.false_statement = parse_statement();
        } else if (warning.parentheses &&
                        true_stmt->kind == STATEMENT_IF &&
@@ -9842,13 +9715,11 @@ static statement_t *parse_for(void)
        scope_t      *old_scope = scope_push(&statement->fors.scope);
 
        bool old_gcc_extension = in_gcc_extension;
-       while (token.type == T___extension__) {
-               next_token();
+       while (next_if(T___extension__)) {
                in_gcc_extension = true;
        }
 
-       if (token.type == ';') {
-               next_token();
+       if (next_if(';')) {
        } else if (is_declaration_specifier(&token, false)) {
                parse_declaration(record_entity, DECL_FLAGS_NONE);
        } else {
@@ -9916,8 +9787,7 @@ static statement_t *parse_goto(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
        eat(T_goto);
 
-       if (GNU_MODE && token.type == '*') {
-               next_token();
+       if (GNU_MODE && next_if('*')) {
                expression_t *expression = parse_expression();
                mark_vars_read(expression, NULL);
 
@@ -9938,7 +9808,7 @@ static statement_t *parse_goto(void)
 
                statement->gotos.expression = expression;
        } else if (token.type == T_IDENTIFIER) {
-               symbol_t *symbol = token.v.symbol;
+               symbol_t *symbol = token.symbol;
                next_token();
                statement->gotos.label = get_label(symbol);
        } else {
@@ -9947,7 +9817,7 @@ static statement_t *parse_goto(void)
                else
                        parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
                eat_until_anchor();
-               goto end_error;
+               return create_invalid_statement();
        }
 
        /* remember the goto's in a list for later checking */
@@ -9956,9 +9826,8 @@ static statement_t *parse_goto(void)
 
        expect(';', end_error);
 
-       return statement;
 end_error:
-       return create_invalid_statement();
+       return statement;
 }
 
 /**
@@ -10200,8 +10069,7 @@ static statement_t *parse_ms_try_statment(void)
 
        POP_PARENT;
 
-       if (token.type == T___except) {
-               eat(T___except);
+       if (next_if(T___except)) {
                expect('(', end_error);
                add_anchor_token(')');
                expression_t *const expr = parse_expression();
@@ -10218,8 +10086,7 @@ static statement_t *parse_ms_try_statment(void)
                rem_anchor_token(')');
                expect(')', end_error);
                statement->ms_try.final_statement = parse_compound_statement(false);
-       } else if (token.type == T__finally) {
-               eat(T___finally);
+       } else if (next_if(T__finally)) {
                statement->ms_try.final_statement = parse_compound_statement(false);
        } else {
                parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
@@ -10246,15 +10113,16 @@ static statement_t *parse_local_label_declaration(void)
 
        eat(T___label__);
 
-       entity_t *begin = NULL, *end = NULL;
-
-       while (true) {
+       entity_t *begin   = NULL;
+       entity_t *end     = NULL;
+       entity_t **anchor = &begin;
+       do {
                if (token.type != T_IDENTIFIER) {
                        parse_error_expected("while parsing local label declaration",
                                T_IDENTIFIER, NULL);
                        goto end_error;
                }
-               symbol_t *symbol = token.v.symbol;
+               symbol_t *symbol = token.symbol;
                entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
                if (entity != NULL && entity->base.parent_scope == current_scope) {
                        errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)",
@@ -10267,21 +10135,15 @@ static statement_t *parse_local_label_declaration(void)
                        entity->base.source_position = token.source_position;
                        entity->base.symbol          = symbol;
 
-                       if (end != NULL)
-                               end->base.next = entity;
-                       end = entity;
-                       if (begin == NULL)
-                               begin = entity;
+                       *anchor = entity;
+                       anchor  = &entity->base.next;
+                       end     = entity;
 
                        environment_push(entity);
                }
                next_token();
-
-               if (token.type != ',')
-                       break;
-               next_token();
-       }
-       eat(';');
+       } while (next_if(','));
+       expect(';', end_error);
 end_error:
        statement->declaration.declarations_begin = begin;
        statement->declaration.declarations_end   = end;
@@ -10296,13 +10158,13 @@ static void parse_namespace_definition(void)
        symbol_t *symbol = NULL;
 
        if (token.type == T_IDENTIFIER) {
-               symbol = token.v.symbol;
+               symbol = token.symbol;
                next_token();
 
                entity = get_entity(symbol, NAMESPACE_NORMAL);
-               if (entity       != NULL             &&
-                               entity->kind != ENTITY_NAMESPACE &&
-                               entity->base.parent_scope == current_scope) {
+               if (entity != NULL
+                               && entity->kind != ENTITY_NAMESPACE
+                               && entity->base.parent_scope == current_scope) {
                        if (!is_error_entity(entity)) {
                                error_redefined_as_different_kind(&token.source_position,
                                                entity, ENTITY_NAMESPACE);
@@ -10330,12 +10192,17 @@ static void parse_namespace_definition(void)
        size_t const  top       = environment_top();
        scope_t      *old_scope = scope_push(&entity->namespacee.members);
 
+       entity_t     *old_current_entity = current_entity;
+       current_entity = entity;
+
        expect('{', end_error);
        parse_externals();
        expect('}', end_error);
 
 end_error:
        assert(current_scope == &entity->namespacee.members);
+       assert(current_entity == entity);
+       current_entity = old_current_entity;
        scope_pop(old_scope);
        environment_pop_to(top);
 }
@@ -10356,7 +10223,7 @@ static statement_t *intern_parse_statement(void)
                token_type_t la1_type = (token_type_t)look_ahead(1)->type;
                if (la1_type == ':') {
                        statement = parse_label_statement();
-               } else if (is_typedef_symbol(token.v.symbol)) {
+               } else if (is_typedef_symbol(token.symbol)) {
                        statement = parse_declaration_statement();
                } else {
                        /* it's an identifier, the grammar says this must be an
@@ -10366,18 +10233,14 @@ static statement_t *intern_parse_statement(void)
                        switch (la1_type) {
                        case '&':
                        case '*':
-                               if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL)
-                                       goto expression_statment;
-                               /* FALLTHROUGH */
-
+                               if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) {
+                       default:
+                                       statement = parse_expression_statement();
+                               } else {
                        DECLARATION_START
                        case T_IDENTIFIER:
-                               statement = parse_declaration_statement();
-                               break;
-
-                       default:
-expression_statment:
-                               statement = parse_expression_statement();
+                                       statement = parse_declaration_statement();
+                               }
                                break;
                        }
                }
@@ -10387,9 +10250,7 @@ expression_statment:
        case T___extension__:
                /* This can be a prefix to a declaration or an expression statement.
                 * We simply eat it now and parse the rest with tail recursion. */
-               do {
-                       next_token();
-               } while (token.type == T___extension__);
+               while (next_if(T___extension__)) {}
                bool old_gcc_extension = in_gcc_extension;
                in_gcc_extension       = true;
                statement = intern_parse_statement();
@@ -10786,8 +10647,7 @@ static void parse_linkage_specification(void)
        }
        current_linkage = new_linkage;
 
-       if (token.type == '{') {
-               next_token();
+       if (next_if('{')) {
                parse_externals();
                expect('}', end_error);
        } else {
@@ -10916,8 +10776,7 @@ void start_parsing(void)
        error_count       = 0;
        warning_count     = 0;
 
-       type_set_output(stderr);
-       ast_set_output(stderr);
+       print_to_file(stderr);
 
        assert(unit == NULL);
        unit = allocate_ast_zero(sizeof(unit[0]));
@@ -11024,104 +10883,6 @@ void parse(void)
        incomplete_arrays = NULL;
 }
 
-/**
- * create a builtin function.
- */
-static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type)
-{
-       symbol_t *symbol = symbol_table_insert(name);
-       entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
-       entity->declaration.storage_class          = STORAGE_CLASS_EXTERN;
-       entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
-       entity->declaration.type                   = function_type;
-       entity->declaration.implicit               = true;
-       entity->base.symbol                        = symbol;
-       entity->base.source_position               = builtin_source_position;
-
-       entity->function.btk                       = kind;
-
-       record_entity(entity, /*is_definition=*/false);
-       return entity;
-}
-
-
-/**
- * Create predefined gnu builtins.
- */
-static void create_gnu_builtins(void)
-{
-#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b)
-
-       GNU_BUILTIN(alloca,         make_function_1_type(type_void_ptr, type_size_t));
-       GNU_BUILTIN(huge_val,       make_function_0_type(type_double));
-       GNU_BUILTIN(inf,            make_function_0_type(type_double));
-       GNU_BUILTIN(inff,           make_function_0_type(type_float));
-       GNU_BUILTIN(infl,           make_function_0_type(type_long_double));
-       GNU_BUILTIN(nan,            make_function_1_type(type_double, type_char_ptr));
-       GNU_BUILTIN(nanf,           make_function_1_type(type_float, type_char_ptr));
-       GNU_BUILTIN(nanl,           make_function_1_type(type_long_double, type_char_ptr));
-       GNU_BUILTIN(va_end,         make_function_1_type(type_void, type_valist));
-       GNU_BUILTIN(expect,         make_function_2_type(type_long, type_long, type_long));
-       GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int));
-       GNU_BUILTIN(frame_address,  make_function_1_type(type_void_ptr, type_unsigned_int));
-       GNU_BUILTIN(ffs,            make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(clz,            make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(ctz,            make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(popcount,       make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(parity,         make_function_1_type(type_int, type_unsigned_int));
-       GNU_BUILTIN(prefetch,       make_function_1_type_variadic(type_float, type_void_ptr));
-       GNU_BUILTIN(trap,           make_function_0_type_noreturn(type_void));
-
-#undef GNU_BUILTIN
-}
-
-/**
- * Create predefined MS intrinsics.
- */
-static void create_microsoft_intrinsics(void)
-{
-#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b)
-
-       /* intrinsics for all architectures */
-       MS_BUILTIN(_rotl,                  make_function_2_type(type_unsigned_int,   type_unsigned_int, type_int));
-       MS_BUILTIN(_rotr,                  make_function_2_type(type_unsigned_int,   type_unsigned_int, type_int));
-       MS_BUILTIN(_rotl64,                make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
-       MS_BUILTIN(_rotr64,                make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
-       MS_BUILTIN(_byteswap_ushort,       make_function_1_type(type_unsigned_short, type_unsigned_short));
-       MS_BUILTIN(_byteswap_ulong,        make_function_1_type(type_unsigned_long,  type_unsigned_long));
-       MS_BUILTIN(_byteswap_uint64,       make_function_1_type(type_unsigned_int64, type_unsigned_int64));
-
-       MS_BUILTIN(__debugbreak,            make_function_0_type(type_void));
-       MS_BUILTIN(_ReturnAddress,          make_function_0_type(type_void_ptr));
-       MS_BUILTIN(_AddressOfReturnAddress, make_function_0_type(type_void_ptr));
-       MS_BUILTIN(__popcount,              make_function_1_type(type_unsigned_int, type_unsigned_int));
-
-       /* x86/x64 only */
-       MS_BUILTIN(_enable,                make_function_0_type(type_void));
-       MS_BUILTIN(_disable,               make_function_0_type(type_void));
-       MS_BUILTIN(__inbyte,               make_function_1_type(type_unsigned_char, type_unsigned_short));
-       MS_BUILTIN(__inword,               make_function_1_type(type_unsigned_short, type_unsigned_short));
-       MS_BUILTIN(__indword,              make_function_1_type(type_unsigned_long, type_unsigned_short));
-       MS_BUILTIN(__outbyte,              make_function_2_type(type_void, type_unsigned_short, type_unsigned_char));
-       MS_BUILTIN(__outword,              make_function_2_type(type_void, type_unsigned_short, type_unsigned_short));
-       MS_BUILTIN(__outdword,             make_function_2_type(type_void, type_unsigned_short, type_unsigned_long));
-       MS_BUILTIN(__ud2,                  make_function_0_type_noreturn(type_void));
-       MS_BUILTIN(_BitScanForward,        make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
-       MS_BUILTIN(_BitScanReverse,        make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
-       MS_BUILTIN(_InterlockedExchange,   make_function_2_type(type_long, type_long_ptr, type_long));
-       MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64));
-
-       if (machine_size <= 32) {
-               MS_BUILTIN(__readeflags,           make_function_0_type(type_unsigned_int));
-               MS_BUILTIN(__writeeflags,          make_function_1_type(type_void, type_unsigned_int));
-       } else {
-               MS_BUILTIN(__readeflags,           make_function_0_type(type_unsigned_int64));
-               MS_BUILTIN(__writeeflags,          make_function_1_type(type_void, type_unsigned_int64));
-       }
-
-#undef MS_BUILTIN
-}
-
 /**
  * Initialize the parser.
  */