+ case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
+ atomic_type = ATOMIC_TYPE_LONG_DOUBLE_IMAGINARY;
+ break;
+#endif
+ default:
+ /* invalid specifier combination, give an error message */
+ if(type_specifiers == 0) {
+#ifndef STRICT_C99
+ parse_warning("no type specifiers in declaration (using int)");
+ atomic_type = ATOMIC_TYPE_INT;
+ break;
+#else
+ parse_error("no type specifiers given in declaration");
+#endif
+ } else if((type_specifiers & SPECIFIER_SIGNED) &&
+ (type_specifiers & SPECIFIER_UNSIGNED)) {
+ parse_error("signed and unsigned specifiers gives");
+ } else if(type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) {
+ parse_error("only integer types can be signed or unsigned");
+ } else {
+ parse_error("multiple datatypes in declaration");
+ }
+ atomic_type = ATOMIC_TYPE_INVALID;
+ }
+
+ type = allocate_type_zero(TYPE_ATOMIC);
+ type->atomic.atype = atomic_type;
+ newtype = 1;
+ } else {
+ if(type_specifiers != 0) {
+ parse_error("multiple datatypes in declaration");
+ }
+ }
+
+ type->base.qualifiers = type_qualifiers;
+
+ type_t *result = typehash_insert(type);
+ if(newtype && result != type) {
+ free_type(type);
+ }
+
+ specifiers->type = result;
+}
+
+static type_qualifiers_t parse_type_qualifiers(void)
+{
+ type_qualifiers_t type_qualifiers = TYPE_QUALIFIER_NONE;
+
+ while(true) {
+ switch(token.type) {
+ /* type qualifiers */
+ MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
+ MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
+ MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+
+ default:
+ return type_qualifiers;
+ }
+ }
+}
+
+static void parse_identifier_list(void)
+{
+ while(true) {
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing parameter identifier list",
+ T_IDENTIFIER, 0);
+ return;
+ }
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration->symbol = token.v.symbol;
+
+ next_token();
+
+ if(token.type != ',')
+ break;
+ next_token();
+ }
+}
+
+static declaration_t *parse_parameter(void)
+{
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+
+ parse_declaration_specifiers(&specifiers);
+
+ declaration_t *declaration
+ = parse_declarator(&specifiers, specifiers.type, true);
+
+ /* TODO check declaration constraints for parameters */
+ if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
+ parse_error("typedef not allowed in parameter list");
+ }
+
+ /* Array as last part of a paramter type is just syntactic sugar. Turn it
+ * into a pointer */
+ if (declaration->type->type == TYPE_ARRAY) {
+ const array_type_t *const arr_type = &declaration->type->array;
+ type_t *element_type = arr_type->element_type;
+ declaration->type = make_pointer_type(element_type, TYPE_QUALIFIER_NONE);
+ }
+
+ return declaration;
+}
+
+static declaration_t *parse_parameters(function_type_t *type)
+{
+ if(token.type == T_IDENTIFIER) {
+ symbol_t *symbol = token.v.symbol;
+ if(!is_typedef_symbol(symbol)) {
+ /* TODO: K&R style C parameters */
+ parse_identifier_list();
+ return NULL;
+ }
+ }
+
+ if(token.type == ')') {
+ type->unspecified_parameters = 1;
+ return NULL;
+ }
+ if(token.type == T_void && look_ahead(1)->type == ')') {
+ next_token();
+ return NULL;
+ }
+
+ declaration_t *declarations = NULL;
+ declaration_t *declaration;
+ declaration_t *last_declaration = NULL;
+ function_parameter_t *parameter;
+ function_parameter_t *last_parameter = NULL;
+
+ while(true) {
+ switch(token.type) {
+ case T_DOTDOTDOT:
+ next_token();
+ type->variadic = 1;
+ return declarations;
+
+ case T_IDENTIFIER:
+ case T___extension__:
+ DECLARATION_START
+ declaration = parse_parameter();
+
+ parameter = obstack_alloc(type_obst, sizeof(parameter[0]));
+ memset(parameter, 0, sizeof(parameter[0]));
+ parameter->type = declaration->type;
+
+ if(last_parameter != NULL) {
+ last_declaration->next = declaration;
+ last_parameter->next = parameter;
+ } else {
+ type->parameters = parameter;
+ declarations = declaration;
+ }
+ last_parameter = parameter;
+ last_declaration = declaration;
+ break;
+
+ default:
+ return declarations;
+ }
+ if(token.type != ',')
+ return declarations;
+ next_token();
+ }
+}
+
+typedef enum {
+ CONSTRUCT_INVALID,
+ CONSTRUCT_POINTER,
+ CONSTRUCT_FUNCTION,
+ CONSTRUCT_ARRAY
+} construct_type_type_t;
+
+typedef struct construct_type_t construct_type_t;
+struct construct_type_t {
+ construct_type_type_t type;
+ construct_type_t *next;
+};
+
+typedef struct parsed_pointer_t parsed_pointer_t;
+struct parsed_pointer_t {
+ construct_type_t construct_type;
+ type_qualifiers_t type_qualifiers;
+};
+
+typedef struct construct_function_type_t construct_function_type_t;
+struct construct_function_type_t {
+ construct_type_t construct_type;
+ type_t *function_type;
+};
+
+typedef struct parsed_array_t parsed_array_t;
+struct parsed_array_t {
+ construct_type_t construct_type;
+ type_qualifiers_t type_qualifiers;
+ bool is_static;
+ bool is_variable;
+ expression_t *size;
+};
+
+typedef struct construct_base_type_t construct_base_type_t;
+struct construct_base_type_t {
+ construct_type_t construct_type;
+ type_t *type;
+};
+
+static construct_type_t *parse_pointer_declarator(void)
+{
+ eat('*');
+
+ parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
+ memset(pointer, 0, sizeof(pointer[0]));
+ pointer->construct_type.type = CONSTRUCT_POINTER;
+ pointer->type_qualifiers = parse_type_qualifiers();
+
+ return (construct_type_t*) pointer;
+}
+
+static construct_type_t *parse_array_declarator(void)
+{
+ eat('[');
+
+ parsed_array_t *array = obstack_alloc(&temp_obst, sizeof(array[0]));
+ memset(array, 0, sizeof(array[0]));
+ array->construct_type.type = CONSTRUCT_ARRAY;
+
+ if(token.type == T_static) {
+ array->is_static = true;
+ next_token();
+ }
+
+ type_qualifiers_t type_qualifiers = parse_type_qualifiers();
+ if(type_qualifiers != 0) {
+ if(token.type == T_static) {
+ array->is_static = true;
+ next_token();
+ }
+ }
+ array->type_qualifiers = type_qualifiers;
+
+ if(token.type == '*' && look_ahead(1)->type == ']') {
+ array->is_variable = true;
+ next_token();
+ } else if(token.type != ']') {
+ array->size = parse_assignment_expression();
+ }
+
+ expect(']');
+
+ return (construct_type_t*) array;
+}
+
+static construct_type_t *parse_function_declarator(declaration_t *declaration)
+{
+ eat('(');
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+
+ declaration_t *parameters = parse_parameters(&type->function);
+ if(declaration != NULL) {
+ declaration->context.declarations = parameters;
+ }
+
+ construct_function_type_t *construct_function_type =
+ obstack_alloc(&temp_obst, sizeof(construct_function_type[0]));
+ memset(construct_function_type, 0, sizeof(construct_function_type[0]));
+ construct_function_type->construct_type.type = CONSTRUCT_FUNCTION;
+ construct_function_type->function_type = type;
+
+ expect(')');
+
+ return (construct_type_t*) construct_function_type;
+}
+
+static construct_type_t *parse_inner_declarator(declaration_t *declaration,
+ bool may_be_abstract)
+{
+ /* construct a single linked list of construct_type_t's which describe
+ * how to construct the final declarator type */
+ construct_type_t *first = NULL;
+ construct_type_t *last = NULL;
+
+ /* pointers */
+ while(token.type == '*') {
+ construct_type_t *type = parse_pointer_declarator();
+
+ if(last == NULL) {
+ first = type;
+ last = type;
+ } else {
+ last->next = type;
+ last = type;
+ }
+ }
+
+ /* TODO: find out if this is correct */
+ parse_attributes();
+
+ construct_type_t *inner_types = NULL;
+
+ switch(token.type) {
+ case T_IDENTIFIER:
+ if(declaration == NULL) {
+ parse_error("no identifier expected in typename");
+ } else {
+ declaration->symbol = token.v.symbol;
+ declaration->source_position = token.source_position;
+ }
+ next_token();
+ break;
+ case '(':
+ next_token();
+ inner_types = parse_inner_declarator(declaration, may_be_abstract);
+ expect(')');
+ break;
+ default:
+ if(may_be_abstract)
+ break;
+ parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', 0);
+ /* avoid a loop in the outermost scope, because eat_statement doesn't
+ * eat '}' */
+ if(token.type == '}' && current_function == NULL) {
+ next_token();
+ } else {
+ eat_statement();
+ }
+ return NULL;
+ }
+
+ construct_type_t *p = last;
+
+ while(true) {
+ construct_type_t *type;
+ switch(token.type) {
+ case '(':
+ type = parse_function_declarator(declaration);
+ break;
+ case '[':
+ type = parse_array_declarator();
+ break;
+ default:
+ goto declarator_finished;
+ }
+
+ /* insert in the middle of the list (behind p) */
+ if(p != NULL) {
+ type->next = p->next;
+ p->next = type;
+ } else {
+ type->next = first;
+ first = type;
+ }
+ if(last == p) {
+ last = type;
+ }
+ }
+
+declarator_finished:
+ parse_attributes();
+
+ /* append inner_types at the end of the list, we don't to set last anymore
+ * as it's not needed anymore */
+ if(last == NULL) {
+ assert(first == NULL);
+ first = inner_types;
+ } else {
+ last->next = inner_types;
+ }
+
+ return first;
+}
+
+static type_t *construct_declarator_type(construct_type_t *construct_list,
+ type_t *type)
+{
+ construct_type_t *iter = construct_list;
+ for( ; iter != NULL; iter = iter->next) {
+ switch(iter->type) {
+ case CONSTRUCT_INVALID:
+ panic("invalid type construction found");
+ case CONSTRUCT_FUNCTION: {
+ construct_function_type_t *construct_function_type
+ = (construct_function_type_t*) iter;
+
+ type_t *function_type = construct_function_type->function_type;
+
+ function_type->function.result_type = type;
+
+ type = function_type;
+ break;
+ }
+
+ case CONSTRUCT_POINTER: {
+ parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
+ type_t *pointer_type = allocate_type_zero(TYPE_POINTER);
+ pointer_type->pointer.points_to = type;
+ pointer_type->base.qualifiers = parsed_pointer->type_qualifiers;
+
+ type = pointer_type;
+ break;
+ }
+
+ case CONSTRUCT_ARRAY: {
+ parsed_array_t *parsed_array = (parsed_array_t*) iter;
+ type_t *array_type = allocate_type_zero(TYPE_ARRAY);
+
+ array_type->base.qualifiers = parsed_array->type_qualifiers;
+ array_type->array.element_type = type;
+ array_type->array.is_static = parsed_array->is_static;
+ array_type->array.is_variable = parsed_array->is_variable;
+ array_type->array.size = parsed_array->size;
+
+ type = array_type;
+ break;
+ }
+ }
+
+ type_t *hashed_type = typehash_insert(type);
+ if(hashed_type != type) {
+ /* the function type was constructed earlier freeing it here will
+ * destroy other types... */
+ if(iter->type != CONSTRUCT_FUNCTION) {
+ free_type(type);
+ }
+ type = hashed_type;
+ }
+ }
+
+ return type;
+}
+
+static declaration_t *parse_declarator(
+ const declaration_specifiers_t *specifiers,
+ type_t *type, bool may_be_abstract)
+{
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration->storage_class = specifiers->storage_class;
+ declaration->is_inline = specifiers->is_inline;
+
+ construct_type_t *construct_type
+ = parse_inner_declarator(declaration, may_be_abstract);
+ declaration->type = construct_declarator_type(construct_type, type);
+
+ if(construct_type != NULL) {
+ obstack_free(&temp_obst, construct_type);
+ }
+
+ return declaration;
+}
+
+static type_t *parse_abstract_declarator(type_t *base_type)
+{
+ construct_type_t *construct_type = parse_inner_declarator(NULL, 1);
+
+ type_t *result = construct_declarator_type(construct_type, base_type);
+ if(construct_type != NULL) {
+ obstack_free(&temp_obst, construct_type);
+ }
+
+ return result;
+}
+
+static declaration_t *record_declaration(declaration_t *declaration)
+{
+ assert(context != NULL);
+
+ symbol_t *symbol = declaration->symbol;
+ if(symbol != NULL) {
+ declaration_t *alias = environment_push(declaration);
+ if(alias != declaration)
+ return alias;
+ } else {
+ declaration->parent_context = context;
+ }
+
+ if(last_declaration != NULL) {
+ last_declaration->next = declaration;
+ } else {
+ context->declarations = declaration;
+ }
+ last_declaration = declaration;
+
+ return declaration;
+}
+
+static void parser_error_multiple_definition(declaration_t *previous,
+ declaration_t *declaration)
+{
+ parser_print_error_prefix_pos(declaration->source_position);
+ fprintf(stderr, "multiple definition of symbol '%s'\n",
+ declaration->symbol->string);
+ parser_print_error_prefix_pos(previous->source_position);
+ fprintf(stderr, "this is the location of the previous definition.\n");
+}
+
+static void parse_init_declarators(const declaration_specifiers_t *specifiers)
+{
+ while(true) {
+ declaration_t *ndeclaration
+ = parse_declarator(specifiers, specifiers->type, false);
+
+ declaration_t *declaration = record_declaration(ndeclaration);
+
+ type_t *orig_type = declaration->type;
+ type_t *type = skip_typeref(orig_type);
+ if(type->type != TYPE_FUNCTION && declaration->is_inline) {
+ parser_print_warning_prefix_pos(declaration->source_position);
+ fprintf(stderr, "variable '%s' declared 'inline'\n",
+ declaration->symbol->string);
+ }
+
+ if(token.type == '=') {
+ next_token();
+
+ /* TODO: check that this is an allowed type (no function type) */
+
+ if(declaration->init.initializer != NULL) {
+ parser_error_multiple_definition(declaration, ndeclaration);
+ }
+
+ initializer_t *initializer = parse_initializer(type);
+
+ if(type->type == TYPE_ARRAY && initializer != NULL) {
+ array_type_t *array_type = &type->array;
+
+ if(array_type->size == NULL) {
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+
+ cnst->base.datatype = type_size_t;
+
+ if(initializer->type == INITIALIZER_LIST) {
+ initializer_list_t *list = &initializer->list;
+ cnst->conste.v.int_value = list->len;
+ } else {
+ assert(initializer->type == INITIALIZER_STRING);
+ initializer_string_t *string = &initializer->string;
+ cnst->conste.v.int_value = strlen(string->string) + 1;
+ }
+
+ array_type->size = cnst;
+ }
+ }
+
+
+ ndeclaration->init.initializer = initializer;
+ } else if(token.type == '{') {
+ if(type->type != TYPE_FUNCTION) {
+ parser_print_error_prefix();
+ fprintf(stderr, "declarator '");
+ print_type_ext(orig_type, declaration->symbol, NULL);
+ fprintf(stderr, "' has a body but is not a function type.\n");
+ eat_block();
+ continue;
+ }
+ function_type_t *function_type = &type->function;
+ /* § 6.7.5.3 (14) a function definition with () means no
+ * parameters */
+ if(function_type->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);
+ }
+ function_type = &type->function;
+ }
+
+ if(declaration->init.statement != NULL) {
+ parser_error_multiple_definition(declaration, ndeclaration);
+ }
+ if(ndeclaration != declaration) {
+ memcpy(&declaration->context, &ndeclaration->context,
+ sizeof(declaration->context));
+ }
+
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ /* push function parameters */
+ declaration_t *parameter = declaration->context.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ environment_push(parameter);
+ }
+
+ int label_stack_top = label_top();
+ declaration_t *old_current_function = current_function;
+ current_function = declaration;
+
+ statement_t *statement = parse_compound_statement();
+
+ assert(current_function == declaration);
+ current_function = old_current_function;
+ label_pop_to(label_stack_top);
+
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+
+ declaration->init.statement = statement;
+ return;
+ }
+
+ if(token.type != ',')
+ break;
+ next_token();
+ }
+ expect_void(';');
+}
+
+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, specifiers->type, true);
+
+ /* TODO: check constraints for struct declarations */
+ /* TODO: check for doubled fields */
+ record_declaration(declaration);
+
+ if(token.type == ':') {
+ next_token();
+ parse_constant_expression();
+ /* TODO (bitfields) */
+ }
+ }
+
+ if(token.type != ',')