+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->type = specifiers->type;
+ declaration->storage_class = specifiers->storage_class;
+ declaration->source_position = specifiers->source_position;
+
+ if (declaration->storage_class != STORAGE_CLASS_NONE) {
+ warningf(declaration->source_position, "useless storage class in empty declaration");
+ }
+
+ type_t *type = declaration->type;
+ switch (type->kind) {
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION: {
+ const compound_type_t *compound_type = &type->compound;
+ if (compound_type->declaration->symbol == NULL) {
+ warningf(declaration->source_position, "unnamed struct/union that defines no instances");
+ }
+ break;
+ }
+
+ case TYPE_ENUM:
+ break;
+
+ default:
+ warningf(declaration->source_position, "empty declaration");
+ break;
+ }
+
+ finished_declaration(declaration);
+}
+
+static void parse_declaration_rest(declaration_t *ndeclaration,
+ const declaration_specifiers_t *specifiers,
+ parsed_declaration_func finished_declaration)
+{
+ while(true) {
+ declaration_t *declaration = finished_declaration(ndeclaration);
+
+ type_t *orig_type = declaration->type;
+ type_t *type = skip_typeref(orig_type);
+
+ if(type->kind != TYPE_FUNCTION && declaration->is_inline) {
+ warningf(declaration->source_position, "variable '%s' declared 'inline'\n", declaration->symbol->string);
+ }
+
+ if(token.type == '=') {
+ parse_init_declarator_rest(declaration);
+ }
+
+ if(token.type != ',')
+ break;
+ eat(',');
+
+ ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false);
+ }
+ expect_void(';');
+}
+
+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, /*may_be_abstract=*/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
+ errorf(HERE, "no type specified for function parameter '%s'", parameter_declaration->symbol->string);
+#else
+ warningf(HERE, "no type specified for function parameter '%s', using int", 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, /*may_be_abstract=*/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->kind != TYPE_FUNCTION) {
+ errorf(HERE, "declarator '%#T' has a body but is not a function type", type, ndeclaration->symbol);
+ 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);
+}
+
+static void parse_struct_declarators(const declaration_specifiers_t *specifiers)
+{
+ while(1) {
+ if(token.type == ':') {
+ next_token();
+ parse_constant_expression();
+ /* TODO (bitfields) */
+ } else {
+ declaration_t *declaration = parse_declarator(specifiers, /*may_be_abstract=*/true);
+
+ /* TODO: check constraints for struct declarations */
+ /* TODO: check for doubled fields */
+ record_declaration(declaration);