+/**
+ * Checks if a given expression can be used as an constant initializer.
+ */
+static bool is_initializer_constant(const expression_t *expression)
+{
+ return is_constant_expression(expression)
+ || is_address_constant(expression);
+}
+
+/**
+ * Parses an scalar initializer.
+ *
+ * § 6.7.8.11; eat {} without warning
+ */
+static initializer_t *parse_scalar_initializer(type_t *type,
+ bool must_be_constant)
+{
+ /* there might be extra {} hierarchies */
+ int braces = 0;
+ while(token.type == '{') {
+ next_token();
+ if(braces == 0) {
+ warningf(HERE, "extra curly braces around scalar initializer");
+ }
+ braces++;
+ }
+
+ expression_t *expression = parse_assignment_expression();
+ if(must_be_constant && !is_initializer_constant(expression)) {
+ errorf(expression->base.source_position,
+ "Initialisation expression '%E' is not constant\n",
+ expression);
+ }
+
+ initializer_t *initializer = initializer_from_expression(type, expression);
+
+ if(initializer == NULL) {
+ errorf(expression->base.source_position,
+ "expression '%E' doesn't match expected type '%T'",
+ expression, type);
+ /* TODO */
+ return NULL;
+ }
+
+ bool additional_warning_displayed = false;
+ while(braces > 0) {
+ if(token.type == ',') {
+ next_token();
+ }
+ if(token.type != '}') {
+ if(!additional_warning_displayed) {
+ warningf(HERE, "additional elements in scalar initializer");
+ additional_warning_displayed = true;
+ }
+ }
+ eat_block();
+ braces--;
+ }
+
+ return initializer;
+}
+
+/**
+ * An entry in the type path.
+ */
+typedef struct type_path_entry_t type_path_entry_t;
+struct type_path_entry_t {
+ type_t *type; /**< the upper top type. restored to path->top_tye if this entry is popped. */
+ union {
+ size_t index; /**< For array types: the current index. */
+ declaration_t *compound_entry; /**< For compound types: the current declaration. */
+ } v;
+};
+
+/**
+ * A type path expression a position inside compound or array types.
+ */
+typedef struct type_path_t type_path_t;
+struct type_path_t {
+ type_path_entry_t *path; /**< An flexible array containing the current path. */
+ type_t *top_type; /**< type of the element the path points */
+ size_t max_index; /**< largest index in outermost array */
+};
+
+/**
+ * Prints a type path for debugging.
+ */
+static __attribute__((unused)) void debug_print_type_path(
+ const type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+
+ for(size_t i = 0; i < len; ++i) {
+ const type_path_entry_t *entry = & path->path[i];
+
+ type_t *type = skip_typeref(entry->type);
+ if(is_type_compound(type)) {
+ /* in gcc mode structs can have no members */
+ if(entry->v.compound_entry == NULL) {
+ assert(i == len-1);
+ continue;
+ }
+ fprintf(stderr, ".%s", entry->v.compound_entry->symbol->string);
+ } else if(is_type_array(type)) {
+ fprintf(stderr, "[%zd]", entry->v.index);
+ } else {
+ fprintf(stderr, "-INVALID-");
+ }
+ }
+ if(path->top_type != NULL) {
+ fprintf(stderr, " (");
+ print_type(path->top_type);
+ fprintf(stderr, ")");
+ }
+}
+
+/**
+ * Return the top type path entry, ie. in a path
+ * (type).a.b returns the b.
+ */
+static type_path_entry_t *get_type_path_top(const type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ assert(len > 0);
+ return &path->path[len-1];
+}
+
+/**
+ * Enlarge the type path by an (empty) element.
+ */
+static type_path_entry_t *append_to_type_path(type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len+1);
+
+ type_path_entry_t *result = & path->path[len];
+ memset(result, 0, sizeof(result[0]));
+ return result;
+}
+
+/**
+ * Descending into a sub-type. Enter the scope of the current
+ * top_type.
+ */
+static void descend_into_subtype(type_path_t *path)
+{
+ type_t *orig_top_type = path->top_type;
+ type_t *top_type = skip_typeref(orig_top_type);
+
+ assert(is_type_compound(top_type) || is_type_array(top_type));
+
+ type_path_entry_t *top = append_to_type_path(path);
+ top->type = top_type;
+
+ if(is_type_compound(top_type)) {
+ declaration_t *declaration = top_type->compound.declaration;
+ declaration_t *entry = declaration->scope.declarations;
+ top->v.compound_entry = entry;
+
+ if(entry != NULL) {
+ path->top_type = entry->type;
+ } else {
+ path->top_type = NULL;
+ }
+ } else {
+ assert(is_type_array(top_type));
+
+ top->v.index = 0;
+ path->top_type = top_type->array.element_type;
+ }
+}
+
+/**
+ * Pop an entry from the given type path, ie. returning from
+ * (type).a.b to (type).a
+ */
+static void ascend_from_subtype(type_path_t *path)
+{
+ type_path_entry_t *top = get_type_path_top(path);
+
+ path->top_type = top->type;
+
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len-1);
+}
+
+/**
+ * Pop entries from the given type path until the given
+ * path level is reached.
+ */
+static void ascend_to(type_path_t *path, size_t top_path_level)
+{
+ size_t len = ARR_LEN(path->path);
+
+ while(len > top_path_level) {
+ ascend_from_subtype(path);
+ len = ARR_LEN(path->path);
+ }
+}
+
+static bool walk_designator(type_path_t *path, const designator_t *designator,
+ bool used_in_offsetof)
+{
+ for( ; designator != NULL; designator = designator->next) {
+ type_path_entry_t *top = get_type_path_top(path);
+ type_t *orig_type = top->type;
+
+ type_t *type = skip_typeref(orig_type);
+
+ if(designator->symbol != NULL) {
+ symbol_t *symbol = designator->symbol;
+ if(!is_type_compound(type)) {
+ if(is_type_valid(type)) {
+ errorf(designator->source_position,
+ "'.%Y' designator used for non-compound type '%T'",
+ symbol, orig_type);
+ }
+ goto failed;
+ }
+
+ declaration_t *declaration = type->compound.declaration;
+ declaration_t *iter = declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next) {
+ if(iter->symbol == symbol) {
+ break;
+ }
+ }
+ if(iter == NULL) {
+ errorf(designator->source_position,
+ "'%T' has no member named '%Y'", orig_type, symbol);
+ goto failed;
+ }
+ if(used_in_offsetof) {
+ type_t *real_type = skip_typeref(iter->type);
+ if(real_type->kind == TYPE_BITFIELD) {
+ errorf(designator->source_position,
+ "offsetof designator '%Y' may not specify bitfield",
+ symbol);
+ goto failed;
+ }
+ }
+
+ top->type = orig_type;
+ top->v.compound_entry = iter;
+ orig_type = iter->type;
+ } else {
+ expression_t *array_index = designator->array_index;
+ assert(designator->array_index != NULL);
+
+ if(!is_type_array(type)) {
+ if(is_type_valid(type)) {
+ errorf(designator->source_position,
+ "[%E] designator used for non-array type '%T'",
+ array_index, orig_type);
+ }
+ goto failed;
+ }
+ if(!is_type_valid(array_index->base.type)) {
+ goto failed;
+ }
+
+ long index = fold_constant(array_index);
+ if(!used_in_offsetof) {
+ if(index < 0) {
+ errorf(designator->source_position,
+ "array index [%E] must be positive", array_index);
+ goto failed;
+ }
+ if(type->array.size_constant == true) {
+ long array_size = type->array.size;
+ if(index >= array_size) {
+ errorf(designator->source_position,
+ "designator [%E] (%d) exceeds array size %d",
+ array_index, index, array_size);
+ goto failed;
+ }
+ }
+ }
+
+ top->type = orig_type;
+ top->v.index = (size_t) index;
+ orig_type = type->array.element_type;
+ }
+ path->top_type = orig_type;
+
+ if(designator->next != NULL) {
+ descend_into_subtype(path);
+ }
+ }
+ return true;
+
+failed:
+ return false;
+}
+
+static void advance_current_object(type_path_t *path, size_t top_path_level)
+{
+ type_path_entry_t *top = get_type_path_top(path);
+
+ type_t *type = skip_typeref(top->type);
+ if(is_type_union(type)) {
+ /* in unions only the first element is initialized */
+ top->v.compound_entry = NULL;
+ } else if(is_type_struct(type)) {
+ declaration_t *entry = top->v.compound_entry;
+
+ entry = entry->next;
+ top->v.compound_entry = entry;
+ if(entry != NULL) {
+ path->top_type = entry->type;
+ return;
+ }
+ } else {
+ assert(is_type_array(type));
+
+ top->v.index++;
+
+ if(!type->array.size_constant || top->v.index < type->array.size) {
+ return;
+ }
+ }
+
+ /* we're past the last member of the current sub-aggregate, try if we
+ * can ascend in the type hierarchy and continue with another subobject */
+ size_t len = ARR_LEN(path->path);
+
+ if(len > top_path_level) {
+ ascend_from_subtype(path);
+ advance_current_object(path, top_path_level);
+ } else {
+ path->top_type = NULL;
+ }
+}
+
+/**
+ * skip until token is found.
+ */
+static void skip_until(int type) {
+ while(token.type != type) {
+ if(token.type == T_EOF)
+ return;
+ next_token();
+ }
+}
+
+/**
+ * skip any {...} blocks until a closing braket is reached.
+ */
+static void skip_initializers(void)
+{
+ if(token.type == '{')
+ next_token();
+
+ while(token.type != '}') {
+ if(token.type == T_EOF)
+ return;
+ if(token.type == '{') {
+ eat_block();
+ continue;
+ }
+ next_token();
+ }
+}
+
+static initializer_t *create_empty_initializer(void)