mirror of https://github.com/rui314/chibicc
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:
parent
0d717373cc
commit
5b95533603
46
parse.c
46
parse.c
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue