Skip to content

Commit

Permalink
[add] union
Browse files Browse the repository at this point in the history
  • Loading branch information
karintou8710 committed Jul 7, 2022
1 parent bfa7d00 commit 14fb788
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 46 deletions.
7 changes: 3 additions & 4 deletions README.md
Expand Up @@ -8,7 +8,7 @@ Rui Ueyama さんの「低レイヤを知りたい人のための C コンパイ
- if, for, 配列, ポインター
- グローバル変数の定義
- 関数の定義、呼び出し
- 構造体の基礎
- struct, union
- ブロックスコープ
- 配列の初期化式
- typedef, enum
Expand All @@ -18,7 +18,6 @@ Rui Ueyama さんの「低レイヤを知りたい人のための C コンパイ
## TODO

- switch
- union
- 構造体の初期化式
- \_Bool

Expand Down Expand Up @@ -52,8 +51,8 @@ $ make diff
| <storage_class>? "void"
| <storage_class>? "short"
| <storage_class>? "long" "long"? "int"?
| <storage_class>? "struct" <ident>
| <storage_class>? "struct" <ident> "{" <struct_declaration>* "}"
| <storage_class>? ("struct" | "union") <ident>
| <storage_class>? ("struct" | "union") <ident> "{" <struct_declaration>* "}"
| <storage_class>? "enum" <ident>
| <storage_class>? "enum" <ident>? "{" <enumerator_list> "}"
<type_name> = <type_specifier> <pointer> <type_suffix>
Expand Down
4 changes: 2 additions & 2 deletions src/codegen.c
Expand Up @@ -167,7 +167,7 @@ static void gen_addr(Node *node) {
}

static void load(Type *ty) {
if (ty->kind == TYPE_ARRAY || ty->kind == TYPE_STRUCT) {
if (ty->kind == TYPE_ARRAY || ty->kind == TYPE_STRUCT || ty->kind == TYPE_UNION) {
// アドレスのまま読みこむようにする
return;
}
Expand Down Expand Up @@ -232,7 +232,7 @@ static void gen(Node *node) {
pop_rdi();
pop();
add_type(node->lhs);
if (node->type->kind == TYPE_STRUCT) {
if (node->type->kind == TYPE_STRUCT || node->type->kind == TYPE_UNION) {
// メモリコピー
for (int i = 0; i < node->type->size; i++) {
printf(" mov r8, [rdi+%d]\n", i);
Expand Down
4 changes: 3 additions & 1 deletion src/debug.c
Expand Up @@ -196,6 +196,8 @@ void print_type_kind(TypeKind kind) {
fprintf(stderr, "TYPE_VOID");
else if (kind == TYPE_STRUCT)
fprintf(stderr, "TYPE_STRUCT");
else if (kind == TYPE_UNION)
fprintf(stderr, "TYPE_UNION");
else if (kind == TYPE_ENUM)
fprintf(stderr, "TYPE_ENUM");
else
Expand Down Expand Up @@ -274,7 +276,7 @@ void debug_type(Type *ty, int depth) {
print_type_kind(ty->kind);
puts("");

if (ty->kind == TYPE_STRUCT) {
if (ty->kind == TYPE_STRUCT || ty->kind == TYPE_UNION) {
recursion_line_printf(depth, "name -> %s\n", ty->name);
recursion_line_printf(depth, "size -> %d\n", ty->size);
for (Var *member = ty->member; member; member = member->next) {
Expand Down
3 changes: 3 additions & 0 deletions src/kcc.h
Expand Up @@ -77,6 +77,7 @@ enum TypeKind {
TYPE_ARRAY,
TYPE_VOID,
TYPE_STRUCT,
TYPE_UNION,
TYPE_ENUM,
};

Expand Down Expand Up @@ -306,6 +307,8 @@ Vector *string_literal;
Vector *funcs; // Function型のVector
Vector *struct_global_lists;
Vector *struct_local_lists;
Vector *union_global_lists;
Vector *union_local_lists;
Vector *enum_global_lists;
Vector *enum_local_lists; // 既出の列挙型
Vector *typedef_alias;
2 changes: 2 additions & 0 deletions src/main.c
Expand Up @@ -6,6 +6,8 @@ static void init() {
globals = NULL; // グローバル変数の初期化
struct_global_lists = new_vec();
struct_local_lists = new_vec();
union_global_lists = new_vec();
union_local_lists = new_vec();
enum_global_lists = new_vec();
enum_local_lists = new_vec();
funcs = new_vec();
Expand Down
131 changes: 101 additions & 30 deletions src/parse.c
Expand Up @@ -199,7 +199,8 @@ static void new_struct_member(Token *tok, Type *member_type, Type *struct_type)
member->name = my_strndup(tok->str, tok->len);
member->len = tok->len;
member->type = member_type;
// offsetはalignmentを考慮するので後で決める
// offsetはalignmentを考慮するので後で決める。unionは0。
member->offset = 0;
struct_type->member = member;
struct_type->size += member_type->size;
}
Expand Down Expand Up @@ -287,6 +288,14 @@ static Type *find_gstruct_type(char *name) {
return find_aggregate_type(name, struct_global_lists);
}

static Type *find_lunion_type(char *name) {
return find_aggregate_type(name, union_local_lists);
}

static Type *find_gunion_type(char *name) {
return find_aggregate_type(name, union_global_lists);
}

static Type *find_lenum_type(char *name) {
return find_aggregate_type(name, enum_local_lists);
}
Expand Down Expand Up @@ -567,12 +576,12 @@ static void create_lvar_from_params(Var *params) {
create_lvar_from_params(params->next);
}

bool is_already_defined_global_obj(Token *tok) {
static bool is_already_defined_global_obj(Token *tok) {
char *name = my_strndup(tok->str, tok->len);
return find_gvar(tok) || find_func(name);
}

bool is_same_params(Var *params1, Var *params2) {
static bool is_same_params(Var *params1, Var *params2) {
for (Var *v1 = params1, *v2 = params2;; v1 = v1->next, v2 = v2->next) {
if (v1 == NULL || v2 == NULL) {
// NULL == NULL -> params1とparams2は等しい
Expand All @@ -585,13 +594,56 @@ bool is_same_params(Var *params1, Var *params2) {
}
}

bool has_lvar_in_all_params(Var *params) {
static bool has_lvar_in_all_params(Var *params) {
for (Var *v = params; v; v = v->next) {
if (v->is_only_type) return false;
}
return true;
}

static Var *reverse_linked_list_var(Var *cur) {
Var *reversed = NULL;
while (cur) {
Var *tmp = cur->next;
cur->next = reversed;
reversed = cur;
cur = tmp;
}
return reversed->next;
}

static Type *struct_defined_or_forward(Type *type) {
if (is_global) {
Type *t = find_gstruct_type(type->name);
if (t != NULL && !t->is_forward) {
error("find_gstruct_type() failure: %s構造体は既に宣言済みです。", type->name);
}
return t;
} else {
Type *t = find_lstruct_type(type->name);
if (t != NULL && !t->is_forward) {
error("find_lstruct_type() failure: %s構造体は既に宣言済みです。", type->name);
}
return t;
}
}

static Type *union_defined_or_forward(Type *type) {
if (is_global) {
Type *t = find_gunion_type(type->name);
if (t != NULL && !t->is_forward) {
error("find_gunion_type() failure: %s構造体は既に宣言済みです。", type->name);
}
return t;
} else {
Type *t = find_lunion_type(type->name);
if (t != NULL && !t->is_forward) {
error("find_lunion_type() failure: %s構造体は既に宣言済みです。", type->name);
}
return t;
}
}

/*************************************/
/****** ******/
/****** NEW_NODE ******/
Expand Down Expand Up @@ -840,7 +892,7 @@ void program() {
if (fn != NULL) vec_push(funcs, fn);
is_global = true;
} else {
if ((type->kind == TYPE_STRUCT || type->kind == TYPE_ENUM) &&
if ((type->kind == TYPE_STRUCT || type->kind == TYPE_UNION || type->kind == TYPE_ENUM) &&
consume(';')) {
// 構造体・列強型の作成 or 宣言
continue;
Expand Down Expand Up @@ -1046,6 +1098,7 @@ static Type *pointer(Type *type) {
* | <storage_class>? "enum" <ident>? "{" <enumerator_list> "}"
*/
static Type *type_specifier() {
// storage class
if (consume(TK_TYPEDEF))
current_storage = STORAGE_TYPEDEF;
else if (consume(TK_EXTERN)) {
Expand All @@ -1070,19 +1123,8 @@ static Type *type_specifier() {
}

if (type->kind == TYPE_STRUCT && consume('{')) {
if (is_global) {
Type *t = find_gstruct_type(type->name);
if (t != NULL && !t->is_forward) {
error("find_gstruct_type() failure: %s構造体は既に宣言済みです。", type->name);
}
if (t) type = t;
} else {
Type *t = find_lstruct_type(type->name);
if (t != NULL && !t->is_forward) {
error("find_lstruct_type() failure: %s構造体は既に宣言済みです。", type->name);
}
if (t) type = t;
}
Type *t = struct_defined_or_forward(type);
if (t != NULL) type = t;

if (!type->is_forward) {
vec_push(is_global ? struct_global_lists : struct_local_lists, type);
Expand All @@ -1096,16 +1138,31 @@ static Type *type_specifier() {
type = struct_declaration(type);
}
// 定義した順に並べ直す
Var *reverse_member = NULL;
while (type->member) {
Var *tmp = type->member->next;
type->member->next = reverse_member;
reverse_member = type->member;
type->member = tmp;
type->member = reverse_linked_list_var(type->member);
// memberのアライメントを考慮したoffsetを決定する
apply_align_struct(type);

return type;
}

if (type->kind == TYPE_UNION && consume('{')) {
Type *t = union_defined_or_forward(type);
if (t != NULL) type = t;

if (!type->is_forward) {
vec_push(is_global ? union_global_lists : union_local_lists, type);
} else {
type->is_forward = false;
}
type->member = reverse_member->next;

// memberのアライメントを考慮したoffsetを決定する
// 構造体のメンバーの宣言
type->member = memory_alloc(sizeof(Var));
while (!consume('}')) {
type = struct_declaration(type);
}
// 定義した順に並べ直す
type->member = reverse_linked_list_var(type->member);

apply_align_struct(type);

return type;
Expand Down Expand Up @@ -1142,6 +1199,19 @@ static Type *type_specifier() {
type = stype;
}

if (type->kind == TYPE_UNION) {
Type *stype = find_lunion_type(type->name);
if (stype == NULL) {
stype = find_gunion_type(type->name);
if (stype == NULL) {
type->is_forward = true;
stype = type;
vec_push(is_global ? union_global_lists : union_local_lists, stype);
}
}
type = stype;
}

if (type->kind == TYPE_ENUM) {
Type *etype = find_enum_type(type->name);
if (etype == NULL) {
Expand Down Expand Up @@ -1364,6 +1434,7 @@ static Function *func_define(Type *type) {

locals = memory_alloc(sizeof(Var));
struct_local_lists = new_vec(); // 関数毎に構造体を初期化
union_local_lists = new_vec();
enum_local_lists = new_vec();
locals->offset = 0;
start_local_scope();
Expand Down Expand Up @@ -1396,7 +1467,7 @@ static Node *compound_stmt() {
Node *n;
if (consume_is_type_nostep(token)) {
Type *type = type_specifier();
if ((type->kind == TYPE_STRUCT || type->kind == TYPE_ENUM) &&
if ((type->kind == TYPE_STRUCT || type->kind == TYPE_UNION || type->kind == TYPE_ENUM) &&
consume_nostep(';')) {
// 構造体か列挙型の作成 or 宣言
continue;
Expand Down Expand Up @@ -1471,7 +1542,7 @@ static Node *stmt() {
if (consume_is_type_nostep(token)) {
// <declaration>
Type *type = type_specifier();
if ((type->kind == TYPE_STRUCT || type->kind == TYPE_ENUM) &&
if ((type->kind == TYPE_STRUCT || type->kind == TYPE_UNION || type->kind == TYPE_ENUM) &&
consume_nostep('{')) {
// 構造体か列挙型の作成
error("stmt() failure: failure");
Expand Down Expand Up @@ -1858,8 +1929,8 @@ static Node *postfix() {
Token *tok = token;
expect(TK_IDENT);
add_type(node);
if (node->type->kind != TYPE_STRUCT) {
error("postfix() failure: struct型ではありません。");
if (node->type->kind != TYPE_STRUCT && node->type->kind != TYPE_UNION) {
error("postfix() failure: struct or union型ではありません。");
}
Var *member = node->type->member;
while (member) {
Expand Down
18 changes: 18 additions & 0 deletions src/token.c
Expand Up @@ -416,6 +416,24 @@ Token *tokenize(char *p) {
}
}

if (strncmp(p, "union", 5) == 0 && !is_alnum(p[5])) {
cur = new_token(TK_TYPE, cur, p, 5);
cur->type = new_type(TYPE_UNION);
p += 5;

skip_space(&p);

if (is_alpha(*p)) {
char *q = p;
str_advanve(&p);
cur->type->name = my_strndup(q, p - q);
continue;
} else {
/* TODO: 無名共用体 */
error_at(p, "tokenize() failure: unionの型名が存在しません。");
}
}

if (strncmp(p, "enum", 4) == 0 && !is_alnum(p[4])) {
cur = new_token(TK_TYPE, cur, p, 4);
cur->type = new_type(TYPE_ENUM);
Expand Down

0 comments on commit 14fb788

Please sign in to comment.