mirror of https://github.com/rui314/chibicc
Add array designated initializer
This commit is contained in:
parent
2b2fa25507
commit
c618c3b582
67
parse.c
67
parse.c
|
@ -116,6 +116,7 @@ static Type *enum_specifier(Token **rest, Token *tok);
|
|||
static Type *type_suffix(Token **rest, Token *tok, Type *ty);
|
||||
static Type *declarator(Token **rest, Token *tok, Type *ty);
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr);
|
||||
static void array_initializer2(Token **rest, Token *tok, Initializer *init, int i);
|
||||
static void initializer2(Token **rest, Token *tok, Initializer *init);
|
||||
static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty);
|
||||
static Node *lvar_initializer(Token **rest, Token *tok, Obj *var);
|
||||
|
@ -846,6 +847,49 @@ static void string_initializer(Token **rest, Token *tok, Initializer *init) {
|
|||
*rest = tok->next;
|
||||
}
|
||||
|
||||
// array-designator = "[" const-expr "]"
|
||||
//
|
||||
// C99 added the designated initializer to the language, which allows
|
||||
// programmers to move the "cursor" of an initializer to any element.
|
||||
// The syntax looks like this:
|
||||
//
|
||||
// int x[10] = { 1, 2, [5]=3, 4, 5, 6, 7 };
|
||||
//
|
||||
// `[5]` moves the cursor to the 5th element, so the 5th element of x
|
||||
// is set to 3. Initialization then continues forward in order, so
|
||||
// 6th, 7th, 8th and 9th elements are initialized with 4, 5, 6 and 7,
|
||||
// respectively. Unspecified elements (in this case, 3rd and 4th
|
||||
// elements) are initialized with zero.
|
||||
//
|
||||
// Nesting is allowed, so the following initializer is valid:
|
||||
//
|
||||
// int x[5][10] = { [5][8]=1, 2, 3 };
|
||||
//
|
||||
// It sets x[5][8], x[5][9] and x[6][0] to 1, 2 and 3, respectively.
|
||||
static int array_designator(Token **rest, Token *tok, Type *ty) {
|
||||
Token *start = tok;
|
||||
int i = const_expr(&tok, tok->next);
|
||||
if (i >= ty->array_len)
|
||||
error_tok(start, "array designator index exceeds array bounds");
|
||||
*rest = skip(tok, "]");
|
||||
return i;
|
||||
}
|
||||
|
||||
// designation = ("[" const-expr "]")* "=" initializer
|
||||
static void designation(Token **rest, Token *tok, Initializer *init) {
|
||||
if (equal(tok, "[")) {
|
||||
if (init->ty->kind != TY_ARRAY)
|
||||
error_tok(tok, "array index in non-array initializer");
|
||||
int i = array_designator(&tok, tok, init->ty);
|
||||
designation(&tok, tok, init->children[i]);
|
||||
array_initializer2(rest, tok, init, i + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
tok = skip(tok, "=");
|
||||
initializer2(rest, tok, init);
|
||||
}
|
||||
|
||||
static int count_array_init_elements(Token *tok, Type *ty) {
|
||||
Initializer *dummy = new_initializer(ty->base, false);
|
||||
int i = 0;
|
||||
|
@ -861,6 +905,7 @@ static int count_array_init_elements(Token *tok, Type *ty) {
|
|||
// array-initializer1 = "{" initializer ("," initializer)* ","? "}"
|
||||
static void array_initializer1(Token **rest, Token *tok, Initializer *init) {
|
||||
tok = skip(tok, "{");
|
||||
bool first = true;
|
||||
|
||||
if (init->is_flexible) {
|
||||
int len = count_array_init_elements(tok, init->ty);
|
||||
|
@ -868,8 +913,15 @@ static void array_initializer1(Token **rest, Token *tok, Initializer *init) {
|
|||
}
|
||||
|
||||
for (int i = 0; !consume_end(rest, tok); i++) {
|
||||
if (i > 0)
|
||||
if (!first)
|
||||
tok = skip(tok, ",");
|
||||
first = false;
|
||||
|
||||
if (equal(tok, "[")) {
|
||||
i = array_designator(&tok, tok, init->ty);
|
||||
designation(&tok, tok, init->children[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < init->ty->array_len)
|
||||
initializer2(&tok, tok, init->children[i]);
|
||||
|
@ -879,15 +931,22 @@ static void array_initializer1(Token **rest, Token *tok, Initializer *init) {
|
|||
}
|
||||
|
||||
// array-initializer2 = initializer ("," initializer)*
|
||||
static void array_initializer2(Token **rest, Token *tok, Initializer *init) {
|
||||
static void array_initializer2(Token **rest, Token *tok, Initializer *init, int i) {
|
||||
if (init->is_flexible) {
|
||||
int len = count_array_init_elements(tok, init->ty);
|
||||
*init = *new_initializer(array_of(init->ty->base, len), false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < init->ty->array_len && !is_end(tok); i++) {
|
||||
for (; i < init->ty->array_len && !is_end(tok); i++) {
|
||||
Token *start = tok;
|
||||
if (i > 0)
|
||||
tok = skip(tok, ",");
|
||||
|
||||
if (equal(tok, "[")) {
|
||||
*rest = start;
|
||||
return;
|
||||
}
|
||||
|
||||
initializer2(&tok, tok, init->children[i]);
|
||||
}
|
||||
*rest = tok;
|
||||
|
@ -950,7 +1009,7 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) {
|
|||
if (equal(tok, "{"))
|
||||
array_initializer1(rest, tok, init);
|
||||
else
|
||||
array_initializer2(rest, tok, init);
|
||||
array_initializer2(rest, tok, init, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,27 @@ int main() {
|
|||
ASSERT(0, strcmp(g65.b, "oo"));
|
||||
ASSERT(0, strcmp(g66.b, "oobar"));
|
||||
|
||||
ASSERT(4, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[0]; }));
|
||||
ASSERT(5, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[1]; }));
|
||||
ASSERT(3, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[2]; }));
|
||||
|
||||
ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][0]; }));
|
||||
ASSERT(11, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][1]; }));
|
||||
ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][2]; }));
|
||||
ASSERT(12, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][0]; }));
|
||||
ASSERT(5, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][1]; }));
|
||||
ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][2]; }));
|
||||
|
||||
ASSERT(7, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][0]; }));
|
||||
ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][1]; }));
|
||||
ASSERT(3, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][2]; }));
|
||||
ASSERT(9, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][0]; }));
|
||||
ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][1]; }));
|
||||
ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][2]; }));
|
||||
|
||||
ASSERT(7, ((int[10]){ [3]=7 })[3]);
|
||||
ASSERT(0, ((int[10]){ [3]=7 })[4]);
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue