+static declaration_t *finished_kr_declaration(declaration_t *declaration)
+{
+ /* TODO: check that it was actually a parameter that gets a type */
+
+ /* we should have a declaration for the parameter in the current
+ * scope */
+ return record_declaration(declaration);
+}
+
+static void parse_declaration(parsed_declaration_func finished_declaration)
+{
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
+
+ if(token.type == ';') {
+ parse_anonymous_declaration_rest(&specifiers, finished_declaration);
+ } else {
+ declaration_t *declaration = parse_declarator(&specifiers, false);
+ parse_declaration_rest(declaration, &specifiers, finished_declaration);
+ }
+}
+
+static void parse_kr_declaration_list(declaration_t *declaration)
+{
+ type_t *type = skip_typeref(declaration->type);
+ if(!is_type_function(type))
+ return;
+
+ if(!type->function.kr_style_parameters)
+ return;
+
+ /* push function parameters */
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ declaration_t *parameter = declaration->context.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ environment_push(parameter);
+ }
+
+ /* parse declaration list */
+ while(is_declaration_specifier(&token, false)) {
+ parse_declaration(finished_kr_declaration);
+ }
+
+ /* pop function parameters */
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+
+ /* 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;
+
+ declaration_t *parameter_declaration = declaration->context.declarations;
+ for( ; parameter_declaration != NULL;
+ parameter_declaration = parameter_declaration->next) {
+ type_t *parameter_type = parameter_declaration->type;
+ if(parameter_type == NULL) {
+#ifdef STRICT_C99
+ parser_print_error_prefix();
+ fprintf(stderr, "no type specified for function parameter '%s'\n",
+ parameter_declaration->symbol->string);
+#else
+ parser_print_warning_prefix();
+ fprintf(stderr, "no type specified for function parameter '%s', "
+ "using int\n", parameter_declaration->symbol->string);
+ parameter_type = type_int;
+ parameter_declaration->type = parameter_type;
+#endif
+ }
+
+ semantic_parameter(parameter_declaration);
+ parameter_type = parameter_declaration->type;
+
+ function_parameter_t *function_parameter
+ = obstack_alloc(type_obst, sizeof(function_parameter[0]));
+ memset(function_parameter, 0, sizeof(function_parameter[0]));
+
+ function_parameter->type = parameter_type;
+ if(last_parameter != NULL) {
+ last_parameter->next = function_parameter;
+ } else {
+ parameters = function_parameter;
+ }
+ last_parameter = function_parameter;
+ }
+ new_type->function.parameters = parameters;
+
+ type = typehash_insert(new_type);
+ if(type != new_type) {
+ obstack_free(type_obst, new_type);
+ }
+
+ declaration->type = type;
+}
+
+static void parse_external_declaration(void)
+{
+ /* function-definitions and declarations both start with declaration
+ * specifiers */
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
+
+ /* must be a declaration */
+ if(token.type == ';') {
+ parse_anonymous_declaration_rest(&specifiers, record_declaration);
+ return;
+ }
+
+ /* declarator is common to both function-definitions and declarations */
+ declaration_t *ndeclaration = parse_declarator(&specifiers, false);
+
+ /* must be a declaration */
+ if(token.type == ',' || token.type == '=' || token.type == ';') {
+ parse_declaration_rest(ndeclaration, &specifiers, record_declaration);
+ return;
+ }
+
+ /* must be a function definition */
+ parse_kr_declaration_list(ndeclaration);
+
+ if(token.type != '{') {
+ parse_error_expected("while parsing function definition", '{', 0);
+ eat_statement();
+ return;
+ }
+
+ type_t *type = ndeclaration->type;
+ if(type == NULL) {
+ eat_block();
+ return;
+ }
+
+ /* note that we don't skip typerefs: the standard doesn't allow them here
+ * (so we can't use is_type_function here) */
+ if(type->type != TYPE_FUNCTION) {
+ parser_print_error_prefix();
+ fprintf(stderr, "declarator '");
+ print_type_ext(type, ndeclaration->symbol, NULL);
+ fprintf(stderr, "' has a body but is not a function type.\n");
+ eat_block();
+ return;
+ }
+
+ /* § 6.7.5.3 (14) a function definition with () means no
+ * parameters (and not unspecified parameters) */
+ if(type->function.unspecified_parameters) {
+ type_t *duplicate = duplicate_type(type);
+ duplicate->function.unspecified_parameters = false;
+
+ type = typehash_insert(duplicate);
+ if(type != duplicate) {
+ obstack_free(type_obst, duplicate);
+ }
+ ndeclaration->type = type;
+ }
+
+ declaration_t *declaration = record_declaration(ndeclaration);
+ if(ndeclaration != declaration) {
+ memcpy(&declaration->context, &ndeclaration->context,
+ sizeof(declaration->context));
+ }
+ type = skip_typeref(declaration->type);
+
+ /* push function parameters and switch context */
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ declaration_t *parameter = declaration->context.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ environment_push(parameter);
+ }
+
+ if(declaration->init.statement != NULL) {
+ parser_error_multiple_definition(declaration, token.source_position);
+ eat_block();
+ goto end_of_parse_external_declaration;
+ } else {
+ /* parse function body */
+ int label_stack_top = label_top();
+ declaration_t *old_current_function = current_function;
+ current_function = declaration;
+
+ declaration->init.statement = parse_compound_statement();
+
+ assert(current_function == declaration);
+ current_function = old_current_function;
+ label_pop_to(label_stack_top);
+ }
+
+end_of_parse_external_declaration:
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+}
+