+ /* descend into subtype */
+ initializer_t *result = NULL;
+ initializer_t **elems;
+ if(is_type_array(type)) {
+ array_type_t *array_type = &type->array;
+ type_t *element_type = array_type->element_type;
+ element_type = skip_typeref(element_type);
+
+ if(token.type == '.') {
+ errorf(HERE,
+ "compound designator in initializer for array type '%T'",
+ type);
+ skip_designator();
+ }
+
+ initializer_t *sub;
+ had_initializer_brace_warning = false;
+ if(expression == NULL) {
+ sub = parse_sub_initializer_elem(element_type);
+ } else {
+ sub = parse_sub_initializer(element_type, expression,
+ expression_type);
+ }
+
+ /* didn't match the subtypes -> try the parent type */
+ if(sub == NULL) {
+ assert(!read_paren);
+ return NULL;
+ }
+
+ elems = NEW_ARR_F(initializer_t*, 0);
+ ARR_APP1(initializer_t*, elems, sub);
+
+ while(true) {
+ if(token.type == '}')
+ break;
+ expect_block(',');
+ if(token.type == '}')
+ break;
+
+ sub = parse_sub_initializer_elem(element_type);
+ if(sub == NULL) {
+ /* TODO error, do nicer cleanup */
+ errorf(HERE, "member initializer didn't match");
+ DEL_ARR_F(elems);
+ return NULL;
+ }
+ ARR_APP1(initializer_t*, elems, sub);
+ }
+ } else {
+ assert(is_type_compound(type));
+ compound_type_t *compound_type = &type->compound;
+ context_t *context = &compound_type->declaration->context;
+
+ if(token.type == '[') {
+ errorf(HERE,
+ "array designator in initializer for compound type '%T'",
+ type);
+ skip_designator();
+ }
+
+ declaration_t *first = context->declarations;
+ if(first == NULL)
+ return NULL;
+ type_t *first_type = first->type;
+ first_type = skip_typeref(first_type);
+
+ initializer_t *sub;
+ had_initializer_brace_warning = false;
+ if(expression == NULL) {
+ sub = parse_sub_initializer_elem(first_type);
+ } else {
+ sub = parse_sub_initializer(first_type, expression,expression_type);
+ }
+
+ /* didn't match the subtypes -> try our parent type */
+ if(sub == NULL) {
+ assert(!read_paren);
+ return NULL;
+ }
+
+ elems = NEW_ARR_F(initializer_t*, 0);
+ ARR_APP1(initializer_t*, elems, sub);
+
+ declaration_t *iter = first->next;
+ for( ; iter != NULL; iter = iter->next) {
+ if(iter->symbol == NULL)
+ continue;
+ if(iter->namespc != NAMESPACE_NORMAL)
+ continue;
+
+ if(token.type == '}')
+ break;
+ expect_block(',');
+ if(token.type == '}')
+ break;
+
+ type_t *iter_type = iter->type;
+ iter_type = skip_typeref(iter_type);
+
+ sub = parse_sub_initializer_elem(iter_type);
+ if(sub == NULL) {
+ /* TODO error, do nicer cleanup */
+ errorf(HERE, "member initializer didn't match");
+ DEL_ARR_F(elems);
+ return NULL;
+ }
+ ARR_APP1(initializer_t*, elems, sub);
+ }
+ }
+
+ int len = ARR_LEN(elems);
+ size_t elems_size = sizeof(initializer_t*) * len;
+
+ initializer_list_t *init = allocate_ast_zero(sizeof(init[0]) + elems_size);
+
+ init->initializer.kind = INITIALIZER_LIST;
+ init->len = len;
+ memcpy(init->initializers, elems, elems_size);
+ DEL_ARR_F(elems);
+
+ result = (initializer_t*) init;
+
+ if(read_paren) {
+ if(token.type == ',')
+ next_token();
+ expect('}');
+ }
+ return result;
+}
+
+static initializer_t *parse_initializer(type_t *type)
+{
+ initializer_t *result;
+
+ type = skip_typeref(type);
+
+ if(token.type != '{') {
+ expression_t *expression = parse_assignment_expression();
+ initializer_t *initializer = initializer_from_expression(type, expression);
+ if(initializer == NULL) {
+ errorf(HERE, "initializer expression '%E', type '%T' is incompatible with type '%T'", expression, expression->base.datatype, type);
+ }
+ return initializer;
+ }
+
+ if(is_type_scalar(type)) {
+ /* § 6.7.8.11 */
+ eat('{');
+
+ expression_t *expression = parse_assignment_expression();
+ result = initializer_from_expression(type, expression);
+
+ if(token.type == ',')
+ next_token();
+
+ expect('}');
+ return result;
+ } else {
+ result = parse_sub_initializer(type, NULL, NULL);
+ }
+
+ return result;
+}
+
+static declaration_t *append_declaration(declaration_t *declaration);
+
+static declaration_t *parse_compound_type_specifier(bool is_struct)
+{
+ if(is_struct) {
+ eat(T_struct);
+ } else {
+ eat(T_union);
+ }
+
+ symbol_t *symbol = NULL;
+ declaration_t *declaration = NULL;
+
+ if (token.type == T___attribute__) {
+ /* TODO */
+ parse_attributes();
+ }
+
+ if(token.type == T_IDENTIFIER) {
+ symbol = token.v.symbol;
+ next_token();
+
+ if(is_struct) {
+ declaration = get_declaration(symbol, NAMESPACE_STRUCT);
+ } else {
+ declaration = get_declaration(symbol, NAMESPACE_UNION);
+ }
+ } else if(token.type != '{') {
+ if(is_struct) {
+ parse_error_expected("while parsing struct type specifier",
+ T_IDENTIFIER, '{', 0);
+ } else {
+ parse_error_expected("while parsing union type specifier",
+ T_IDENTIFIER, '{', 0);
+ }
+
+ return NULL;
+ }
+
+ if(declaration == NULL) {
+ declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ if(is_struct) {
+ declaration->namespc = NAMESPACE_STRUCT;
+ } else {
+ declaration->namespc = NAMESPACE_UNION;
+ }
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_context = context;
+ if (symbol != NULL) {
+ environment_push(declaration);
+ }
+ append_declaration(declaration);
+ }
+
+ if(token.type == '{') {
+ if(declaration->init.is_defined) {
+ assert(symbol != NULL);
+ errorf(HERE, "multiple definition of '%s %Y'",
+ is_struct ? "struct" : "union", symbol);
+ declaration->context.declarations = NULL;
+ }
+ declaration->init.is_defined = true;
+
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ parse_compound_type_entries();
+ parse_attributes();
+
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+ }
+
+ return declaration;
+}
+
+static void parse_enum_entries(enum_type_t *const enum_type)
+{
+ eat('{');
+
+ if(token.type == '}') {
+ next_token();
+ errorf(HERE, "empty enum not allowed");
+ return;
+ }
+
+ do {
+ declaration_t *entry = allocate_ast_zero(sizeof(entry[0]));
+
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing enum entry", T_IDENTIFIER, 0);
+ eat_block();
+ return;
+ }
+ entry->storage_class = STORAGE_CLASS_ENUM_ENTRY;
+ entry->type = (type_t*) enum_type;
+ entry->symbol = token.v.symbol;
+ entry->source_position = token.source_position;
+ next_token();
+
+ if(token.type == '=') {
+ next_token();
+ entry->init.enum_value = parse_constant_expression();
+
+ /* TODO semantic */
+ }
+
+ record_declaration(entry);
+
+ if(token.type != ',')
+ break;
+ next_token();
+ } while(token.type != '}');
+
+ expect_void('}');
+}
+
+static type_t *parse_enum_specifier(void)
+{
+ eat(T_enum);
+
+ declaration_t *declaration;
+ symbol_t *symbol;
+
+ if(token.type == T_IDENTIFIER) {
+ symbol = token.v.symbol;
+ next_token();
+
+ declaration = get_declaration(symbol, NAMESPACE_ENUM);
+ } else if(token.type != '{') {
+ parse_error_expected("while parsing enum type specifier",
+ T_IDENTIFIER, '{', 0);
+ return NULL;
+ } else {
+ declaration = NULL;
+ symbol = NULL;
+ }
+
+ if(declaration == NULL) {
+ declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->namespc = NAMESPACE_ENUM;
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_context = context;
+ }
+
+ type_t *const type = allocate_type_zero(TYPE_ENUM);
+ type->enumt.declaration = declaration;
+
+ if(token.type == '{') {
+ if(declaration->init.is_defined) {
+ errorf(HERE, "multiple definitions of enum %Y", symbol);
+ }
+ if (symbol != NULL) {
+ environment_push(declaration);
+ }
+ append_declaration(declaration);
+ declaration->init.is_defined = 1;
+
+ parse_enum_entries(&type->enumt);
+ parse_attributes();
+ }
+
+ return type;
+}
+
+/**
+ * if a symbol is a typedef to another type, return true
+ */
+static bool is_typedef_symbol(symbol_t *symbol)
+{
+ const declaration_t *const declaration =
+ get_declaration(symbol, NAMESPACE_NORMAL);
+ return
+ declaration != NULL &&
+ declaration->storage_class == STORAGE_CLASS_TYPEDEF;
+}
+
+static type_t *parse_typeof(void)
+{
+ eat(T___typeof__);
+
+ type_t *type;
+
+ expect('(');
+
+ expression_t *expression = NULL;
+
+restart:
+ switch(token.type) {
+ case T___extension__:
+ /* this can be a prefix to a typename or an expression */
+ /* we simply eat it now. */
+ do {
+ next_token();
+ } while(token.type == T___extension__);
+ goto restart;
+
+ case T_IDENTIFIER:
+ if(is_typedef_symbol(token.v.symbol)) {
+ type = parse_typename();
+ } else {
+ expression = parse_expression();
+ type = expression->base.datatype;
+ }
+ break;
+
+ TYPENAME_START
+ type = parse_typename();
+ break;
+
+ default:
+ expression = parse_expression();
+ type = expression->base.datatype;
+ break;
+ }
+
+ expect(')');
+
+ type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF);
+ typeof_type->typeoft.expression = expression;
+ typeof_type->typeoft.typeof_type = type;
+
+ return typeof_type;
+}
+
+typedef enum {
+ SPECIFIER_SIGNED = 1 << 0,
+ SPECIFIER_UNSIGNED = 1 << 1,
+ SPECIFIER_LONG = 1 << 2,
+ SPECIFIER_INT = 1 << 3,
+ SPECIFIER_DOUBLE = 1 << 4,
+ SPECIFIER_CHAR = 1 << 5,
+ SPECIFIER_SHORT = 1 << 6,
+ SPECIFIER_LONG_LONG = 1 << 7,
+ SPECIFIER_FLOAT = 1 << 8,
+ SPECIFIER_BOOL = 1 << 9,
+ SPECIFIER_VOID = 1 << 10,
+#ifdef PROVIDE_COMPLEX
+ SPECIFIER_COMPLEX = 1 << 11,
+ SPECIFIER_IMAGINARY = 1 << 12,
+#endif
+} specifiers_t;
+
+static type_t *create_builtin_type(symbol_t *const symbol,
+ type_t *const real_type)
+{
+ type_t *type = allocate_type_zero(TYPE_BUILTIN);
+ type->builtin.symbol = symbol;
+ type->builtin.real_type = real_type;
+
+ type_t *result = typehash_insert(type);
+ if (type != result) {
+ free_type(type);
+ }
+
+ return result;
+}
+
+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)
+ return NULL;
+
+ type_t *type = allocate_type_zero(TYPE_TYPEDEF);
+ type->typedeft.declaration = declaration;
+
+ return type;
+}
+
+static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
+{
+ type_t *type = NULL;
+ unsigned type_qualifiers = 0;
+ unsigned type_specifiers = 0;
+ int newtype = 0;
+
+ specifiers->source_position = token.source_position;
+
+ while(true) {
+ switch(token.type) {
+
+ /* storage class */
+#define MATCH_STORAGE_CLASS(token, class) \
+ case token: \
+ if(specifiers->storage_class != STORAGE_CLASS_NONE) { \
+ errorf(HERE, "multiple storage classes in declaration specifiers"); \
+ } \
+ specifiers->storage_class = class; \
+ next_token(); \
+ break;
+
+ MATCH_STORAGE_CLASS(T_typedef, STORAGE_CLASS_TYPEDEF)
+ MATCH_STORAGE_CLASS(T_extern, STORAGE_CLASS_EXTERN)
+ MATCH_STORAGE_CLASS(T_static, STORAGE_CLASS_STATIC)
+ MATCH_STORAGE_CLASS(T_auto, STORAGE_CLASS_AUTO)
+ MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
+
+ case T___thread:
+ switch (specifiers->storage_class) {
+ case STORAGE_CLASS_NONE:
+ specifiers->storage_class = STORAGE_CLASS_THREAD;
+ break;
+
+ case STORAGE_CLASS_EXTERN:
+ specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN;
+ break;
+
+ case STORAGE_CLASS_STATIC:
+ specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC;
+ break;
+
+ default:
+ errorf(HERE, "multiple storage classes in declaration specifiers");
+ break;
+ }
+ next_token();
+ break;
+
+ /* type qualifiers */
+#define MATCH_TYPE_QUALIFIER(token, qualifier) \
+ case token: \
+ type_qualifiers |= qualifier; \
+ next_token(); \
+ break;
+
+ MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
+ MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
+ MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+
+ case T___extension__:
+ /* TODO */
+ next_token();
+ break;
+
+ /* type specifiers */
+#define MATCH_SPECIFIER(token, specifier, name) \
+ case token: \
+ next_token(); \
+ if(type_specifiers & specifier) { \
+ errorf(HERE, "multiple " name " type specifiers given"); \
+ } else { \
+ type_specifiers |= specifier; \
+ } \
+ break;
+
+ MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void")
+ MATCH_SPECIFIER(T_char, SPECIFIER_CHAR, "char")
+ MATCH_SPECIFIER(T_short, SPECIFIER_SHORT, "short")
+ MATCH_SPECIFIER(T_int, SPECIFIER_INT, "int")
+ MATCH_SPECIFIER(T_float, SPECIFIER_FLOAT, "float")
+ MATCH_SPECIFIER(T_double, SPECIFIER_DOUBLE, "double")
+ MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed")
+ MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned")
+ MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool")
+#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;
+
+ case T_inline:
+ next_token();
+ specifiers->is_inline = true;
+ break;
+
+ case T_long:
+ next_token();
+ if(type_specifiers & SPECIFIER_LONG_LONG) {
+ errorf(HERE, "multiple type specifiers given");
+ } else if(type_specifiers & SPECIFIER_LONG) {
+ type_specifiers |= SPECIFIER_LONG_LONG;
+ } else {
+ type_specifiers |= SPECIFIER_LONG;
+ }
+ break;
+
+ /* TODO: if type != NULL for the following rules should issue
+ * an error */
+ case T_struct: {
+ type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
+
+ type->compound.declaration = parse_compound_type_specifier(true);
+ break;
+ }
+ case T_union: {
+ type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
+
+ type->compound.declaration = parse_compound_type_specifier(false);
+ break;
+ }
+ case T_enum:
+ type = parse_enum_specifier();
+ break;
+ case T___typeof__:
+ type = parse_typeof();
+ break;
+ case T___builtin_va_list:
+ type = duplicate_type(type_valist);
+ next_token();
+ break;
+
+ case T___attribute__:
+ /* TODO */
+ parse_attributes();
+ break;
+
+ case T_IDENTIFIER: {
+ type_t *typedef_type = get_typedef_type(token.v.symbol);
+
+ if(typedef_type == NULL)
+ goto finish_specifiers;
+
+ next_token();
+ type = typedef_type;
+ break;
+ }
+
+ /* function specifier */
+ default:
+ goto finish_specifiers;
+ }
+ }
+
+finish_specifiers:
+
+ if(type == NULL) {
+ atomic_type_kind_t atomic_type;
+
+ /* match valid basic types */
+ switch(type_specifiers) {
+ case SPECIFIER_VOID:
+ atomic_type = ATOMIC_TYPE_VOID;
+ break;
+ case SPECIFIER_CHAR:
+ atomic_type = ATOMIC_TYPE_CHAR;
+ break;
+ case SPECIFIER_SIGNED | SPECIFIER_CHAR:
+ atomic_type = ATOMIC_TYPE_SCHAR;
+ break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_CHAR:
+ atomic_type = ATOMIC_TYPE_UCHAR;
+ break;
+ case SPECIFIER_SHORT:
+ case SPECIFIER_SIGNED | SPECIFIER_SHORT:
+ case SPECIFIER_SHORT | SPECIFIER_INT:
+ case SPECIFIER_SIGNED | SPECIFIER_SHORT | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_SHORT;
+ break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_SHORT:
+ case SPECIFIER_UNSIGNED | SPECIFIER_SHORT | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_USHORT;
+ break;
+ case SPECIFIER_INT: