Simplify daisy chaining local labels.
[cparser] / parser.c
index 0d88cc0..c99427c 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);
 }
 
 /**
@@ -1137,8 +1055,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,7 +1077,7 @@ 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)) {
                errorf(&result->base.source_position,
@@ -1171,18 +1089,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 +1168,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 +1189,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 +1219,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 +1261,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 +1286,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 +1319,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 +1366,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 +1582,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 +1606,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 +1630,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 +1639,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 +1659,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 +1683,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 +1691,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;
                        }
                }
        }
@@ -1864,13 +1746,12 @@ 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();
@@ -1893,9 +1774,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 +1964,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 +1996,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 +2072,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 +2124,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(':');
 
@@ -2327,9 +2205,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);
@@ -2427,6 +2303,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.
@@ -2434,7 +2322,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)) {
@@ -2492,13 +2380,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;
@@ -2517,7 +2401,8 @@ 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;
 }
 
 
@@ -2536,7 +2421,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);
@@ -2621,12 +2506,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);
@@ -2636,11 +2520,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);
@@ -2651,33 +2531,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) {
@@ -2739,29 +2624,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;
@@ -2828,7 +2705,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);
@@ -2836,7 +2713,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;
@@ -2853,15 +2730,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;
 
@@ -2874,11 +2748,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) {
@@ -2904,10 +2777,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;
 }
@@ -2918,37 +2789,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);
@@ -3027,10 +2885,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;
                                }
@@ -3167,7 +3025,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
@@ -3181,7 +3039,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;
@@ -3444,18 +3302,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)
@@ -3491,7 +3344,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)
@@ -3518,7 +3371,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;
@@ -3536,7 +3389,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();
@@ -3572,11 +3425,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(','));
        }
 
 
@@ -3635,60 +3484,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;
@@ -3703,6 +3556,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);
 
@@ -3710,6 +3566,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);
@@ -3720,11 +3577,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;
 }
@@ -3739,6 +3593,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
@@ -3753,32 +3608,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 */
                        }
 
@@ -3798,11 +3632,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) {
@@ -3810,7 +3639,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();
@@ -3877,7 +3706,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) {
@@ -4036,15 +3866,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) {
@@ -4101,10 +3927,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);
                                }
@@ -4317,7 +4143,7 @@ static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
  * 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;
@@ -4480,15 +4306,15 @@ warn_redundant_declaration: ;
                                                        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;
@@ -4574,7 +4400,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
@@ -4722,9 +4548,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);
@@ -5087,9 +4912,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
@@ -5789,7 +5612,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;
@@ -5821,6 +5646,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);
        }
@@ -5843,7 +5670,7 @@ 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;
@@ -5989,7 +5816,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 == ':') {
@@ -6002,15 +5829,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;
@@ -6061,7 +5884,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 */
@@ -6069,7 +5892,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);
                                                }
                                        }
@@ -6078,11 +5901,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:
@@ -6117,12 +5936,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);
@@ -6159,82 +5978,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();
        }
+       literal->base.source_position = begin;
+       literal->literal.value        = res;
+
+       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;
+}
 
-       for (;;) {
-               switch (token.type) {
-                       case T_WIDE_STRING_LITERAL:
-                               wres = concat_wide_strings(&wres, &token.v.wide_string);
-                               break;
+static void warn_traditional_suffix(void)
+{
+       if (!warning.traditional)
+               return;
+       warningf(&token.source_position, "traditional C rejects the '%Y' suffix",
+                token.symbol);
+}
 
-                       case T_STRING_LITERAL:
-                               wres = concat_wide_string_string(&wres, &token.v.string);
-                               break;
+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;
 }
 
 /**
@@ -6242,20 +6163,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;
 }
 
 /**
@@ -6263,34 +6187,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,
@@ -6320,91 +6228,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.
  *
@@ -6435,57 +6258,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;
 }
 
 /**
@@ -6517,10 +6341,8 @@ static entity_t *parse_qualified_identifier(void)
        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) {
@@ -6528,16 +6350,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:
@@ -6575,12 +6396,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);
 }
@@ -6727,7 +6543,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;
 
@@ -6791,7 +6607,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();
                }
        }
@@ -6878,13 +6694,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);
@@ -6892,15 +6707,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;
@@ -7226,7 +7040,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);
@@ -7250,10 +7064,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);
 
@@ -7263,21 +7078,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;
 }
 
 /**
@@ -7286,54 +7096,57 @@ 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);
@@ -7429,7 +7242,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;
@@ -7478,7 +7291,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;
@@ -7605,8 +7418,21 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                        }
                        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)) {
+                               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;
 
@@ -7627,7 +7453,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                                locality = rw->next;
                        }
                        break;
-               }
                default:
                        break;
        }
@@ -7670,17 +7495,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(')');
@@ -7708,6 +7529,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);
 
@@ -7840,7 +7665,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;
@@ -7869,13 +7694,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;
@@ -7927,7 +7745,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;
@@ -7958,7 +7776,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;
 }
@@ -7996,14 +7814,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);
@@ -8267,7 +8084,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);                                         \
                                                                                 \
@@ -8583,8 +8400,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");
        }
@@ -8934,13 +8751,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;
@@ -9074,7 +8898,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);                                                 \
@@ -9114,7 +8938,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();
@@ -9159,7 +8983,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);
 }
 
 /**
@@ -9274,14 +9098,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);
                }
@@ -9341,7 +9164,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);
@@ -9354,9 +9179,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;
@@ -9369,23 +9193,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;
@@ -9401,36 +9220,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();
 
@@ -9450,6 +9268,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.
  */
@@ -9477,8 +9325,7 @@ 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)) {
@@ -9533,11 +9380,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;
@@ -9555,6 +9398,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) {
@@ -9576,17 +9421,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();
 }
 
 /**
@@ -9595,7 +9433,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);
@@ -9618,28 +9456,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;
@@ -9681,8 +9498,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 &&
@@ -9885,13 +9701,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 {
@@ -9959,8 +9773,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);
 
@@ -9981,7 +9794,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 {
@@ -9990,7 +9803,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 */
@@ -9999,9 +9812,8 @@ static statement_t *parse_goto(void)
 
        expect(';', end_error);
 
-       return statement;
 end_error:
-       return create_invalid_statement();
+       return statement;
 }
 
 /**
@@ -10243,8 +10055,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();
@@ -10261,8 +10072,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);
@@ -10289,15 +10099,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)",
@@ -10310,21 +10121,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;
@@ -10339,13 +10144,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);
@@ -10373,12 +10178,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);
 }
@@ -10399,7 +10209,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
@@ -10409,18 +10219,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;
                        }
                }
@@ -10430,9 +10236,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();
@@ -10829,8 +10633,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 {
@@ -10959,8 +10762,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]));
@@ -11067,104 +10869,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.
  */