Create AST for select expressions even if the LHS has incomplete type.
[cparser] / parser.c
index 315d17c..3c10013 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -110,6 +110,7 @@ static token_t             lookahead_buffer[MAX_LOOKAHEAD];
 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;
 static scope_t            *scope             = NULL;
 static declaration_t      *last_declaration  = NULL;
@@ -315,6 +316,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_VA_START]                = sizeof(va_start_expression_t),
                [EXPR_VA_ARG]                  = sizeof(va_arg_expression_t),
                [EXPR_STATEMENT]               = sizeof(statement_expression_t),
+               [EXPR_LABEL_ADDRESS]           = sizeof(label_address_expression_t),
        };
        if (kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) {
                return sizes[EXPR_UNARY_FIRST];
@@ -479,13 +481,21 @@ static size_t environment_top(void)
 }
 
 /**
- * Returns the index of the top element of the label stack.
+ * Returns the index of the top element of the global label stack.
  */
 static size_t label_top(void)
 {
        return ARR_LEN(label_stack);
 }
 
+/**
+ * Returns the index of the top element of the local label stack.
+ */
+static size_t local_label_top(void)
+{
+       return ARR_LEN(local_label_stack);
+}
+
 /**
  * Return the next token.
  */
@@ -764,6 +774,11 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration)
        ARR_APP1(stack_entry_t, *stack_ptr, entry);
 }
 
+/**
+ * Push a declaration on the environment stack.
+ *
+ * @param declaration  the declaration
+ */
 static void environment_push(declaration_t *declaration)
 {
        assert(declaration->source_position.input_name != NULL);
@@ -772,7 +787,7 @@ static void environment_push(declaration_t *declaration)
 }
 
 /**
- * Push a declaration of the label stack.
+ * Push a declaration on the global label stack.
  *
  * @param declaration  the declaration
  */
@@ -782,6 +797,17 @@ static void label_push(declaration_t *declaration)
        stack_push(&label_stack, declaration);
 }
 
+/**
+ * Push a declaration of the local label stack.
+ *
+ * @param declaration  the declaration
+ */
+static void local_label_push(declaration_t *declaration)
+{
+       assert(declaration->parent_scope != NULL);
+       stack_push(&local_label_stack, declaration);
+}
+
 /**
  * pops symbols from the environment stack until @p new_top is the top element
  */
@@ -832,13 +858,19 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
        ARR_SHRINKLEN(*stack_ptr, (int) new_top);
 }
 
+/**
+ * Pop all entries from the environment stack until the new_top
+ * is reached.
+ *
+ * @param new_top  the new stack top
+ */
 static void environment_pop_to(size_t new_top)
 {
        stack_pop_to(&environment_stack, new_top);
 }
 
 /**
- * Pop all entries on the label stack until the new_top
+ * Pop all entries from the global label stack until the new_top
  * is reached.
  *
  * @param new_top  the new stack top
@@ -848,6 +880,18 @@ static void label_pop_to(size_t new_top)
        stack_pop_to(&label_stack, new_top);
 }
 
+/**
+ * Pop all entries from the local label stack until the new_top
+ * is reached.
+ *
+ * @param new_top  the new stack top
+ */
+static void local_label_pop_to(size_t new_top)
+{
+       stack_pop_to(&local_label_stack, new_top);
+}
+
+
 static int get_akind_rank(atomic_type_kind_t akind)
 {
        return (int) akind;
@@ -3076,6 +3120,95 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t
        return decl;
 }
 
+/**
+ * Finish the construction of a struct type by calculating
+ * its size, offsets, alignment.
+ */
+static void finish_struct_type(compound_type_t *type) {
+       if (type->declaration == NULL)
+               return;
+       declaration_t *struct_decl = type->declaration;
+       if (! struct_decl->init.complete)
+               return;
+
+       il_size_t      size      = 0;
+       il_size_t      new_size;
+       il_alignment_t alignment = 1;
+       bool           need_pad  = false;
+
+       declaration_t *entry = struct_decl->scope.declarations;
+       for (; entry != NULL; entry = entry->next) {
+               if (entry->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               type_t         *m_type      = skip_typeref(entry->type);
+               il_alignment_t  m_alignment = m_type->base.alignment;
+
+               new_size = (size + m_alignment - 1) & -m_alignment;
+               if (m_alignment > alignment)
+                       alignment = m_alignment;
+               if (new_size > size)
+                       need_pad = true;
+               entry->offset = new_size;
+               size = new_size + m_type->base.size;
+       }
+       if (type->base.alignment != 0) {
+               alignment = type->base.alignment;
+       }
+
+       new_size = (size + alignment - 1) & -alignment;
+       if (new_size > size)
+               need_pad = true;
+
+       if (warning.padded && need_pad) {
+               warningf(&struct_decl->source_position,
+                       "'%#T' needs padding", type, struct_decl->symbol);
+       }
+       if (warning.packed && !need_pad) {
+               warningf(&struct_decl->source_position,
+                       "superfluous packed attribute on '%#T'",
+                       type, struct_decl->symbol);
+       }
+
+       type->base.size      = new_size;
+       type->base.alignment = alignment;
+}
+
+/**
+ * Finish the construction of an union type by calculating
+ * its size and alignment.
+ */
+static void finish_union_type(compound_type_t *type) {
+       if (type->declaration == NULL)
+               return;
+       declaration_t *union_decl = type->declaration;
+       if (! union_decl->init.complete)
+               return;
+
+       il_size_t      size      = 0;
+       il_alignment_t alignment = 1;
+
+       declaration_t *entry = union_decl->scope.declarations;
+       for (; entry != NULL; entry = entry->next) {
+               if (entry->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               type_t *m_type = skip_typeref(entry->type);
+
+               entry->offset = 0;
+               if (m_type->base.size > size)
+                       size = m_type->base.size;
+               if (m_type->base.alignment > alignment)
+                       alignment = m_type->base.alignment;
+       }
+       if (type->base.alignment != 0) {
+               alignment = type->base.alignment;
+       }
+       size = (size + alignment - 1) & -alignment;
+       type->base.size      = size;
+       type->base.alignment = alignment;
+}
+
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
        type_t            *type            = NULL;
@@ -3215,6 +3348,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE);
 
                        type->compound.declaration = parse_compound_type_specifier(true);
+                       finish_struct_type(&type->compound);
                        break;
                }
                case T_union: {
@@ -3223,6 +3357,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
                                modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
                        break;
+                       finish_union_type(&type->compound);
                }
                case T_enum:
                        type = parse_enum_specifier();
@@ -3897,8 +4032,10 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
                next_token();
                add_anchor_token(')');
                inner_types = parse_inner_declarator(declaration, may_be_abstract);
-               /* All later declarators only modify the return type, not declaration */
-               declaration = NULL;
+               if (inner_types != NULL) {
+                       /* All later declarators only modify the return type, not declaration */
+                       declaration = NULL;
+               }
                rem_anchor_token(')');
                expect(')');
                break;
@@ -4703,6 +4840,10 @@ static void check_labels(void)
        for (const goto_statement_t *goto_statement = goto_first;
            goto_statement != NULL;
            goto_statement = goto_statement->next) {
+               /* skip computed gotos */
+               if (goto_statement->expression != NULL)
+                       continue;
+
                declaration_t *label = goto_statement->label;
 
                label->used = true;
@@ -4908,9 +5049,16 @@ found_break_parent:
                }
 
                case STATEMENT_GOTO:
-                       next = stmt->gotos.label->init.statement;
-                       if (next == NULL) /* missing label */
-                               return;
+                       if (stmt->gotos.expression) {
+                               statement_t *parent = stmt->base.parent;
+                               if (parent == NULL) /* top level goto */
+                                       return;
+                               next = parent;
+                       } else {
+                               next = stmt->gotos.label->init.statement;
+                               if (next == NULL) /* missing label */
+                                       return;
+                       }
                        break;
 
                case STATEMENT_LABEL:
@@ -5404,12 +5552,12 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
 {
        declaration_t *last_declaration = struct_declaration->scope.declarations;
        if (last_declaration != NULL) {
-               while(last_declaration->next != NULL) {
+               while (last_declaration->next != NULL) {
                        last_declaration = last_declaration->next;
                }
        }
 
-       while(1) {
+       while (true) {
                declaration_t *declaration;
 
                if (token.type == ':') {
@@ -5502,7 +5650,7 @@ static void parse_compound_type_entries(declaration_t *compound_declaration)
        eat('{');
        add_anchor_token('}');
 
-       while(token.type != '}' && token.type != T_EOF) {
+       while (token.type != '}' && token.type != T_EOF) {
                declaration_specifiers_t specifiers;
                memset(&specifiers, 0, sizeof(specifiers));
                parse_declaration_specifiers(&specifiers);
@@ -5848,7 +5996,10 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
 {
        switch (expression->kind) {
                case EXPR_REFERENCE: return expression->reference.declaration->type;
-               case EXPR_SELECT:    return expression->select.compound_entry->type;
+
+               case EXPR_SELECT:
+                       return get_qualified_type(expression->select.compound_entry->type,
+                                                 expression->base.type->base.qualifiers);
 
                case EXPR_UNARY_DEREFERENCE: {
                        const expression_t *const value = expression->unary.value;
@@ -6500,6 +6651,71 @@ end_error:
        return create_invalid_expression();
 }
 
+/**
+ * Return the declaration for a given label symbol or create a new one.
+ *
+ * @param symbol  the symbol of the label
+ */
+static declaration_t *get_label(symbol_t *symbol)
+{
+       declaration_t *candidate;
+       assert(current_function != NULL);
+
+       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);
+               return candidate;
+       }
+
+       candidate = get_declaration(symbol, NAMESPACE_LABEL);
+       /* if we found a label in the same function, then we already created the
+        * declaration */
+       if (candidate != NULL
+                       && candidate->parent_scope == &current_function->scope) {
+               return candidate;
+       }
+
+       /* otherwise we need to create a new one */
+       declaration_t *const declaration = allocate_declaration_zero();
+       declaration->namespc       = NAMESPACE_LABEL;
+       declaration->symbol        = symbol;
+
+       label_push(declaration);
+
+       return declaration;
+}
+
+/**
+ * Parses a GNU && label address expression.
+ */
+static expression_t *parse_label_address(void)
+{
+       source_position_t source_position = token.source_position;
+       eat(T_ANDAND);
+       if (token.type != T_IDENTIFIER) {
+               parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
+               goto end_error;
+       }
+       symbol_t *symbol = token.v.symbol;
+       next_token();
+
+       declaration_t *label = get_label(symbol);
+
+       label->used          = true;
+       label->address_taken = true;
+
+       expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS);
+       expression->base.source_position = source_position;
+
+       /* label address is threaten as a void pointer */
+       expression->base.type                 = type_void_ptr;
+       expression->label_address.declaration = label;
+       return expression;
+end_error:
+       return create_invalid_expression();
+}
+
 /**
  * Parse a microsoft __noop expression.
  */
@@ -6577,6 +6793,10 @@ static expression_t *parse_primary_expression(void)
                case T___builtin_constant_p:     return parse_builtin_constant();
                case T___builtin_prefetch:       return parse_builtin_prefetch();
                case T__assume:                  return parse_assume();
+               case T_ANDAND:
+                       if (c_mode & _GNUC)
+                               return parse_label_address();
+                       break;
 
                case '(':                        return parse_parenthesized_expression();
                case T___noop:                   return parse_noop_expression();
@@ -6746,24 +6966,23 @@ static expression_t *parse_select_expression(unsigned precedence,
        type_t *const orig_type = compound->base.type;
        type_t *const type      = skip_typeref(orig_type);
 
-       type_t *type_left = type;
+       type_t *type_left;
        bool    saw_error = false;
        if (is_type_pointer(type)) {
                if (!is_pointer) {
                        errorf(HERE,
                               "request for member '%Y' in something not a struct or union, but '%T'",
-                              symbol, type_left);
+                              symbol, orig_type);
                        saw_error = true;
                }
-               type_left = type->pointer.points_to;
-       } else if (is_pointer) {
-               if (is_type_valid(type)) {
+               type_left = skip_typeref(type->pointer.points_to);
+       } else {
+               if (is_pointer && is_type_valid(type)) {
                        errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
                        saw_error = true;
                }
                type_left = type;
        }
-       type_left = skip_typeref(type_left);
 
        declaration_t *entry;
        if (type_left->kind == TYPE_COMPOUND_STRUCT ||
@@ -6773,7 +6992,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                if (!declaration->init.complete) {
                        errorf(HERE, "request for member '%Y' of incomplete type '%T'",
                               symbol, type_left);
-                       return create_invalid_expression();
+                       goto create_error_entry;
                }
 
                entry = find_compound_entry(declaration, symbol);
@@ -6793,11 +7012,15 @@ create_error_entry:
        }
 
        select->select.compound_entry = entry;
+
+       type_t *const res_type =
+               get_qualified_type(entry->type, type_left->base.qualifiers);
+
        /* we always do the auto-type conversions; the & and sizeof parser contains
         * code to revert this! */
-       select->base.type = automatic_type_conversion(entry->type);
+       select->base.type = automatic_type_conversion(res_type);
 
-       type_t *skipped = skip_typeref(entry->type);
+       type_t *skipped = skip_typeref(res_type);
        if (skipped->kind == TYPE_BITFIELD) {
                select->base.type = skipped->bitfield.base_type;
        }
@@ -7084,13 +7307,8 @@ static expression_t *parse_conditional_expression(unsigned precedence,
                                to = type_void;
                        }
 
-                       type_t *const copy = duplicate_type(to);
-                       copy->base.qualifiers = to1->base.qualifiers | to2->base.qualifiers;
-
-                       type_t *const type = typehash_insert(copy);
-                       if (type != copy)
-                               free_type(copy);
-
+                       type_t *const type =
+                               get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers);
                        result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE);
                } else if (is_type_integer(other_type)) {
                        warningf(&conditional->base.source_position,
@@ -7284,7 +7502,7 @@ static void semantic_dereference(unary_expression_t *expression)
        if (!is_type_pointer(type)) {
                if (is_type_valid(type)) {
                        errorf(&expression->base.source_position,
-                              "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type);
+                              "Unary '*' needs pointer or array type, but type '%T' given", orig_type);
                }
                return;
        }
@@ -7824,9 +8042,6 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        expression_t *left           = expression->left;
        type_t       *orig_type_left = left->base.type;
 
-       type_t *type_left = revert_automatic_type_conversion(left);
-       type_left         = skip_typeref(orig_type_left);
-
        if (!is_valid_assignment_lhs(left))
                return;
 
@@ -7861,6 +8076,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_WIDE_CHARACTER_CONSTANT:   return false;
                case EXPR_STRING_LITERAL:            return false;
                case EXPR_WIDE_STRING_LITERAL:       return false;
+               case EXPR_LABEL_ADDRESS:             return false;
 
                case EXPR_CALL: {
                        const call_expression_t *const call = &expr->call;
@@ -8533,32 +8749,6 @@ end_error:
        return create_invalid_statement();
 }
 
-/**
- * Return the declaration for a given label symbol or create a new one.
- *
- * @param symbol  the symbol of the label
- */
-static declaration_t *get_label(symbol_t *symbol)
-{
-       declaration_t *candidate = get_declaration(symbol, NAMESPACE_LABEL);
-       assert(current_function != NULL);
-       /* if we found a label in the same function, then we already created the
-        * declaration */
-       if (candidate != NULL
-                       && candidate->parent_scope == &current_function->scope) {
-               return candidate;
-       }
-
-       /* otherwise we need to create a new one */
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->namespc       = NAMESPACE_LABEL;
-       declaration->symbol        = symbol;
-
-       label_push(declaration);
-
-       return declaration;
-}
-
 /**
  * Parse a label statement.
  */
@@ -8576,9 +8766,9 @@ static statement_t *parse_label_statement(void)
 
        PUSH_PARENT(statement);
 
-       /* if source position is already set then the label is defined twice,
-        * otherwise it was just mentioned in a goto so far */
-       if (label->source_position.input_name != NULL) {
+       /* if statement is already set then the label is defined twice,
+        * otherwise it was just mentioned in a goto/local label declaration so far */
+       if (label->init.statement != NULL) {
                errorf(HERE, "duplicate label '%Y' (declared %P)",
                       symbol, &label->source_position);
        } else {
@@ -8896,22 +9086,47 @@ end_error:
  */
 static statement_t *parse_goto(void)
 {
+       source_position_t source_position = token.source_position;
        eat(T_goto);
 
-       if (token.type != T_IDENTIFIER) {
-               parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
-               eat_statement();
-               goto end_error;
-       }
-       symbol_t *symbol = token.v.symbol;
-       next_token();
+       statement_t *statement;
+       if (c_mode & _GNUC && token.type == '*') {
+               next_token();
+               expression_t *expression = parse_expression();
 
-       declaration_t *label = get_label(symbol);
+               /* Argh: although documentation say the expression must be of type void *,
+                * gcc excepts anything that can be casted into void * without error */
+               type_t *type = expression->base.type;
 
-       statement_t *statement          = allocate_statement_zero(STATEMENT_GOTO);
-       statement->base.source_position = token.source_position;
+               if (type != type_error_type) {
+                       if (!is_type_pointer(type) && !is_type_integer(type)) {
+                               errorf(&source_position, "cannot convert to a pointer type");
+                       } else if (type != type_void_ptr) {
+                               warningf(&source_position,
+                                       "type of computed goto expression should be 'void*' not '%T'", type);
+                       }
+                       expression = create_implicit_cast(expression, type_void_ptr);
+               }
 
-       statement->gotos.label = label;
+               statement                       = allocate_statement_zero(STATEMENT_GOTO);
+               statement->base.source_position = source_position;
+               statement->gotos.expression     = expression;
+       } else {
+               if (token.type != T_IDENTIFIER) {
+                       if (c_mode & _GNUC)
+                               parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+                       else
+                               parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+                       eat_statement();
+                       goto end_error;
+               }
+               symbol_t *symbol = token.v.symbol;
+               next_token();
+
+               statement                       = allocate_statement_zero(STATEMENT_GOTO);
+               statement->base.source_position = source_position;
+               statement->gotos.label          = get_label(symbol);
+       }
 
        /* remember the goto's in a list for later checking */
        if (goto_last == NULL) {
@@ -8969,7 +9184,7 @@ end_error:
 /**
  * Parse a __leave statement.
  */
-static statement_t *parse_leave(void)
+static statement_t *parse_leave_statement(void)
 {
        if (current_try == NULL) {
                errorf(HERE, "__leave statement not within __try");
@@ -9197,6 +9412,54 @@ static statement_t *parse_empty_statement(void)
        return statement;
 }
 
+static statement_t *parse_local_label_declaration(void) {
+       statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
+       statement->base.source_position = token.source_position;
+
+       eat(T___label__);
+
+       declaration_t *begin = NULL, *end = NULL;
+
+       while (true) {
+               if (token.type != T_IDENTIFIER) {
+                       parse_error_expected("while parsing local label declaration",
+                               T_IDENTIFIER, NULL);
+                       goto end_error;
+               }
+               symbol_t      *symbol      = token.v.symbol;
+               declaration_t *declaration = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
+               if (declaration != NULL) {
+                       errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition at %P)",
+                               symbol, &declaration->source_position);
+               } else {
+                       declaration = allocate_declaration_zero();
+                       declaration->namespc         = NAMESPACE_LOCAL_LABEL;
+                       declaration->source_position = token.source_position;
+                       declaration->symbol          = symbol;
+                       declaration->parent_scope    = scope;
+                       declaration->init.statement  = NULL;
+
+                       if (end != NULL)
+                               end->next = declaration;
+                       end = declaration;
+                       if (begin == NULL)
+                               begin = declaration;
+
+                       local_label_push(declaration);
+               }
+               next_token();
+
+               if (token.type != ',')
+                       break;
+               next_token();
+       }
+       eat(';');
+end_error:
+       statement->declaration.declarations_begin = begin;
+       statement->declaration.declarations_end   = end;
+       return statement;
+}
+
 /**
  * Parse a statement.
  * There's also parse_statement() which additionally checks for
@@ -9242,9 +9505,13 @@ static statement_t *intern_parse_statement(void)
                statement = parse_declaration_statement();
                break;
 
+       case T___label__:
+               statement = parse_local_label_declaration();
+               break;
+
        case ';':        statement = parse_empty_statement();         break;
        case '{':        statement = parse_compound_statement(false); break;
-       case T___leave:  statement = parse_leave();                   break;
+       case T___leave:  statement = parse_leave_statement();                   break;
        case T___try:    statement = parse_ms_try_statment();         break;
        case T_asm:      statement = parse_asm_statement();           break;
        case T_break:    statement = parse_break();                   break;
@@ -9303,6 +9570,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token('}');
 
        int      top        = environment_top();
+       int      top_local  = local_label_top();
        scope_t *last_scope = scope;
        set_scope(&statement->compound.scope);
 
@@ -9365,6 +9633,7 @@ end_error:
        assert(scope == &statement->compound.scope);
        set_scope(last_scope);
        environment_pop_to(top);
+       local_label_pop_to(top_local);
 
        POP_PARENT;
        return statement;
@@ -9491,6 +9760,7 @@ void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
+       local_label_stack = NEW_ARR_F(stack_entry_t, 0);
        diagnostic_count  = 0;
        error_count       = 0;
        warning_count     = 0;
@@ -9522,6 +9792,7 @@ translation_unit_t *finish_parsing(void)
 
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);
+       DEL_ARR_F(local_label_stack);
 
        translation_unit_t *result = unit;
        unit = NULL;
@@ -9531,7 +9802,7 @@ translation_unit_t *finish_parsing(void)
 void parse(void)
 {
        lookahead_bufpos = 0;
-       for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
+       for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
                next_token();
        }
        parse_translation_unit();