Support struct tags

This commit is contained in:
Rui Ueyama 2020-10-07 10:43:02 +09:00
parent dfec1157b4
commit e1e831ea3e
2 changed files with 54 additions and 3 deletions

52
parse.c
View File

@ -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;
}

View File

@ -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;
}