revert accidental commit
[cparser] / parser.c
index d83c261..4e37812 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -104,6 +104,7 @@ static goto_statement_t   *goto_first        = NULL;
 static goto_statement_t   *goto_last         = NULL;
 static label_statement_t  *label_first       = NULL;
 static label_statement_t  *label_last        = NULL;
+static translation_unit_t *unit              = NULL;
 static struct obstack      temp_obst;
 
 static source_position_t null_position = { NULL, 0 };
@@ -132,7 +133,7 @@ static const symbol_t *sym_noalias    = NULL;
 static unsigned char token_anchor_set[T_LAST_TOKEN];
 
 /** The current source position. */
-#define HERE &token.source_position
+#define HERE (&token.source_position)
 
 static type_t *type_valist;
 
@@ -366,6 +367,8 @@ static size_t get_type_struct_size(type_kind_t kind)
 {
        static const size_t sizes[] = {
                [TYPE_ATOMIC]          = sizeof(atomic_type_t),
+               [TYPE_COMPLEX]         = sizeof(complex_type_t),
+               [TYPE_IMAGINARY]       = sizeof(imaginary_type_t),
                [TYPE_BITFIELD]        = sizeof(bitfield_type_t),
                [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t),
                [TYPE_COMPOUND_UNION]  = sizeof(compound_type_t),
@@ -488,6 +491,18 @@ static void add_anchor_token(int token_type) {
        ++token_anchor_set[token_type];
 }
 
+static int save_and_reset_anchor_state(int token_type) {
+       assert(0 <= token_type && token_type < T_LAST_TOKEN);
+       int count = token_anchor_set[token_type];
+       token_anchor_set[token_type] = 0;
+       return count;
+}
+
+static void restore_anchor_state(int token_type, int count) {
+       assert(0 <= token_type && token_type < T_LAST_TOKEN);
+       token_anchor_set[token_type] = count;
+}
+
 /**
  * Remove a token from the token anchor set (a multi-set).
  */
@@ -580,7 +595,10 @@ static void eat_statement(void) {
 /**
  * Report a parse error because an expected token was not found.
  */
-static __attribute__((sentinel))
+static
+#if defined __GNUC__ && __GNUC__ >= 4
+__attribute__((sentinel))
+#endif
 void parse_error_expected(const char *message, ...)
 {
        if(message != NULL) {
@@ -622,6 +640,8 @@ static void type_error_incompatible(const char *msg,
         parse_error_expected(NULL, (expected), NULL); \
                add_anchor_token(expected);                   \
         eat_until_anchor();                           \
+        if (token.type == expected)                   \
+               next_token();                             \
                rem_anchor_token(expected);                   \
         goto end_error;                               \
     }                                                 \
@@ -1043,6 +1063,7 @@ static const char *gnu_attribute_names[GNU_AK_LAST] = {
        [GNU_AK_TLS_MODEL]              = "tls_model",
        [GNU_AK_VISIBILITY]             = "visibility",
        [GNU_AK_REGPARM]                = "regparm",
+       [GNU_AK_MODE]                   = "mode",
        [GNU_AK_MODEL]                  = "model",
        [GNU_AK_TRAP_EXIT]              = "trap_exit",
        [GNU_AK_SP_SWITCH]              = "sp_switch",
@@ -1076,7 +1097,6 @@ static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) {
        attribute->have_arguments  = false;
 
        return attribute;
-       return attribute;
 }
 
 /**
@@ -1207,6 +1227,21 @@ static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute) {
        attribute->invalid = true;
 }
 
+static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
+{
+       /* TODO: find out what is allowed here... */
+
+       /* at least: byte, word, pointer, list of machine modes
+        * __XXX___ is interpreted as XXX */
+       add_anchor_token(')');
+       expect(T_IDENTIFIER);
+       rem_anchor_token(')');
+       expect(')');
+       return;
+end_error:
+       attribute->invalid = true;
+}
+
 /**
  * parse one interrupt argument.
  */
@@ -1531,8 +1566,18 @@ static void parse_gnu_attribute(gnu_attribute_t **attributes)
                                        if(!attribute->have_arguments) {
                                                /* should have arguments */
                                                errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
-                                       } else
+                                       } else {
                                                parse_gnu_attribute_model_arg(attribute);
+                                       }
+                                       break;
+                               case GNU_AK_MODE:
+                                       if(!attribute->have_arguments) {
+                                               /* should have arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                       } else {
+                                               parse_gnu_attribute_mode_arg(attribute);
+                                       }
+                                       break;
                                case GNU_AK_INTERRUPT:
                                        /* may have one string argument */
                                        if(attribute->have_arguments)
@@ -2071,7 +2116,7 @@ static void skip_until(int type) {
 }
 
 /**
- * skip any {...} blocks until a closing braket is reached.
+ * skip any {...} blocks until a closing bracket is reached.
  */
 static void skip_initializers(void)
 {
@@ -2142,6 +2187,9 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                                = allocate_initializer_zero(INITIALIZER_DESIGNATOR);
                        designator_initializer->designator.designator = designator;
                        ARR_APP1(initializer_t*, initializers, designator_initializer);
+
+                       orig_type = path->top_type;
+                       type      = orig_type != NULL ? skip_typeref(orig_type) : NULL;
                }
 
                initializer_t *sub;
@@ -2280,14 +2328,14 @@ error_parse_next:
               len * sizeof(initializers[0]));
 
        DEL_ARR_F(initializers);
-       ascend_to(path, top_path_level);
+       ascend_to(path, top_path_level+1);
 
        return result;
 
 end_error:
        skip_initializers();
        DEL_ARR_F(initializers);
-       ascend_to(path, top_path_level);
+       ascend_to(path, top_path_level+1);
        return NULL;
 }
 
@@ -2411,7 +2459,7 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                        (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
                declaration->source_position = token.source_position;
                declaration->symbol          = symbol;
-               declaration->parent_scope  = scope;
+               declaration->parent_scope    = scope;
                if (symbol != NULL) {
                        environment_push(declaration);
                }
@@ -2419,13 +2467,13 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if(token.type == '{') {
-               if(declaration->init.is_defined) {
+               if (declaration->init.complete) {
                        assert(symbol != NULL);
                        errorf(HERE, "multiple definitions of '%s %Y'",
                               is_struct ? "struct" : "union", symbol);
                        declaration->scope.declarations = NULL;
                }
-               declaration->init.is_defined = true;
+               declaration->init.complete = true;
 
                parse_compound_type_entries(declaration);
                parse_attributes(&attributes);
@@ -2517,14 +2565,14 @@ static type_t *parse_enum_specifier(void)
        type->enumt.declaration = declaration;
 
        if(token.type == '{') {
-               if(declaration->init.is_defined) {
+               if(declaration->init.complete) {
                        errorf(HERE, "multiple definitions of enum %Y", symbol);
                }
                if (symbol != NULL) {
                        environment_push(declaration);
                }
                append_declaration(declaration);
-               declaration->init.is_defined = 1;
+               declaration->init.complete = true;
 
                parse_enum_entries(type);
                parse_attributes(&attributes);
@@ -2614,10 +2662,8 @@ typedef enum {
        SPECIFIER_INT32     = 1 << 13,
        SPECIFIER_INT64     = 1 << 14,
        SPECIFIER_INT128    = 1 << 15,
-#ifdef PROVIDE_COMPLEX
        SPECIFIER_COMPLEX   = 1 << 16,
        SPECIFIER_IMAGINARY = 1 << 17,
-#endif
 } specifiers_t;
 
 static type_t *create_builtin_type(symbol_t *const symbol,
@@ -2628,7 +2674,7 @@ static type_t *create_builtin_type(symbol_t *const symbol,
        type->builtin.real_type = real_type;
 
        type_t *result = typehash_insert(type);
-       if (type != result) {
+       if(type != result) {
                free_type(type);
        }
 
@@ -2638,8 +2684,8 @@ static type_t *create_builtin_type(symbol_t *const symbol,
 static type_t *get_typedef_type(symbol_t *symbol)
 {
        declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL);
-       if(declaration == NULL
-                       || declaration->storage_class != STORAGE_CLASS_TYPEDEF)
+       if(declaration == NULL ||
+          declaration->storage_class != STORAGE_CLASS_TYPEDEF)
                return NULL;
 
        type_t *type               = allocate_type_zero(TYPE_TYPEDEF, &declaration->source_position);
@@ -2757,7 +2803,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                                        }
                                }
                                next_token();
-                           if(token.type == ',') {
+                               if(token.type == ',') {
                                        next_token();
                                        continue;
                                }
@@ -2910,10 +2956,9 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_SPECIFIER(T__int32,     SPECIFIER_INT32,     "_int32")
                MATCH_SPECIFIER(T__int64,     SPECIFIER_INT64,     "_int64")
                MATCH_SPECIFIER(T__int128,    SPECIFIER_INT128,    "_int128")
-#ifdef PROVIDE_COMPLEX
                MATCH_SPECIFIER(T__Complex,   SPECIFIER_COMPLEX,   "_Complex")
                MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary")
-#endif
+
                case T__forceinline:
                        /* only in microsoft mode */
                        specifiers->decl_modifiers |= DM_FORCEINLINE;
@@ -3100,26 +3145,18 @@ finish_specifiers:
                case SPECIFIER_BOOL:
                        atomic_type = ATOMIC_TYPE_BOOL;
                        break;
-#ifdef PROVIDE_COMPLEX
                case SPECIFIER_FLOAT | SPECIFIER_COMPLEX:
-                       atomic_type = ATOMIC_TYPE_FLOAT_COMPLEX;
-                       break;
-               case SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-                       atomic_type = ATOMIC_TYPE_DOUBLE_COMPLEX;
-                       break;
-               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-                       atomic_type = ATOMIC_TYPE_LONG_DOUBLE_COMPLEX;
-                       break;
                case SPECIFIER_FLOAT | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_FLOAT_IMAGINARY;
+                       atomic_type = ATOMIC_TYPE_FLOAT;
                        break;
+               case SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
                case SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_DOUBLE_IMAGINARY;
+                       atomic_type = ATOMIC_TYPE_DOUBLE;
                        break;
+               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
                case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_LONG_DOUBLE_IMAGINARY;
+                       atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
                        break;
-#endif
                default:
                        /* invalid specifier combination, give an error message */
                        if(type_specifiers == 0) {
@@ -3143,9 +3180,19 @@ finish_specifiers:
                        atomic_type = ATOMIC_TYPE_INVALID;
                }
 
-               type               = allocate_type_zero(TYPE_ATOMIC, &builtin_source_position);
-               type->atomic.akind = atomic_type;
-               newtype            = 1;
+               if(type_specifiers & SPECIFIER_COMPLEX &&
+                  atomic_type != ATOMIC_TYPE_INVALID) {
+                       type                = allocate_type_zero(TYPE_COMPLEX, &builtin_source_position);
+                       type->complex.akind = atomic_type;
+               } else if(type_specifiers & SPECIFIER_IMAGINARY &&
+                         atomic_type != ATOMIC_TYPE_INVALID) {
+                       type                  = allocate_type_zero(TYPE_IMAGINARY, &builtin_source_position);
+                       type->imaginary.akind = atomic_type;
+               } else {
+                       type               = allocate_type_zero(TYPE_ATOMIC, &builtin_source_position);
+                       type->atomic.akind = atomic_type;
+               }
+               newtype = 1;
        } else {
                if(type_specifiers != 0) {
                        errorf(HERE, "multiple datatypes in declaration");
@@ -3206,8 +3253,9 @@ static declaration_t *parse_identifier_list(void)
                }
                last_declaration = declaration;
 
-               if(token.type != ',')
+               if (token.type != ',') {
                        break;
+               }
                next_token();
        } while(token.type == T_IDENTIFIER);
 
@@ -3260,24 +3308,30 @@ static declaration_t *parse_parameter(void)
 
 static declaration_t *parse_parameters(function_type_t *type)
 {
+       declaration_t *declarations = NULL;
+
+       eat('(');
+       add_anchor_token(')');
+       int saved_comma_state = save_and_reset_anchor_state(',');
+
        if(token.type == T_IDENTIFIER) {
                symbol_t *symbol = token.v.symbol;
                if(!is_typedef_symbol(symbol)) {
                        type->kr_style_parameters = true;
-                       return parse_identifier_list();
+                       declarations = parse_identifier_list();
+                       goto parameters_finished;
                }
        }
 
        if(token.type == ')') {
                type->unspecified_parameters = 1;
-               return NULL;
+               goto parameters_finished;
        }
        if(token.type == T_void && look_ahead(1)->type == ')') {
                next_token();
-               return NULL;
+               goto parameters_finished;
        }
 
-       declaration_t        *declarations = NULL;
        declaration_t        *declaration;
        declaration_t        *last_declaration = NULL;
        function_parameter_t *parameter;
@@ -3288,7 +3342,7 @@ static declaration_t *parse_parameters(function_type_t *type)
                case T_DOTDOTDOT:
                        next_token();
                        type->variadic = 1;
-                       return declarations;
+                       goto parameters_finished;
 
                case T_IDENTIFIER:
                case T___extension__:
@@ -3311,12 +3365,25 @@ static declaration_t *parse_parameters(function_type_t *type)
                        break;
 
                default:
-                       return declarations;
+                       goto parameters_finished;
+               }
+               if (token.type != ',') {
+                       goto parameters_finished;
                }
-               if(token.type != ',')
-                       return declarations;
                next_token();
        }
+
+
+parameters_finished:
+       rem_anchor_token(')');
+       expect(')');
+
+       restore_anchor_state(',', saved_comma_state);
+       return declarations;
+
+end_error:
+       restore_anchor_state(',', saved_comma_state);
+       return NULL;
 }
 
 typedef enum {
@@ -3411,9 +3478,6 @@ end_error:
 
 static construct_type_t *parse_function_declarator(declaration_t *declaration)
 {
-       eat('(');
-       add_anchor_token(')');
-
        type_t *type;
        if(declaration != NULL) {
                type = allocate_type_zero(TYPE_FUNCTION, &declaration->source_position);
@@ -3432,10 +3496,6 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration)
        construct_function_type->construct_type.kind = CONSTRUCT_FUNCTION;
        construct_function_type->function_type       = type;
 
-       rem_anchor_token(')');
-       expect(')');
-
-end_error:
        return (construct_type_t*) construct_function_type;
 }
 
@@ -3758,11 +3818,15 @@ static declaration_t *internal_record_declaration(
        const symbol_t *const symbol  = declaration->symbol;
        const namespace_t     namespc = (namespace_t)declaration->namespc;
 
+       assert(declaration->symbol != NULL);
+       declaration_t *previous_declaration = get_declaration(symbol, namespc);
+
        type_t *const orig_type = declaration->type;
        type_t *const type      = skip_typeref(orig_type);
        if (is_type_function(type) &&
                        type->function.unspecified_parameters &&
-                       warning.strict_prototypes) {
+                       warning.strict_prototypes &&
+                       previous_declaration == NULL) {
                warningf(&declaration->source_position,
                         "function declaration '%#T' is not a prototype",
                         orig_type, declaration->symbol);
@@ -3772,102 +3836,103 @@ static declaration_t *internal_record_declaration(
                check_type_of_main(declaration, &type->function);
        }
 
-       assert(declaration->symbol != NULL);
-       declaration_t *previous_declaration = get_declaration(symbol, namespc);
-
        assert(declaration != previous_declaration);
-       if (previous_declaration != NULL) {
-               if (previous_declaration->parent_scope == scope) {
-                       /* can happen for K&R style declarations */
-                       if(previous_declaration->type == NULL) {
-                               previous_declaration->type = declaration->type;
+       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;
+               }
+
+               const type_t *prev_type = skip_typeref(previous_declaration->type);
+               if (!types_compatible(type, prev_type)) {
+                       errorf(&declaration->source_position,
+                                  "declaration '%#T' is incompatible with '%#T' (declared %P)",
+                                  orig_type, symbol, previous_declaration->type, symbol,
+                                  &previous_declaration->source_position);
+               } else {
+                       unsigned old_storage_class = previous_declaration->storage_class;
+                       if (old_storage_class == STORAGE_CLASS_ENUM_ENTRY) {
+                               errorf(&declaration->source_position,
+                                          "redeclaration of enum entry '%Y' (declared %P)",
+                                          symbol, &previous_declaration->source_position);
+                               return previous_declaration;
                        }
 
-                       const type_t *prev_type = skip_typeref(previous_declaration->type);
-                       if (!types_compatible(type, prev_type)) {
-                               errorf(&declaration->source_position,
-                                      "declaration '%#T' is incompatible with '%#T' (declared %P)",
-                                      orig_type, symbol, previous_declaration->type, symbol,
-                                  &previous_declaration->source_position);
-                       } else {
-                               unsigned old_storage_class = previous_declaration->storage_class;
-                               if(old_storage_class == STORAGE_CLASS_ENUM_ENTRY) {
-                                       errorf(&declaration->source_position,
-                                              "redeclaration of enum entry '%Y' (declared %P)",
-                                              symbol, &previous_declaration->source_position);
-                                       return previous_declaration;
-                               }
+                       unsigned new_storage_class = declaration->storage_class;
 
-                               unsigned new_storage_class = declaration->storage_class;
+                       if (is_type_incomplete(prev_type)) {
+                               previous_declaration->type = type;
+                               prev_type                  = type;
+                       }
 
-                               if(is_type_incomplete(prev_type)) {
+                       /* pretend no storage class means extern for function
+                        * declarations (except if the previous declaration is neither
+                        * none nor extern) */
+                       if (is_type_function(type)) {
+                               if (prev_type->function.unspecified_parameters) {
                                        previous_declaration->type = type;
                                        prev_type                  = type;
                                }
 
-                               /* pretend no storage class means extern for function
-                                * declarations (except if the previous declaration is neither
-                                * none nor extern) */
-                               if (is_type_function(type)) {
-                                       switch (old_storage_class) {
-                                               case STORAGE_CLASS_NONE:
-                                                       old_storage_class = STORAGE_CLASS_EXTERN;
-
-                                               case STORAGE_CLASS_EXTERN:
-                                                       if (is_function_definition) {
-                                                               if (warning.missing_prototypes &&
-                                                                   prev_type->function.unspecified_parameters &&
-                                                                   !is_sym_main(symbol)) {
-                                                                       warningf(&declaration->source_position,
-                                                                                "no previous prototype for '%#T'",
-                                                                                orig_type, symbol);
-                                                               }
-                                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
-                                                               new_storage_class = STORAGE_CLASS_EXTERN;
-                                                       }
-                                                       break;
-
-                                               default: break;
+                               switch (old_storage_class) {
+                               case STORAGE_CLASS_NONE:
+                                       old_storage_class = STORAGE_CLASS_EXTERN;
+
+                               case STORAGE_CLASS_EXTERN:
+                                       if (is_function_definition) {
+                                               if (warning.missing_prototypes &&
+                                                       prev_type->function.unspecified_parameters &&
+                                                       !is_sym_main(symbol)) {
+                                                       warningf(&declaration->source_position,
+                                                                        "no previous prototype for '%#T'",
+                                                                        orig_type, symbol);
+                                               }
+                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
+                                               new_storage_class = STORAGE_CLASS_EXTERN;
                                        }
+                                       break;
+
+                               default:
+                                       break;
                                }
+                       }
 
-                               if (old_storage_class == STORAGE_CLASS_EXTERN &&
-                                               new_storage_class == STORAGE_CLASS_EXTERN) {
+                       if (old_storage_class == STORAGE_CLASS_EXTERN &&
+                                       new_storage_class == STORAGE_CLASS_EXTERN) {
 warn_redundant_declaration:
-                                       if (warning.redundant_decls) {
-                                               warningf(&declaration->source_position,
-                                                        "redundant declaration for '%Y' (declared %P)",
-                                                        symbol, &previous_declaration->source_position);
-                                       }
-                               } else if (current_function == NULL) {
-                                       if (old_storage_class != STORAGE_CLASS_STATIC &&
-                                                       new_storage_class == STORAGE_CLASS_STATIC) {
-                                               errorf(&declaration->source_position,
-                                                      "static declaration of '%Y' follows non-static declaration (declared %P)",
-                                                      symbol, &previous_declaration->source_position);
-                                       } else {
-                                               if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
-                                                       goto warn_redundant_declaration;
-                                               }
-                                               if (new_storage_class == STORAGE_CLASS_NONE) {
-                                                       previous_declaration->storage_class = STORAGE_CLASS_NONE;
-                                                       previous_declaration->declared_storage_class = STORAGE_CLASS_NONE;
-                                               }
-                                       }
-                               } else {
-                                       if (old_storage_class == new_storage_class) {
-                                               errorf(&declaration->source_position,
-                                                      "redeclaration of '%Y' (declared %P)",
-                                                      symbol, &previous_declaration->source_position);
-                                       } else {
-                                               errorf(&declaration->source_position,
-                                                      "redeclaration of '%Y' with different linkage (declared %P)",
-                                                      symbol, &previous_declaration->source_position);
-                                       }
+                               if (warning.redundant_decls && strcmp(previous_declaration->source_position.input_name, "<builtin>") != 0) {
+                                       warningf(&declaration->source_position,
+                                                        "redundant declaration for '%Y' (declared %P)",
+                                                        symbol, &previous_declaration->source_position);
                                }
+                       } else if (current_function == NULL) {
+                               if (old_storage_class != STORAGE_CLASS_STATIC &&
+                                               new_storage_class == STORAGE_CLASS_STATIC) {
+                                       errorf(&declaration->source_position,
+                                                  "static declaration of '%Y' follows non-static declaration (declared %P)",
+                                                  symbol, &previous_declaration->source_position);
+                               } else if (old_storage_class != STORAGE_CLASS_EXTERN
+                                               && !is_function_definition) {
+                                       goto warn_redundant_declaration;
+                               } else if (new_storage_class == STORAGE_CLASS_NONE) {
+                                               previous_declaration->storage_class = STORAGE_CLASS_NONE;
+                                               previous_declaration->declared_storage_class = STORAGE_CLASS_NONE;
+                               }
+                       } else if (old_storage_class == new_storage_class) {
+                               errorf(&declaration->source_position,
+                                          "redeclaration of '%Y' (declared %P)",
+                                          symbol, &previous_declaration->source_position);
+                       } else {
+                               errorf(&declaration->source_position,
+                                          "redeclaration of '%Y' with different linkage (declared %P)",
+                                          symbol, &previous_declaration->source_position);
                        }
-                       return previous_declaration;
                }
+
+               if (declaration->is_inline)
+                       previous_declaration->is_inline = true;
+               return previous_declaration;
        } else if (is_function_definition) {
                if (declaration->storage_class != STORAGE_CLASS_STATIC) {
                        if (warning.missing_prototypes && !is_sym_main(symbol)) {
@@ -3916,18 +3981,18 @@ static void parser_error_multiple_definition(declaration_t *declaration,
 }
 
 static bool is_declaration_specifier(const token_t *token,
-                                     bool only_type_specifiers)
+                                     bool only_specifiers_qualifiers)
 {
        switch(token->type) {
                TYPE_SPECIFIERS
+               TYPE_QUALIFIERS
                        return true;
                case T_IDENTIFIER:
                        return is_typedef_symbol(token->v.symbol);
 
                case T___extension__:
                STORAGE_CLASSES
-               TYPE_QUALIFIERS
-                       return !only_type_specifiers;
+                       return !only_specifiers_qualifiers;
 
                default:
                        return false;
@@ -4098,13 +4163,27 @@ static void parse_declaration(parsed_declaration_func finished_declaration)
        }
 }
 
+static type_t *get_default_promoted_type(type_t *orig_type)
+{
+       type_t *result = orig_type;
+
+       type_t *type = skip_typeref(orig_type);
+       if(is_type_integer(type)) {
+               result = promote_integer(type);
+       } else if(type == type_float) {
+               result = type_double;
+       }
+
+       return result;
+}
+
 static void parse_kr_declaration_list(declaration_t *declaration)
 {
        type_t *type = skip_typeref(declaration->type);
-       if(!is_type_function(type))
+       if (!is_type_function(type))
                return;
 
-       if(!type->function.kr_style_parameters)
+       if (!type->function.kr_style_parameters)
                return;
 
        /* push function parameters */
@@ -4113,14 +4192,14 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        set_scope(&declaration->scope);
 
        declaration_t *parameter = declaration->scope.declarations;
-       for( ; parameter != NULL; parameter = parameter->next) {
+       for ( ; parameter != NULL; parameter = parameter->next) {
                assert(parameter->parent_scope == NULL);
                parameter->parent_scope = scope;
                environment_push(parameter);
        }
 
        /* parse declaration list */
-       while(is_declaration_specifier(&token, false)) {
+       while (is_declaration_specifier(&token, false)) {
                parse_declaration(finished_kr_declaration);
        }
 
@@ -4131,7 +4210,6 @@ static void parse_kr_declaration_list(declaration_t *declaration)
 
        /* update function type */
        type_t *new_type = duplicate_type(type);
-       new_type->function.kr_style_parameters = false;
 
        function_parameter_t *parameters     = NULL;
        function_parameter_t *last_parameter = NULL;
@@ -4157,6 +4235,11 @@ static void parse_kr_declaration_list(declaration_t *declaration)
                semantic_parameter(parameter_declaration);
                parameter_type = parameter_declaration->type;
 
+               /*
+                * we need the default promoted types for the function type
+                */
+               parameter_type = get_default_promoted_type(parameter_type);
+
                function_parameter_t *function_parameter
                        = obstack_alloc(type_obst, sizeof(function_parameter[0]));
                memset(function_parameter, 0, sizeof(function_parameter[0]));
@@ -4169,7 +4252,11 @@ static void parse_kr_declaration_list(declaration_t *declaration)
                }
                last_parameter = function_parameter;
        }
-       new_type->function.parameters = parameters;
+
+       /* Â§ 6.9.1.7: A K&R style parameter list does NOT act as a function
+        * prototype */
+       new_type->function.parameters             = parameters;
+       new_type->function.unspecified_parameters = true;
 
        type = typehash_insert(new_type);
        if(type != new_type) {
@@ -4309,7 +4396,9 @@ static void parse_external_declaration(void)
 
        /* Â§ 6.7.5.3 (14) a function definition with () means no
         * parameters (and not unspecified parameters) */
-       if(type->function.unspecified_parameters) {
+       if(type->function.unspecified_parameters
+                       && type->function.parameters == NULL
+                       && !type->function.kr_style_parameters) {
                type_t *duplicate = duplicate_type(type);
                duplicate->function.unspecified_parameters = false;
 
@@ -4717,18 +4806,11 @@ static declaration_t *create_implicit_function(symbol_t *symbol,
        declaration->type                   = type;
        declaration->symbol                 = symbol;
        declaration->source_position        = *source_position;
-       declaration->parent_scope           = global_scope;
-
-       scope_t *old_scope = scope;
-       set_scope(global_scope);
-
-       environment_push(declaration);
-       /* prepends the declaration to the global declarations list */
-       declaration->next   = scope->declarations;
-       scope->declarations = declaration;
 
-       assert(scope == global_scope);
-       set_scope(old_scope);
+       bool strict_prototypes_old = warning.strict_prototypes;
+       warning.strict_prototypes  = false;
+       record_declaration(declaration);
+       warning.strict_prototypes = strict_prototypes_old;
 
        return declaration;
 }
@@ -4759,6 +4841,20 @@ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
        return result;
 }
 
+static type_t *make_function_0_type(type_t *return_type)
+{
+       type_t *type               = allocate_type_zero(TYPE_FUNCTION, &builtin_source_position);
+       type->function.return_type = return_type;
+       type->function.parameters  = NULL;
+
+       type_t *result = typehash_insert(type);
+       if(result != type) {
+               free_type(type);
+       }
+
+       return result;
+}
+
 /**
  * Creates a function type for some function like builtins.
  *
@@ -4769,6 +4865,8 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
        switch(symbol->ID) {
        case T___builtin_alloca:
                return make_function_1_type(type_void_ptr, type_size_t);
+       case T___builtin_huge_val:
+               return make_function_0_type(type_double);
        case T___builtin_nan:
                return make_function_1_type(type_double, type_char_ptr);
        case T___builtin_nanf:
@@ -5475,6 +5573,7 @@ static expression_t *parse_primary_expression(void)
                case T___builtin_nan:
                case T___builtin_nand:
                case T___builtin_nanf:
+               case T___builtin_huge_val:
                case T___builtin_va_end:         return parse_builtin_symbol();
                case T___builtin_isgreater:
                case T___builtin_isgreaterequal:
@@ -5563,20 +5662,50 @@ static expression_t *parse_array_expression(unsigned precedence,
        return expression;
 }
 
-static expression_t *parse_typeprop(expression_kind_t kind, unsigned precedence)
+static expression_t *parse_typeprop(expression_kind_t const kind,
+                                    source_position_t const pos,
+                                    unsigned const precedence)
 {
        expression_t *tp_expression = allocate_expression_zero(kind);
-       tp_expression->base.type    = type_size_t;
+       tp_expression->base.type            = type_size_t;
+       tp_expression->base.source_position = pos;
 
-       if(token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
+       char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+
+       if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
                next_token();
                add_anchor_token(')');
-               tp_expression->typeprop.type = parse_typename();
+               type_t* const orig_type = parse_typename();
+               tp_expression->typeprop.type = orig_type;
+
+               type_t const* const type = skip_typeref(orig_type);
+               char const* const wrong_type =
+                       is_type_incomplete(type)    ? "incomplete"          :
+                       type->kind == TYPE_FUNCTION ? "function designator" :
+                       type->kind == TYPE_BITFIELD ? "bitfield"            :
+                       NULL;
+               if (wrong_type != NULL) {
+                       errorf(&pos, "operand of %s expression must not be %s type '%T'",
+                              what, wrong_type, type);
+               }
+
                rem_anchor_token(')');
                expect(')');
        } else {
                expression_t *expression = parse_sub_expression(precedence);
-               expression->base.type    = revert_automatic_type_conversion(expression);
+
+               type_t* const orig_type = revert_automatic_type_conversion(expression);
+               expression->base.type = orig_type;
+
+               type_t const* const type = skip_typeref(orig_type);
+               char const* const wrong_type =
+                       is_type_incomplete(type)    ? "incomplete"          :
+                       type->kind == TYPE_FUNCTION ? "function designator" :
+                       type->kind == TYPE_BITFIELD ? "bitfield"            :
+                       NULL;
+               if (wrong_type != NULL) {
+                       errorf(&pos, "operand of %s expression must not be expression of %s type '%T'", what, wrong_type, type);
+               }
 
                tp_expression->typeprop.type          = expression->base.type;
                tp_expression->typeprop.tp_expression = expression;
@@ -5589,14 +5718,16 @@ end_error:
 
 static expression_t *parse_sizeof(unsigned precedence)
 {
+       source_position_t pos = *HERE;
        eat(T_sizeof);
-       return parse_typeprop(EXPR_SIZEOF, precedence);
+       return parse_typeprop(EXPR_SIZEOF, pos, precedence);
 }
 
 static expression_t *parse_alignof(unsigned precedence)
 {
+       source_position_t pos = *HERE;
        eat(T___alignof__);
-       return parse_typeprop(EXPR_SIZEOF, precedence);
+       return parse_typeprop(EXPR_ALIGNOF, pos, precedence);
 }
 
 static expression_t *parse_select_expression(unsigned precedence,
@@ -5611,7 +5742,7 @@ static expression_t *parse_select_expression(unsigned precedence,
        expression_t *select    = allocate_expression_zero(EXPR_SELECT);
        select->select.compound = compound;
 
-       if(token.type != T_IDENTIFIER) {
+       if (token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
                return select;
        }
@@ -5623,7 +5754,7 @@ static expression_t *parse_select_expression(unsigned precedence,
        type_t *const type      = skip_typeref(orig_type);
 
        type_t *type_left = type;
-       if(is_pointer) {
+       if (is_pointer) {
                if (!is_type_pointer(type)) {
                        if (is_type_valid(type)) {
                                errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
@@ -5645,14 +5776,14 @@ static expression_t *parse_select_expression(unsigned precedence,
 
        declaration_t *const declaration = type_left->compound.declaration;
 
-       if(!declaration->init.is_defined) {
+       if (!declaration->init.complete) {
                errorf(HERE, "request for member '%Y' of incomplete type '%T'",
                       symbol, type_left);
                return create_invalid_expression();
        }
 
        declaration_t *iter = find_compound_entry(declaration, symbol);
-       if(iter == NULL) {
+       if (iter == NULL) {
                errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
                return create_invalid_expression();
        }
@@ -5664,13 +5795,9 @@ static expression_t *parse_select_expression(unsigned precedence,
        select->select.compound_entry = iter;
        select->base.type             = expression_type;
 
-       if(expression_type->kind == TYPE_BITFIELD) {
-               expression_t *extract
-                       = allocate_expression_zero(EXPR_UNARY_BITFIELD_EXTRACT);
-               extract->unary.value = select;
-               extract->base.type   = expression_type->bitfield.base_type;
-
-               return extract;
+       type_t *skipped = skip_typeref(iter->type);
+       if (skipped->kind == TYPE_BITFIELD) {
+               select->base.type = skipped->bitfield.base_type;
        }
 
        return select;
@@ -5736,17 +5863,20 @@ static expression_t *parse_call_expression(unsigned precedence,
        rem_anchor_token(')');
        expect(')');
 
-       if(function_type != NULL) {
-               function_parameter_t *parameter = function_type->parameters;
-               call_argument_t      *argument  = call->arguments;
+       if(function_type == NULL)
+               return result;
+
+       function_parameter_t *parameter = function_type->parameters;
+       call_argument_t      *argument  = call->arguments;
+       if (!function_type->unspecified_parameters) {
                for( ; parameter != NULL && argument != NULL;
                                parameter = parameter->next, argument = argument->next) {
                        type_t *expected_type = parameter->type;
                        /* TODO report scope in error messages */
                        expression_t *const arg_expr = argument->expression;
                        type_t       *const res_type = semantic_assign(expected_type, arg_expr,
-                                                                      "function call",
-                                                                      &arg_expr->base.source_position);
+                                                                                                                  "function call",
+                                                                                                                  &arg_expr->base.source_position);
                        if (res_type == NULL) {
                                /* TODO improve error message */
                                errorf(&arg_expr->base.source_position,
@@ -5756,37 +5886,26 @@ static expression_t *parse_call_expression(unsigned precedence,
                                argument->expression = create_implicit_cast(argument->expression, expected_type);
                        }
                }
-               /* too few parameters */
-               if(parameter != NULL) {
+
+               if (parameter != NULL) {
                        errorf(HERE, "too few arguments to function '%E'", expression);
-               } else if(argument != NULL) {
-                       /* too many parameters */
-                       if(!function_type->variadic
-                                       && !function_type->unspecified_parameters) {
-                               errorf(HERE, "too many arguments to function '%E'", expression);
-                       } else {
-                               /* do default promotion */
-                               for( ; argument != NULL; argument = argument->next) {
-                                       type_t *type = argument->expression->base.type;
-
-                                       type = skip_typeref(type);
-                                       if(is_type_integer(type)) {
-                                               type = promote_integer(type);
-                                       } else if(type == type_float) {
-                                               type = type_double;
-                                       }
+               } else if (argument != NULL && !function_type->variadic) {
+                       errorf(HERE, "too many arguments to function '%E'", expression);
+               }
+       }
 
-                                       argument->expression
-                                               = create_implicit_cast(argument->expression, type);
-                               }
+       /* do default promotion */
+       for( ; argument != NULL; argument = argument->next) {
+               type_t *type = argument->expression->base.type;
 
-                               check_format(&result->call);
-                       }
-               } else {
-                       check_format(&result->call);
-               }
+               type = get_default_promoted_type(type);
+
+               argument->expression
+                       = create_implicit_cast(argument->expression, type);
        }
 
+       check_format(&result->call);
+
        return result;
 end_error:
        return create_invalid_expression();
@@ -6287,9 +6406,9 @@ static void semantic_comparison(binary_expression_t *expression)
                                other_expr = left;
                        }
 
-                       type_t *other_type = skip_typeref(other_expr->base.type);
                        if(const_expr != NULL) {
-                               long val = fold_constant(const_expr);
+                               type_t *other_type = skip_typeref(other_expr->base.type);
+                               long    val        = fold_constant(const_expr);
                                /* TODO: check if val can be represented by other_type */
                                (void) other_type;
                                (void) val;
@@ -6322,6 +6441,66 @@ static void semantic_comparison(binary_expression_t *expression)
        expression->base.type = type_int;
 }
 
+/**
+ * Checks if a compound type has constant fields.
+ */
+static bool has_const_fields(const compound_type_t *type)
+{
+       const scope_t       *scope       = &type->declaration->scope;
+       const declaration_t *declaration = scope->declarations;
+
+       for (; declaration != NULL; declaration = declaration->next) {
+               if (declaration->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               const type_t *decl_type = skip_typeref(declaration->type);
+               if (decl_type->base.qualifiers & TYPE_QUALIFIER_CONST)
+                       return true;
+       }
+       /* TODO */
+       return false;
+}
+
+static bool is_valid_assignment_lhs(expression_t const* const left)
+{
+       type_t *const orig_type_left = revert_automatic_type_conversion(left);
+       type_t *const type_left      = skip_typeref(orig_type_left);
+
+       switch (left->kind)  {
+               case EXPR_REFERENCE:
+               case EXPR_ARRAY_ACCESS:
+               case EXPR_SELECT:
+               case EXPR_UNARY_DEREFERENCE:
+                       break;
+
+               default:
+                       errorf(HERE, "left hand side '%E' of assignment is not an lvalue", left);
+                       return false;
+       }
+
+       if (is_type_array(type_left)) {
+               errorf(HERE, "cannot assign to arrays ('%E')", left);
+               return false;
+       }
+       if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
+               errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
+                      orig_type_left);
+               return false;
+       }
+       if (is_type_incomplete(type_left)) {
+               errorf(HERE, "left-hand side '%E' of assignment has incomplete type '%T'",
+                      left, orig_type_left);
+               return false;
+       }
+       if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
+               errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
+                      left, orig_type_left);
+               return false;
+       }
+
+       return true;
+}
+
 static void semantic_arithmetic_assign(binary_expression_t *expression)
 {
        expression_t *left            = expression->left;
@@ -6329,6 +6508,9 @@ static void semantic_arithmetic_assign(binary_expression_t *expression)
        type_t       *orig_type_left  = left->base.type;
        type_t       *orig_type_right = right->base.type;
 
+       if (!is_valid_assignment_lhs(left))
+               return;
+
        type_t *type_left  = skip_typeref(orig_type_left);
        type_t *type_right = skip_typeref(orig_type_right);
 
@@ -6358,6 +6540,9 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
        type_t       *const type_left       = skip_typeref(orig_type_left);
        type_t       *const type_right      = skip_typeref(orig_type_right);
 
+       if (!is_valid_assignment_lhs(left))
+               return;
+
        if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
                /* combined instructions are tricky. We can't create an implicit cast on
                 * the left side, because we need the uncasted form for the store.
@@ -6396,26 +6581,6 @@ static void semantic_logical_op(binary_expression_t *expression)
        expression->base.type = type_int;
 }
 
-/**
- * Checks if a compound type has constant fields.
- */
-static bool has_const_fields(const compound_type_t *type)
-{
-       const scope_t       *scope       = &type->declaration->scope;
-       const declaration_t *declaration = scope->declarations;
-
-       for (; declaration != NULL; declaration = declaration->next) {
-               if (declaration->namespc != NAMESPACE_NORMAL)
-                       continue;
-
-               const type_t *decl_type = skip_typeref(declaration->type);
-               if (decl_type->base.qualifiers & TYPE_QUALIFIER_CONST)
-                       return true;
-       }
-       /* TODO */
-       return false;
-}
-
 /**
  * Check the semantic restrictions of a binary assign expression.
  */
@@ -6427,27 +6592,8 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        type_t *type_left = revert_automatic_type_conversion(left);
        type_left         = skip_typeref(orig_type_left);
 
-       /* must be a modifiable lvalue */
-       if (is_type_array(type_left)) {
-               errorf(HERE, "cannot assign to arrays ('%E')", left);
-               return;
-       }
-       if(type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
-               errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
-                      orig_type_left);
-               return;
-       }
-       if(is_type_incomplete(type_left)) {
-               errorf(HERE,
-                      "left-hand side of assignment '%E' has incomplete type '%T'",
-                      left, orig_type_left);
+       if (!is_valid_assignment_lhs(left))
                return;
-       }
-       if(is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
-               errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
-                      left, orig_type_left);
-               return;
-       }
 
        type_t *const res_type = semantic_assign(orig_type_left, expression->right,
                        "assignment", &left->base.source_position);
@@ -6543,7 +6689,6 @@ static bool expression_has_effect(const expression_t *const expr)
 
                case EXPR_UNARY_CAST_IMPLICIT:       return true;
                case EXPR_UNARY_ASSUME:              return true;
-               case EXPR_UNARY_BITFIELD_EXTRACT:    return false;
 
                case EXPR_BINARY_ADD:                return false;
                case EXPR_BINARY_SUB:                return false;
@@ -6784,13 +6929,13 @@ static void init_expression_parsers(void)
        register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT,
                                                              T_MINUSMINUS,     30);
 
-       register_infix_parser(parse_EXPR_BINARY_MUL,          '*',              16);
-       register_infix_parser(parse_EXPR_BINARY_DIV,          '/',              16);
-       register_infix_parser(parse_EXPR_BINARY_MOD,          '%',              16);
-       register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT,    T_LESSLESS,       16);
-       register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT,   T_GREATERGREATER, 16);
-       register_infix_parser(parse_EXPR_BINARY_ADD,          '+',              15);
-       register_infix_parser(parse_EXPR_BINARY_SUB,          '-',              15);
+       register_infix_parser(parse_EXPR_BINARY_MUL,          '*',              17);
+       register_infix_parser(parse_EXPR_BINARY_DIV,          '/',              17);
+       register_infix_parser(parse_EXPR_BINARY_MOD,          '%',              17);
+       register_infix_parser(parse_EXPR_BINARY_ADD,          '+',              16);
+       register_infix_parser(parse_EXPR_BINARY_SUB,          '-',              16);
+       register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT,    T_LESSLESS,       15);
+       register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT,   T_GREATERGREATER, 15);
        register_infix_parser(parse_EXPR_BINARY_LESS,         '<',              14);
        register_infix_parser(parse_EXPR_BINARY_GREATER,      '>',              14);
        register_infix_parser(parse_EXPR_BINARY_LESSEQUAL,    T_LESSEQUAL,      14);
@@ -7356,7 +7501,7 @@ static statement_t *parse_goto(void)
        if(token.type != T_IDENTIFIER) {
                parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
                eat_statement();
-               return NULL;
+               goto end_error;
        }
        symbol_t *symbol = token.v.symbol;
        next_token();
@@ -7549,7 +7694,8 @@ static statement_t *parse_return(void)
                        }
                }
                /* check for returning address of a local var */
-               if (return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
+               if (return_value != NULL &&
+                               return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
                        const expression_t *expression = return_value->unary.value;
                        if (is_local_variable(expression)) {
                                warningf(&statement->base.source_position,
@@ -7921,18 +8067,8 @@ static void check_unused_globals(void)
 /**
  * Parse a translation unit.
  */
-static translation_unit_t *parse_translation_unit(void)
+static void parse_translation_unit(void)
 {
-       translation_unit_t *unit = allocate_ast_zero(sizeof(unit[0]));
-
-       assert(global_scope == NULL);
-       global_scope = &unit->scope;
-
-       assert(scope == NULL);
-       set_scope(&unit->scope);
-
-       initialize_builtin_types();
-
        while(token.type != T_EOF) {
                if (token.type == ';') {
                        /* TODO error in strict mode */
@@ -7942,16 +8078,6 @@ static translation_unit_t *parse_translation_unit(void)
                        parse_external_declaration();
                }
        }
-
-       assert(scope == &unit->scope);
-       scope          = NULL;
-       last_declaration = NULL;
-
-       assert(global_scope == &unit->scope);
-       check_unused_globals();
-       global_scope = NULL;
-
-       return unit;
 }
 
 /**
@@ -7959,7 +8085,7 @@ static translation_unit_t *parse_translation_unit(void)
  *
  * @return  the translation unit or NULL if errors occurred.
  */
-translation_unit_t *parse(void)
+void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
@@ -7970,16 +8096,43 @@ translation_unit_t *parse(void)
        type_set_output(stderr);
        ast_set_output(stderr);
 
-       lookahead_bufpos = 0;
-       for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
-               next_token();
-       }
-       translation_unit_t *unit = parse_translation_unit();
+       assert(unit == NULL);
+       unit = allocate_ast_zero(sizeof(unit[0]));
+
+       assert(global_scope == NULL);
+       global_scope = &unit->scope;
+
+       assert(scope == NULL);
+       set_scope(&unit->scope);
+
+       initialize_builtin_types();
+}
+
+translation_unit_t *finish_parsing(void)
+{
+       assert(scope == &unit->scope);
+       scope          = NULL;
+       last_declaration = NULL;
+
+       assert(global_scope == &unit->scope);
+       check_unused_globals();
+       global_scope = NULL;
 
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);
 
-       return unit;
+       translation_unit_t *result = unit;
+       unit = NULL;
+       return result;
+}
+
+void parse(void)
+{
+       lookahead_bufpos = 0;
+       for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
+               next_token();
+       }
+       parse_translation_unit();
 }
 
 /**