Allow to omit array length if an initializer is given

So that you can write something like `int x[] = {1, 2, 3}`
instead of `int x[3] = {1, 2, 3}`.
This commit is contained in:
Rui Ueyama 2020-09-04 14:39:22 +09:00
parent 0d717373cc
commit 5b95533603
2 changed files with 47 additions and 8 deletions

46
parse.c
View File

@ -63,6 +63,7 @@ struct Initializer {
Initializer *next;
Type *ty;
Token *tok;
bool is_flexible;
// If it's not an aggregate type and has an initializer,
// `expr` has an initialization expression.
@ -112,7 +113,7 @@ 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);
static void initializer2(Token **rest, Token *tok, Initializer *init);
static Initializer *initializer(Token **rest, Token *tok, Type *ty);
static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty);
static Node *lvar_initializer(Token **rest, Token *tok, Obj *var);
static Node *compound_stmt(Token **rest, Token *tok);
static Node *stmt(Token **rest, Token *tok);
@ -226,14 +227,19 @@ static VarScope *push_scope(char *name) {
return sc;
}
static Initializer *new_initializer(Type *ty) {
static Initializer *new_initializer(Type *ty, bool is_flexible) {
Initializer *init = calloc(1, sizeof(Initializer));
init->ty = ty;
if (ty->kind == TY_ARRAY) {
if (is_flexible && ty->size < 0) {
init->is_flexible = true;
return init;
}
init->children = calloc(ty->array_len, sizeof(Initializer *));
for (int i = 0; i < ty->array_len; i++)
init->children[i] = new_initializer(ty->base);
init->children[i] = new_initializer(ty->base, false);
}
return init;
@ -587,8 +593,6 @@ static Node *declaration(Token **rest, Token *tok, Type *basety) {
tok = skip(tok, ",");
Type *ty = declarator(&tok, tok, basety);
if (ty->size < 0)
error_tok(tok, "variable has incomplete type");
if (ty->kind == TY_VOID)
error_tok(tok, "variable declared void");
@ -597,6 +601,11 @@ static Node *declaration(Token **rest, Token *tok, Type *basety) {
Node *expr = lvar_initializer(&tok, tok->next, var);
cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok);
}
if (var->ty->size < 0)
error_tok(ty->name, "variable has incomplete type");
if (var->ty->kind == TY_VOID)
error_tok(ty->name, "variable declared void");
}
Node *node = new_node(ND_BLOCK, tok);
@ -617,16 +626,36 @@ static Token *skip_excess_element(Token *tok) {
// string-initializer = string-literal
static void string_initializer(Token **rest, Token *tok, Initializer *init) {
if (init->is_flexible)
*init = *new_initializer(array_of(init->ty->base, tok->ty->array_len), false);
int len = MIN(init->ty->array_len, tok->ty->array_len);
for (int i = 0; i < len; i++)
init->children[i]->expr = new_num(tok->str[i], tok);
*rest = tok->next;
}
static int count_array_init_elements(Token *tok, Type *ty) {
Initializer *dummy = new_initializer(ty->base, false);
int i = 0;
for (; !equal(tok, "}"); i++) {
if (i > 0)
tok = skip(tok, ",");
initializer2(&tok, tok, dummy);
}
return i;
}
// array-initializer = "{" initializer ("," initializer)* "}"
static void array_initializer(Token **rest, Token *tok, Initializer *init) {
tok = skip(tok, "{");
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; !consume(rest, tok, "}"); i++) {
if (i > 0)
tok = skip(tok, ",");
@ -653,9 +682,10 @@ static void initializer2(Token **rest, Token *tok, Initializer *init) {
init->expr = assign(rest, tok);
}
static Initializer *initializer(Token **rest, Token *tok, Type *ty) {
Initializer *init = new_initializer(ty);
static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty) {
Initializer *init = new_initializer(ty, true);
initializer2(rest, tok, init);
*new_ty = init->ty;
return init;
}
@ -697,7 +727,7 @@ static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, Token
// x[1][0] = 8;
// x[1][1] = 9;
static Node *lvar_initializer(Token **rest, Token *tok, Obj *var) {
Initializer *init = initializer(rest, tok, var->ty);
Initializer *init = initializer(rest, tok, var->ty, &var->ty);
InitDesg desg = {NULL, 0, var};
// If a partial initializer list is given, the standard requires

View File

@ -26,6 +26,15 @@ int main() {
ASSERT('d', ({ char x[2][4]={"abc","def"}; x[1][0]; }));
ASSERT('f', ({ char x[2][4]={"abc","def"}; x[1][2]; }));
ASSERT(4, ({ int x[]={1,2,3,4}; x[3]; }));
ASSERT(16, ({ int x[]={1,2,3,4}; sizeof(x); }));
ASSERT(4, ({ char x[]="foo"; sizeof(x); }));
ASSERT(4, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(x); }));
ASSERT(2, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(y); }));
ASSERT(2, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(x); }));
ASSERT(4, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(y); }));
printf("OK\n");
return 0;
}