mirror of https://github.com/rui314/chibicc
Support struct tags
This commit is contained in:
parent
dfec1157b4
commit
e1e831ea3e
52
parse.c
52
parse.c
|
@ -26,16 +26,30 @@ struct VarScope {
|
|||
Obj *var;
|
||||
};
|
||||
|
||||
// Scope for struct tags
|
||||
typedef struct TagScope TagScope;
|
||||
struct TagScope {
|
||||
TagScope *next;
|
||||
char *name;
|
||||
Type *ty;
|
||||
};
|
||||
|
||||
// Represents a block scope.
|
||||
typedef struct Scope Scope;
|
||||
struct Scope {
|
||||
Scope *next;
|
||||
|
||||
// C has two block scopes; one is for variables and the other is
|
||||
// for struct tags.
|
||||
VarScope *vars;
|
||||
TagScope *tags;
|
||||
};
|
||||
|
||||
// All local variable instances created during parsing are
|
||||
// accumulated to this list.
|
||||
static Obj *locals;
|
||||
|
||||
// Likewise, global variables are accumulated to this list.
|
||||
static Obj *globals;
|
||||
|
||||
static Scope *scope = &(Scope){};
|
||||
|
@ -76,6 +90,14 @@ static Obj *find_var(Token *tok) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static Type *find_tag(Token *tok) {
|
||||
for (Scope *sc = scope; sc; sc = sc->next)
|
||||
for (TagScope *sc2 = sc->tags; sc2; sc2 = sc2->next)
|
||||
if (equal(tok, sc2->name))
|
||||
return sc2->ty;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Node *new_node(NodeKind kind, Token *tok) {
|
||||
Node *node = calloc(1, sizeof(Node));
|
||||
node->kind = kind;
|
||||
|
@ -167,6 +189,14 @@ static int get_number(Token *tok) {
|
|||
return tok->val;
|
||||
}
|
||||
|
||||
static void push_tag_scope(Token *tok, Type *ty) {
|
||||
TagScope *sc = calloc(1, sizeof(TagScope));
|
||||
sc->name = strndup(tok->loc, tok->len);
|
||||
sc->ty = ty;
|
||||
sc->next = scope->tags;
|
||||
scope->tags = sc;
|
||||
}
|
||||
|
||||
// declspec = "char" | "int" | struct-decl
|
||||
static Type *declspec(Token **rest, Token *tok) {
|
||||
if (equal(tok, "char")) {
|
||||
|
@ -583,14 +613,27 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
|
|||
ty->members = head.next;
|
||||
}
|
||||
|
||||
// struct-decl = "{" struct-members
|
||||
// struct-decl = ident? "{" struct-members
|
||||
static Type *struct_decl(Token **rest, Token *tok) {
|
||||
tok = skip(tok, "{");
|
||||
// Read a struct tag.
|
||||
Token *tag = NULL;
|
||||
if (tok->kind == TK_IDENT) {
|
||||
tag = tok;
|
||||
tok = tok->next;
|
||||
}
|
||||
|
||||
if (tag && !equal(tok, "{")) {
|
||||
Type *ty = find_tag(tag);
|
||||
if (!ty)
|
||||
error_tok(tag, "unknown struct type");
|
||||
*rest = tok;
|
||||
return ty;
|
||||
}
|
||||
|
||||
// Construct a struct object.
|
||||
Type *ty = calloc(1, sizeof(Type));
|
||||
ty->kind = TY_STRUCT;
|
||||
struct_members(rest, tok, ty);
|
||||
struct_members(rest, tok->next, ty);
|
||||
ty->align = 1;
|
||||
|
||||
// Assign offsets within the struct to members.
|
||||
|
@ -605,6 +648,9 @@ static Type *struct_decl(Token **rest, Token *tok) {
|
|||
}
|
||||
ty->size = align_to(offset, ty->align);
|
||||
|
||||
// Register the struct type if a name was given.
|
||||
if (tag)
|
||||
push_tag_scope(tag, ty);
|
||||
return ty;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,11 @@ int main() {
|
|||
ASSERT(16, ({ struct {char a; int b;} x; sizeof(x); }));
|
||||
ASSERT(16, ({ struct {int a; char b;} x; sizeof(x); }));
|
||||
|
||||
ASSERT(16, ({ struct t {int a; int b;} x; struct t y; sizeof(y); }));
|
||||
ASSERT(16, ({ struct t {int a; int b;}; struct t y; sizeof(y); }));
|
||||
ASSERT(2, ({ struct t {char a[2];}; { struct t {char a[4];}; } struct t y; sizeof(y); }));
|
||||
ASSERT(3, ({ struct t {int x;}; int t=1; struct t y; y.x=2; t+y.x; }));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue