main: rework preprocessor invocation
[cparser] / parser.c
index 8d29162..76343b5 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -20,6 +20,7 @@
 #include <config.h>
 
 #include <assert.h>
+#include <ctype.h>
 #include <stdarg.h>
 #include <stdbool.h>
 
@@ -27,7 +28,7 @@
 #include "parser.h"
 #include "diagnostic.h"
 #include "format_check.h"
-#include "lexer.h"
+#include "preprocessor.h"
 #include "symbol_t.h"
 #include "token_t.h"
 #include "types.h"
@@ -40,6 +41,7 @@
 #include "walk.h"
 #include "warning.h"
 #include "printer.h"
+#include "ast2firm.h"
 #include "adt/bitfiddle.h"
 #include "adt/error.h"
 #include "adt/array.h"
@@ -59,7 +61,7 @@ struct declaration_specifiers_t {
        storage_class_t    storage_class;
        unsigned char      alignment;         /**< Alignment, 0 if not set. */
        bool               is_inline    : 1;
-       bool               thread_local : 1;  /**< GCC __thread */
+       bool               thread_local : 1;
        attribute_t       *attributes;        /**< list of attributes */
        type_t            *type;
 };
@@ -109,6 +111,12 @@ static declaration_t      **incomplete_arrays;
 static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 
 
+#define PUSH_CURRENT_ENTITY(entity) \
+       entity_t *const new_current_entity = (entity); \
+       entity_t *const old_current_entity = current_entity; \
+       ((void)(current_entity = new_current_entity))
+#define POP_CURRENT_ENTITY() (assert(current_entity == new_current_entity), (void)(current_entity = old_current_entity))
+
 #define PUSH_PARENT(stmt) \
        statement_t *const new_parent = (stmt); \
        statement_t *const old_parent = current_parent; \
@@ -118,22 +126,20 @@ static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 #define PUSH_SCOPE(scope) \
        size_t   const top       = environment_top(); \
        scope_t *const new_scope = (scope); \
-       scope_t *const old_scope = scope_push(new_scope)
-#define POP_SCOPE() (assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top))
+       scope_t *const old_scope = (new_scope ? scope_push(new_scope) : NULL)
+#define PUSH_SCOPE_STATEMENT(scope) PUSH_SCOPE(c_mode & (_C99 | _CXX) ? (scope) : NULL)
+#define POP_SCOPE() (new_scope ? assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top) : (void)0)
 
 #define PUSH_EXTENSION() \
        (void)0; \
        bool const old_gcc_extension = in_gcc_extension; \
-       while (next_if(T___extension__)) { \
+       while (accept(T___extension__)) { \
                in_gcc_extension = true; \
        } \
        do {} while (0)
 #define POP_EXTENSION() \
        ((void)(in_gcc_extension = old_gcc_extension))
 
-/** special symbol used for anonymous entities. */
-static symbol_t *sym_anonymous = NULL;
-
 /** The token anchor set */
 static unsigned short token_anchor_set[T_LAST_TOKEN];
 
@@ -178,7 +184,7 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_static:          \
        case T_auto:            \
        case T_register:        \
-       case T___thread:
+       case T__Thread_local:
 
 #define TYPE_QUALIFIERS     \
        case T_const:           \
@@ -240,21 +246,14 @@ static void semantic_comparison(binary_expression_t *expression);
        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_NUMBER:                    \
        case T_MINUSMINUS:                \
        case T_PLUSPLUS:                  \
        case T_STRING_LITERAL:            \
-       case T_WIDE_CHARACTER_CONSTANT:   \
-       case T_WIDE_STRING_LITERAL:       \
+       case T__Alignof:                  \
        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:       \
@@ -298,7 +297,6 @@ static size_t get_statement_struct_size(statement_kind_t kind)
                [STATEMENT_GOTO]          = sizeof(goto_statement_t),
                [STATEMENT_LABEL]         = sizeof(label_statement_t),
                [STATEMENT_CASE_LABEL]    = sizeof(case_label_statement_t),
-               [STATEMENT_WHILE]         = sizeof(while_statement_t),
                [STATEMENT_DO_WHILE]      = sizeof(do_while_statement_t),
                [STATEMENT_FOR]           = sizeof(for_statement_t),
                [STATEMENT_ASM]           = sizeof(asm_statement_t),
@@ -323,14 +321,10 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_ENUM_CONSTANT]              = sizeof(reference_expression_t),
                [EXPR_LITERAL_BOOLEAN]            = sizeof(literal_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_LITERAL_CHARACTER]          = sizeof(string_literal_expression_t),
+               [EXPR_LITERAL_MS_NOOP]            = sizeof(literal_expression_t),
                [EXPR_STRING_LITERAL]             = sizeof(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),
@@ -374,7 +368,7 @@ static statement_t *allocate_statement_zero(statement_kind_t kind)
 
        res->base.kind            = kind;
        res->base.parent          = current_parent;
-       res->base.source_position = token.base.source_position;
+       res->base.source_position = *HERE;
        return res;
 }
 
@@ -391,7 +385,7 @@ static expression_t *allocate_expression_zero(expression_kind_t kind)
 
        res->base.kind            = kind;
        res->base.type            = type_error_type;
-       res->base.source_position = token.base.source_position;
+       res->base.source_position = *HERE;
        return res;
 }
 
@@ -431,8 +425,7 @@ static size_t get_initializer_size(initializer_kind_t kind)
 {
        static const size_t sizes[] = {
                [INITIALIZER_VALUE]       = sizeof(initializer_value_t),
-               [INITIALIZER_STRING]      = sizeof(initializer_string_t),
-               [INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t),
+               [INITIALIZER_STRING]      = sizeof(initializer_value_t),
                [INITIALIZER_LIST]        = sizeof(initializer_list_t),
                [INITIALIZER_DESIGNATOR]  = sizeof(initializer_designator_t)
        };
@@ -475,8 +468,8 @@ static size_t label_top(void)
 static inline void next_token(void)
 {
        token                              = lookahead_buffer[lookahead_bufpos];
-       lookahead_buffer[lookahead_bufpos] = lexer_token;
-       lexer_next_token();
+       lookahead_buffer[lookahead_bufpos] = pp_token;
+       next_preprocessing_token();
 
        lookahead_bufpos = (lookahead_bufpos + 1) % MAX_LOOKAHEAD;
 
@@ -486,10 +479,23 @@ static inline void next_token(void)
 #endif
 }
 
-static inline bool next_if(int const type)
+static inline void eat(token_kind_t const kind)
 {
-       if (token.kind == type) {
-               next_token();
+       assert(token.kind == kind);
+       (void)kind;
+       next_token();
+}
+
+/**
+ * Consume the current token, if it is of the expected kind.
+ *
+ * @param  kind  The kind of token to consume.
+ * @return Whether the token was consumed.
+ */
+static inline bool accept(token_kind_t const kind)
+{
+       if (token.kind == kind) {
+               eat(kind);
                return true;
        } else {
                return false;
@@ -509,39 +515,18 @@ static inline const token_t *look_ahead(size_t num)
 /**
  * Adds a token type to the token type anchor set (a multi-set).
  */
-static void add_anchor_token(int token_kind)
+static void add_anchor_token(token_kind_t const token_kind)
 {
-       assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+       assert(token_kind < T_LAST_TOKEN);
        ++token_anchor_set[token_kind];
 }
 
-/**
- * Set the number of tokens types of the given type
- * to zero and return the old count.
- */
-static int save_and_reset_anchor_state(int token_kind)
-{
-       assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
-       int count = token_anchor_set[token_kind];
-       token_anchor_set[token_kind] = 0;
-       return count;
-}
-
-/**
- * Restore the number of token types to the given count.
- */
-static void restore_anchor_state(int token_kind, int count)
-{
-       assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
-       token_anchor_set[token_kind] = count;
-}
-
 /**
  * Remove a token type from the token type anchor set (a multi-set).
  */
-static void rem_anchor_token(int token_kind)
+static void rem_anchor_token(token_kind_t const token_kind)
 {
-       assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+       assert(token_kind < T_LAST_TOKEN);
        assert(token_anchor_set[token_kind] != 0);
        --token_anchor_set[token_kind];
 }
@@ -549,9 +534,9 @@ static void rem_anchor_token(int token_kind)
 /**
  * Eat tokens until a matching token type is found.
  */
-static void eat_until_matching_token(int type)
+static void eat_until_matching_token(token_kind_t const type)
 {
-       int end_token;
+       token_kind_t end_token;
        switch (type) {
                case '(': end_token = ')';  break;
                case '{': end_token = '}';  break;
@@ -618,11 +603,9 @@ static void eat_until_anchor(void)
 static void eat_block(void)
 {
        eat_until_matching_token('{');
-       next_if('}');
+       accept('}');
 }
 
-#define eat(token_kind) (assert(token.kind == (token_kind)), next_token())
-
 /**
  * Report a parse error because an expected token was not found.
  */
@@ -651,23 +634,39 @@ static void type_error_incompatible(const char *msg,
               msg, type1, type2);
 }
 
+static bool skip_till(token_kind_t const expected, char const *const context)
+{
+       if (UNLIKELY(token.kind != expected)) {
+               parse_error_expected(context, expected, NULL);
+               add_anchor_token(expected);
+               eat_until_anchor();
+               rem_anchor_token(expected);
+               if (token.kind != expected)
+                       return false;
+       }
+       return true;
+}
+
 /**
  * Expect the current token is the expected token.
- * If not, generate an error, eat the current statement,
- * and goto the error_label label.
- */
-#define expect(expected, error_label)                     \
-       do {                                                  \
-               if (UNLIKELY(token.kind != (expected))) {         \
-                       parse_error_expected(NULL, (expected), NULL); \
-                       add_anchor_token(expected);                   \
-                       eat_until_anchor();                           \
-                       rem_anchor_token(expected);                   \
-                       if (token.kind != (expected))                 \
-                         goto error_label;                           \
-               }                                                 \
-               next_token();                                     \
-       } while (0)
+ * If not, generate an error and skip until the next anchor.
+ */
+static void expect(token_kind_t const expected)
+{
+       if (skip_till(expected, NULL))
+               eat(expected);
+}
+
+static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
+{
+       if (!skip_till(T_IDENTIFIER, context))
+               return NULL;
+       symbol_t *const sym = token.base.symbol;
+       if (pos)
+               *pos = *HERE;
+       eat(T_IDENTIFIER);
+       return sym;
+}
 
 /**
  * Push a given scope on the scope stack and make it the
@@ -1041,27 +1040,67 @@ static expression_t *parse_assignment_expression(void)
        return parse_subexpression(PREC_ASSIGNMENT);
 }
 
-static void warn_string_concat(const source_position_t *pos)
+static void append_string(string_t const *const s)
 {
-       warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation");
+       /* FIXME Using the ast_obstack is a hack.  Using the symbol_obstack is not
+        * possible, because other tokens are grown there alongside. */
+       obstack_grow(&ast_obstack, s->begin, s->size);
 }
 
-static string_t parse_string_literals(void)
+static string_t finish_string(string_encoding_t const enc)
 {
-       assert(token.kind == T_STRING_LITERAL);
-       string_t result = token.string.string;
+       obstack_1grow(&ast_obstack, '\0');
+       size_t      const size   = obstack_object_size(&ast_obstack) - 1;
+       char const *const string = obstack_finish(&ast_obstack);
+       return (string_t){ string, size, enc };
+}
 
-       next_token();
+static string_t concat_string_literals(void)
+{
+       assert(token.kind == T_STRING_LITERAL);
 
-       while (token.kind == T_STRING_LITERAL) {
-               warn_string_concat(&token.base.source_position);
-               result = concat_strings(&result, &token.string.string);
-               next_token();
+       string_t result;
+       if (look_ahead(1)->kind == T_STRING_LITERAL) {
+               append_string(&token.literal.string);
+               eat(T_STRING_LITERAL);
+               warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
+               string_encoding_t enc = token.literal.string.encoding;
+               do {
+                       string_encoding_t const new_enc = token.literal.string.encoding;
+                       if (new_enc != enc && new_enc != STRING_ENCODING_CHAR) {
+                               if (enc == STRING_ENCODING_CHAR) {
+                                       enc = new_enc;
+                               } else {
+                                       errorf(HERE, "concatenating string literals with encodings %s and %s", get_string_encoding_prefix(enc), get_string_encoding_prefix(new_enc));
+                               }
+                       }
+                       append_string(&token.literal.string);
+                       eat(T_STRING_LITERAL);
+               } while (token.kind == T_STRING_LITERAL);
+               result = finish_string(enc);
+       } else {
+               result = token.literal.string;
+               eat(T_STRING_LITERAL);
        }
 
        return result;
 }
 
+static string_t parse_string_literals(char const *const context)
+{
+       if (!skip_till(T_STRING_LITERAL, context))
+               return (string_t){ "", 0, STRING_ENCODING_CHAR };
+
+       source_position_t const pos = *HERE;
+       string_t          const res = concat_string_literals();
+
+       if (res.encoding != STRING_ENCODING_CHAR) {
+               errorf(&pos, "expected plain string literal, got %s string literal", get_string_encoding_prefix(res.encoding));
+       }
+
+       return res;
+}
+
 static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
 {
        attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
@@ -1108,10 +1147,9 @@ static attribute_argument_t *parse_attribute_arguments(void)
                /* is it an identifier */
                if (token.kind == T_IDENTIFIER
                                && (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
-                       symbol_t *symbol   = token.identifier.symbol;
                        argument->kind     = ATTRIBUTE_ARGUMENT_SYMBOL;
-                       argument->v.symbol = symbol;
-                       next_token();
+                       argument->v.symbol = token.base.symbol;
+                       eat(T_IDENTIFIER);
                } else {
                        /* must be an expression */
                        expression_t *expression = parse_assignment_expression();
@@ -1123,9 +1161,8 @@ static attribute_argument_t *parse_attribute_arguments(void)
                /* append argument */
                *anchor = argument;
                anchor  = &argument->next;
-       } while (next_if(','));
-       expect(')', end_error);
-end_error:
+       } while (accept(','));
+       expect(')');
        return first;
 }
 
@@ -1133,59 +1170,15 @@ static attribute_t *parse_attribute_asm(void)
 {
        attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
        eat(T_asm);
-
-       expect('(', end_error);
+       expect('(');
        attribute->a.arguments = parse_attribute_arguments();
        return attribute;
-
-end_error:
-       return NULL;
-}
-
-static symbol_t *get_symbol_from_token(void)
-{
-       switch(token.kind) {
-       case T_IDENTIFIER:
-               return token.identifier.symbol;
-       case T_auto:
-       case T_char:
-       case T_double:
-       case T_enum:
-       case T_extern:
-       case T_float:
-       case T_int:
-       case T_long:
-       case T_register:
-       case T_short:
-       case T_static:
-       case T_struct:
-       case T_union:
-       case T_unsigned:
-       case T_void:
-       case T_bool:
-       case T__Bool:
-       case T_class:
-       case T_explicit:
-       case T_export:
-       case T_wchar_t:
-       case T_const:
-       case T_signed:
-       case T___real__:
-       case T___imag__:
-       case T_restrict:
-       case T_volatile:
-       case T_inline:
-               /* maybe we need more tokens ... add them on demand */
-               return get_token_kind_symbol(token.kind);
-       default:
-               return NULL;
-       }
 }
 
 static attribute_t *parse_attribute_gnu_single(void)
 {
        /* parse "any-word" */
-       symbol_t *symbol = get_symbol_from_token();
+       symbol_t *const symbol = token.base.symbol;
        if (symbol == NULL) {
                parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
                return NULL;
@@ -1195,6 +1188,12 @@ static attribute_t *parse_attribute_gnu_single(void)
        char const *const name = symbol->string;
        for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) {
                if (kind > ATTRIBUTE_GNU_LAST) {
+                       /* special case for "__const" */
+                       if (token.kind == T_const) {
+                               kind = ATTRIBUTE_GNU_CONST;
+                               break;
+                       }
+
                        warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name);
                        /* TODO: we should still save the attribute in the list... */
                        kind = ATTRIBUTE_UNKNOWN;
@@ -1210,7 +1209,7 @@ static attribute_t *parse_attribute_gnu_single(void)
        next_token();
 
        /* parse arguments */
-       if (next_if('('))
+       if (accept('('))
                attribute->a.arguments = parse_attribute_arguments();
 
        return attribute;
@@ -1222,21 +1221,23 @@ static attribute_t *parse_attribute_gnu(void)
        attribute_t **anchor = &first;
 
        eat(T___attribute__);
-       expect('(', end_error);
-       expect('(', end_error);
+       add_anchor_token(')');
+       add_anchor_token(',');
+       expect('(');
+       expect('(');
 
        if (token.kind != ')') do {
                attribute_t *attribute = parse_attribute_gnu_single();
-               if (attribute == NULL)
-                       goto end_error;
-
-               *anchor = attribute;
-               anchor  = &attribute->next;
-       } while (next_if(','));
-       expect(')', end_error);
-       expect(')', end_error);
+               if (attribute) {
+                       *anchor = attribute;
+                       anchor  = &attribute->next;
+               }
+       } while (accept(','));
+       rem_anchor_token(',');
+       rem_anchor_token(')');
 
-end_error:
+       expect(')');
+       expect(')');
        return first;
 }
 
@@ -1373,11 +1374,7 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
                                return;
 
                        if (lhs_ent != entity && lhs_ent != ENT_ANY) {
-                               if (entity->kind == ENTITY_VARIABLE) {
-                                       entity->variable.read = true;
-                               } else {
-                                       entity->parameter.read = true;
-                               }
+                               entity->variable.read = true;
                        }
                        return;
                }
@@ -1508,9 +1505,9 @@ unary:
                        return;
 
                case EXPR_LITERAL_CASES:
+               case EXPR_LITERAL_CHARACTER:
                case EXPR_ERROR:
                case EXPR_STRING_LITERAL:
-               case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO init?
                case EXPR_SIZEOF:
                case EXPR_CLASSIFY_TYPE:
@@ -1538,27 +1535,23 @@ static designator_t *parse_designation(void)
                switch (token.kind) {
                case '[':
                        designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = token.base.source_position;
-                       next_token();
+                       designator->source_position = *HERE;
+                       eat('[');
                        add_anchor_token(']');
                        designator->array_index = parse_constant_expression();
                        rem_anchor_token(']');
-                       expect(']', end_error);
+                       expect(']');
                        break;
                case '.':
                        designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = token.base.source_position;
-                       next_token();
-                       if (token.kind != T_IDENTIFIER) {
-                               parse_error_expected("while parsing designator",
-                                                    T_IDENTIFIER, NULL);
+                       designator->source_position = *HERE;
+                       eat('.');
+                       designator->symbol = expect_identifier("while parsing designator", NULL);
+                       if (!designator->symbol)
                                return NULL;
-                       }
-                       designator->symbol = token.identifier.symbol;
-                       next_token();
                        break;
                default:
-                       expect('=', end_error);
+                       expect('=');
                        return result;
                }
 
@@ -1566,33 +1559,6 @@ static designator_t *parse_designation(void)
                *anchor = designator;
                anchor  = &designator->next;
        }
-end_error:
-       return NULL;
-}
-
-static initializer_t *initializer_from_string(array_type_t *const type,
-                                              const string_t *const string)
-{
-       /* TODO: check len vs. size of array type */
-       (void) type;
-
-       initializer_t *initializer = allocate_initializer_zero(INITIALIZER_STRING);
-       initializer->string.string = *string;
-
-       return initializer;
-}
-
-static initializer_t *initializer_from_wide_string(array_type_t *const type,
-                                                   const string_t *const string)
-{
-       /* TODO: check len vs. size of array type */
-       (void) type;
-
-       initializer_t *const initializer =
-               allocate_initializer_zero(INITIALIZER_WIDE_STRING);
-       initializer->wide_string.string = *string;
-
-       return initializer;
 }
 
 /**
@@ -1603,39 +1569,36 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
 {
        /* TODO check that expression is a constant expression */
 
-       /* Â§6.7.8.14/15 char array may be initialized by string literals */
-       type_t *type           = skip_typeref(orig_type);
-       type_t *expr_type_orig = expression->base.type;
-       type_t *expr_type      = skip_typeref(expr_type_orig);
+       type_t *const type = skip_typeref(orig_type);
 
-       if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
+       /* Â§6.7.8.14/15 char array may be initialized by string literals */
+       if (expression->kind == EXPR_STRING_LITERAL && is_type_array(type)) {
                array_type_t *const array_type   = &type->array;
                type_t       *const element_type = skip_typeref(array_type->element_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_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->string_literal.value);
-                               }
-                               break;
+               switch (expression->string_literal.value.encoding) {
+               case STRING_ENCODING_CHAR:
+               case STRING_ENCODING_UTF8: {
+                       if (is_type_atomic(element_type, ATOMIC_TYPE_CHAR)  ||
+                           is_type_atomic(element_type, ATOMIC_TYPE_SCHAR) ||
+                           is_type_atomic(element_type, ATOMIC_TYPE_UCHAR)) {
+                               goto make_string_init;
                        }
+                       break;
+               }
 
-                       default:
-                               break;
+               case STRING_ENCODING_CHAR16:
+               case STRING_ENCODING_CHAR32:
+               case STRING_ENCODING_WIDE: {
+                       assert(is_type_pointer(expression->base.type));
+                       type_t *const init_type = get_unqualified_type(expression->base.type->pointer.points_to);
+                       if (types_compatible(get_unqualified_type(element_type), init_type)) {
+make_string_init:;
+                               initializer_t *const init = allocate_initializer_zero(INITIALIZER_STRING);
+                               init->value.value = expression;
+                               return init;
                        }
+                       break;
+               }
                }
        }
 
@@ -1689,7 +1652,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 
        bool additional_warning_displayed = false;
        while (braces > 0) {
-               next_if(',');
+               accept(',');
                if (token.kind != '}') {
                        if (!additional_warning_displayed) {
                                warningf(WARN_OTHER, HERE, "additional elements in scalar initializer");
@@ -1887,7 +1850,8 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        }
                } else {
                        expression_t *array_index = designator->array_index;
-                       assert(designator->array_index != NULL);
+                       if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT)
+                               return true;
 
                        if (!is_type_array(type)) {
                                if (is_type_valid(type)) {
@@ -1980,7 +1944,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
  */
 static void skip_initializers(void)
 {
-       next_if('{');
+       accept('{');
 
        while (token.kind != '}') {
                if (token.kind == T_EOF)
@@ -2012,6 +1976,8 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                return create_empty_initializer();
        }
 
+       initializer_t *result = NULL;
+
        type_t *orig_type = path->top_type;
        type_t *type      = NULL;
 
@@ -2031,8 +1997,8 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') {
                        /* GNU-style designator ("identifier: value") */
                        designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = token.base.source_position;
-                       designator->symbol          = token.identifier.symbol;
+                       designator->source_position = *HERE;
+                       designator->symbol          = token.base.symbol;
                        eat(T_IDENTIFIER);
                        eat(':');
 
@@ -2061,9 +2027,7 @@ finish_designator:
                        } else {
                                if (type == NULL) {
                                        if (env->entity != NULL) {
-                                               errorf(HERE,
-                                                    "extra brace group at end of initializer for '%Y'",
-                                                    env->entity->base.symbol);
+                                               errorf(HERE, "extra brace group at end of initializer for '%N'", env->entity);
                                        } else {
                                                errorf(HERE, "extra brace group at end of initializer");
                                        }
@@ -2078,13 +2042,12 @@ finish_designator:
                                                            env);
                                rem_anchor_token('}');
 
-                               if (type != NULL) {
-                                       ascend_from_subtype(path);
-                                       expect('}', end_error);
-                               } else {
-                                       expect('}', end_error);
+                               expect('}');
+
+                               if (!type)
                                        goto error_parse_next;
-                               }
+
+                               ascend_from_subtype(path);
                        }
                } else {
                        /* must be an expression */
@@ -2109,7 +2072,7 @@ finish_designator:
 
                                source_position_t const* const pos = &expression->base.source_position;
                                if (env->entity != NULL) {
-                                       warningf(WARN_OTHER, pos, "excess elements in initializer for '%Y'", env->entity->base.symbol);
+                                       warningf(WARN_OTHER, pos, "excess elements in initializer for '%N'", env->entity);
                                } else {
                                        warningf(WARN_OTHER, pos, "excess elements in initializer");
                                }
@@ -2117,17 +2080,15 @@ finish_designator:
                        }
 
                        /* handle { "string" } special case */
-                       if ((expression->kind == EXPR_STRING_LITERAL
-                                       || expression->kind == EXPR_WIDE_STRING_LITERAL)
-                                       && outer_type != NULL) {
-                               sub = initializer_from_expression(outer_type, expression);
-                               if (sub != NULL) {
-                                       next_if(',');
+                       if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
+                               result = initializer_from_expression(outer_type, expression);
+                               if (result != NULL) {
+                                       accept(',');
                                        if (token.kind != '}') {
-                                               warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type);
+                                               warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type);
                                        }
                                        /* TODO: eat , ... */
-                                       return sub;
+                                       goto out;
                                }
                        }
 
@@ -2168,10 +2129,8 @@ finish_designator:
                ARR_APP1(initializer_t*, initializers, sub);
 
 error_parse_next:
-               if (token.kind == '}') {
+               if (!accept(','))
                        break;
-               }
-               expect(',', end_error);
                if (token.kind == '}') {
                        break;
                }
@@ -2189,22 +2148,19 @@ error_parse_next:
 
        size_t len  = ARR_LEN(initializers);
        size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]);
-       initializer_t *result = allocate_ast_zero(size);
-       result->kind          = INITIALIZER_LIST;
-       result->list.len      = len;
+       result = allocate_ast_zero(size);
+       result->kind     = INITIALIZER_LIST;
+       result->list.len = len;
        memcpy(&result->list.initializers, initializers,
               len * sizeof(initializers[0]));
-
-       DEL_ARR_F(initializers);
-       ascend_to(path, top_path_level+1);
-
-       return result;
+       goto out;
 
 end_error:
        skip_initializers();
+out:
        DEL_ARR_F(initializers);
        ascend_to(path, top_path_level+1);
-       return NULL;
+       return result;
 }
 
 static expression_t *make_size_literal(size_t value)
@@ -2248,8 +2204,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                max_index = path.max_index;
                DEL_ARR_F(path.path);
 
-               expect('}', end_error);
-end_error:;
+               expect('}');
        } else {
                /* parse_scalar_initializer() also works in this case: we simply
                 * have an expression without {} around it */
@@ -2267,13 +2222,10 @@ end_error:;
                        size = max_index + 1;
                        break;
 
-               case INITIALIZER_STRING:
-                       size = result->string.string.size;
-                       break;
-
-               case INITIALIZER_WIDE_STRING:
-                       size = result->wide_string.string.size;
+               case INITIALIZER_STRING: {
+                       size = get_string_len(&get_init_string(result)->value) + 1;
                        break;
+               }
 
                case INITIALIZER_DESIGNATOR:
                case INITIALIZER_VALUE:
@@ -2325,9 +2277,9 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
        if (token.kind == T_IDENTIFIER) {
                /* the compound has a name, check if we have seen it already */
-               symbol = token.identifier.symbol;
+               symbol = token.base.symbol;
                entity = get_tag(symbol, kind);
-               next_token();
+               eat(T_IDENTIFIER);
 
                if (entity != NULL) {
                        if (entity->base.parent_scope != current_scope &&
@@ -2352,10 +2304,9 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol);
-               entity->compound.alignment   = 1;
-               entity->base.source_position = pos;
-               entity->base.parent_scope    = current_scope;
+               entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol, &pos);
+               entity->compound.alignment = 1;
+               entity->base.parent_scope  = current_scope;
                if (symbol != NULL) {
                        environment_push(entity);
                }
@@ -2373,6 +2324,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if (attributes != NULL) {
+               entity->compound.attributes = attributes;
                handle_entity_attributes(attributes, entity);
        }
 
@@ -2385,27 +2337,21 @@ static void parse_enum_entries(type_t *const enum_type)
 
        if (token.kind == '}') {
                errorf(HERE, "empty enum not allowed");
-               next_token();
+               eat('}');
                return;
        }
 
        add_anchor_token('}');
+       add_anchor_token(',');
        do {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing enum entry", T_IDENTIFIER, NULL);
-                       eat_block();
-                       rem_anchor_token('}');
-                       return;
-               }
-
-               symbol_t *symbol       = token.identifier.symbol;
-               entity_t *const entity
-                       = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol);
+               add_anchor_token('=');
+               source_position_t pos;
+               symbol_t *const symbol = expect_identifier("while parsing enum entry", &pos);
+               entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol, &pos);
                entity->enum_value.enum_type = enum_type;
-               entity->base.source_position = token.base.source_position;
-               next_token();
+               rem_anchor_token('=');
 
-               if (next_if('=')) {
+               if (accept('=')) {
                        expression_t *value = parse_constant_expression();
 
                        value = create_implicit_cast(value, enum_type);
@@ -2415,13 +2361,11 @@ static void parse_enum_entries(type_t *const enum_type)
                }
 
                record_entity(entity, false);
-       } while (next_if(',') && token.kind != '}');
+       } while (accept(',') && token.kind != '}');
+       rem_anchor_token(',');
        rem_anchor_token('}');
 
-       expect('}', end_error);
-
-end_error:
-       ;
+       expect('}');
 }
 
 static type_t *parse_enum_specifier(void)
@@ -2433,9 +2377,9 @@ static type_t *parse_enum_specifier(void)
        eat(T_enum);
        switch (token.kind) {
                case T_IDENTIFIER:
-                       symbol = token.identifier.symbol;
+                       symbol = token.base.symbol;
                        entity = get_tag(symbol, ENTITY_ENUM);
-                       next_token();
+                       eat(T_IDENTIFIER);
 
                        if (entity != NULL) {
                                if (entity->base.parent_scope != current_scope &&
@@ -2462,9 +2406,8 @@ static type_t *parse_enum_specifier(void)
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol);
-               entity->base.source_position = pos;
-               entity->base.parent_scope    = current_scope;
+               entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol, &pos);
+               entity->base.parent_scope = current_scope;
        }
 
        type_t *const type     = allocate_type_zero(TYPE_ENUM);
@@ -2508,14 +2451,14 @@ static type_t *parse_typeof(void)
 
        type_t *type;
 
-       expect('(', end_error);
        add_anchor_token(')');
+       expect('(');
 
        expression_t *expression  = NULL;
 
        switch (token.kind) {
        case T_IDENTIFIER:
-               if (is_typedef_symbol(token.identifier.symbol)) {
+               if (is_typedef_symbol(token.base.symbol)) {
        DECLARATION_START
                        type = parse_typename();
                } else {
@@ -2527,18 +2470,17 @@ static type_t *parse_typeof(void)
        }
 
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        type_t *typeof_type              = allocate_type_zero(TYPE_TYPEOF);
        typeof_type->typeoft.expression  = expression;
        typeof_type->typeoft.typeof_type = type;
 
        return typeof_type;
-end_error:
-       return NULL;
 }
 
 typedef enum specifiers_t {
+       SPECIFIER_NONE      = 0,
        SPECIFIER_SIGNED    = 1 << 0,
        SPECIFIER_UNSIGNED  = 1 << 1,
        SPECIFIER_LONG      = 1 << 2,
@@ -2574,55 +2516,53 @@ static type_t *get_typedef_type(symbol_t *symbol)
 
 static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
 {
-       expect('(', end_error);
+       attribute_property_argument_t *const property = allocate_ast_zero(sizeof(*property));
 
-       attribute_property_argument_t *property
-               = allocate_ast_zero(sizeof(*property));
+       add_anchor_token(')');
+       add_anchor_token(',');
+       expect('(');
 
        do {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing property declspec",
-                                            T_IDENTIFIER, NULL);
-                       goto end_error;
-               }
-
-               symbol_t **prop;
-               symbol_t  *symbol = token.identifier.symbol;
-               if (streq(symbol->string, "put")) {
-                       prop = &property->put_symbol;
-               } else if (streq(symbol->string, "get")) {
-                       prop = &property->get_symbol;
-               } else {
-                       errorf(HERE, "expected put or get in property declspec");
-                       prop = NULL;
-               }
-               eat(T_IDENTIFIER);
-               expect('=', end_error);
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing property declspec",
-                                            T_IDENTIFIER, NULL);
-                       goto end_error;
+               add_anchor_token('=');
+               source_position_t pos;
+               symbol_t *const prop_sym = expect_identifier("while parsing property declspec", &pos);
+               rem_anchor_token('=');
+
+               symbol_t **prop = NULL;
+               if (prop_sym) {
+                       if (streq(prop_sym->string, "put")) {
+                               prop = &property->put_symbol;
+                       } else if (streq(prop_sym->string, "get")) {
+                               prop = &property->get_symbol;
+                       } else {
+                               errorf(&pos, "expected put or get in property declspec, but got '%Y'", prop_sym);
+                       }
                }
+
+               add_anchor_token(T_IDENTIFIER);
+               expect('=');
+               rem_anchor_token(T_IDENTIFIER);
+
+               symbol_t *const sym = expect_identifier("while parsing property declspec", NULL);
                if (prop != NULL)
-                       *prop = token.identifier.symbol;
-               next_token();
-       } while (next_if(','));
+                       *prop = sym ? sym : sym_anonymous;
+       } while (accept(','));
+       rem_anchor_token(',');
+       rem_anchor_token(')');
 
        attribute->a.property = property;
 
-       expect(')', end_error);
-
-end_error:
+       expect(')');
        return attribute;
 }
 
 static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
 {
        attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
-       if (next_if(T_restrict)) {
+       if (accept(T_restrict)) {
                kind = ATTRIBUTE_MS_RESTRICT;
        } else if (token.kind == T_IDENTIFIER) {
-               const char *name = token.identifier.symbol->string;
+               char const *const name = token.base.symbol->string;
                for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
                     ++k) {
                        const char *attribute_name = get_attribute_name(k);
@@ -2648,7 +2588,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
        }
 
        /* parse arguments */
-       if (next_if('('))
+       if (accept('('))
                attribute->a.arguments = parse_attribute_arguments();
 
        return attribute;
@@ -2658,10 +2598,9 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 {
        eat(T__declspec);
 
-       expect('(', end_error);
+       add_anchor_token(')');
+       expect('(');
        if (token.kind != ')') {
-               add_anchor_token(')');
-
                attribute_t **anchor = &first;
                do {
                        while (*anchor != NULL)
@@ -2674,19 +2613,16 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 
                        *anchor = attribute;
                        anchor  = &attribute->next;
-               } while (next_if(','));
-
-               rem_anchor_token(')');
+               } while (accept(','));
        }
-       expect(')', end_error);
-end_error:
+       rem_anchor_token(')');
+       expect(')');
        return first;
 }
 
 static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
 {
-       entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol);
-       entity->base.source_position = *HERE;
+       entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol, HERE);
        if (is_declaration(entity)) {
                entity->declaration.type     = type_error_type;
                entity->declaration.implicit = true;
@@ -2708,7 +2644,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
        bool               saw_error       = false;
 
        memset(specifiers, 0, sizeof(*specifiers));
-       specifiers->source_position = token.base.source_position;
+       specifiers->source_position = *HERE;
 
        while (true) {
                specifiers->attributes = parse_attributes(specifiers->attributes);
@@ -2723,7 +2659,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        specifiers->storage_class = class;                             \
                        if (specifiers->thread_local)                                  \
                                goto check_thread_storage_class;                           \
-                       next_token();                                                  \
+                       eat(token); \
                        break;
 
                MATCH_STORAGE_CLASS(T_typedef,  STORAGE_CLASS_TYPEDEF)
@@ -2737,9 +2673,9 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                                = parse_microsoft_extended_decl_modifier(specifiers->attributes);
                        break;
 
-               case T___thread:
+               case T__Thread_local:
                        if (specifiers->thread_local) {
-                               errorf(HERE, "duplicate '__thread'");
+                               errorf(HERE, "duplicate %K", &token);
                        } else {
                                specifiers->thread_local = true;
 check_thread_storage_class:
@@ -2754,7 +2690,7 @@ check_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);
+                                               errorf(HERE, "%K used with '%s'", &token, wrong);
                                                break;
                                }
                        }
@@ -2765,7 +2701,7 @@ wrong_thread_storage_class:
 #define MATCH_TYPE_QUALIFIER(token, qualifier)                          \
                case token:                                                     \
                        qualifiers |= qualifier;                                    \
-                       next_token();                                               \
+                       eat(token); \
                        break
 
                MATCH_TYPE_QUALIFIER(T_const,    TYPE_QUALIFIER_CONST);
@@ -2785,7 +2721,7 @@ wrong_thread_storage_class:
                        } else {                                                    \
                                type_specifiers |= specifier;                           \
                        }                                                           \
-                       next_token();                                               \
+                       eat(token); \
                        break
 
                MATCH_SPECIFIER(T__Bool,      SPECIFIER_BOOL,      "_Bool");
@@ -2808,13 +2744,13 @@ wrong_thread_storage_class:
                MATCH_SPECIFIER(T_wchar_t,    SPECIFIER_WCHAR_T,   "wchar_t");
 
                case T_inline:
-                       next_token();
+                       eat(T_inline);
                        specifiers->is_inline = true;
                        break;
 
 #if 0
                case T__forceinline:
-                       next_token();
+                       eat(T__forceinline);
                        specifiers->modifiers |= DM_FORCEINLINE;
                        break;
 #endif
@@ -2827,7 +2763,7 @@ wrong_thread_storage_class:
                        } else {
                                type_specifiers |= SPECIFIER_LONG;
                        }
-                       next_token();
+                       eat(T_long);
                        break;
 
 #define CHECK_DOUBLE_TYPE() \
@@ -2855,7 +2791,7 @@ wrong_thread_storage_class:
                case T___builtin_va_list:
                        CHECK_DOUBLE_TYPE();
                        type = duplicate_type(type_valist);
-                       next_token();
+                       eat(T___builtin_va_list);
                        break;
 
                case T_IDENTIFIER: {
@@ -2876,7 +2812,7 @@ wrong_thread_storage_class:
                                        case '&':
                                        case '*':
                                                errorf(HERE, "discarding stray %K in declaration specifier", &token);
-                                               next_token();
+                                               eat(T_IDENTIFIER);
                                                continue;
 
                                        default:
@@ -2884,7 +2820,7 @@ wrong_thread_storage_class:
                                }
                        }
 
-                       type_t *const typedef_type = get_typedef_type(token.identifier.symbol);
+                       type_t *const typedef_type = get_typedef_type(token.base.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
@@ -2897,14 +2833,12 @@ wrong_thread_storage_class:
                                        case '*': {
                                                errorf(HERE, "%K does not name a type", &token);
 
-                                               symbol_t *symbol = token.identifier.symbol;
-                                               entity_t *entity
-                                                       = create_error_entity(symbol, ENTITY_TYPEDEF);
+                                               entity_t *const entity = create_error_entity(token.base.symbol, ENTITY_TYPEDEF);
 
                                                type = allocate_type_zero(TYPE_TYPEDEF);
                                                type->typedeft.typedefe = &entity->typedefe;
 
-                                               next_token();
+                                               eat(T_IDENTIFIER);
                                                saw_error = true;
                                                continue;
                                        }
@@ -2914,7 +2848,7 @@ wrong_thread_storage_class:
                                }
                        }
 
-                       next_token();
+                       eat(T_IDENTIFIER);
                        type = typedef_type;
                        break;
                }
@@ -3085,7 +3019,8 @@ warn_about_long_long:
                        } else {
                                errorf(pos, "multiple datatypes in declaration");
                        }
-                       goto end_error;
+                       specifiers->type = type_error_type;
+                       return;
                }
                }
 
@@ -3114,10 +3049,6 @@ warn_about_long_long:
        if (specifiers->attributes != NULL)
                type = handle_type_attributes(specifiers->attributes, type);
        specifiers->type = type;
-       return;
-
-end_error:
-       specifiers->type = type_error_type;
 }
 
 static type_qualifiers_t parse_type_qualifiers(void)
@@ -3150,14 +3081,13 @@ static void parse_identifier_list(scope_t *scope)
 {
        assert(token.kind == T_IDENTIFIER);
        do {
-               entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol);
-               entity->base.source_position = token.base.source_position;
+               entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.base.symbol, HERE);
                /* a K&R parameter has no type, yet */
-               next_token();
+               eat(T_IDENTIFIER);
 
                if (scope != NULL)
                        append_entity(scope, entity);
-       } while (next_if(',') && token.kind == T_IDENTIFIER);
+       } while (accept(',') && token.kind == T_IDENTIFIER);
 }
 
 static entity_t *parse_parameter(void)
@@ -3191,8 +3121,7 @@ static bool has_parameters(void)
        if (look_ahead(1)->kind != ')')
                return true;
        if (token.kind == T_IDENTIFIER) {
-               entity_t const *const entity
-                       = get_entity(token.identifier.symbol, NAMESPACE_NORMAL);
+               entity_t const *const entity = get_entity(token.base.symbol, NAMESPACE_NORMAL);
                if (entity == NULL)
                        return true;
                if (entity->kind != ENTITY_TYPEDEF)
@@ -3221,30 +3150,25 @@ static bool has_parameters(void)
  */
 static void parse_parameters(function_type_t *type, scope_t *scope)
 {
-       eat('(');
        add_anchor_token(')');
-       int saved_comma_state = save_and_reset_anchor_state(',');
-
-       if (token.kind == T_IDENTIFIER
-           && !is_typedef_symbol(token.identifier.symbol)) {
-               token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
-               if (la1_type == ',' || la1_type == ')') {
-                       type->kr_style_parameters = true;
-                       parse_identifier_list(scope);
-                       goto parameters_finished;
-               }
-       }
+       eat('(');
 
-       if (token.kind == ')') {
+       if (token.kind == T_IDENTIFIER            &&
+           !is_typedef_symbol(token.base.symbol) &&
+           (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
+               type->kr_style_parameters = true;
+               parse_identifier_list(scope);
+       } else if (token.kind == ')') {
                /* ISO/IEC 14882:1998(E) Â§C.1.6:1 */
                if (!(c_mode & _CXX))
                        type->unspecified_parameters = true;
        } else if (has_parameters()) {
                function_parameter_t **anchor = &type->parameters;
+               add_anchor_token(',');
                do {
                        switch (token.kind) {
                        case T_DOTDOTDOT:
-                               next_token();
+                               eat(T_DOTDOTDOT);
                                type->variadic = true;
                                goto parameters_finished;
 
@@ -3276,15 +3200,13 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                        default:
                                goto parameters_finished;
                        }
-               } while (next_if(','));
+               } while (accept(','));
+parameters_finished:
+               rem_anchor_token(',');
        }
 
-parameters_finished:
        rem_anchor_token(')');
-       expect(')', end_error);
-
-end_error:
-       restore_anchor_state(',', saved_comma_state);
+       expect(')');
 }
 
 typedef enum construct_type_kind_t {
@@ -3375,12 +3297,12 @@ static construct_type_t *parse_array_declarator(void)
        eat('[');
        add_anchor_token(']');
 
-       bool is_static = next_if(T_static);
+       bool is_static = accept(T_static);
 
        type_qualifiers_t type_qualifiers = parse_type_qualifiers();
 
        if (!is_static)
-               is_static = next_if(T_static);
+               is_static = accept(T_static);
 
        array->type_qualifiers = type_qualifiers;
        array->is_static       = is_static;
@@ -3388,7 +3310,7 @@ static construct_type_t *parse_array_declarator(void)
        expression_t *size = NULL;
        if (token.kind == '*' && look_ahead(1)->kind == ']') {
                array->is_variable = true;
-               next_token();
+               eat('*');
        } else if (token.kind != ']') {
                size = parse_assignment_expression();
 
@@ -3409,9 +3331,7 @@ static construct_type_t *parse_array_declarator(void)
                errorf(&array->base.pos, "static array parameters require a size");
 
        rem_anchor_token(']');
-       expect(']', end_error);
-
-end_error:
+       expect(']');
        return cons;
 }
 
@@ -3489,10 +3409,10 @@ ptr_operator_end: ;
                if (env->must_be_abstract) {
                        errorf(HERE, "no identifier expected in typename");
                } else {
-                       env->symbol          = token.identifier.symbol;
-                       env->source_position = token.base.source_position;
+                       env->symbol          = token.base.symbol;
+                       env->source_position = *HERE;
                }
-               next_token();
+               eat(T_IDENTIFIER);
                break;
 
        case '(': {
@@ -3500,7 +3420,7 @@ ptr_operator_end: ;
                token_t const *const la1 = look_ahead(1);
                switch (la1->kind) {
                        case T_IDENTIFIER:
-                               if (is_typedef_symbol(la1->identifier.symbol)) {
+                               if (is_typedef_symbol(la1->base.symbol)) {
                        case ')':
                                        /* Â§6.7.6:2 footnote 126:  Empty parentheses in a type name are
                                         * interpreted as ``function with no parameter specification'', rather
@@ -3517,7 +3437,7 @@ ptr_operator_end: ;
                        case '[':
                        case T___attribute__: /* FIXME __attribute__ might also introduce a parameter of a function declarator. */
                                        /* Paranthesized declarator. */
-                                       next_token();
+                                       eat('(');
                                        add_anchor_token(')');
                                        inner_types = parse_inner_declarator(env);
                                        if (inner_types != NULL) {
@@ -3525,7 +3445,7 @@ ptr_operator_end: ;
                                                env->must_be_abstract = true;
                                        }
                                        rem_anchor_token(')');
-                                       expect(')', end_error);
+                                       expect(')');
                                }
                                break;
                }
@@ -3574,8 +3494,6 @@ declarator_finished:
        *anchor = inner_types;
 
        return first;
-end_error:
-       return NULL;
 }
 
 static type_t *construct_declarator_type(construct_type_t *construct_list,
@@ -3749,9 +3667,8 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        entity_t *entity;
        if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
-               entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol);
-               entity->base.source_position = env.source_position;
-               entity->typedefe.type        = orig_type;
+               entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.source_position);
+               entity->typedefe.type = orig_type;
 
                if (anonymous_entity != NULL) {
                        if (is_type_compound(type)) {
@@ -3769,27 +3686,25 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                }
        } else {
                /* create a declaration type entity */
+               source_position_t const *const pos = env.symbol ? &env.source_position : &specifiers->source_position;
                if (flags & DECL_CREATE_COMPOUND_MEMBER) {
-                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol);
+                       entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol, pos);
 
                        if (env.symbol != NULL) {
                                if (specifiers->is_inline && is_type_valid(type)) {
-                                       errorf(&env.source_position,
-                                                       "compound member '%Y' declared 'inline'", env.symbol);
+                                       errorf(&env.source_position, "'%N' declared 'inline'", entity);
                                }
 
                                if (specifiers->thread_local ||
                                                specifiers->storage_class != STORAGE_CLASS_NONE) {
-                                       errorf(&env.source_position,
-                                                       "compound member '%Y' must have no storage class",
-                                                       env.symbol);
+                                       errorf(&env.source_position, "'%N' must have no storage class", entity);
                                }
                        }
                } else if (flags & DECL_IS_PARAMETER) {
-                       entity    = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol);
+                       entity    = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol, pos);
                        orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
                } else if (is_type_function(type)) {
-                       entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol);
+                       entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol, pos);
                        entity->function.is_inline      = specifiers->is_inline;
                        entity->function.elf_visibility = default_visibility;
                        entity->function.parameters     = env.parameters;
@@ -3807,7 +3722,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                }
                        }
                } else {
-                       entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol);
+                       entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol, pos);
                        entity->variable.elf_visibility = default_visibility;
                        entity->variable.thread_local   = specifiers->thread_local;
 
@@ -3830,12 +3745,11 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                        }
                                }
                                if (invalid_storage_class) {
-                                       errorf(&env.source_position, "invalid storage class for variable '%N'", entity);
+                                       errorf(&env.source_position, "invalid storage class for '%N'", entity);
                                }
                        }
                }
 
-               entity->base.source_position   = env.symbol != NULL ? env.source_position : specifiers->source_position;
                entity->declaration.type       = orig_type;
                entity->declaration.alignment  = get_type_alignment(orig_type);
                entity->declaration.modifiers  = env.modifiers;
@@ -3942,14 +3856,6 @@ warn_arg_count:
        }
 }
 
-/**
- * Check if a symbol is the equal to "main".
- */
-static bool is_sym_main(const symbol_t *const sym)
-{
-       return streq(sym->string, "main");
-}
-
 static void error_redefined_as_different_kind(const source_position_t *pos,
                const entity_t *old, entity_kind_t new_kind)
 {
@@ -4009,6 +3915,8 @@ static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
        }
 }
 
+static bool is_main(entity_t*);
+
 /**
  * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
  * for various problems that occur for multiple definitions
@@ -4023,6 +3931,10 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
        if (symbol == NULL)
                return entity;
 
+       assert(!entity->base.parent_scope);
+       assert(current_scope);
+       entity->base.parent_scope = current_scope;
+
        entity_t *const previous_entity = get_entity(symbol, namespc);
        /* pushing the same entity twice will break the stack structure */
        assert(previous_entity != entity);
@@ -4038,7 +3950,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                        warningf(WARN_STRICT_PROTOTYPES, pos, "function declaration '%#N' is not a prototype", entity);
                }
 
-               if (current_scope == file_scope && is_sym_main(symbol)) {
+               if (is_main(entity)) {
                        check_main(entity);
                }
        }
@@ -4142,7 +4054,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                                                case STORAGE_CLASS_EXTERN:
                                                        if (is_definition) {
-                                                               if (prev_type->function.unspecified_parameters && !is_sym_main(symbol)) {
+                                                               if (prev_type->function.unspecified_parameters && !is_main(entity)) {
                                                                        warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
                                                                }
                                                        } else if (new_storage_class == STORAGE_CLASS_NONE) {
@@ -4169,12 +4081,12 @@ warn_redundant_declaration: ;
                                        } else if (!is_definition        &&
                                                        is_type_valid(prev_type) &&
                                                        !pos->is_system_header) {
-                                               warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
+                                               warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%N' (declared %P)", entity, ppos);
                                        }
                                } 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, ppos);
+                                               errorf(pos, "static declaration of '%N' follows non-static declaration (declared %P)", entity, ppos);
                                        } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
                                                prev_decl->storage_class          = STORAGE_CLASS_NONE;
                                                prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
@@ -4187,9 +4099,9 @@ warn_redundant_declaration: ;
                                } else if (is_type_valid(prev_type)) {
                                        if (old_storage_class == new_storage_class) {
 error_redeclaration:
-                                               errorf(pos, "redeclaration of '%Y' (declared %P)", symbol, ppos);
+                                               errorf(pos, "redeclaration of '%N' (declared %P)", entity, ppos);
                                        } else {
-                                               errorf(pos, "redeclaration of '%Y' with different linkage (declared %P)", symbol, ppos);
+                                               errorf(pos, "redeclaration of '%N' with different linkage (declared %P)", entity, ppos);
                                        }
                                }
                        }
@@ -4212,7 +4124,7 @@ error_redeclaration:
        if (entity->kind == ENTITY_FUNCTION) {
                if (is_definition &&
                                entity->declaration.storage_class != STORAGE_CLASS_STATIC &&
-                               !is_sym_main(symbol)) {
+                               !is_main(entity)) {
                        if (is_warn_on(WARN_MISSING_PROTOTYPES)) {
                                warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
                        } else {
@@ -4229,10 +4141,6 @@ warn_missing_declaration:
        }
 
 finish:
-       assert(entity->base.parent_scope == NULL);
-       assert(current_scope != NULL);
-
-       entity->base.parent_scope = current_scope;
        environment_push(entity);
        append_entity(current_scope, entity);
 
@@ -4242,8 +4150,7 @@ finish:
 static void parser_error_multiple_definition(entity_t *entity,
                const source_position_t *source_position)
 {
-       errorf(source_position, "multiple definition of '%Y' (declared %P)",
-              entity->base.symbol, &entity->base.source_position);
+       errorf(source_position, "redefinition of '%N' (declared %P)", entity, &entity->base.source_position);
 }
 
 static bool is_declaration_specifier(const token_t *token)
@@ -4252,7 +4159,7 @@ static bool is_declaration_specifier(const token_t *token)
                DECLARATION_START
                        return true;
                case T_IDENTIFIER:
-                       return is_typedef_symbol(token->identifier.symbol);
+                       return is_typedef_symbol(token->base.symbol);
 
                default:
                        return false;
@@ -4382,30 +4289,27 @@ static void parse_declaration_rest(entity_t *ndeclaration,
                        /* ISO/IEC 14882:1998(E) Â§8.5.3:3  The initializer can be omitted
                         * [...] where the extern specifier is explicitly used. */
                        declaration_t *decl = &entity->declaration;
-                       if (decl->storage_class != STORAGE_CLASS_EXTERN) {
-                               type_t *type = decl->type;
-                               if (is_type_reference(skip_typeref(type))) {
-                                       source_position_t const *const pos = &entity->base.source_position;
-                                       errorf(pos, "reference '%#N' must be initialized", entity);
-                               }
+                       if (decl->storage_class != STORAGE_CLASS_EXTERN &&
+                           is_type_reference(skip_typeref(decl->type))) {
+                               source_position_t const *const pos = &entity->base.source_position;
+                               errorf(pos, "reference '%#N' must be initialized", entity);
                        }
                }
 
                check_variable_type_complete(entity);
 
-               if (!next_if(','))
+               if (!accept(','))
                        break;
 
                add_anchor_token('=');
                ndeclaration = parse_declarator(specifiers, flags);
                rem_anchor_token('=');
        }
-       expect(';', end_error);
+       rem_anchor_token(',');
+       rem_anchor_token(';');
+       expect(';');
 
-end_error:
        anonymous_entity = NULL;
-       rem_anchor_token(';');
-       rem_anchor_token(',');
 }
 
 static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
@@ -4681,15 +4585,10 @@ static void check_declarations(void)
 {
        if (is_warn_on(WARN_UNUSED_PARAMETER)) {
                const scope_t *scope = &current_function->parameters;
-
-               /* do not issue unused warnings for main */
-               if (!is_sym_main(current_function->base.base.symbol)) {
-                       warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
-               }
+               warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
        }
        if (is_warn_on(WARN_UNUSED_VARIABLE)) {
-               walk_statements(current_function->statement, check_unused_variables,
-                               NULL);
+               walk_statements(current_function->body, check_unused_variables, NULL);
        }
 }
 
@@ -4732,8 +4631,8 @@ static bool expression_returns(expression_t const *const expr)
                case EXPR_REFERENCE:
                case EXPR_ENUM_CONSTANT:
                case EXPR_LITERAL_CASES:
+               case EXPR_LITERAL_CHARACTER:
                case EXPR_STRING_LITERAL:
-               case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
                case EXPR_LABEL_ADDRESS:
                case EXPR_CLASSIFY_TYPE:
@@ -4818,7 +4717,6 @@ static bool initializer_returns(initializer_t const *const init)
                }
 
                case INITIALIZER_STRING:
-               case INITIALIZER_WIDE_STRING:
                case INITIALIZER_DESIGNATOR: // designators have no payload
                        return true;
        }
@@ -4907,7 +4805,7 @@ static void check_reachable(statement_t *const stmt)
                                return;
 
                        if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
-                               long                    const val      = fold_constant_to_int(expr);
+                               ir_tarval              *const val      = fold_constant_to_tarval(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
                                        if (i->expression == NULL) {
@@ -4915,7 +4813,9 @@ static void check_reachable(statement_t *const stmt)
                                                continue;
                                        }
 
-                                       if (i->first_case <= val && val <= i->last_case) {
+                                       if (i->first_case == val || i->last_case == val ||
+                                               ((tarval_cmp(i->first_case, val) & ir_relation_less_equal)
+                                           && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) {
                                                check_reachable((statement_t*)i);
                                                return;
                                        }
@@ -4960,7 +4860,6 @@ static void check_reachable(statement_t *const stmt)
 
                                next = parent;
                                switch (parent->kind) {
-                                       case STATEMENT_WHILE:    goto continue_while;
                                        case STATEMENT_DO_WHILE: goto continue_do_while;
                                        case STATEMENT_FOR:      goto continue_for;
 
@@ -4976,7 +4875,6 @@ static void check_reachable(statement_t *const stmt)
 
                                switch (parent->kind) {
                                        case STATEMENT_SWITCH:
-                                       case STATEMENT_WHILE:
                                        case STATEMENT_DO_WHILE:
                                        case STATEMENT_FOR:
                                                last = parent;
@@ -5014,25 +4912,6 @@ found_break_parent:
                        next = stmt->case_label.statement;
                        break;
 
-               case STATEMENT_WHILE: {
-                       while_statement_t const *const whiles = &stmt->whiles;
-                       expression_t      const *const cond   = whiles->condition;
-
-                       if (!expression_returns(cond))
-                               return;
-
-                       int const val = determine_truth(cond);
-
-                       if (val >= 0)
-                               check_reachable(whiles->body);
-
-                       if (val > 0)
-                               return;
-
-                       next = stmt->base.next;
-                       break;
-               }
-
                case STATEMENT_DO_WHILE:
                        next = stmt->do_while.body;
                        break;
@@ -5102,7 +4981,7 @@ found_break_parent:
                        type_t *const ret  = skip_typeref(type->function.return_type);
                        if (!is_type_void(ret) &&
                            is_type_valid(ret) &&
-                           !is_sym_main(current_function->base.base.symbol)) {
+                           !is_main(current_entity)) {
                                source_position_t const *const pos = &stmt->base.source_position;
                                warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
                        }
@@ -5137,33 +5016,8 @@ found_break_parent:
                                next = next->base.next;
                                break;
 
-                       case STATEMENT_WHILE: {
-continue_while:
-                               if (next->base.reachable)
-                                       return;
-                               next->base.reachable = true;
-
-                               while_statement_t const *const whiles = &next->whiles;
-                               expression_t      const *const cond   = whiles->condition;
-
-                               if (!expression_returns(cond))
-                                       return;
-
-                               int const val = determine_truth(cond);
-
-                               if (val >= 0)
-                                       check_reachable(whiles->body);
-
-                               if (val > 0)
-                                       return;
-
-                               last = next;
-                               next = next->base.next;
-                               break;
-                       }
-
-                       case STATEMENT_DO_WHILE: {
-continue_do_while:
+                       case STATEMENT_DO_WHILE: {
+continue_do_while:
                                if (next->base.reachable)
                                        return;
                                next->base.reachable = true;
@@ -5318,6 +5172,8 @@ static bool is_main(entity_t *entity)
        return true;
 }
 
+static void prepare_main_collect2(entity_t*);
+
 static void parse_external_declaration(void)
 {
        /* function-definitions and declarations both start with declaration
@@ -5411,8 +5267,6 @@ static void parse_external_declaration(void)
        if (ndeclaration != entity) {
                function->parameters = ndeclaration->function.parameters;
        }
-       assert(is_declaration(entity));
-       type = skip_typeref(entity->declaration.type);
 
        PUSH_SCOPE(&function->parameters);
 
@@ -5431,16 +5285,15 @@ static void parse_external_declaration(void)
                environment_push(parameter);
        }
 
-       if (function->statement != NULL) {
+       if (function->body != NULL) {
                parser_error_multiple_definition(entity, HERE);
                eat_block();
        } else {
                /* 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;
+               PUSH_CURRENT_ENTITY(entity);
                PUSH_PARENT(NULL);
 
                goto_first   = NULL;
@@ -5449,7 +5302,7 @@ static void parse_external_declaration(void)
                label_anchor = &label_first;
 
                statement_t *const body = parse_compound_statement(false);
-               function->statement = body;
+               function->body = body;
                first_err = true;
                check_labels();
                check_declarations();
@@ -5467,13 +5320,23 @@ static void parse_external_declaration(void)
                        }
                }
 
-               if (is_main(entity) && enable_main_collect2_hack)
-                       prepare_main_collect2(entity);
+               if (is_main(entity)) {
+                       /* Force main to C linkage. */
+                       type_t *const type = entity->declaration.type;
+                       assert(is_type_function(type));
+                       if (type->function.linkage != LINKAGE_C) {
+                               type_t *new_type           = duplicate_type(type);
+                               new_type->function.linkage = LINKAGE_C;
+                               entity->declaration.type   = identify_new_type(new_type);
+                       }
+
+                       if (enable_main_collect2_hack)
+                               prepare_main_collect2(entity);
+               }
 
+               POP_CURRENT_ENTITY();
                POP_PARENT();
                assert(current_function == function);
-               assert(current_entity   == entity);
-               current_entity   = old_current_entity;
                current_function = old_current_function;
                label_pop_to(label_stack_top);
        }
@@ -5574,8 +5437,7 @@ static expression_t *find_create_select(const source_position_t *pos,
                symbol_t *iter_symbol = iter->base.symbol;
                if (iter_symbol == NULL) {
                        type_t *type = iter->declaration.type;
-                       if (type->kind != TYPE_COMPOUND_STRUCT
-                                       && type->kind != TYPE_COMPOUND_UNION)
+                       if (!is_type_compound(type))
                                continue;
 
                        compound_t *sub_compound = type->compound.compound;
@@ -5644,15 +5506,15 @@ static void parse_bitfield_member(entity_t *entity)
 static void parse_compound_declarators(compound_t *compound,
                const declaration_specifiers_t *specifiers)
 {
+       add_anchor_token(';');
+       add_anchor_token(',');
        do {
                entity_t *entity;
 
                if (token.kind == ':') {
                        /* anonymous bitfield */
                        type_t *type = specifiers->type;
-                       entity_t *entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER,
-                                                               NAMESPACE_NORMAL, NULL);
-                       entity->base.source_position               = *HERE;
+                       entity_t *const entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE);
                        entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
                        entity->declaration.storage_class          = STORAGE_CLASS_NONE;
                        entity->declaration.type                   = type;
@@ -5685,7 +5547,7 @@ static void parse_compound_declarators(compound_t *compound,
                                        entity_t *prev = find_compound_entry(compound, symbol);
                                        if (prev != NULL) {
                                                source_position_t const *const ppos = &prev->base.source_position;
-                                               errorf(pos, "multiple declarations of symbol '%Y' (declared %P)", symbol, ppos);
+                                               errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
                                        }
                                }
 
@@ -5714,10 +5576,11 @@ static void parse_compound_declarators(compound_t *compound,
                                append_entity(&compound->members, entity);
                        }
                }
-       } while (next_if(','));
-       expect(';', end_error);
+       } while (accept(','));
+       rem_anchor_token(',');
+       rem_anchor_token(';');
+       expect(';');
 
-end_error:
        anonymous_entity = NULL;
 }
 
@@ -5741,8 +5604,7 @@ static void parse_compound_type_entries(compound_t *compound)
 
                        default:
                                rem_anchor_token('}');
-                               expect('}', end_error);
-end_error:
+                               expect('}');
                                /* Â§6.7.2.1:7 */
                                compound->complete = true;
                                return;
@@ -5782,28 +5644,17 @@ struct expression_parser_function_t {
 
 static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
-/**
- * Prints an error message if an expression was expected but not read
- */
-static expression_t *expected_expression_error(void)
+static type_t *get_string_type(string_encoding_t const enc)
 {
-       /* skip the error message if the error token was read */
-       if (token.kind != T_ERROR) {
-               errorf(HERE, "expected expression, got token %K", &token);
+       bool const warn = is_warn_on(WARN_WRITE_STRINGS);
+       switch (enc) {
+       case STRING_ENCODING_CHAR:
+       case STRING_ENCODING_UTF8:   return warn ? type_const_char_ptr     : type_char_ptr;
+       case STRING_ENCODING_CHAR16: return warn ? type_char16_t_const_ptr : type_char16_t_ptr;
+       case STRING_ENCODING_CHAR32: return warn ? type_char32_t_const_ptr : type_char32_t_ptr;
+       case STRING_ENCODING_WIDE:   return warn ? type_const_wchar_t_ptr  : type_wchar_t_ptr;
        }
-       next_token();
-
-       return create_error_expression();
-}
-
-static type_t *get_string_type(void)
-{
-       return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr;
-}
-
-static type_t *get_wide_string_type(void)
-{
-       return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+       panic("invalid string encoding");
 }
 
 /**
@@ -5811,31 +5662,10 @@ static type_t *get_wide_string_type(void)
  */
 static expression_t *parse_string_literal(void)
 {
-       source_position_t begin   = token.base.source_position;
-       string_t          res     = token.string.string;
-       bool              is_wide = (token.kind == T_WIDE_STRING_LITERAL);
-
-       next_token();
-       while (token.kind == T_STRING_LITERAL
-                       || token.kind == T_WIDE_STRING_LITERAL) {
-               warn_string_concat(&token.base.source_position);
-               res = concat_strings(&res, &token.string.string);
-               next_token();
-               is_wide |= token.kind == T_WIDE_STRING_LITERAL;
-       }
-
-       expression_t *literal;
-       if (is_wide) {
-               literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
-               literal->base.type = get_wide_string_type();
-       } else {
-               literal = allocate_expression_zero(EXPR_STRING_LITERAL);
-               literal->base.type = get_string_type();
-       }
-       literal->base.source_position = begin;
-       literal->literal.value        = res;
-
-       return literal;
+       expression_t *const expr = allocate_expression_zero(EXPR_STRING_LITERAL);
+       expr->string_literal.value = concat_string_literals();
+       expr->base.type            = get_string_type(expr->string_literal.value.encoding);
+       return expr;
 }
 
 /**
@@ -5848,173 +5678,248 @@ static expression_t *parse_boolean_literal(bool value)
        literal->literal.value.begin = value ? "true" : "false";
        literal->literal.value.size  = value ? 4 : 5;
 
-       next_token();
+       eat(value ? T_true : T_false);
        return literal;
 }
 
-static void warn_traditional_suffix(void)
+static void warn_traditional_suffix(char const *const suffix)
 {
-       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix",
-                &token.number.suffix);
+       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
 }
 
-static void check_integer_suffix(void)
+static void check_integer_suffix(expression_t *const expr, char const *const suffix)
 {
-       const string_t *suffix = &token.number.suffix;
-       if (suffix->size == 0)
-               return;
-
-       bool not_traditional = false;
-       const char *c = suffix->begin;
-       if (*c == 'l' || *c == 'L') {
-               ++c;
-               if (*c == *(c-1)) {
-                       not_traditional = true;
-                       ++c;
-                       if (*c == 'u' || *c == 'U') {
+       unsigned     spec = SPECIFIER_NONE;
+       char const  *c    = suffix;
+       for (;;) {
+               specifiers_t add;
+               if (*c == 'L' || *c == 'l') {
+                       add = SPECIFIER_LONG;
+                       if (*c == c[1]) {
+                               add |= SPECIFIER_LONG_LONG;
                                ++c;
                        }
-               } else if (*c == 'u' || *c == 'U') {
-                       not_traditional = true;
-                       ++c;
+               } else if (*c == 'U' || *c == 'u') {
+                       add = SPECIFIER_UNSIGNED;
+               } else {
+                       break;
                }
-       } else if (*c == 'u' || *c == 'U') {
-               not_traditional = true;
                ++c;
-               if (*c == 'l' || *c == 'L') {
-                       ++c;
-                       if (*c == *(c-1)) {
-                               ++c;
-                       }
-               }
-       }
-       if (*c != '\0') {
-               errorf(&token.base.source_position,
-                      "invalid suffix '%S' on integer constant", suffix);
-       } else if (not_traditional) {
-               warn_traditional_suffix();
+               if (spec & add)
+                       goto error;
+               spec |= add;
+       }
+
+       if (*c == '\0') {
+               type_t *type;
+               switch (spec) {
+               case SPECIFIER_NONE:                                            type = type_int;                break;
+               case                      SPECIFIER_LONG:                       type = type_long;               break;
+               case                      SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long;          break;
+               case SPECIFIER_UNSIGNED:                                        type = type_unsigned_int;       break;
+               case SPECIFIER_UNSIGNED | SPECIFIER_LONG:                       type = type_unsigned_long;      break;
+               case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break;
+               default: panic("inconsistent suffix");
+               }
+               if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) {
+                       warn_traditional_suffix(suffix);
+               }
+               expr->base.type = type;
+               /* 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(&expr->literal);
+       } else {
+error:
+               errorf(HERE, "invalid suffix '%s' on integer constant", suffix);
        }
 }
 
-static type_t *check_floatingpoint_suffix(void)
+static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
 {
-       const string_t *suffix = &token.number.suffix;
-       type_t         *type   = type_double;
-       if (suffix->size == 0)
-               return type;
-
-       bool not_traditional = false;
-       const char *c = suffix->begin;
-       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.base.source_position,
-                      "invalid suffix '%S' on floatingpoint constant", suffix);
-       } else if (not_traditional) {
-               warn_traditional_suffix();
+       type_t     *type;
+       char const *c    = suffix;
+       switch (*c) {
+       case 'F':
+       case 'f': type = type_float;       ++c; break;
+       case 'L':
+       case 'l': type = type_long_double; ++c; break;
+       default:  type = type_double;           break;
        }
 
-       return type;
+       if (*c == '\0') {
+               expr->base.type = type;
+               if (suffix[0] != '\0') {
+                       warn_traditional_suffix(suffix);
+               }
+       } else {
+               errorf(HERE, "invalid suffix '%s' on floatingpoint constant", suffix);
+       }
 }
 
-/**
- * Parse an integer constant.
- */
 static expression_t *parse_number_literal(void)
 {
-       expression_kind_t  kind;
-       type_t            *type;
+       string_t const *const str      = &token.literal.string;
+       char     const *      i        = str->begin;
+       unsigned              digits   = 0;
+       bool                  is_float = false;
 
-       switch (token.kind) {
-       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;
+       /* Parse base prefix. */
+       unsigned base;
+       if (*i == '0') {
+               switch (*++i) {
+               case 'B': case 'b': base =  2; ++i;               break;
+               case 'X': case 'x': base = 16; ++i;               break;
+               default:            base =  8; digits |= 1U << 0; break;
+               }
+       } else {
+               base = 10;
+       }
+
+       /* Parse mantissa. */
+       for (;; ++i) {
+               unsigned digit;
+               switch (*i) {
+               case '.':
+                       if (is_float) {
+                               errorf(HERE, "multiple decimal points in %K", &token);
+                               i = 0;
+                               goto done;
+                       }
+                       is_float = true;
+                       if (base == 8)
+                               base = 10;
+                       continue;
+
+               case '0':           digit =  0; break;
+               case '1':           digit =  1; break;
+               case '2':           digit =  2; break;
+               case '3':           digit =  3; break;
+               case '4':           digit =  4; break;
+               case '5':           digit =  5; break;
+               case '6':           digit =  6; break;
+               case '7':           digit =  7; break;
+               case '8':           digit =  8; break;
+               case '9':           digit =  9; break;
+               case 'A': case 'a': digit = 10; break;
+               case 'B': case 'b': digit = 11; break;
+               case 'C': case 'c': digit = 12; break;
+               case 'D': case 'd': digit = 13; break;
+               case 'E': case 'e': digit = 14; break;
+               case 'F': case 'f': digit = 15; break;
+
+               default: goto done_mantissa;
+               }
+
+               if (digit >= 10 && base != 16)
+                       goto done_mantissa;
+
+               digits |= 1U << digit;
+       }
+done_mantissa:
+
+       /* Parse exponent. */
+       switch (base) {
+       case 2:
+               if (is_float)
+                       errorf(HERE, "binary floating %K not allowed", &token);
                break;
-       case T_FLOATINGPOINT:
-               kind = EXPR_LITERAL_FLOATINGPOINT;
-               type = check_floatingpoint_suffix();
+
+       case  8:
+       case 10:
+               if (*i == 'E' || *i == 'e') {
+                       base = 10;
+                       goto parse_exponent;
+               }
                break;
-       case T_FLOATINGPOINT_HEXADECIMAL:
-               kind = EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL;
-               type = check_floatingpoint_suffix();
+
+       case 16:
+               if (*i == 'P' || *i == 'p') {
+parse_exponent:
+                       ++i;
+                       is_float = true;
+
+                       if (*i == '-' || *i == '+')
+                               ++i;
+
+                       if (isdigit(*i)) {
+                               do {
+                                       ++i;
+                               } while (isdigit(*i));
+                       } else {
+                               errorf(HERE, "exponent of %K has no digits", &token);
+                       }
+               } else if (is_float) {
+                       errorf(HERE, "hexadecimal floating %K requires an exponent", &token);
+                       i = 0;
+               }
                break;
+
        default:
-               panic("unexpected token type in parse_number_literal");
+               panic("invalid base");
        }
 
-       expression_t *literal = allocate_expression_zero(kind);
-       literal->base.type      = type;
-       literal->literal.value  = token.number.number;
-       literal->literal.suffix = token.number.suffix;
-       next_token();
-
-       /* 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;
-}
+done:;
+       expression_t *const expr = allocate_expression_zero(is_float ? EXPR_LITERAL_FLOATINGPOINT : EXPR_LITERAL_INTEGER);
+       expr->literal.value = *str;
 
-/**
- * Parse a character constant.
- */
-static expression_t *parse_character_constant(void)
-{
-       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
-       literal->base.type     = c_mode & _CXX ? type_char : type_int;
-       literal->literal.value = token.string.string;
-
-       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");
+       if (i) {
+               if (digits == 0) {
+                       errorf(HERE, "%K has no digits", &token);
+               } else if (digits & ~((1U << base) - 1)) {
+                       errorf(HERE, "invalid digit in %K", &token);
                } else {
-                       literal->base.type = type_int;
-                       warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+                       expr->literal.suffix = i;
+                       if (is_float) {
+                               check_floatingpoint_suffix(expr, i);
+                       } else {
+                               check_integer_suffix(expr, i);
+                       }
                }
        }
 
-       next_token();
-       return literal;
+       eat(T_NUMBER);
+       return expr;
 }
 
 /**
- * Parse a wide character constant.
+ * Parse a character constant.
  */
-static expression_t *parse_wide_character_constant(void)
+static expression_t *parse_character_constant(void)
 {
-       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
-       literal->base.type     = type_int;
-       literal->literal.value = token.string.string;
+       expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
+       literal->string_literal.value = token.literal.string;
+
+       size_t const size = get_string_len(&token.literal.string);
+       switch (token.literal.string.encoding) {
+       case STRING_ENCODING_CHAR:
+       case STRING_ENCODING_UTF8:
+               literal->base.type = c_mode & _CXX ? type_char : type_int;
+               if (size > 1) {
+                       if (!GNU_MODE && !(c_mode & _C99)) {
+                               errorf(HERE, "more than 1 character in character constant");
+                       } else {
+                               literal->base.type = type_int;
+                               warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+                       }
+               }
+               break;
 
-       size_t len = wstrlen(&literal->literal.value);
-       if (len > 1) {
-               warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+       case STRING_ENCODING_CHAR16: literal->base.type = type_char16_t; goto warn_multi;
+       case STRING_ENCODING_CHAR32: literal->base.type = type_char32_t; goto warn_multi;
+       case STRING_ENCODING_WIDE:   literal->base.type = type_wchar_t;  goto warn_multi;
+warn_multi:
+               if (size > 1) {
+                       warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+               }
+               break;
        }
 
-       next_token();
+       eat(T_CHARACTER_CONSTANT);
        return literal;
 }
 
-static entity_t *create_implicit_function(symbol_t *symbol,
-               const source_position_t *source_position)
+static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos)
 {
        type_t *ntype                          = allocate_type_zero(TYPE_FUNCTION);
        ntype->function.return_type            = type_int;
@@ -6022,12 +5927,11 @@ static entity_t *create_implicit_function(symbol_t *symbol,
        ntype->function.linkage                = LINKAGE_C;
        type_t *type                           = identify_new_type(ntype);
 
-       entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol);
+       entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol, pos);
        entity->declaration.storage_class          = STORAGE_CLASS_EXTERN;
        entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
        entity->declaration.type                   = type;
        entity->declaration.implicit               = true;
-       entity->base.source_position               = *source_position;
 
        if (current_scope != NULL)
                record_entity(entity, false);
@@ -6100,13 +6004,9 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
        }
 
        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 = wstrlen(&expression->string_literal.value);
-               return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+               size_t  const size = get_string_len(&expression->string_literal.value) + 1;
+               type_t *const elem = get_unqualified_type(expression->base.type->pointer.points_to);
+               return make_array_type(elem, size, TYPE_QUALIFIER_NONE);
        }
 
        case EXPR_COMPOUND_LITERAL:
@@ -6148,23 +6048,19 @@ static entity_t *parse_qualified_identifier(void)
        source_position_t  pos;
        const scope_t     *lookup_scope = NULL;
 
-       if (next_if(T_COLONCOLON))
+       if (accept(T_COLONCOLON))
                lookup_scope = &unit->scope;
 
        entity_t *entity;
        while (true) {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
+               symbol = expect_identifier("while parsing identifier", &pos);
+               if (!symbol)
                        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
-               }
-               symbol = token.identifier.symbol;
-               pos    = *HERE;
-               next_token();
 
                /* lookup entity */
                entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
 
-               if (!next_if(T_COLONCOLON))
+               if (!accept(T_COLONCOLON))
                        break;
 
                switch (entity->kind) {
@@ -6181,7 +6077,7 @@ static entity_t *parse_qualified_identifier(void)
                               symbol, get_entity_kind_name(entity->kind));
 
                        /* skip further qualifications */
-                       while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+                       while (accept(T_IDENTIFIER) && accept(T_COLONCOLON)) {}
 
                        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
                }
@@ -6190,9 +6086,8 @@ static entity_t *parse_qualified_identifier(void)
        if (entity == NULL) {
                if (!strict_mode && token.kind == '(') {
                        /* an implicitly declared function */
-                       warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos,
-                                "implicit declaration of function '%Y'", symbol);
                        entity = create_implicit_function(symbol, &pos);
+                       warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of '%N'", entity);
                } else {
                        errorf(&pos, "unknown identifier '%Y' found.", symbol);
                        entity = create_error_entity(symbol, ENTITY_VARIABLE);
@@ -6204,7 +6099,7 @@ static entity_t *parse_qualified_identifier(void)
 
 static expression_t *parse_reference(void)
 {
-       source_position_t const pos    = token.base.source_position;
+       source_position_t const pos    = *HERE;
        entity_t         *const entity = parse_qualified_identifier();
 
        type_t *orig_type;
@@ -6238,12 +6133,8 @@ static expression_t *parse_reference(void)
                && (current_function != NULL
                        && entity->base.parent_scope->depth < current_function->parameters.depth)
                && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) {
-               if (entity->kind == ENTITY_VARIABLE) {
-                       /* access of a variable from an outer function */
-                       entity->variable.address_taken = true;
-               } else if (entity->kind == ENTITY_PARAMETER) {
-                       entity->parameter.address_taken = true;
-               }
+               /* access of a variable from an outer function */
+               entity->variable.address_taken = true;
                current_function->need_closure = true;
        }
 
@@ -6328,7 +6219,7 @@ static expression_t *parse_cast(void)
        type_t *type = parse_typename();
 
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        if (token.kind == '{') {
                return parse_compound_literal(&pos, type);
@@ -6346,8 +6237,6 @@ static expression_t *parse_cast(void)
        }
 
        return cast;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6381,9 +6270,7 @@ static expression_t *parse_statement_expression(void)
        expression->base.type = type;
 
        rem_anchor_token(')');
-       expect(')', end_error);
-
-end_error:
+       expect(')');
        return expression;
 }
 
@@ -6399,7 +6286,7 @@ static expression_t *parse_parenthesized_expression(void)
                return parse_statement_expression();
 
        case T_IDENTIFIER:
-               if (is_typedef_symbol(la1->identifier.symbol)) {
+               if (is_typedef_symbol(la1->base.symbol)) {
        DECLARATION_START
                        return parse_cast();
                }
@@ -6410,111 +6297,52 @@ static expression_t *parse_parenthesized_expression(void)
        expression_t *result = parse_expression();
        result->base.parenthesized = true;
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
-end_error:
        return result;
 }
 
-static expression_t *parse_function_keyword(void)
+static expression_t *parse_function_keyword(funcname_kind_t const kind)
 {
-       /* TODO */
-
        if (current_function == NULL) {
-               errorf(HERE, "'__func__' used outside of a function");
+               errorf(HERE, "'%K' used outside of a function", &token);
        }
 
        expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
        expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_FUNCTION;
+       expression->funcname.kind = kind;
 
        next_token();
 
        return expression;
 }
 
-static expression_t *parse_pretty_function_keyword(void)
-{
-       if (current_function == NULL) {
-               errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function");
-       }
-
-       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
-       expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_PRETTY_FUNCTION;
-
-       eat(T___PRETTY_FUNCTION__);
-
-       return expression;
-}
-
-static expression_t *parse_funcsig_keyword(void)
-{
-       if (current_function == NULL) {
-               errorf(HERE, "'__FUNCSIG__' used outside of a function");
-       }
-
-       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
-       expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_FUNCSIG;
-
-       eat(T___FUNCSIG__);
-
-       return expression;
-}
-
-static expression_t *parse_funcdname_keyword(void)
-{
-       if (current_function == NULL) {
-               errorf(HERE, "'__FUNCDNAME__' used outside of a function");
-       }
-
-       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
-       expression->base.type     = type_char_ptr;
-       expression->funcname.kind = FUNCNAME_FUNCDNAME;
-
-       eat(T___FUNCDNAME__);
-
-       return expression;
-}
-
 static designator_t *parse_designator(void)
 {
-       designator_t *result    = allocate_ast_zero(sizeof(result[0]));
-       result->source_position = *HERE;
-
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected("while parsing member designator",
-                                    T_IDENTIFIER, NULL);
+       designator_t *const result = allocate_ast_zero(sizeof(result[0]));
+       result->symbol = expect_identifier("while parsing member designator", &result->source_position);
+       if (!result->symbol)
                return NULL;
-       }
-       result->symbol = token.identifier.symbol;
-       next_token();
 
        designator_t *last_designator = result;
        while (true) {
-               if (next_if('.')) {
-                       if (token.kind != T_IDENTIFIER) {
-                               parse_error_expected("while parsing member designator",
-                                                    T_IDENTIFIER, NULL);
+               if (accept('.')) {
+                       designator_t *const designator = allocate_ast_zero(sizeof(result[0]));
+                       designator->symbol = expect_identifier("while parsing member designator", &designator->source_position);
+                       if (!designator->symbol)
                                return NULL;
-                       }
-                       designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
-                       designator->source_position = *HERE;
-                       designator->symbol          = token.identifier.symbol;
-                       next_token();
 
                        last_designator->next = designator;
                        last_designator       = designator;
                        continue;
                }
-               if (next_if('[')) {
+               if (accept('[')) {
                        add_anchor_token(']');
                        designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
                        designator->source_position = *HERE;
                        designator->array_index     = parse_expression();
                        rem_anchor_token(']');
-                       expect(']', end_error);
+                       expect(']');
                        if (designator->array_index == NULL) {
                                return NULL;
                        }
@@ -6527,8 +6355,6 @@ static designator_t *parse_designator(void)
        }
 
        return result;
-end_error:
-       return NULL;
 }
 
 /**
@@ -6541,15 +6367,15 @@ static expression_t *parse_offsetof(void)
 
        eat(T___builtin_offsetof);
 
-       expect('(', end_error);
+       add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        type_t *type = parse_typename();
        rem_anchor_token(',');
-       expect(',', end_error);
-       add_anchor_token(')');
+       expect(',');
        designator_t *designator = parse_designator();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        expression->offsetofe.type       = type;
        expression->offsetofe.designator = designator;
@@ -6568,12 +6394,27 @@ static expression_t *parse_offsetof(void)
        DEL_ARR_F(path.path);
 
        return expression;
-end_error:
-       return create_error_expression();
+}
+
+static bool is_last_parameter(expression_t *const param)
+{
+       if (param->kind == EXPR_REFERENCE) {
+               entity_t *const entity = param->reference.entity;
+               if (entity->kind == ENTITY_PARAMETER &&
+                   !entity->base.next               &&
+                   entity->base.parent_scope == &current_function->parameters) {
+                       return true;
+               }
+       }
+
+       if (!is_type_valid(skip_typeref(param->base.type)))
+               return true;
+
+       return false;
 }
 
 /**
- * Parses a _builtin_va_start() expression.
+ * Parses a __builtin_va_start() expression.
  */
 static expression_t *parse_va_start(void)
 {
@@ -6581,31 +6422,26 @@ static expression_t *parse_va_start(void)
 
        eat(T___builtin_va_start);
 
-       expect('(', end_error);
+       add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        expression->va_starte.ap = parse_assignment_expression();
        rem_anchor_token(',');
-       expect(',', end_error);
-       expression_t *const expr = parse_assignment_expression();
-       if (expr->kind == EXPR_REFERENCE) {
-               entity_t *const entity = expr->reference.entity;
-               if (!current_function->base.type->function.variadic) {
-                       errorf(&expr->base.source_position,
-                                       "'va_start' used in non-variadic function");
-               } else if (entity->base.parent_scope != &current_function->parameters ||
-                               entity->base.next != NULL ||
-                               entity->kind != ENTITY_PARAMETER) {
-                       errorf(&expr->base.source_position,
-                              "second argument of 'va_start' must be last parameter of the current function");
-               } else {
-                       expression->va_starte.parameter = &entity->variable;
-               }
-               expect(')', end_error);
-               return expression;
+       expect(',');
+       expression_t *const param = parse_assignment_expression();
+       expression->va_starte.parameter = param;
+       rem_anchor_token(')');
+       expect(')');
+
+       if (!current_function) {
+               errorf(&expression->base.source_position, "'va_start' used outside of function");
+       } else if (!current_function->base.type->function.variadic) {
+               errorf(&expression->base.source_position, "'va_start' used in non-variadic function");
+       } else if (!is_last_parameter(param)) {
+               errorf(&param->base.source_position, "second argument of 'va_start' must be last parameter of the current function");
        }
-       expect(')', end_error);
-end_error:
-       return create_error_expression();
+
+       return expression;
 }
 
 /**
@@ -6617,19 +6453,21 @@ static expression_t *parse_va_arg(void)
 
        eat(T___builtin_va_arg);
 
-       expect('(', end_error);
+       add_anchor_token(')');
+       add_anchor_token(',');
+       expect('(');
        call_argument_t ap;
        ap.expression = parse_assignment_expression();
        expression->va_arge.ap = ap.expression;
        check_call_argument(type_valist, &ap, 1);
 
-       expect(',', end_error);
+       rem_anchor_token(',');
+       expect(',');
        expression->base.type = parse_typename();
-       expect(')', end_error);
+       rem_anchor_token(')');
+       expect(')');
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6641,24 +6479,26 @@ static expression_t *parse_va_copy(void)
 
        eat(T___builtin_va_copy);
 
-       expect('(', end_error);
+       add_anchor_token(')');
+       add_anchor_token(',');
+       expect('(');
        expression_t *dst = parse_assignment_expression();
        assign_error_t error = semantic_assign(type_valist, dst);
        report_assign_error(error, type_valist, dst, "call argument 1",
                            &dst->base.source_position);
        expression->va_copye.dst = dst;
 
-       expect(',', end_error);
+       rem_anchor_token(',');
+       expect(',');
 
        call_argument_t src;
        src.expression = parse_assignment_expression();
        check_call_argument(type_valist, &src, 2);
        expression->va_copye.src = src.expression;
-       expect(')', end_error);
+       rem_anchor_token(')');
+       expect(')');
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6670,16 +6510,14 @@ static expression_t *parse_builtin_constant(void)
 
        eat(T___builtin_constant_p);
 
-       expect('(', end_error);
        add_anchor_token(')');
+       expect('(');
        expression->builtin_constant.value = parse_assignment_expression();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
        expression->base.type = type_int;
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6691,20 +6529,18 @@ static expression_t *parse_builtin_types_compatible(void)
 
        eat(T___builtin_types_compatible_p);
 
-       expect('(', end_error);
        add_anchor_token(')');
        add_anchor_token(',');
+       expect('(');
        expression->builtin_types_compatible.left = parse_typename();
        rem_anchor_token(',');
-       expect(',', end_error);
+       expect(',');
        expression->builtin_types_compatible.right = parse_typename();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
        expression->base.type = type_int;
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6712,38 +6548,28 @@ end_error:
  */
 static expression_t *parse_compare_builtin(void)
 {
-       expression_t *expression;
-
+       expression_kind_t kind;
        switch (token.kind) {
-       case T___builtin_isgreater:
-               expression = allocate_expression_zero(EXPR_BINARY_ISGREATER);
-               break;
-       case T___builtin_isgreaterequal:
-               expression = allocate_expression_zero(EXPR_BINARY_ISGREATEREQUAL);
-               break;
-       case T___builtin_isless:
-               expression = allocate_expression_zero(EXPR_BINARY_ISLESS);
-               break;
-       case T___builtin_islessequal:
-               expression = allocate_expression_zero(EXPR_BINARY_ISLESSEQUAL);
-               break;
-       case T___builtin_islessgreater:
-               expression = allocate_expression_zero(EXPR_BINARY_ISLESSGREATER);
-               break;
-       case T___builtin_isunordered:
-               expression = allocate_expression_zero(EXPR_BINARY_ISUNORDERED);
-               break;
-       default:
-               internal_errorf(HERE, "invalid compare builtin found");
-       }
-       expression->base.source_position = *HERE;
+       case T___builtin_isgreater:      kind = EXPR_BINARY_ISGREATER;      break;
+       case T___builtin_isgreaterequal: kind = EXPR_BINARY_ISGREATEREQUAL; break;
+       case T___builtin_isless:         kind = EXPR_BINARY_ISLESS;         break;
+       case T___builtin_islessequal:    kind = EXPR_BINARY_ISLESSEQUAL;    break;
+       case T___builtin_islessgreater:  kind = EXPR_BINARY_ISLESSGREATER;  break;
+       case T___builtin_isunordered:    kind = EXPR_BINARY_ISUNORDERED;    break;
+       default: internal_errorf(HERE, "invalid compare builtin found");
+       }
+       expression_t *const expression = allocate_expression_zero(kind);
        next_token();
 
-       expect('(', end_error);
+       add_anchor_token(')');
+       add_anchor_token(',');
+       expect('(');
        expression->binary.left = parse_assignment_expression();
-       expect(',', end_error);
+       rem_anchor_token(',');
+       expect(',');
        expression->binary.right = parse_assignment_expression();
-       expect(')', end_error);
+       rem_anchor_token(')');
+       expect(')');
 
        type_t *const orig_type_left  = expression->binary.left->base.type;
        type_t *const orig_type_right = expression->binary.right->base.type;
@@ -6760,8 +6586,6 @@ static expression_t *parse_compare_builtin(void)
        }
 
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -6773,27 +6597,28 @@ static expression_t *parse_assume(void)
 
        eat(T__assume);
 
-       expect('(', end_error);
        add_anchor_token(')');
+       expect('(');
        expression->unary.value = parse_assignment_expression();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        expression->base.type = type_void;
        return expression;
-end_error:
-       return create_error_expression();
 }
 
 /**
  * Return the label for the current symbol or create a new one.
  */
-static label_t *get_label(void)
+static label_t *get_label(char const *const context)
 {
-       assert(token.kind == T_IDENTIFIER);
        assert(current_function != NULL);
 
-       entity_t *label = get_entity(token.identifier.symbol, NAMESPACE_LABEL);
+       symbol_t *const sym = expect_identifier(context, NULL);
+       if (!sym)
+               return NULL;
+
+       entity_t *label = get_entity(sym, NAMESPACE_LABEL);
        /* If we find a local label, we already created the declaration. */
        if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
                if (label->base.parent_scope != current_scope) {
@@ -6802,11 +6627,11 @@ static label_t *get_label(void)
                }
        } else if (label == NULL || label->base.parent_scope != &current_function->parameters) {
                /* There is no matching label in the same function, so create a new one. */
-               label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol);
+               source_position_t const nowhere = { NULL, 0, 0, false };
+               label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym, &nowhere);
                label_push(label);
        }
 
-       eat(T_IDENTIFIER);
        return &label->label;
 }
 
@@ -6815,14 +6640,13 @@ static label_t *get_label(void)
  */
 static expression_t *parse_label_address(void)
 {
-       source_position_t source_position = token.base.source_position;
+       source_position_t const source_position = *HERE;
        eat(T_ANDAND);
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
+
+       label_t *const label = get_label("while parsing label address");
+       if (!label)
                return create_error_expression();
-       }
 
-       label_t *const label = get_label();
        label->used          = true;
        label->address_taken = true;
 
@@ -6856,14 +6680,13 @@ static expression_t *parse_noop_expression(void)
 
                if (token.kind != ')') do {
                        (void)parse_assignment_expression();
-               } while (next_if(','));
+               } while (accept(','));
 
                rem_anchor_token(',');
                rem_anchor_token(')');
        }
-       expect(')', end_error);
+       expect(')');
 
-end_error:
        return literal;
 }
 
@@ -6875,20 +6698,13 @@ static expression_t *parse_primary_expression(void)
        switch (token.kind) {
        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_NUMBER:                       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_STRING_LITERAL:               return parse_string_literal();
+       case T___func__:                     return parse_function_keyword(FUNCNAME_FUNCTION);
+       case T___PRETTY_FUNCTION__:          return parse_function_keyword(FUNCNAME_PRETTY_FUNCTION);
+       case T___FUNCSIG__:                  return parse_function_keyword(FUNCNAME_FUNCSIG);
+       case T___FUNCDNAME__:                return parse_function_keyword(FUNCNAME_FUNCDNAME);
        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();
@@ -6914,7 +6730,7 @@ static expression_t *parse_primary_expression(void)
        case T_COLONCOLON:
                return parse_reference();
        case T_IDENTIFIER:
-               if (!is_typedef_symbol(token.identifier.symbol)) {
+               if (!is_typedef_symbol(token.base.symbol)) {
                        return parse_reference();
                }
                /* FALLTHROUGH */
@@ -6968,7 +6784,8 @@ static expression_t *parse_array_expression(expression_t *left)
 check_idx:
                res_type = automatic_type_conversion(res_type);
                if (!is_type_integer(idx_type)) {
-                       errorf(&idx->base.source_position, "array subscript must have integer type");
+                       if (is_type_valid(idx_type))
+                               errorf(&idx->base.source_position, "array subscript must have integer type");
                } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) {
                        source_position_t const *const pos = &idx->base.source_position;
                        warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type");
@@ -6987,8 +6804,7 @@ check_idx:
        arr->base.type = res_type;
 
        rem_anchor_token(']');
-       expect(']', end_error);
-end_error:
+       expect(']');
        return expr;
 }
 
@@ -7003,17 +6819,17 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
        expression_t  *tp_expression = allocate_expression_zero(kind);
        tp_expression->base.type     = type_size_t;
 
-       eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
+       eat(kind == EXPR_SIZEOF ? T_sizeof : T__Alignof);
 
        type_t       *orig_type;
        expression_t *expression;
        if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) {
                source_position_t const pos = *HERE;
-               next_token();
+               eat('(');
                add_anchor_token(')');
                orig_type = parse_typename();
                rem_anchor_token(')');
-               expect(')', end_error);
+               expect(')');
 
                if (token.kind == '{') {
                        /* It was not sizeof(type) after all.  It is sizeof of an expression
@@ -7061,7 +6877,6 @@ typeprop_expression:
                                what, wrong_type, orig_type);
        }
 
-end_error:
        return tp_expression;
 }
 
@@ -7082,12 +6897,9 @@ static expression_t *parse_select_expression(expression_t *addr)
        source_position_t const pos = *HERE;
        next_token();
 
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
+       symbol_t *const symbol = expect_identifier("while parsing select", NULL);
+       if (!symbol)
                return create_error_expression();
-       }
-       symbol_t *symbol = token.identifier.symbol;
-       next_token();
 
        type_t *const orig_type = addr->base.type;
        type_t *const type      = skip_typeref(orig_type);
@@ -7110,9 +6922,7 @@ static expression_t *parse_select_expression(expression_t *addr)
                type_left = type;
        }
 
-       if (type_left->kind != TYPE_COMPOUND_STRUCT &&
-           type_left->kind != TYPE_COMPOUND_UNION) {
-
+       if (!is_type_compound(type_left)) {
                if (is_type_valid(type_left) && !saw_error) {
                        errorf(&pos,
                               "request for member '%Y' in something not a struct or union, but '%T'",
@@ -7237,7 +7047,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
                                                   "third argument of '%Y' must be a constant expression",
                                                   call->function->reference.entity->base.symbol);
                                }
-                               locality = rw->next;
                        }
                        break;
                default:
@@ -7303,11 +7112,11 @@ static expression_t *parse_call_expression(expression_t *expression)
 
                        *anchor = argument;
                        anchor  = &argument->next;
-               } while (next_if(','));
+               } while (accept(','));
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
 
        if (function_type == NULL)
                return result;
@@ -7356,7 +7165,6 @@ static expression_t *parse_call_expression(expression_t *expression)
                        handle_builtin_argument_restrictions(call);
        }
 
-end_error:
        return result;
 }
 
@@ -7458,8 +7266,7 @@ static expression_t *parse_conditional_expression(expression_t *expression)
                true_expression = parse_expression();
        }
        rem_anchor_token(':');
-       expect(':', end_error);
-end_error:;
+       expect(':');
        expression_t *false_expression =
                parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
 
@@ -7567,16 +7374,14 @@ static expression_t *parse_builtin_classify_type(void)
 
        eat(T___builtin_classify_type);
 
-       expect('(', end_error);
        add_anchor_token(')');
+       expect('(');
        expression_t *expression = parse_expression();
        rem_anchor_token(')');
-       expect(')', end_error);
+       expect(')');
        result->classify_type.type_expression = expression;
 
        return result;
-end_error:
-       return create_error_expression();
 }
 
 /**
@@ -7590,10 +7395,9 @@ static expression_t *parse_delete(void)
 
        eat(T_delete);
 
-       if (next_if('[')) {
+       if (accept('[')) {
                result->kind = EXPR_UNARY_DELETE_ARRAY;
-               expect(']', end_error);
-end_error:;
+               expect(']');
        }
 
        expression_t *const value = parse_subexpression(PREC_CAST);
@@ -7819,12 +7623,7 @@ static void set_address_taken(expression_t *expression, bool may_be_register)
                errorf(pos, "address of register '%N' requested", entity);
        }
 
-       if (entity->kind == ENTITY_VARIABLE) {
-               entity->variable.address_taken = true;
-       } else {
-               assert(entity->kind == ENTITY_PARAMETER);
-               entity->parameter.address_taken = true;
-       }
+       entity->variable.address_taken = true;
 }
 
 /**
@@ -8196,8 +7995,7 @@ 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) {
                source_position_t const *const pos = &expr->base.source_position;
                warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour");
        }
@@ -8535,14 +8333,9 @@ static bool expression_has_effect(const expression_t *const expr)
                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_CALL: {
                        const call_expression_t *const call = &expr->call;
@@ -8715,10 +8508,6 @@ CREATE_BINEXPR_PARSER(',',                    EXPR_BINARY_COMMA,              PR
 
 static expression_t *parse_subexpression(precedence_t precedence)
 {
-       if (token.kind < 0) {
-               return expected_expression_error();
-       }
-
        expression_parser_function_t *parser
                = &expression_parsers[token.kind];
        expression_t                 *left;
@@ -8731,10 +8520,6 @@ static expression_t *parse_subexpression(precedence_t precedence)
        assert(left != NULL);
 
        while (true) {
-               if (token.kind < 0) {
-                       return expected_expression_error();
-               }
-
                parser = &expression_parsers[token.kind];
                if (parser->infix_parser == NULL)
                        break;
@@ -8768,10 +8553,7 @@ static void register_expression_parser(parse_expression_function parser,
 {
        expression_parser_function_t *entry = &expression_parsers[token_kind];
 
-       if (entry->parser != NULL) {
-               diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
-               panic("trying to register multiple expression parsers for a token");
-       }
+       assert(!entry->parser);
        entry->parser = parser;
 }
 
@@ -8787,11 +8569,7 @@ static void register_infix_parser(parse_expression_infix_function parser,
 {
        expression_parser_function_t *entry = &expression_parsers[token_kind];
 
-       if (entry->infix_parser != NULL) {
-               diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
-               panic("trying to register multiple infix expression parsers for a "
-                     "token");
-       }
+       assert(!entry->infix_parser);
        entry->infix_parser     = parser;
        entry->infix_precedence = precedence;
 }
@@ -8850,7 +8628,7 @@ static void init_expression_parsers(void)
        register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS);
        register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS);
        register_expression_parser(parse_sizeof,                      T_sizeof);
-       register_expression_parser(parse_alignof,                     T___alignof__);
+       register_expression_parser(parse_alignof,                     T__Alignof);
        register_expression_parser(parse_extension,                   T___extension__);
        register_expression_parser(parse_builtin_classify_type,       T___builtin_classify_type);
        register_expression_parser(parse_delete,                      T_delete);
@@ -8860,125 +8638,131 @@ static void init_expression_parsers(void)
 /**
  * Parse a asm statement arguments specification.
  */
-static asm_argument_t *parse_asm_arguments(bool is_out)
+static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
 {
-       asm_argument_t  *result = NULL;
-       asm_argument_t **anchor = &result;
+       if (token.kind == T_STRING_LITERAL || token.kind == '[') {
+               add_anchor_token(',');
+               do {
+                       asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
 
-       while (token.kind == T_STRING_LITERAL || token.kind == '[') {
-               asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
-               memset(argument, 0, sizeof(argument[0]));
+                       add_anchor_token(')');
+                       add_anchor_token('(');
+                       add_anchor_token(T_STRING_LITERAL);
 
-               if (next_if('[')) {
-                       if (token.kind != T_IDENTIFIER) {
-                               parse_error_expected("while parsing asm argument",
-                                                    T_IDENTIFIER, NULL);
-                               return NULL;
+                       if (accept('[')) {
+                               add_anchor_token(']');
+                               argument->symbol = expect_identifier("while parsing asm argument", NULL);
+                               rem_anchor_token(']');
+                               expect(']');
                        }
-                       argument->symbol = token.identifier.symbol;
-
-                       expect(']', end_error);
-               }
-
-               argument->constraints = parse_string_literals();
-               expect('(', end_error);
-               add_anchor_token(')');
-               expression_t *expression = parse_expression();
-               rem_anchor_token(')');
-               if (is_out) {
-                       /* Ugly GCC stuff: Allow lvalue casts.  Skip casts, when they do not
-                        * change size or type representation (e.g. int -> long is ok, but
-                        * int -> float is not) */
-                       if (expression->kind == EXPR_UNARY_CAST) {
-                               type_t      *const type = expression->base.type;
-                               type_kind_t  const kind = type->kind;
-                               if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
-                                       unsigned flags;
-                                       unsigned size;
-                                       if (kind == TYPE_ATOMIC) {
-                                               atomic_type_kind_t const akind = type->atomic.akind;
-                                               flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
-                                               size  = get_atomic_type_size(akind);
-                                       } else {
-                                               flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                               size  = get_type_size(type_void_ptr);
-                                       }
 
-                                       do {
-                                               expression_t *const value      = expression->unary.value;
-                                               type_t       *const value_type = value->base.type;
-                                               type_kind_t   const value_kind = value_type->kind;
-
-                                               unsigned value_flags;
-                                               unsigned value_size;
-                                               if (value_kind == TYPE_ATOMIC) {
-                                                       atomic_type_kind_t const value_akind = value_type->atomic.akind;
-                                                       value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
-                                                       value_size  = get_atomic_type_size(value_akind);
-                                               } else if (value_kind == TYPE_POINTER) {
-                                                       value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                                       value_size  = get_type_size(type_void_ptr);
+                       rem_anchor_token(T_STRING_LITERAL);
+                       argument->constraints = parse_string_literals("asm argument");
+                       rem_anchor_token('(');
+                       expect('(');
+                       expression_t *expression = parse_expression();
+                       if (is_out) {
+                               /* Ugly GCC stuff: Allow lvalue casts.  Skip casts, when they do not
+                                * change size or type representation (e.g. int -> long is ok, but
+                                * int -> float is not) */
+                               if (expression->kind == EXPR_UNARY_CAST) {
+                                       type_t      *const type = expression->base.type;
+                                       type_kind_t  const kind = type->kind;
+                                       if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
+                                               unsigned flags;
+                                               unsigned size;
+                                               if (kind == TYPE_ATOMIC) {
+                                                       atomic_type_kind_t const akind = type->atomic.akind;
+                                                       flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+                                                       size  = get_atomic_type_size(akind);
                                                } else {
-                                                       break;
+                                                       flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+                                                       size  = get_type_size(type_void_ptr);
                                                }
 
-                                               if (value_flags != flags || value_size != size)
-                                                       break;
+                                               do {
+                                                       expression_t *const value      = expression->unary.value;
+                                                       type_t       *const value_type = value->base.type;
+                                                       type_kind_t   const value_kind = value_type->kind;
+
+                                                       unsigned value_flags;
+                                                       unsigned value_size;
+                                                       if (value_kind == TYPE_ATOMIC) {
+                                                               atomic_type_kind_t const value_akind = value_type->atomic.akind;
+                                                               value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+                                                               value_size  = get_atomic_type_size(value_akind);
+                                                       } else if (value_kind == TYPE_POINTER) {
+                                                               value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+                                                               value_size  = get_type_size(type_void_ptr);
+                                                       } else {
+                                                               break;
+                                                       }
+
+                                                       if (value_flags != flags || value_size != size)
+                                                               break;
 
-                                               expression = value;
-                                       } while (expression->kind == EXPR_UNARY_CAST);
+                                                       expression = value;
+                                               } while (expression->kind == EXPR_UNARY_CAST);
+                                       }
                                }
-                       }
 
-                       if (!is_lvalue(expression)) {
-                               errorf(&expression->base.source_position,
-                                      "asm output argument is not an lvalue");
-                       }
+                               if (!is_lvalue(expression))
+                                       errorf(&expression->base.source_position, "asm output argument is not an lvalue");
 
-                       if (argument->constraints.begin[0] == '=')
-                               determine_lhs_ent(expression, NULL);
-                       else
+                               if (argument->constraints.begin[0] == '=')
+                                       determine_lhs_ent(expression, NULL);
+                               else
+                                       mark_vars_read(expression, NULL);
+                       } else {
                                mark_vars_read(expression, NULL);
-               } else {
-                       mark_vars_read(expression, NULL);
-               }
-               argument->expression = expression;
-               expect(')', end_error);
-
-               set_address_taken(expression, true);
+                       }
+                       argument->expression = expression;
+                       rem_anchor_token(')');
+                       expect(')');
 
-               *anchor = argument;
-               anchor  = &argument->next;
+                       set_address_taken(expression, true);
 
-               if (!next_if(','))
-                       break;
+                       *anchor = argument;
+                       anchor  = &argument->next;
+               } while (accept(','));
+               rem_anchor_token(',');
        }
-
-       return result;
-end_error:
-       return NULL;
 }
 
 /**
  * Parse a asm statement clobber specification.
  */
-static asm_clobber_t *parse_asm_clobbers(void)
+static void parse_asm_clobbers(asm_clobber_t **anchor)
 {
-       asm_clobber_t *result  = NULL;
-       asm_clobber_t **anchor = &result;
+       if (token.kind == T_STRING_LITERAL) {
+               add_anchor_token(',');
+               do {
+                       asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
+                       clobber->clobber       = parse_string_literals(NULL);
 
-       while (token.kind == T_STRING_LITERAL) {
-               asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
-               clobber->clobber       = parse_string_literals();
+                       *anchor = clobber;
+                       anchor  = &clobber->next;
+               } while (accept(','));
+               rem_anchor_token(',');
+       }
+}
 
-               *anchor = clobber;
-               anchor  = &clobber->next;
+static void parse_asm_labels(asm_label_t **anchor)
+{
+       if (token.kind == T_IDENTIFIER) {
+               add_anchor_token(',');
+               do {
+                       label_t *const label = get_label("while parsing 'asm goto' labels");
+                       if (label) {
+                               asm_label_t *const asm_label = allocate_ast_zero(sizeof(*asm_label));
+                               asm_label->label = label;
 
-               if (!next_if(','))
-                       break;
+                               *anchor = asm_label;
+                               anchor  = &asm_label->next;
+                       }
+               } while (accept(','));
+               rem_anchor_token(',');
        }
-
-       return result;
 }
 
 /**
@@ -8990,45 +8774,39 @@ static statement_t *parse_asm_statement(void)
        asm_statement_t *asm_statement = &statement->asms;
 
        eat(T_asm);
+       add_anchor_token(')');
+       add_anchor_token(':');
+       add_anchor_token(T_STRING_LITERAL);
 
-       if (next_if(T_volatile))
+       if (accept(T_volatile))
                asm_statement->is_volatile = true;
 
-       expect('(', end_error);
-       add_anchor_token(')');
-       if (token.kind != T_STRING_LITERAL) {
-               parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
-               goto end_of_asm;
-       }
-       asm_statement->asm_text = parse_string_literals();
+       bool const asm_goto = accept(T_goto);
 
-       add_anchor_token(':');
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
+       expect('(');
+       rem_anchor_token(T_STRING_LITERAL);
+       asm_statement->asm_text = parse_string_literals("asm statement");
 
-       asm_statement->outputs = parse_asm_arguments(true);
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
+       if (accept(':')) parse_asm_arguments(&asm_statement->outputs, true);
+       if (accept(':')) parse_asm_arguments(&asm_statement->inputs, false);
+       if (accept(':')) parse_asm_clobbers( &asm_statement->clobbers);
 
-       asm_statement->inputs = parse_asm_arguments(false);
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
        rem_anchor_token(':');
+       if (accept(':')) {
+               if (!asm_goto)
+                       warningf(WARN_OTHER, &statement->base.source_position, "assembler statement with labels should be 'asm goto'");
+               parse_asm_labels(&asm_statement->labels);
+               if (asm_statement->labels)
+                       errorf(&statement->base.source_position, "'asm goto' not supported");
+       } else {
+               if (asm_goto)
+                       warningf(WARN_OTHER, &statement->base.source_position, "'asm goto' without labels");
+       }
 
-       asm_statement->clobbers = parse_asm_clobbers();
-
-end_of_asm:
        rem_anchor_token(')');
-       expect(')', end_error);
-       expect(';', end_error);
+       expect(')');
+       expect(';');
 
-end_error:
        if (asm_statement->outputs == NULL) {
                /* GCC: An 'asm' instruction without any output operands will be treated
                 * identically to a volatile 'asm' instruction. */
@@ -9053,7 +8831,7 @@ static statement_t *parse_label_inner_statement(statement_t const *const label,
                                 * statement after a label.  label:; is commonly used to have a label
                                 * before a closing brace. */
                                inner_stmt = create_empty_statement();
-                               next_token();
+                               eat(';');
                                break;
                        }
                        /* FALLTHROUGH */
@@ -9079,6 +8857,7 @@ static statement_t *parse_case_statement(void)
        source_position_t *const pos       = &statement->base.source_position;
 
        eat(T_case);
+       add_anchor_token(':');
 
        expression_t *expression = parse_expression();
        type_t *expression_type = expression->base.type;
@@ -9104,13 +8883,13 @@ static statement_t *parse_case_statement(void)
                }
                statement->case_label.is_bad = true;
        } else {
-               long const val = fold_constant_to_int(expression);
+               ir_tarval *val = fold_constant_to_tarval(expression);
                statement->case_label.first_case = val;
                statement->case_label.last_case  = val;
        }
 
        if (GNU_MODE) {
-               if (next_if(T_DOTDOTDOT)) {
+               if (accept(T_DOTDOTDOT)) {
                        expression_t *end_range = parse_expression();
                        expression_type = expression->base.type;
                        skipped         = skip_typeref(expression_type);
@@ -9128,10 +8907,11 @@ static statement_t *parse_case_statement(void)
                                }
                                statement->case_label.is_bad = true;
                        } else {
-                               long const val = fold_constant_to_int(end_range);
+                               ir_tarval *val = fold_constant_to_tarval(end_range);
                                statement->case_label.last_case = val;
 
-                               if (val < statement->case_label.first_case) {
+                               if (tarval_cmp(val, statement->case_label.first_case)
+                                   == ir_relation_less) {
                                        statement->case_label.is_empty_range = true;
                                        warningf(WARN_OTHER, pos, "empty range specified");
                                }
@@ -9141,8 +8921,8 @@ static statement_t *parse_case_statement(void)
 
        PUSH_PARENT(statement);
 
-       expect(':', end_error);
-end_error:
+       rem_anchor_token(':');
+       expect(':');
 
        if (current_switch != NULL) {
                if (! statement->case_label.is_bad) {
@@ -9188,8 +8968,7 @@ static statement_t *parse_default_statement(void)
 
        PUSH_PARENT(statement);
 
-       expect(':', end_error);
-end_error:
+       expect(':');
 
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
@@ -9223,7 +9002,7 @@ end_error:
 static statement_t *parse_label_statement(void)
 {
        statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
-       label_t     *const label     = get_label();
+       label_t     *const label     = get_label(NULL /* Cannot fail, token is T_IDENTIFIER. */);
        statement->label.label = label;
 
        PUSH_PARENT(statement);
@@ -9237,6 +9016,7 @@ static statement_t *parse_label_statement(void)
        } else {
                label->base.source_position = *pos;
                label->statement            = statement;
+               label->n_users             += 1;
        }
 
        eat(':');
@@ -9271,16 +9051,13 @@ static statement_t *parse_inner_statement(void)
  */
 static expression_t *parse_condition(void)
 {
-       expect('(', end_error0);
        add_anchor_token(')');
+       expect('(');
        expression_t *const expr = parse_expression();
        mark_vars_read(expr, NULL);
        rem_anchor_token(')');
-       expect(')', end_error1);
-end_error1:
+       expect(')');
        return expr;
-end_error0:
-       return create_error_expression();
 }
 
 /**
@@ -9293,8 +9070,9 @@ static statement_t *parse_if(void)
        eat(T_if);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->ifs.scope);
 
-       add_anchor_token('{');
+       add_anchor_token(T_else);
 
        expression_t *const expr = parse_condition();
        statement->ifs.condition = expr;
@@ -9302,9 +9080,6 @@ static statement_t *parse_if(void)
         *             scalar type. */
        semantic_condition(expr, "condition of 'if'-statment");
 
-       rem_anchor_token('{');
-
-       add_anchor_token(T_else);
        statement_t *const true_stmt = parse_inner_statement();
        statement->ifs.true_statement = true_stmt;
        rem_anchor_token(T_else);
@@ -9314,7 +9089,7 @@ static statement_t *parse_if(void)
                        "suggest braces around empty body in an â€˜if’ statement");
        }
 
-       if (next_if(T_else)) {
+       if (accept(T_else)) {
                statement->ifs.false_statement = parse_inner_statement();
 
                if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) {
@@ -9327,6 +9102,7 @@ static statement_t *parse_if(void)
                warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
        }
 
+       POP_SCOPE();
        POP_PARENT();
        return statement;
 }
@@ -9340,28 +9116,32 @@ static void check_enum_cases(const switch_statement_t *statement)
 {
        if (!is_warn_on(WARN_SWITCH_ENUM))
                return;
-       const type_t *type = skip_typeref(statement->expression->base.type);
+       type_t *type = skip_typeref(statement->expression->base.type);
        if (! is_type_enum(type))
                return;
-       const enum_type_t *enumt = &type->enumt;
+       enum_type_t *enumt = &type->enumt;
 
        /* if we have a default, no warnings */
        if (statement->default_label != NULL)
                return;
 
+       determine_enum_values(enumt);
+
        /* FIXME: calculation of value should be done while parsing */
        /* TODO: quadratic algorithm here. Change to an n log n one */
-       long            last_value = -1;
-       const entity_t *entry      = enumt->enume->base.next;
+       const entity_t *entry = enumt->enume->base.next;
        for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
             entry = entry->base.next) {
-               const expression_t *expression = entry->enum_value.value;
-               long                value      = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
-               bool                found      = false;
-               for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+               ir_tarval *value = entry->enum_value.tv;
+               bool       found = false;
+               for (const case_label_statement_t *l = statement->first_case; l != NULL;
+                    l = l->next) {
                        if (l->expression == NULL)
                                continue;
-                       if (l->first_case <= value && value <= l->last_case) {
+                       if (l->first_case == l->last_case && l->first_case != value)
+                               continue;
+                       if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal)
+                        && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) {
                                found = true;
                                break;
                        }
@@ -9370,7 +9150,6 @@ static void check_enum_cases(const switch_statement_t *statement)
                        source_position_t const *const pos = &statement->base.source_position;
                        warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
                }
-               last_value = value;
        }
 }
 
@@ -9384,6 +9163,7 @@ static statement_t *parse_switch(void)
        eat(T_switch);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->switchs.scope);
 
        expression_t *const expr = parse_condition();
        type_t       *      type = skip_typeref(expr->base.type);
@@ -9409,6 +9189,7 @@ static statement_t *parse_switch(void)
        }
        check_enum_cases(&statement->switchs);
 
+       POP_SCOPE();
        POP_PARENT();
        return statement;
 }
@@ -9429,20 +9210,22 @@ static statement_t *parse_loop_body(statement_t *const loop)
  */
 static statement_t *parse_while(void)
 {
-       statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
+       statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
 
        eat(T_while);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->fors.scope);
 
        expression_t *const cond = parse_condition();
-       statement->whiles.condition = cond;
+       statement->fors.condition = cond;
        /* Â§6.8.5:2    The controlling expression of an iteration statement shall
         *             have scalar type. */
        semantic_condition(cond, "condition of 'while'-statement");
 
-       statement->whiles.body = parse_loop_body(statement);
+       statement->fors.body = parse_loop_body(statement);
 
+       POP_SCOPE();
        POP_PARENT();
        return statement;
 }
@@ -9457,21 +9240,21 @@ static statement_t *parse_do(void)
        eat(T_do);
 
        PUSH_PARENT(statement);
+       PUSH_SCOPE_STATEMENT(&statement->do_while.scope);
 
        add_anchor_token(T_while);
        statement->do_while.body = parse_loop_body(statement);
        rem_anchor_token(T_while);
 
-       expect(T_while, end_error0);
-end_error0:;
+       expect(T_while);
        expression_t *const cond = parse_condition();
        statement->do_while.condition = cond;
        /* Â§6.8.5:2    The controlling expression of an iteration statement shall
         *             have scalar type. */
        semantic_condition(cond, "condition of 'do-while'-statement");
-       expect(';', end_error1);
-end_error1:
+       expect(';');
 
+       POP_SCOPE();
        POP_PARENT();
        return statement;
 }
@@ -9486,14 +9269,14 @@ static statement_t *parse_for(void)
        eat(T_for);
 
        PUSH_PARENT(statement);
-       PUSH_SCOPE(&statement->fors.scope);
+       PUSH_SCOPE_STATEMENT(&statement->fors.scope);
 
-       expect('(', end_error1);
        add_anchor_token(')');
+       expect('(');
 
        PUSH_EXTENSION();
 
-       if (next_if(';')) {
+       if (accept(';')) {
        } else if (is_declaration_specifier(&token)) {
                parse_declaration(record_entity, DECL_FLAGS_NONE);
        } else {
@@ -9505,8 +9288,7 @@ static statement_t *parse_for(void)
                        warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
                }
                rem_anchor_token(';');
-               expect(';', end_error3);
-end_error3:;
+               expect(';');
        }
 
        POP_EXTENSION();
@@ -9521,8 +9303,7 @@ end_error3:;
                mark_vars_read(cond, NULL);
                rem_anchor_token(';');
        }
-       expect(';', end_error2);
-end_error2:
+       expect(';');
        if (token.kind != ')') {
                expression_t *const step = parse_expression();
                statement->fors.step = step;
@@ -9532,8 +9313,7 @@ end_error2:
                }
        }
        rem_anchor_token(')');
-       expect(')', end_error1);
-end_error1:
+       expect(')');
        statement->fors.body = parse_loop_body(statement);
 
        POP_SCOPE();
@@ -9573,8 +9353,10 @@ static statement_t *parse_goto(void)
        } else {
                statement = allocate_statement_zero(STATEMENT_GOTO);
                eat(T_goto);
-               if (token.kind == T_IDENTIFIER) {
-                       label_t *const label = get_label();
+
+               label_t *const label = get_label("while parsing goto");
+               if (label) {
+                       label->n_users        += 1;
                        label->used            = true;
                        statement->gotos.label = label;
 
@@ -9582,18 +9364,11 @@ static statement_t *parse_goto(void)
                        *goto_anchor = &statement->gotos;
                        goto_anchor  = &statement->gotos.next;
                } else {
-                       if (GNU_MODE)
-                               parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
-                       else
-                               parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
-                       eat_until_anchor();
-                       statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous)->label;
+                       statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
                }
        }
 
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9609,9 +9384,7 @@ static statement_t *parse_continue(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
 
        eat(T_continue);
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9627,9 +9400,7 @@ static statement_t *parse_break(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
 
        eat(T_break);
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9645,9 +9416,7 @@ static statement_t *parse_leave_statement(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
 
        eat(T___leave);
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9686,22 +9455,6 @@ static bool expression_is_local_variable(const expression_t *expression)
        return is_local_variable(entity);
 }
 
-/**
- * Check if a given expression represents a local variable and
- * return its declaration then, else return NULL.
- */
-entity_t *expression_is_variable(const expression_t *expression)
-{
-       if (expression->base.kind != EXPR_REFERENCE) {
-               return NULL;
-       }
-       entity_t *entity = expression->reference.entity;
-       if (entity->kind != ENTITY_VARIABLE)
-               return NULL;
-
-       return entity;
-}
-
 static void err_or_warn(source_position_t const *const pos, char const *const msg)
 {
        if (c_mode & _CXX || strict_mode) {
@@ -9761,9 +9514,7 @@ static statement_t *parse_return(void)
        }
        statement->returns.value = return_value;
 
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9801,9 +9552,7 @@ static statement_t *parse_expression_statement(void)
        statement->expression.expression = expr;
        mark_vars_read(expr, ENT_ANY);
 
-       expect(';', end_error);
-
-end_error:
+       expect(';');
        return statement;
 }
 
@@ -9825,7 +9574,7 @@ static statement_t *parse_ms_try_statment(void)
 
        POP_PARENT();
 
-       if (next_if(T___except)) {
+       if (accept(T___except)) {
                expression_t *const expr = parse_condition();
                type_t       *      type = skip_typeref(expr->base.type);
                if (is_type_integer(type)) {
@@ -9836,7 +9585,7 @@ static statement_t *parse_ms_try_statment(void)
                        type = type_error_type;
                }
                statement->ms_try.except_expression = create_implicit_cast(expr, type);
-       } else if (!next_if(T__finally)) {
+       } else if (!accept(T__finally)) {
                parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
        }
        statement->ms_try.final_statement = parse_compound_statement(false);
@@ -9860,32 +9609,31 @@ static statement_t *parse_local_label_declaration(void)
        entity_t *begin   = NULL;
        entity_t *end     = NULL;
        entity_t **anchor = &begin;
+       add_anchor_token(';');
+       add_anchor_token(',');
        do {
-               if (token.kind != T_IDENTIFIER) {
-                       parse_error_expected("while parsing local label declaration",
-                               T_IDENTIFIER, NULL);
-                       goto end_error;
-               }
-               symbol_t *symbol = token.identifier.symbol;
-               entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
-               if (entity != NULL && entity->base.parent_scope == current_scope) {
-                       source_position_t const *const ppos = &entity->base.source_position;
-                       errorf(HERE, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
-               } else {
-                       entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol);
-                       entity->base.parent_scope    = current_scope;
-                       entity->base.source_position = token.base.source_position;
+               source_position_t pos;
+               symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
+               if (symbol) {
+                       entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
+                       if (entity != NULL && entity->base.parent_scope == current_scope) {
+                               source_position_t const *const ppos = &entity->base.source_position;
+                               errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
+                       } else {
+                               entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
+                               entity->base.parent_scope = current_scope;
 
-                       *anchor = entity;
-                       anchor  = &entity->base.next;
-                       end     = entity;
+                               *anchor = entity;
+                               anchor  = &entity->base.next;
+                               end     = entity;
 
-                       environment_push(entity);
+                               environment_push(entity);
+                       }
                }
-               next_token();
-       } while (next_if(','));
-       expect(';', end_error);
-end_error:
+       } while (accept(','));
+       rem_anchor_token(',');
+       rem_anchor_token(';');
+       expect(';');
        statement->declaration.declarations_begin = begin;
        statement->declaration.declarations_end   = end;
        return statement;
@@ -9899,25 +9647,20 @@ static void parse_namespace_definition(void)
        symbol_t *symbol = NULL;
 
        if (token.kind == T_IDENTIFIER) {
-               symbol = token.identifier.symbol;
-               next_token();
-
+               symbol = token.base.symbol;
                entity = get_entity(symbol, NAMESPACE_NORMAL);
-               if (entity != NULL
-                               && entity->kind != ENTITY_NAMESPACE
-                               && entity->base.parent_scope == current_scope) {
-                       if (is_entity_valid(entity)) {
-                               error_redefined_as_different_kind(&token.base.source_position,
-                                               entity, ENTITY_NAMESPACE);
-                       }
+               if (entity && entity->kind != ENTITY_NAMESPACE) {
                        entity = NULL;
+                       if (entity->base.parent_scope == current_scope && is_entity_valid(entity)) {
+                               error_redefined_as_different_kind(HERE, entity, ENTITY_NAMESPACE);
+                       }
                }
+               eat(T_IDENTIFIER);
        }
 
        if (entity == NULL) {
-               entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
-               entity->base.source_position = token.base.source_position;
-               entity->base.parent_scope    = current_scope;
+               entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol, HERE);
+               entity->base.parent_scope = current_scope;
        }
 
        if (token.kind == '=') {
@@ -9929,17 +9672,15 @@ static void parse_namespace_definition(void)
        append_entity(current_scope, entity);
 
        PUSH_SCOPE(&entity->namespacee.members);
+       PUSH_CURRENT_ENTITY(entity);
 
-       entity_t     *old_current_entity = current_entity;
-       current_entity = entity;
-
-       expect('{', end_error);
+       add_anchor_token('}');
+       expect('{');
        parse_externals();
-       expect('}', end_error);
+       rem_anchor_token('}');
+       expect('}');
 
-end_error:
-       assert(current_entity == entity);
-       current_entity = old_current_entity;
+       POP_CURRENT_ENTITY();
        POP_SCOPE();
 }
 
@@ -9957,7 +9698,7 @@ static statement_t *intern_parse_statement(void)
                token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
                if (la1_type == ':') {
                        statement = parse_label_statement();
-               } else if (is_typedef_symbol(token.identifier.symbol)) {
+               } else if (is_typedef_symbol(token.base.symbol)) {
                        statement = parse_declaration_statement();
                } else {
                        /* it's an identifier, the grammar says this must be an
@@ -9967,7 +9708,7 @@ static statement_t *intern_parse_statement(void)
                        switch (la1_type) {
                        case '&':
                        case '*':
-                               if (get_entity(token.identifier.symbol, NAMESPACE_NORMAL) != NULL) {
+                               if (get_entity(token.base.symbol, NAMESPACE_NORMAL) != NULL) {
                        default:
                                        statement = parse_expression_statement();
                                } else {
@@ -10074,20 +9815,17 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token('~');
        add_anchor_token(T_CHARACTER_CONSTANT);
        add_anchor_token(T_COLONCOLON);
-       add_anchor_token(T_FLOATINGPOINT);
        add_anchor_token(T_IDENTIFIER);
-       add_anchor_token(T_INTEGER);
        add_anchor_token(T_MINUSMINUS);
+       add_anchor_token(T_NUMBER);
        add_anchor_token(T_PLUSPLUS);
        add_anchor_token(T_STRING_LITERAL);
-       add_anchor_token(T_WIDE_CHARACTER_CONSTANT);
-       add_anchor_token(T_WIDE_STRING_LITERAL);
+       add_anchor_token(T__Alignof);
        add_anchor_token(T__Bool);
        add_anchor_token(T__Complex);
        add_anchor_token(T__Imaginary);
-       add_anchor_token(T___FUNCTION__);
+       add_anchor_token(T__Thread_local);
        add_anchor_token(T___PRETTY_FUNCTION__);
-       add_anchor_token(T___alignof__);
        add_anchor_token(T___attribute__);
        add_anchor_token(T___builtin_va_start);
        add_anchor_token(T___extension__);
@@ -10095,7 +9833,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token(T___imag__);
        add_anchor_token(T___label__);
        add_anchor_token(T___real__);
-       add_anchor_token(T___thread);
        add_anchor_token(T_asm);
        add_anchor_token(T_auto);
        add_anchor_token(T_bool);
@@ -10169,8 +9906,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
                *anchor = sub_statement;
                anchor  = &sub_statement->base.next;
        }
-       expect('}', end_error);
-end_error:
+       expect('}');
 
        /* look over all statements again to produce no effect warnings */
        if (is_warn_on(WARN_UNUSED_VALUE)) {
@@ -10244,7 +9980,6 @@ end_error:
        rem_anchor_token(T_bool);
        rem_anchor_token(T_auto);
        rem_anchor_token(T_asm);
-       rem_anchor_token(T___thread);
        rem_anchor_token(T___real__);
        rem_anchor_token(T___label__);
        rem_anchor_token(T___imag__);
@@ -10252,20 +9987,17 @@ end_error:
        rem_anchor_token(T___extension__);
        rem_anchor_token(T___builtin_va_start);
        rem_anchor_token(T___attribute__);
-       rem_anchor_token(T___alignof__);
        rem_anchor_token(T___PRETTY_FUNCTION__);
-       rem_anchor_token(T___FUNCTION__);
+       rem_anchor_token(T__Thread_local);
        rem_anchor_token(T__Imaginary);
        rem_anchor_token(T__Complex);
        rem_anchor_token(T__Bool);
-       rem_anchor_token(T_WIDE_STRING_LITERAL);
-       rem_anchor_token(T_WIDE_CHARACTER_CONSTANT);
+       rem_anchor_token(T__Alignof);
        rem_anchor_token(T_STRING_LITERAL);
        rem_anchor_token(T_PLUSPLUS);
+       rem_anchor_token(T_NUMBER);
        rem_anchor_token(T_MINUSMINUS);
-       rem_anchor_token(T_INTEGER);
        rem_anchor_token(T_IDENTIFIER);
-       rem_anchor_token(T_FLOATINGPOINT);
        rem_anchor_token(T_COLONCOLON);
        rem_anchor_token(T_CHARACTER_CONSTANT);
        rem_anchor_token('~');
@@ -10312,7 +10044,7 @@ static void check_unused_globals(void)
                                continue;
 
                        why = WARN_UNUSED_FUNCTION;
-                       s   = entity->function.statement != NULL ? "defined" : "declared";
+                       s   = entity->function.body != NULL ? "defined" : "declared";
                } else {
                        why = WARN_UNUSED_VARIABLE;
                        s   = "defined";
@@ -10327,16 +10059,20 @@ static void parse_global_asm(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
 
        eat(T_asm);
-       expect('(', end_error);
+       add_anchor_token(';');
+       add_anchor_token(')');
+       add_anchor_token(T_STRING_LITERAL);
+       expect('(');
 
-       statement->asms.asm_text = parse_string_literals();
+       rem_anchor_token(T_STRING_LITERAL);
+       statement->asms.asm_text = parse_string_literals("global asm");
        statement->base.next     = unit->global_asm;
        unit->global_asm         = statement;
 
-       expect(')', end_error);
-       expect(';', end_error);
-
-end_error:;
+       rem_anchor_token(')');
+       expect(')');
+       rem_anchor_token(';');
+       expect(';');
 }
 
 static void parse_linkage_specification(void)
@@ -10344,7 +10080,7 @@ static void parse_linkage_specification(void)
        eat(T_extern);
 
        source_position_t const pos     = *HERE;
-       char const       *const linkage = parse_string_literals().begin;
+       char const       *const linkage = parse_string_literals(NULL).begin;
 
        linkage_kind_t old_linkage = current_linkage;
        linkage_kind_t new_linkage;
@@ -10358,14 +10094,13 @@ static void parse_linkage_specification(void)
        }
        current_linkage = new_linkage;
 
-       if (next_if('{')) {
+       if (accept('{')) {
                parse_externals();
-               expect('}', end_error);
+               expect('}');
        } else {
                parse_external();
        }
 
-end_error:
        assert(current_linkage == new_linkage);
        current_linkage = old_linkage;
 }
@@ -10402,7 +10137,7 @@ static void parse_external(void)
                case ';':
                        if (!strict_mode) {
                                warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function");
-                               next_token();
+                               eat(';');
                                return;
                        }
                        /* FALLTHROUGH */
@@ -10483,9 +10218,6 @@ void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
-       diagnostic_count  = 0;
-       error_count       = 0;
-       warning_count     = 0;
 
        print_to_file(stderr);
 
@@ -10546,9 +10278,9 @@ static void complete_incomplete_arrays(void)
        }
 }
 
-void prepare_main_collect2(entity_t *entity)
+static void prepare_main_collect2(entity_t *const entity)
 {
-       PUSH_SCOPE(&entity->function.statement->compound.scope);
+       PUSH_SCOPE(&entity->function.body->compound.scope);
 
        // create call to __main
        symbol_t *symbol         = symbol_table_insert("__main");
@@ -10570,9 +10302,9 @@ void prepare_main_collect2(entity_t *entity)
        expr_statement->base.source_position  = builtin_source_position;
        expr_statement->expression.expression = call;
 
-       statement_t *statement = entity->function.statement;
-       assert(statement->kind == STATEMENT_COMPOUND);
-       compound_statement_t *compounds = &statement->compound;
+       statement_t *const body = entity->function.body;
+       assert(body->kind == STATEMENT_COMPOUND);
+       compound_statement_t *compounds = &body->compound;
 
        expr_statement->base.next = compounds->statements;
        compounds->statements     = expr_statement;
@@ -10599,8 +10331,6 @@ void parse(void)
  */
 void init_parser(void)
 {
-       sym_anonymous = symbol_table_insert("<anonymous>");
-
        memset(token_anchor_set, 0, sizeof(token_anchor_set));
 
        init_expression_parsers();