[GNU] Support array range designator

This commit is contained in:
Rui Ueyama 2020-09-20 15:39:38 +09:00
parent d90c73b605
commit 3d5550e29a
2 changed files with 34 additions and 11 deletions

42
parse.c
View File

@ -975,13 +975,22 @@ static void string_initializer(Token **rest, Token *tok, Initializer *init) {
// struct { int a, b, c; } x = { .c=5 }; // struct { int a, b, c; } x = { .c=5 };
// //
// The above initializer sets x.c to 5. // The above initializer sets x.c to 5.
static int array_designator(Token **rest, Token *tok, Type *ty) { static void array_designator(Token **rest, Token *tok, Type *ty, int *begin, int *end) {
Token *start = tok; *begin = const_expr(&tok, tok->next);
int i = const_expr(&tok, tok->next); if (*begin >= ty->array_len)
if (i >= ty->array_len) error_tok(tok, "array designator index exceeds array bounds");
error_tok(start, "array designator index exceeds array bounds");
if (equal(tok, "...")) {
*end = const_expr(&tok, tok->next);
if (*end >= ty->array_len)
error_tok(tok, "array designator index exceeds array bounds");
if (*end < *begin)
error_tok(tok, "array designator range [%d, %d] is empty", *begin, *end);
} else {
*end = *begin;
}
*rest = skip(tok, "]"); *rest = skip(tok, "]");
return i;
} }
// struct-designator = "." ident // struct-designator = "." ident
@ -1016,9 +1025,14 @@ static void designation(Token **rest, Token *tok, Initializer *init) {
if (equal(tok, "[")) { if (equal(tok, "[")) {
if (init->ty->kind != TY_ARRAY) if (init->ty->kind != TY_ARRAY)
error_tok(tok, "array index in non-array initializer"); error_tok(tok, "array index in non-array initializer");
int i = array_designator(&tok, tok, init->ty);
designation(&tok, tok, init->children[i]); int begin, end;
array_initializer2(rest, tok, init, i + 1); array_designator(&tok, tok, init->ty, &begin, &end);
Token *tok2;
for (int i = begin; i <= end; i++)
designation(&tok2, tok, init->children[i]);
array_initializer2(rest, tok2, init, begin + 1);
return; return;
} }
@ -1097,8 +1111,14 @@ static void array_initializer1(Token **rest, Token *tok, Initializer *init) {
first = false; first = false;
if (equal(tok, "[")) { if (equal(tok, "[")) {
i = array_designator(&tok, tok, init->ty); int begin, end;
designation(&tok, tok, init->children[i]); array_designator(&tok, tok, init->ty, &begin, &end);
Token *tok2;
for (int j = begin; j <= end; j++)
designation(&tok2, tok, init->children[j]);
tok = tok2;
i = end;
continue; continue;
} }

View File

@ -259,6 +259,9 @@ int main() {
ASSERT(4, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.b; })); ASSERT(4, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.b; }));
ASSERT(5, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.c; })); ASSERT(5, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.c; }));
ASSERT(16, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; sizeof(x); }));
ASSERT(0, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16); }));
printf("OK\n"); printf("OK\n");
return 0; return 0;
} }