The standard calls it "file scope", so rename global_scope to file_scope.
[cparser] / parser.c
index fd17b0a..14a84c4 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -114,9 +114,12 @@ static int                 lookahead_bufpos;
 static stack_entry_t      *environment_stack = NULL;
 static stack_entry_t      *label_stack       = NULL;
 static stack_entry_t      *local_label_stack = NULL;
-static scope_t            *global_scope      = NULL;
+/** The global file scope. */
+static scope_t            *file_scope        = NULL;
+/** The current scope. */
 static scope_t            *scope             = NULL;
 static declaration_t      *last_declaration  = NULL;
+/** Point to the current function declaration if inside a function. */
 static declaration_t      *current_function  = NULL;
 static declaration_t      *current_init_decl = NULL;
 static switch_statement_t *current_switch    = NULL;
@@ -637,13 +640,9 @@ check_stop:
  */
 static void eat_until_anchor(void)
 {
-       if (token.type == T_EOF)
-               return;
        while (token_anchor_set[token.type] == 0) {
                if (token.type == '(' || token.type == '{' || token.type == '[')
                        eat_until_matching_token(token.type);
-               if (token.type == T_EOF)
-                       break;
                next_token();
        }
 }
@@ -713,16 +712,25 @@ static void type_error_incompatible(const char *msg,
                next_token();                                     \
        } while (0)
 
-static void set_scope(scope_t *new_scope)
+static void scope_push(scope_t *new_scope)
 {
        if (scope != NULL) {
                scope->last_declaration = last_declaration;
+               new_scope->depth        = scope->depth + 1;
        }
-       scope = new_scope;
+       new_scope->parent = scope;
+       scope             = new_scope;
 
        last_declaration = new_scope->last_declaration;
 }
 
+static void scope_pop(void)
+{
+       scope->last_declaration = last_declaration;
+       scope = scope->parent;
+       last_declaration = scope->last_declaration;
+}
+
 /**
  * Search a symbol in a given namespace and returns its declaration or
  * NULL if this symbol was not found.
@@ -749,28 +757,20 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration)
        namespace_t  namespc = (namespace_t) declaration->namespc;
 
        /* replace/add declaration into declaration list of the symbol */
-       declaration_t *iter = symbol->declaration;
-       if (iter == NULL) {
-               symbol->declaration = declaration;
-       } else {
-               declaration_t *iter_last = NULL;
-               for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
-                       /* replace an entry? */
-                       if (iter->namespc == namespc) {
-                               if (iter_last == NULL) {
-                                       symbol->declaration = declaration;
-                               } else {
-                                       iter_last->symbol_next = declaration;
-                               }
-                               declaration->symbol_next = iter->symbol_next;
-                               break;
-                       }
-               }
-               if (iter == NULL) {
-                       assert(iter_last->symbol_next == NULL);
-                       iter_last->symbol_next = declaration;
+       declaration_t **anchor;
+       declaration_t  *iter;
+       for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+               iter = *anchor;
+               if (iter == NULL)
+                       break;
+
+               /* replace an entry? */
+               if (iter->namespc == namespc) {
+                       declaration->symbol_next = iter->symbol_next;
+                       break;
                }
        }
+       *anchor = declaration;
 
        /* remember old declaration */
        stack_entry_t entry;
@@ -835,30 +835,20 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
                namespace_t    namespc         = (namespace_t)entry->namespc;
 
                /* replace/remove declaration */
-               declaration_t *declaration = symbol->declaration;
-               assert(declaration != NULL);
-               if (declaration->namespc == namespc) {
-                       if (old_declaration == NULL) {
-                               symbol->declaration = declaration->symbol_next;
-                       } else {
-                               symbol->declaration = old_declaration;
-                       }
-               } else {
-                       declaration_t *iter_last = declaration;
-                       declaration_t *iter      = declaration->symbol_next;
-                       for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
-                               /* replace an entry? */
-                               if (iter->namespc == namespc) {
-                                       assert(iter_last != NULL);
-                                       iter_last->symbol_next = old_declaration;
-                                       if (old_declaration != NULL) {
-                                               old_declaration->symbol_next = iter->symbol_next;
-                                       }
-                                       break;
-                               }
-                       }
+               declaration_t **anchor;
+               declaration_t  *iter;
+               for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+                       iter = *anchor;
                        assert(iter != NULL);
+                       /* replace an entry? */
+                       if (iter->namespc == namespc)
+                               break;
                }
+
+               /* Because of scopes and appending other namespaces to the end of
+                * the list, this must hold. */
+               assert((old_declaration != NULL ? old_declaration->symbol_next : NULL) == iter->symbol_next);
+               *anchor = old_declaration;
        }
 
        ARR_SHRINKLEN(*stack_ptr, (int) new_top);
@@ -3122,7 +3112,7 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t
        decl->source_position        = *HERE;
        decl->declared_storage_class = storage_class;
        decl->storage_class          =
-               storage_class != STORAGE_CLASS_NONE || scope == global_scope ?
+               storage_class != STORAGE_CLASS_NONE || scope == file_scope ?
                        storage_class : STORAGE_CLASS_AUTO;
        decl->symbol                 = symbol;
        decl->implicit               = true;
@@ -3374,8 +3364,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        type->compound.declaration = parse_compound_type_specifier(false);
                        if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
                                modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
-                       break;
                        finish_union_type(&type->compound);
+                       break;
                }
                case T_enum:
                        type = parse_enum_specifier();
@@ -3674,7 +3664,13 @@ static type_qualifiers_t parse_type_qualifiers(void)
        }
 }
 
-static declaration_t *parse_identifier_list(void)
+/**
+ * Parses an K&R identifier list and return a list of declarations.
+ *
+ * @param last  points to the last declaration in the list
+ * @return the list of declarations
+ */
+static declaration_t *parse_identifier_list(declaration_t **last)
 {
        declaration_t *declarations     = NULL;
        declaration_t *last_declaration = NULL;
@@ -3698,6 +3694,7 @@ static declaration_t *parse_identifier_list(void)
                next_token();
        } while (token.type == T_IDENTIFIER);
 
+       *last = last_declaration;
        return declarations;
 }
 
@@ -3750,7 +3747,13 @@ static declaration_t *parse_parameter(void)
        return declaration;
 }
 
-static declaration_t *parse_parameters(function_type_t *type)
+/**
+ * Parses a function type parameter list and return a list of declarations.
+ *
+ * @param last  point to the last element of the list
+ * @return the parameter list
+ */
+static declaration_t *parse_parameters(function_type_t *type, declaration_t **last)
 {
        declaration_t *declarations = NULL;
 
@@ -3763,7 +3766,7 @@ static declaration_t *parse_parameters(function_type_t *type)
                token_type_t la1_type = (token_type_t)look_ahead(1)->type;
                if (la1_type == ',' || la1_type == ')') {
                        type->kr_style_parameters = true;
-                       declarations = parse_identifier_list();
+                       declarations = parse_identifier_list(last);
                        goto parameters_finished;
                }
        }
@@ -3829,10 +3832,12 @@ parameters_finished:
        expect(')');
 
        restore_anchor_state(',', saved_comma_state);
+       *last = last_declaration;
        return declarations;
 
 end_error:
        restore_anchor_state(',', saved_comma_state);
+       *last = NULL;
        return NULL;
 }
 
@@ -3968,9 +3973,12 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration)
                type = allocate_type_zero(TYPE_FUNCTION, HERE);
        }
 
-       declaration_t *parameters = parse_parameters(&type->function);
+       declaration_t *last;
+       declaration_t *parameters = parse_parameters(&type->function, &last);
        if (declaration != NULL) {
-               declaration->scope.declarations = parameters;
+               declaration->scope.declarations     = parameters;
+               declaration->scope.last_declaration = last;
+               declaration->scope.is_parameter     = true;
        }
 
        construct_function_type_t *construct_function_type =
@@ -4251,8 +4259,8 @@ static declaration_t *parse_declarator(
        declaration->is_inline              = specifiers->is_inline;
 
        declaration->storage_class          = specifiers->declared_storage_class;
-       if (declaration->storage_class == STORAGE_CLASS_NONE
-                       && scope != global_scope) {
+       if (declaration->storage_class == STORAGE_CLASS_NONE &&
+           scope != file_scope) {
                declaration->storage_class = STORAGE_CLASS_AUTO;
        }
 
@@ -4388,14 +4396,23 @@ static declaration_t *record_declaration(
 
        if (warning.nested_externs                             &&
            declaration->storage_class == STORAGE_CLASS_EXTERN &&
-           scope                      != global_scope) {
+           scope                      != file_scope) {
                warningf(&declaration->source_position,
                         "nested extern declaration of '%#T'", declaration->type, symbol);
        }
 
        assert(declaration != previous_declaration);
-       if (previous_declaration != NULL
-                       && previous_declaration->parent_scope == scope) {
+       if (previous_declaration != NULL &&
+           previous_declaration->parent_scope->is_parameter &&
+           scope->depth == previous_declaration->parent_scope->depth + 1) {
+               errorf(&declaration->source_position,
+                       "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
+                       orig_type, symbol, previous_declaration->type, symbol,
+                       &previous_declaration->source_position);
+               goto finish;
+       }
+       if (previous_declaration != NULL &&
+           previous_declaration->parent_scope == scope) {
                /* can happen for K&R style declarations */
                if (previous_declaration->type == NULL) {
                        previous_declaration->type = declaration->type;
@@ -4519,7 +4536,7 @@ warn_redundant_declaration:
                }
        } else {
                if (warning.missing_declarations &&
-                   scope == global_scope && (
+                   scope == file_scope && (
                      declaration->storage_class == STORAGE_CLASS_NONE ||
                      declaration->storage_class == STORAGE_CLASS_THREAD
                    )) {
@@ -4527,7 +4544,7 @@ warn_redundant_declaration:
                                 "no previous declaration for '%#T'", orig_type, symbol);
                }
        }
-
+finish:
        assert(declaration->parent_scope == NULL);
        assert(scope != NULL);
 
@@ -4575,9 +4592,9 @@ static void parse_init_declarator_rest(declaration_t *declaration)
        }
 
        bool must_be_constant = false;
-       if (declaration->storage_class == STORAGE_CLASS_STATIC
-                       || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC
-                       || declaration->parent_scope == global_scope) {
+       if (declaration->storage_class == STORAGE_CLASS_STATIC        ||
+           declaration->storage_class == STORAGE_CLASS_THREAD_STATIC ||
+           declaration->parent_scope  == file_scope) {
                must_be_constant = true;
        }
 
@@ -4760,10 +4777,11 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        if (!type->function.kr_style_parameters)
                return;
 
+       add_anchor_token('{');
+
        /* push function parameters */
-       int       top        = environment_top();
-       scope_t  *last_scope = scope;
-       set_scope(&declaration->scope);
+       size_t const top = environment_top();
+       scope_push(&declaration->scope);
 
        declaration_t *parameter = declaration->scope.declarations;
        for ( ; parameter != NULL; parameter = parameter->next) {
@@ -4779,7 +4797,7 @@ static void parse_kr_declaration_list(declaration_t *declaration)
 
        /* pop function parameters */
        assert(scope == &declaration->scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 
        /* update function type */
@@ -4838,6 +4856,8 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        }
 
        declaration->type = type;
+
+       rem_anchor_token('{');
 }
 
 static bool first_err = true;
@@ -5398,13 +5418,15 @@ static void parse_external_declaration(void)
        add_anchor_token(',');
        add_anchor_token('=');
        add_anchor_token(';');
+       add_anchor_token('{');
 
        /* declarator is common to both function-definitions and declarations */
        declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
 
-       rem_anchor_token(',');
-       rem_anchor_token('=');
+       rem_anchor_token('{');
        rem_anchor_token(';');
+       rem_anchor_token('=');
+       rem_anchor_token(',');
 
        /* must be a declaration */
        switch (token.type) {
@@ -5473,9 +5495,8 @@ static void parse_external_declaration(void)
        type = skip_typeref(declaration->type);
 
        /* push function parameters and switch scope */
-       int       top        = environment_top();
-       scope_t  *last_scope = scope;
-       set_scope(&declaration->scope);
+       size_t const top = environment_top();
+       scope_push(&declaration->scope);
 
        declaration_t *parameter = declaration->scope.declarations;
        for( ; parameter != NULL; parameter = parameter->next) {
@@ -5530,7 +5551,7 @@ static void parse_external_declaration(void)
        }
 
        assert(scope == &declaration->scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 }
 
@@ -5695,7 +5716,11 @@ static void parse_compound_type_entries(declaration_t *compound_declaration)
        eat('{');
        add_anchor_token('}');
 
-       while (token.type != '}' && token.type != T_EOF) {
+       while (token.type != '}') {
+               if (token.type == T_EOF) {
+                       errorf(HERE, "EOF while parsing struct");
+                       break;
+               }
                declaration_specifiers_t specifiers;
                memset(&specifiers, 0, sizeof(specifiers));
                parse_declaration_specifiers(&specifiers);
@@ -5703,10 +5728,6 @@ static void parse_compound_type_entries(declaration_t *compound_declaration)
                parse_compound_declarators(compound_declaration, &specifiers);
        }
        rem_anchor_token('}');
-
-       if (token.type == T_EOF) {
-               errorf(HERE, "EOF while parsing struct");
-       }
        next_token();
 }
 
@@ -6106,11 +6127,11 @@ static expression_t *parse_reference(void)
                }
        }
 
-       type_t *type = declaration->type;
+       type_t *orig_type = declaration->type;
 
        /* we always do the auto-type conversions; the & and sizeof parser contains
         * code to revert this! */
-       type = automatic_type_conversion(type);
+       type_t *type = automatic_type_conversion(orig_type);
 
        ref->declaration = declaration;
        ref->base.type   = type;
@@ -6118,6 +6139,15 @@ static expression_t *parse_reference(void)
        /* this declaration is used */
        declaration->used = true;
 
+       if (declaration->parent_scope != file_scope                          &&
+           declaration->parent_scope->depth < current_function->scope.depth &&
+           is_type_valid(orig_type) && !is_type_function(orig_type)) {
+               /* access of a variable from an outer function */
+               declaration->address_taken     = true;
+               ref->is_outer_ref              = true;
+               current_function->need_closure = true;
+       }
+
        /* check for deprecated functions */
        if (warning.deprecated_declarations &&
            declaration->modifiers & DM_DEPRECATED) {
@@ -6609,7 +6639,6 @@ static expression_t *parse_compare_builtin(void)
                break;
        default:
                internal_errorf(HERE, "invalid compare builtin found");
-               break;
        }
        expression->base.source_position = *HERE;
        next_token();
@@ -6699,7 +6728,10 @@ static declaration_t *get_label(symbol_t *symbol)
        candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
        /* if we found a local label, we already created the declaration */
        if (candidate != NULL) {
-               assert(candidate->parent_scope == scope);
+               if (candidate->parent_scope != scope) {
+                       assert(candidate->parent_scope->depth < scope->depth);
+                       current_function->goto_to_outer = true;
+               }
                return candidate;
        }
 
@@ -7494,6 +7526,46 @@ static void semantic_unexpr_plus(unary_expression_t *expression)
                        "traditional C rejects the unary plus operator");
 }
 
+static expression_t const *get_reference_address(expression_t const *expr)
+{
+       bool regular_take_address = true;
+       for (;;) {
+               if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+                       expr = expr->unary.value;
+               } else {
+                       regular_take_address = false;
+               }
+
+               if (expr->kind != EXPR_UNARY_DEREFERENCE)
+                       break;
+
+               expr = expr->unary.value;
+       }
+
+       if (expr->kind != EXPR_REFERENCE)
+               return NULL;
+
+       if (!regular_take_address &&
+           !is_type_function(skip_typeref(expr->reference.declaration->type))) {
+               return NULL;
+       }
+
+       return expr;
+}
+
+static void warn_function_address_as_bool(expression_t const* expr)
+{
+       if (!warning.address)
+               return;
+
+       expr = get_reference_address(expr);
+       if (expr != NULL) {
+               warningf(&expr->base.source_position,
+                       "the address of '%Y' will always evaluate as 'true'",
+                       expr->reference.declaration->symbol);
+       }
+}
+
 static void semantic_not(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
@@ -7503,6 +7575,8 @@ static void semantic_not(unary_expression_t *expression)
                       "operand of ! must be of scalar type");
        }
 
+       warn_function_address_as_bool(expression->value);
+
        expression->base.type = type_int;
 }
 
@@ -7850,6 +7924,22 @@ static void semantic_sub(binary_expression_t *expression)
        }
 }
 
+static void warn_string_literal_address(expression_t const* expr)
+{
+       while (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+               expr = expr->unary.value;
+               if (expr->kind != EXPR_UNARY_DEREFERENCE)
+                       return;
+               expr = expr->unary.value;
+       }
+
+       if (expr->kind == EXPR_STRING_LITERAL ||
+           expr->kind == EXPR_WIDE_STRING_LITERAL) {
+               warningf(&expr->base.source_position,
+                       "comparison with string literal results in unspecified behaviour");
+       }
+}
+
 /**
  * Check the semantics of comparison expressions.
  *
@@ -7857,13 +7947,32 @@ static void semantic_sub(binary_expression_t *expression)
  */
 static void semantic_comparison(binary_expression_t *expression)
 {
-       expression_t *left            = expression->left;
-       expression_t *right           = expression->right;
-       type_t       *orig_type_left  = left->base.type;
-       type_t       *orig_type_right = right->base.type;
+       expression_t *left  = expression->left;
+       expression_t *right = expression->right;
 
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       if (warning.address) {
+               warn_string_literal_address(left);
+               warn_string_literal_address(right);
+
+               expression_t const* const func_left = get_reference_address(left);
+               if (func_left != NULL && is_null_pointer_constant(right)) {
+                       warningf(&expression->base.source_position,
+                               "the address of '%Y' will never be NULL",
+                               func_left->reference.declaration->symbol);
+               }
+
+               expression_t const* const func_right = get_reference_address(right);
+               if (func_right != NULL && is_null_pointer_constant(right)) {
+                       warningf(&expression->base.source_position,
+                               "the address of '%Y' will never be NULL",
+                               func_right->reference.declaration->symbol);
+               }
+       }
+
+       type_t *orig_type_left  = left->base.type;
+       type_t *orig_type_right = right->base.type;
+       type_t *type_left       = skip_typeref(orig_type_left);
+       type_t *type_right      = skip_typeref(orig_type_right);
 
        /* TODO non-arithmetic types */
        if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
@@ -8056,6 +8165,9 @@ static void semantic_logical_op(binary_expression_t *expression)
        type_t       *const type_left       = skip_typeref(orig_type_left);
        type_t       *const type_right      = skip_typeref(orig_type_right);
 
+       warn_function_address_as_bool(left);
+       warn_function_address_as_bool(right);
+
        if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
                /* TODO: improve error message */
                if (is_type_valid(type_left) && is_type_valid(type_right)) {
@@ -9067,9 +9179,8 @@ static statement_t *parse_for(void)
 
        PUSH_PARENT(statement);
 
-       int      top        = environment_top();
-       scope_t *last_scope = scope;
-       set_scope(&statement->fors.scope);
+       size_t const top = environment_top();
+       scope_push(&statement->fors.scope);
 
        expect('(');
        add_anchor_token(')');
@@ -9111,7 +9222,7 @@ static statement_t *parse_for(void)
        statement->fors.body = parse_loop_body(statement);
 
        assert(scope == &statement->fors.scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 
        POP_PARENT;
@@ -9121,7 +9232,7 @@ end_error:
        POP_PARENT;
        rem_anchor_token(')');
        assert(scope == &statement->fors.scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 
        return create_invalid_statement();
@@ -9172,6 +9283,10 @@ static statement_t *parse_goto(void)
                statement                       = allocate_statement_zero(STATEMENT_GOTO);
                statement->base.source_position = source_position;
                statement->gotos.label          = get_label(symbol);
+
+               if (statement->gotos.label->parent_scope->depth < current_function->scope.depth) {
+                       statement->gotos.outer_fkt_jmp = true;
+               }
        }
 
        /* remember the goto's in a list for later checking */
@@ -9555,7 +9670,7 @@ expression_statment:
                bool old_gcc_extension = in_gcc_extension;
                in_gcc_extension       = true;
                statement = parse_statement();
-               in_gcc_extension = false;
+               in_gcc_extension = old_gcc_extension;
                break;
 
        DECLARATION_START
@@ -9677,14 +9792,18 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        eat('{');
        add_anchor_token('}');
 
-       int      top        = environment_top();
-       int      top_local  = local_label_top();
-       scope_t *last_scope = scope;
-       set_scope(&statement->compound.scope);
+       size_t const top       = environment_top();
+       size_t const top_local = local_label_top();
+       scope_push(&statement->compound.scope);
 
        statement_t **anchor            = &statement->compound.statements;
        bool          only_decls_so_far = true;
-       while (token.type != '}' && token.type != T_EOF) {
+       while (token.type != '}') {
+               if (token.type == T_EOF) {
+                       errorf(&statement->base.source_position,
+                              "EOF while parsing compound statement");
+                       break;
+               }
                statement_t *sub_statement = intern_parse_statement();
                if (is_invalid_statement(sub_statement)) {
                        /* an error occurred. if we are at an anchor, return */
@@ -9709,13 +9828,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
 
                anchor = &sub_statement->base.next;
        }
-
-       if (token.type == '}') {
-               next_token();
-       } else {
-               errorf(&statement->base.source_position,
-                      "end of file while looking for closing '}'");
-       }
+       next_token();
 
        /* look over all statements again to produce no effect warnings */
        if (warning.unused_value) {
@@ -9739,7 +9852,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
 end_error:
        rem_anchor_token('}');
        assert(scope == &statement->compound.scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
        local_label_pop_to(top_local);
 
@@ -9782,7 +9895,7 @@ static void check_unused_globals(void)
        if (!warning.unused_function && !warning.unused_variable)
                return;
 
-       for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) {
+       for (const declaration_t *decl = file_scope->declarations; decl != NULL; decl = decl->next) {
                if (decl->used                  ||
                    decl->modifiers & DM_UNUSED ||
                    decl->modifiers & DM_USED   ||
@@ -9830,11 +9943,17 @@ end_error:;
  */
 static void parse_translation_unit(void)
 {
+       add_anchor_token(T_EOF);
+
+#ifndef NDEBUG
+       unsigned char token_anchor_copy[T_LAST_TOKEN];
+       memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
+#endif
        for (;;) {
 #ifndef NDEBUG
                bool anchor_leak = false;
                for (int i = 0; i != T_LAST_TOKEN; ++i) {
-                       unsigned char count = token_anchor_set[i];
+                       unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
                        if (count != 0) {
                                errorf(HERE, "Leaked anchor token %k %d times", i, count);
                                anchor_leak = true;
@@ -9861,6 +9980,7 @@ static void parse_translation_unit(void)
                                break;
 
                        case T_EOF:
+                               rem_anchor_token(T_EOF);
                                return;
 
                        case ';':
@@ -9899,24 +10019,25 @@ void start_parsing(void)
        assert(unit == NULL);
        unit = allocate_ast_zero(sizeof(unit[0]));
 
-       assert(global_scope == NULL);
-       global_scope = &unit->scope;
+       assert(file_scope == NULL);
+       file_scope = &unit->scope;
 
        assert(scope == NULL);
-       set_scope(&unit->scope);
+       scope_push(&unit->scope);
 
        initialize_builtin_types();
 }
 
 translation_unit_t *finish_parsing(void)
 {
+       /* do NOT use scope_pop() here, this will crash, will it by hand */
        assert(scope == &unit->scope);
-       scope          = NULL;
+       scope            = NULL;
        last_declaration = NULL;
 
-       assert(global_scope == &unit->scope);
+       assert(file_scope == &unit->scope);
        check_unused_globals();
-       global_scope = NULL;
+       file_scope = NULL;
 
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);