Allow parentheses in initializers to be omitted

This commit is contained in:
Rui Ueyama 2019-08-19 06:53:50 +09:00
parent 1eae5ae367
commit efa0f3366d
2 changed files with 76 additions and 17 deletions

69
parse.c
View File

@ -666,8 +666,8 @@ static int count_array_init_elements(Token *tok, Type *ty) {
return i;
}
// array-initializer = "{" initializer ("," initializer)* "}"
static void array_initializer(Token **rest, Token *tok, Initializer *init) {
// array-initializer1 = "{" initializer ("," initializer)* "}"
static void array_initializer1(Token **rest, Token *tok, Initializer *init) {
tok = skip(tok, "{");
if (init->is_flexible) {
@ -686,8 +686,23 @@ static void array_initializer(Token **rest, Token *tok, Initializer *init) {
}
}
// struct-initializer = "{" initializer ("," initializer)* "}"
static void struct_initializer(Token **rest, Token *tok, Initializer *init) {
// array-initializer2 = initializer ("," initializer)*
static void array_initializer2(Token **rest, Token *tok, Initializer *init) {
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 && !equal(tok, "}"); i++) {
if (i > 0)
tok = skip(tok, ",");
initializer2(&tok, tok, init->children[i]);
}
*rest = tok;
}
// struct-initializer1 = "{" initializer ("," initializer)* "}"
static void struct_initializer1(Token **rest, Token *tok, Initializer *init) {
tok = skip(tok, "{");
Member *mem = init->ty->members;
@ -705,12 +720,28 @@ static void struct_initializer(Token **rest, Token *tok, Initializer *init) {
}
}
// struct-initializer2 = initializer ("," initializer)*
static void struct_initializer2(Token **rest, Token *tok, Initializer *init) {
bool first = true;
for (Member *mem = init->ty->members; mem && !equal(tok, "}"); mem = mem->next) {
if (!first)
tok = skip(tok, ",");
first = false;
initializer2(&tok, tok, init->children[mem->idx]);
}
*rest = tok;
}
static void union_initializer(Token **rest, Token *tok, Initializer *init) {
// Unlike structs, union initializers take only one initializer,
// and that initializes the first union member.
tok = skip(tok, "{");
initializer2(&tok, tok, init->children[0]);
*rest = skip(tok, "}");
if (equal(tok, "{")) {
initializer2(&tok, tok->next, init->children[0]);
*rest = skip(tok, "}");
} else {
initializer2(rest, tok, init->children[0]);
}
}
// initializer = string-initializer | array-initializer
@ -723,24 +754,30 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) {
}
if (init->ty->kind == TY_ARRAY) {
array_initializer(rest, tok, init);
if (equal(tok, "{"))
array_initializer1(rest, tok, init);
else
array_initializer2(rest, tok, init);
return;
}
if (init->ty->kind == TY_STRUCT) {
if (equal(tok, "{")) {
struct_initializer1(rest, tok, init);
return;
}
// A struct can be initialized with another struct. E.g.
// `struct T x = y;` where y is a variable of type `struct T`.
// Handle that case first.
if (!equal(tok, "{")) {
Node *expr = assign(rest, tok);
add_type(expr);
if (expr->ty->kind == TY_STRUCT) {
init->expr = expr;
return;
}
Node *expr = assign(rest, tok);
add_type(expr);
if (expr->ty->kind == TY_STRUCT) {
init->expr = expr;
return;
}
struct_initializer(rest, tok, init);
struct_initializer2(rest, tok, init);
return;
}

View File

@ -7,7 +7,7 @@ long g6 = 6;
int g9[3] = {0, 1, 2};
struct {char a; int b;} g11[2] = {{1, 2}, {3, 4}};
struct {int a[2];} g12[2] = {{{1, 2}}};
union { int a; char b[8]; } g13[2] = {{0x01020304}, {0x05060708}};
union { int a; char b[8]; } g13[2] = {0x01020304, 0x05060708};
char g17[] = "foobar";
char g18[10] = "foobar";
char g19[3] = "foobar";
@ -23,6 +23,9 @@ int *g28 = &g11[1].a;
long g29 = (long)(long)g26;
struct { struct { int a[3]; } a; } g30 = {{{1,2,3}}};
int *g31=g30.a.a;
struct {int a[2];} g40[2] = {{1, 2}, 3, 4};
struct {int a[2];} g41[2] = {1, 2, 3, 4};
char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0};
int main() {
ASSERT(1, ({ int x[3]={1,2,3}; x[0]; }));
@ -136,6 +139,25 @@ int main() {
ASSERT(2, g31[1]);
ASSERT(3, g31[2]);
ASSERT(1, g40[0].a[0]);
ASSERT(2, g40[0].a[1]);
ASSERT(3, g40[1].a[0]);
ASSERT(4, g40[1].a[1]);
ASSERT(1, g41[0].a[0]);
ASSERT(2, g41[0].a[1]);
ASSERT(3, g41[1].a[0]);
ASSERT(4, g41[1].a[1]);
ASSERT(0, ({ int x[2][3]={0,1,2,3,4,5}; x[0][0]; }));
ASSERT(3, ({ int x[2][3]={0,1,2,3,4,5}; x[1][0]; }));
ASSERT(0, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[0].a; }));
ASSERT(2, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[1].a; }));
ASSERT(0, strcmp(g43[0], "foo"));
ASSERT(0, strcmp(g43[1], "bar"));
printf("OK\n");
return 0;
}