Add a notion of an incomplete array type

This commit is contained in:
Rui Ueyama 2019-08-13 21:03:20 +09:00
parent 4f07c7e167
commit 13dd809190
5 changed files with 94 additions and 62 deletions

View File

@ -64,6 +64,7 @@ typedef struct Var Var;
struct Var {
char *name; // Variable name
Type *ty; // Type
Token *tok; // for error message
bool is_local; // local or global
// Local variable
@ -196,19 +197,21 @@ typedef enum {
struct Type {
TypeKind kind;
bool is_typedef; // typedef
bool is_static; // static
int align; // alignment
Type *base; // pointer or array
int array_size; // array
Member *members; // struct
Type *return_ty; // function
bool is_typedef; // typedef
bool is_static; // static
bool is_incomplete; // incomplete array
int align; // alignment
Type *base; // pointer or array
int array_size; // array
Member *members; // struct
Type *return_ty; // function
};
// Struct member
struct Member {
Member *next;
Type *ty;
Token *tok; // for error message
char *name;
int offset;
};
@ -224,7 +227,7 @@ Type *enum_type();
Type *func_type(Type *return_ty);
Type *pointer_to(Type *base);
Type *array_of(Type *base, int size);
int size_of(Type *ty);
int size_of(Type *ty, Token *tok);
void add_type(Program *prog);

View File

@ -46,7 +46,7 @@ void gen_lval(Node *node) {
void load(Type *ty) {
printf(" pop rax\n");
int sz = size_of(ty);
int sz = size_of(ty, NULL);
if (sz == 1) {
printf(" movsx rax, byte ptr [rax]\n");
} else if (sz == 2) {
@ -71,7 +71,7 @@ void store(Type *ty) {
printf(" movzb rdi, dil\n");
}
int sz = size_of(ty);
int sz = size_of(ty, NULL);
if (sz == 1) {
printf(" mov [rax], dil\n");
} else if (sz == 2) {
@ -94,7 +94,7 @@ void truncate(Type *ty) {
printf(" setne al\n");
}
int sz = size_of(ty);
int sz = size_of(ty, NULL);
if (sz == 1) {
printf(" movsx rax, al\n");
} else if (sz == 2) {
@ -105,15 +105,17 @@ void truncate(Type *ty) {
printf(" push rax\n");
}
void inc(Type *ty) {
void inc(Node *node) {
int sz = node->ty->base ? size_of(node->ty->base, node->tok) : 1;
printf(" pop rax\n");
printf(" add rax, %d\n", ty->base ? size_of(ty->base) : 1);
printf(" add rax, %d\n", sz);
printf(" push rax\n");
}
void dec(Type *ty) {
void dec(Node *node) {
int sz = node->ty->base ? size_of(node->ty->base, node->tok) : 1;
printf(" pop rax\n");
printf(" sub rax, %d\n", ty->base ? size_of(ty->base) : 1);
printf(" sub rax, %d\n", sz);
printf(" push rax\n");
}
@ -149,31 +151,31 @@ void gen(Node *node) {
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
inc(node->ty);
inc(node);
store(node->ty);
return;
case ND_PRE_DEC:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
dec(node->ty);
dec(node);
store(node->ty);
return;
case ND_POST_INC:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
inc(node->ty);
inc(node);
store(node->ty);
dec(node->ty);
dec(node);
return;
case ND_POST_DEC:
gen_lval(node->lhs);
printf(" push [rsp]\n");
load(node->ty);
dec(node->ty);
dec(node);
store(node->ty);
inc(node->ty);
inc(node);
return;
case ND_A_ADD:
case ND_A_SUB:
@ -189,12 +191,12 @@ void gen(Node *node) {
switch (node->kind) {
case ND_A_ADD:
if (node->ty->base)
printf(" imul rdi, %d\n", size_of(node->ty->base));
printf(" imul rdi, %d\n", size_of(node->ty->base, node->tok));
printf(" add rax, rdi\n");
break;
case ND_A_SUB:
if (node->ty->base)
printf(" imul rdi, %d\n", size_of(node->ty->base));
printf(" imul rdi, %d\n", size_of(node->ty->base, node->tok));
printf(" sub rax, rdi\n");
break;
case ND_A_MUL:
@ -378,12 +380,12 @@ void gen(Node *node) {
switch (node->kind) {
case ND_ADD:
if (node->ty->base)
printf(" imul rdi, %d\n", size_of(node->ty->base));
printf(" imul rdi, %d\n", size_of(node->ty->base, node->tok));
printf(" add rax, rdi\n");
break;
case ND_SUB:
if (node->ty->base)
printf(" imul rdi, %d\n", size_of(node->ty->base));
printf(" imul rdi, %d\n", size_of(node->ty->base, node->tok));
printf(" sub rax, rdi\n");
break;
case ND_MUL:
@ -435,7 +437,7 @@ void emit_data(Program *prog) {
printf("%s:\n", var->name);
if (!var->contents) {
printf(" .zero %d\n", size_of(var->ty));
printf(" .zero %d\n", size_of(var->ty, var->tok));
continue;
}
@ -445,7 +447,7 @@ void emit_data(Program *prog) {
}
void load_arg(Var *var, int idx) {
int sz = size_of(var->ty);
int sz = size_of(var->ty, var->tok);
if (sz == 1) {
printf(" mov [rbp-%d], %s\n", var->offset, argreg1[idx]);
} else if (sz == 2) {

2
main.c
View File

@ -37,7 +37,7 @@ int main(int argc, char **argv) {
for (VarList *vl = fn->locals; vl; vl = vl->next) {
Var *var = vl->var;
offset = align_to(offset, var->ty->align);
offset += size_of(var->ty);
offset += size_of(var->ty, var->tok);
var->offset = offset;
}
fn->stack_size = align_to(offset, 8);

84
parse.c
View File

@ -19,12 +19,29 @@ struct TagScope {
Type *ty;
};
typedef struct {
VarScope *var_scope;
TagScope *tag_scope;
} Scope;
VarList *locals;
VarList *globals;
VarScope *var_scope;
TagScope *tag_scope;
Scope *enter_scope() {
Scope *sc = calloc(1, sizeof(Scope));
sc->var_scope = var_scope;
sc->tag_scope = tag_scope;
return sc;
}
void leave_scope(Scope *sc) {
var_scope = sc->var_scope;
tag_scope = sc->tag_scope;
}
// Find a variable or a typedef by name.
VarScope *find_var(Token *tok) {
for (VarScope *sc = var_scope; sc; sc = sc->next) {
@ -81,11 +98,12 @@ VarScope *push_scope(char *name) {
return sc;
}
Var *push_var(char *name, Type *ty, bool is_local) {
Var *push_var(char *name, Type *ty, bool is_local, Token *tok) {
Var *var = calloc(1, sizeof(Var));
var->name = name;
var->ty = ty;
var->is_local = is_local;
var->tok = tok;
VarList *vl = calloc(1, sizeof(VarList));
vl->var = var;
@ -318,14 +336,23 @@ Type *abstract_declarator(Type *ty) {
return type_suffix(ty);
}
// type-suffix = ("[" num "]" type-suffix)?
// type-suffix = ("[" num? "]" type-suffix)?
Type *type_suffix(Type *ty) {
if (!consume("["))
return ty;
int sz = expect_number();
expect("]");
int sz = 0;
bool is_incomplete = true;
if (!consume("]")) {
sz = expect_number();
is_incomplete = false;
expect("]");
}
ty = type_suffix(ty);
return array_of(ty, sz);
ty = array_of(ty, sz);
ty->is_incomplete = is_incomplete;
return ty;
}
// type-name = type-specifier abstract-declarator type-suffix
@ -379,7 +406,7 @@ Type *struct_decl() {
for (Member *mem = ty->members; mem; mem = mem->next) {
offset = align_to(offset, mem->ty->align);
mem->offset = offset;
offset += size_of(mem->ty);
offset += size_of(mem->ty, mem->tok);
if (ty->align < mem->ty->align)
ty->align = mem->ty->align;
@ -440,6 +467,7 @@ Type *enum_specifier() {
// struct-member = type-specifier declarator type-suffix ";"
Member *struct_member() {
Type *ty = type_specifier();
Token *tok = token;
char *name = NULL;
ty = declarator(ty, &name);
ty = type_suffix(ty);
@ -448,16 +476,18 @@ Member *struct_member() {
Member *mem = calloc(1, sizeof(Member));
mem->name = name;
mem->ty = ty;
mem->tok = tok;
return mem;
}
VarList *read_func_param() {
Type *ty = type_specifier();
char *name = NULL;
Token *tok = token;
ty = declarator(ty, &name);
ty = type_suffix(ty);
Var *var = push_var(name, ty, true);
Var *var = push_var(name, ty, true, tok);
push_scope(name)->var = var;
VarList *vl = calloc(1, sizeof(VarList));
@ -489,10 +519,11 @@ Function *function() {
Type *ty = type_specifier();
char *name = NULL;
Token *tok = token;
ty = declarator(ty, &name);
// Add a function type to the scope
Var *var = push_var(name, func_type(ty), false);
Var *var = push_var(name, func_type(ty), false, tok);
push_scope(name)->var = var;
// Construct a function object
@ -523,22 +554,24 @@ Function *function() {
void global_var() {
Type *ty = type_specifier();
char *name = NULL;
Token *tok = token;
ty = declarator(ty, &name);
ty = type_suffix(ty);
expect(";");
Var *var = push_var(name, ty, false);
Var *var = push_var(name, ty, false, tok);
push_scope(name)->var = var;
}
// declaration = type-specifier declarator type-suffix ("=" expr)? ";"
// | type-specifier ";"
Node *declaration() {
Token *tok = token;
Token *tok;
Type *ty = type_specifier();
if (consume(";"))
if (tok = consume(";"))
return new_node(ND_NULL, tok);
tok = token;
char *name = NULL;
ty = declarator(ty, &name);
ty = type_suffix(ty);
@ -555,9 +588,9 @@ Node *declaration() {
Var *var;
if (ty->is_static)
var = push_var(new_label(), ty, false);
var = push_var(new_label(), ty, false, tok);
else
var = push_var(name, ty, true);
var = push_var(name, ty, true, tok);
push_scope(name)->var = var;
if (consume(";"))
@ -621,9 +654,7 @@ Node *stmt() {
if (tok = consume("for")) {
Node *node = new_node(ND_FOR, tok);
expect("(");
VarScope *sc1 = var_scope;
TagScope *sc2 = tag_scope;
Scope *sc = enter_scope();
if (!consume(";")) {
if (is_typename()) {
@ -643,8 +674,7 @@ Node *stmt() {
}
node->then = stmt();
var_scope = sc1;
tag_scope = sc2;
leave_scope(sc);
return node;
}
@ -653,14 +683,12 @@ Node *stmt() {
head.next = NULL;
Node *cur = &head;
VarScope *sc1 = var_scope;
TagScope *sc2 = tag_scope;
Scope *sc = enter_scope();
while (!consume("}")) {
cur->next = stmt();
cur = cur->next;
}
var_scope = sc1;
tag_scope = sc2;
leave_scope(sc);
Node *node = new_node(ND_BLOCK, tok);
node->body = head.next;
@ -901,9 +929,7 @@ Node *postfix() {
//
// Statement expression is a GNU C extension.
Node *stmt_expr(Token *tok) {
VarScope *sc1 = var_scope;
TagScope *sc2 = tag_scope;
Scope *sc = enter_scope();
Node *node = new_node(ND_STMT_EXPR, tok);
node->body = stmt();
Node *cur = node->body;
@ -913,9 +939,7 @@ Node *stmt_expr(Token *tok) {
cur = cur->next;
}
expect(")");
var_scope = sc1;
tag_scope = sc2;
leave_scope(sc);
if (cur->kind != ND_EXPR_STMT)
error_tok(cur->tok, "stmt expr returning void is not supported");
@ -962,7 +986,7 @@ Node *primary() {
if (is_typename()) {
Type *ty = type_name();
expect(")");
return new_num(size_of(ty), tok);
return new_num(size_of(ty, tok), tok);
}
token = tok->next;
}
@ -1001,7 +1025,7 @@ Node *primary() {
token = token->next;
Type *ty = array_of(char_type(), tok->cont_len);
Var *var = push_var(new_label(), ty, false);
Var *var = push_var(new_label(), ty, false, NULL);
var->contents = tok->contents;
var->cont_len = tok->cont_len;
return new_var(var, tok);

11
type.c
View File

@ -58,9 +58,12 @@ Type *array_of(Type *base, int size) {
return ty;
}
int size_of(Type *ty) {
int size_of(Type *ty, Token *tok) {
assert(ty->kind != TY_VOID);
if (ty->is_incomplete)
error_tok(tok, "incomplete type");
switch (ty->kind) {
case TY_BOOL:
case TY_CHAR:
@ -74,13 +77,13 @@ int size_of(Type *ty) {
case TY_PTR:
return 8;
case TY_ARRAY:
return size_of(ty->base) * ty->array_size;
return size_of(ty->base, tok) * ty->array_size;
default:
assert(ty->kind == TY_STRUCT);
Member *mem = ty->members;
while (mem->next)
mem = mem->next;
int end = mem->offset + size_of(mem->ty);
int end = mem->offset + size_of(mem->ty, mem->tok);
return align_to(end, ty->align);
}
}
@ -189,7 +192,7 @@ void visit(Node *node) {
case ND_SIZEOF:
node->kind = ND_NUM;
node->ty = int_type();
node->val = size_of(node->lhs->ty);
node->val = size_of(node->lhs->ty, node->tok);
node->lhs = NULL;
return;
case ND_STMT_EXPR: {