mirror of https://github.com/rui314/chibicc
Add union
This commit is contained in:
parent
c38f99488f
commit
198f0e8f1d
|
@ -145,6 +145,7 @@ typedef enum {
|
|||
TY_FUNC,
|
||||
TY_ARRAY,
|
||||
TY_STRUCT,
|
||||
TY_UNION,
|
||||
} TypeKind;
|
||||
|
||||
struct Type {
|
||||
|
|
50
parse.c
50
parse.c
|
@ -27,7 +27,7 @@ struct VarScope {
|
|||
Var *var;
|
||||
};
|
||||
|
||||
// Scope for struct tags
|
||||
// Scope for struct or union tags
|
||||
typedef struct TagScope TagScope;
|
||||
struct TagScope {
|
||||
TagScope *next;
|
||||
|
@ -72,6 +72,7 @@ static Node *relational(Token **rest, Token *tok);
|
|||
static Node *add(Token **rest, Token *tok);
|
||||
static Node *mul(Token **rest, Token *tok);
|
||||
static Type *struct_decl(Token **rest, Token *tok);
|
||||
static Type *union_decl(Token **rest, Token *tok);
|
||||
static Node *postfix(Token **rest, Token *tok);
|
||||
static Node *unary(Token **rest, Token *tok);
|
||||
static Node *primary(Token **rest, Token *tok);
|
||||
|
@ -225,6 +226,9 @@ static Type *typespec(Token **rest, Token *tok) {
|
|||
if (equal(tok, "struct"))
|
||||
return struct_decl(rest, tok->next);
|
||||
|
||||
if (equal(tok, "union"))
|
||||
return union_decl(rest, tok->next);
|
||||
|
||||
error_tok(tok, "typename expected");
|
||||
}
|
||||
|
||||
|
@ -310,7 +314,8 @@ static Node *declaration(Token **rest, Token *tok) {
|
|||
|
||||
// Returns true if a given token represents a type.
|
||||
static bool is_typename(Token *tok) {
|
||||
return equal(tok, "char") || equal(tok, "int") || equal(tok, "struct");
|
||||
return equal(tok, "char") || equal(tok, "int") || equal(tok, "struct") ||
|
||||
equal(tok, "union");
|
||||
}
|
||||
|
||||
// stmt = "return" expr ";"
|
||||
|
@ -626,9 +631,9 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
|
|||
ty->members = head.next;
|
||||
}
|
||||
|
||||
// struct-decl = ident? "{" struct-members
|
||||
static Type *struct_decl(Token **rest, Token *tok) {
|
||||
// Read a struct tag.
|
||||
// struct-union-decl = ident? ("{" struct-members)?
|
||||
static Type *struct_union_decl(Token **rest, Token *tok) {
|
||||
// Read a tag.
|
||||
Token *tag = NULL;
|
||||
if (tok->kind == TK_IDENT) {
|
||||
tag = tok;
|
||||
|
@ -649,6 +654,17 @@ static Type *struct_decl(Token **rest, Token *tok) {
|
|||
struct_members(rest, tok->next, ty);
|
||||
ty->align = 1;
|
||||
|
||||
// Register the struct type if a name was given.
|
||||
if (tag)
|
||||
push_tag_scope(tag, ty);
|
||||
return ty;
|
||||
}
|
||||
|
||||
// struct-decl = struct-union-decl
|
||||
static Type *struct_decl(Token **rest, Token *tok) {
|
||||
Type *ty = struct_union_decl(rest, tok);
|
||||
ty->kind = TY_STRUCT;
|
||||
|
||||
// Assign offsets within the struct to members.
|
||||
int offset = 0;
|
||||
for (Member *mem = ty->members; mem; mem = mem->next) {
|
||||
|
@ -660,10 +676,24 @@ static Type *struct_decl(Token **rest, Token *tok) {
|
|||
ty->align = mem->ty->align;
|
||||
}
|
||||
ty->size = align_to(offset, ty->align);
|
||||
return ty;
|
||||
}
|
||||
|
||||
// Register the struct type if a name was given.
|
||||
if (tag)
|
||||
push_tag_scope(tag, ty);
|
||||
// union-decl = struct-union-decl
|
||||
static Type *union_decl(Token **rest, Token *tok) {
|
||||
Type *ty = struct_union_decl(rest, tok);
|
||||
ty->kind = TY_UNION;
|
||||
|
||||
// If union, we don't have to assign offsets because they
|
||||
// are already initialized to zero. We need to compute the
|
||||
// alignment and the size though.
|
||||
for (Member *mem = ty->members; mem; mem = mem->next) {
|
||||
if (ty->align < mem->ty->align)
|
||||
ty->align = mem->ty->align;
|
||||
if (ty->size < mem->ty->size)
|
||||
ty->size = mem->ty->size;
|
||||
}
|
||||
ty->size = align_to(ty->size, ty->align);
|
||||
return ty;
|
||||
}
|
||||
|
||||
|
@ -677,8 +707,8 @@ static Member *get_struct_member(Type *ty, Token *tok) {
|
|||
|
||||
static Node *struct_ref(Node *lhs, Token *tok) {
|
||||
add_type(lhs);
|
||||
if (lhs->ty->kind != TY_STRUCT)
|
||||
error_tok(lhs->tok, "not a struct");
|
||||
if (lhs->ty->kind != TY_STRUCT && lhs->ty->kind != TY_UNION)
|
||||
error_tok(lhs->tok, "not a struct nor a union");
|
||||
|
||||
Node *node = new_unary(ND_MEMBER, lhs, tok);
|
||||
node->member = get_struct_member(lhs->ty, tok);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#include "test.h"
|
||||
|
||||
int main() {
|
||||
ASSERT(8, ({ union { int a; char b[6]; } x; sizeof(x); }));
|
||||
ASSERT(3, ({ union { int a; char b[4]; } x; x.a = 515; x.b[0]; }));
|
||||
ASSERT(2, ({ union { int a; char b[4]; } x; x.a = 515; x.b[1]; }));
|
||||
ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[2]; }));
|
||||
ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[3]; }));
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
|
@ -117,7 +117,7 @@ static int from_hex(char c) {
|
|||
static bool is_keyword(Token *tok) {
|
||||
static char *kw[] = {
|
||||
"return", "if", "else", "for", "while", "int", "sizeof", "char",
|
||||
"struct",
|
||||
"struct", "union",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
|
|
Loading…
Reference in New Issue