mirror of https://github.com/rui314/chibicc
Add a notion of an incomplete array type
This commit is contained in:
parent
4f07c7e167
commit
13dd809190
|
@ -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
|
||||
|
@ -198,6 +199,7 @@ struct Type {
|
|||
TypeKind kind;
|
||||
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
|
||||
|
@ -209,6 +211,7 @@ struct Type {
|
|||
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);
|
||||
|
||||
|
|
40
codegen.c
40
codegen.c
|
@ -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
2
main.c
|
@ -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);
|
||||
|
|
82
parse.c
82
parse.c
|
@ -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();
|
||||
|
||||
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
11
type.c
|
@ -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: {
|
||||
|
|
Loading…
Reference in New Issue