+ initializer_t **initializers = NEW_ARR_F(initializer_t*, 0);
+
+ while(true) {
+ designator_t *designator = NULL;
+ if(token.type == '.' || token.type == '[') {
+ designator = parse_designation();
+
+ /* reset path to toplevel, evaluate designator from there */
+ ascend_to(path, top_path_level);
+ if(!walk_designator(path, designator, false)) {
+ /* can't continue after designation error */
+ goto end_error;
+ }
+
+ initializer_t *designator_initializer
+ = allocate_initializer_zero(INITIALIZER_DESIGNATOR);
+ designator_initializer->designator.designator = designator;
+ ARR_APP1(initializer_t*, initializers, designator_initializer);
+ }
+
+ initializer_t *sub;
+
+ if(token.type == '{') {
+ if(type != NULL && is_type_scalar(type)) {
+ sub = parse_scalar_initializer(type, env->must_be_constant);
+ } else {
+ eat('{');
+ if(type == NULL) {
+ if (env->declaration != NULL)
+ errorf(HERE, "extra brace group at end of initializer for '%Y'",
+ env->declaration->symbol);
+ else
+ errorf(HERE, "extra brace group at end of initializer");
+ } else
+ descend_into_subtype(path);
+
+ add_anchor_token('}');
+ sub = parse_sub_initializer(path, orig_type, top_path_level+1,
+ env);
+ rem_anchor_token('}');
+
+ if(type != NULL) {
+ ascend_from_subtype(path);
+ expect('}');
+ } else {
+ expect('}');
+ goto error_parse_next;
+ }
+ }
+ } else {
+ /* must be an expression */
+ expression_t *expression = parse_assignment_expression();
+
+ if(env->must_be_constant && !is_initializer_constant(expression)) {
+ errorf(expression->base.source_position,
+ "Initialisation expression '%E' is not constant\n",
+ expression);
+ }
+
+ if(type == NULL) {
+ /* we are already outside, ... */
+ goto error_excess;
+ }
+
+ /* handle { "string" } special case */
+ if((expression->kind == EXPR_STRING_LITERAL
+ || expression->kind == EXPR_WIDE_STRING_LITERAL)
+ && outer_type != NULL) {
+ sub = initializer_from_expression(outer_type, expression);
+ if(sub != NULL) {
+ if(token.type == ',') {
+ next_token();
+ }
+ if(token.type != '}') {
+ warningf(HERE, "excessive elements in initializer for type '%T'",
+ orig_type);
+ }
+ /* TODO: eat , ... */
+ return sub;
+ }
+ }
+
+ /* descend into subtypes until expression matches type */
+ while(true) {
+ orig_type = path->top_type;
+ type = skip_typeref(orig_type);
+
+ sub = initializer_from_expression(orig_type, expression);
+ if(sub != NULL) {
+ break;
+ }
+ if(!is_type_valid(type)) {
+ goto end_error;
+ }
+ if(is_type_scalar(type)) {
+ errorf(expression->base.source_position,
+ "expression '%E' doesn't match expected type '%T'",
+ expression, orig_type);
+ goto end_error;
+ }
+
+ descend_into_subtype(path);
+ }
+ }
+
+ /* update largest index of top array */
+ const type_path_entry_t *first = &path->path[0];
+ type_t *first_type = first->type;
+ first_type = skip_typeref(first_type);
+ if(is_type_array(first_type)) {
+ size_t index = first->v.index;
+ if(index > path->max_index)
+ path->max_index = index;
+ }
+
+ if(type != NULL) {
+ /* append to initializers list */
+ ARR_APP1(initializer_t*, initializers, sub);
+ } else {
+error_excess:
+ if(env->declaration != NULL)
+ warningf(HERE, "excess elements in struct initializer for '%Y'",
+ env->declaration->symbol);
+ else
+ warningf(HERE, "excess elements in struct initializer");
+ }
+
+error_parse_next:
+ if(token.type == '}') {
+ break;
+ }
+ expect(',');
+ if(token.type == '}') {
+ break;
+ }
+
+ if(type != NULL) {
+ /* advance to the next declaration if we are not at the end */
+ advance_current_object(path, top_path_level);
+ orig_type = path->top_type;
+ if(orig_type != NULL)
+ type = skip_typeref(orig_type);
+ else
+ type = NULL;
+ }
+ }
+
+ size_t len = ARR_LEN(initializers);
+ size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]);
+ initializer_t *result = allocate_ast_zero(size);
+ result->kind = INITIALIZER_LIST;
+ result->list.len = len;
+ memcpy(&result->list.initializers, initializers,
+ len * sizeof(initializers[0]));
+
+ DEL_ARR_F(initializers);
+ ascend_to(path, top_path_level);
+
+ return result;
+
+end_error:
+ skip_initializers();
+ DEL_ARR_F(initializers);
+ ascend_to(path, top_path_level);
+ return NULL;
+}
+
+/**
+ * Parses an initializer. Parsers either a compound literal
+ * (env->declaration == NULL) or an initializer of a declaration.
+ */
+static initializer_t *parse_initializer(parse_initializer_env_t *env)
+{
+ type_t *type = skip_typeref(env->type);
+ initializer_t *result = NULL;
+ size_t max_index;
+