// File: /workspace/github_c_makefile_star2_O0/pocari[P]compilerbook-9cc/parser.c
// Function: struct_decl
static Type *struct_decl() {
  expect_token(TK_STRUCT);

  Token *bak = token;
  Token *tk = consume_ident();

  // 構造体のtagのみ宣言（？）
  // struct hoge;
  //
  // その後実際の定義を宣言
  // struct hoge {
  //   int x;
  // }
  // みたいなことができるので、 struct hoge; のような場合はタグ名だけ登録する
  if (tk) {
    if (!peek_token("{")) {
      TagScope *sc = find_tag(tk);
      if (!sc) {
        // 無かったらこのタグ名で登録する
        // (登録はするがまだこの時点では完全な定義でないので、ty->is_incompleteがtrueのままになる)
        Type *ty = struct_type();
        push_tag_scope(tk, ty);
        return ty;
      }
      if (sc->ty->kind != TY_STRUCT) {
        error_at(bak->str, "%s は構造体ではありません", my_strndup(tk->str, tk->len));
      }
      return sc->ty;
    }
  }

  // ここに来た場合 構造体の宣言の struct _ で(もしタグがあればそれの後) _ をこれから読もうとしている
  // chibiccを見ると struct *foo というのもcの文法としてはOKで、「不完全な無名構造体へのポインタ」という変数を定義したことになるらしい。
  // なので、 「struct」 まででその「不完全な無名構造体」とみなしてその型を返すらしい。
  if (!consume("{")) {
    return struct_type();
  }

  Type *ty = NULL;

  TagScope *sc = NULL;
  if (tk) {
    sc = find_tag(tk);
  }

  if (sc && sc->depth == scope_depth) {
    if (sc->ty->kind != TY_STRUCT) {
      error_at(tk->str, "%s は構造体ではありません", my_strndup(tk->str, tk->len));
    }
    // ここに来た場合、不完全型で定義した構造体の定義になるのでその不完全型を設定して、
    // ここ以下のメンバーのパース後に完全型になる
    ty = sc->ty;
  } else {
    // 新規のタグの場合
    // struct tag {
    //   struct tag *next
    // }
    // というような、メンバーの型が自分の構造体のタグのようなケースのために、
    // メンバーのパースの前にタグを登録しておく
    ty = struct_type();
    if (tk) {
      push_tag_scope(tk, ty);
    }
  }

  Member head = {};
  Member *cur = &head;

  while (!consume("}")) {
    cur->next = struct_member();
    cur = cur->next;
  }

  ty->members = head.next;

  int offset = 0;
  for (Member *m = ty->members; m; m = m->next) {
    offset = align_to(offset, m->ty->align);
    m->offset = offset;
    offset += m->ty->size;
    if (ty->align < m->ty->align) {
      // 構造体自身のアラインメントは、構造体のメンバーの中の最大のアラインメントに合わせる
      // 構造体自体のサイズの割当(ループの外)で効いてくるらしい
      ty->align = m->ty->align;
    }
  }
  // アラインメント(このコメントを書いているときのintはまだ8バイト)
  // int, charが混在しているstructを定義すると下記のようになる
  //
  // struct {
  //   char x;
  //   int y;
  // } s1;
  //
  // の場合、アラインメントが考慮されていない場合
  // char 1バイト、int 8バイトの合計9バイトの構造体になるが、
  // アラインメントを考慮する場合、8バイト境界に置かれることになるので、
  // xの直後からyが始まるのではなく、7バイト後からyの8バイトが始まり合計16バイトの構造体になる
  ty->size = align_to(offset, ty->align);

  // メンバーの定義までパースして初めて不完全型->完全型になる
  ty->is_incomplete = false;

  return ty;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movl $0x10, %edi
callq 0x7470
leaq 0xe3f4(%rip), %rax      # 0x155d0
movq (%rax), %rax
movq %rax, -0x10(%rbp)
callq 0x7630
movq %rax, -0x18(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x7297
leaq 0x9092(%rip), %rdi      # 0x10290
callq 0x69d0
testb $0x1, %al
jne 0x7295
movq -0x18(%rbp), %rdi
callq 0x74e0
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x20(%rbp)
jne 0x7242
callq 0xdae0
movq %rax, -0x28(%rbp)
movq -0x18(%rbp), %rdi
movq -0x28(%rbp), %rsi
callq 0x7570
movq -0x28(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x7463
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rax
cmpl $0x9, (%rax)
je 0x7284
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x78(%rbp)
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x18(%rbp), %rax
movl 0x20(%rax), %esi
callq 0x6690
movq -0x78(%rbp), %rdi
movq %rax, %rdx
leaq 0x9456(%rip), %rsi      # 0x106d3
movb $0x0, %al
callq 0x6370
movq -0x20(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x8(%rbp)
jmp 0x7463
jmp 0x7297
leaq 0x8ff2(%rip), %rdi      # 0x10290
callq 0x6780
cmpq $0x0, %rax
jne 0x72b7
callq 0xdae0
movq %rax, -0x8(%rbp)
jmp 0x7463
movq $0x0, -0x30(%rbp)
movq $0x0, -0x38(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x72db
movq -0x18(%rbp), %rdi
callq 0x74e0
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x38(%rbp)
je 0x7341
movq -0x38(%rbp), %rax
movl 0x18(%rax), %eax
cmpl 0xe291(%rip), %eax      # 0x15580
jne 0x7341
movq -0x38(%rbp), %rax
movq 0x10(%rax), %rax
cmpl $0x9, (%rax)
je 0x7333
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x80(%rbp)
movq -0x18(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x18(%rbp), %rax
movl 0x20(%rax), %esi
callq 0x6690
movq -0x80(%rbp), %rdi
movq %rax, %rdx
leaq 0x93a7(%rip), %rsi      # 0x106d3
movb $0x0, %al
callq 0x6370
movq -0x38(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x30(%rbp)
jmp 0x7360
callq 0xdae0
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x18(%rbp)
je 0x735e
movq -0x18(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x7570
jmp 0x7360
leaq -0x58(%rbp), %rdi
xorl %esi, %esi
movl $0x20, %edx
callq 0x20c0
leaq -0x58(%rbp), %rax
movq %rax, -0x60(%rbp)
leaq 0x8f23(%rip), %rdi      # 0x102a2
callq 0x6780
cmpq $0x0, %rax
setne %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x7393
jmp 0x73af
callq 0x7690
movq %rax, %rcx
movq -0x60(%rbp), %rax
movq %rcx, (%rax)
movq -0x60(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x60(%rbp)
jmp 0x7378
movq -0x58(%rbp), %rcx
movq -0x30(%rbp), %rax
movq %rcx, 0x20(%rax)
movl $0x0, -0x64(%rbp)
movq -0x30(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x70(%rbp)
cmpq $0x0, -0x70(%rbp)
je 0x743b
movl -0x64(%rbp), %edi
movq -0x70(%rbp), %rax
movq 0x8(%rax), %rax
movl 0x8(%rax), %esi
callq 0x75f0
movl %eax, -0x64(%rbp)
movl -0x64(%rbp), %ecx
movq -0x70(%rbp), %rax
movl %ecx, 0x18(%rax)
movq -0x70(%rbp), %rax
movq 0x8(%rax), %rax
movl 0x4(%rax), %eax
addl -0x64(%rbp), %eax
movl %eax, -0x64(%rbp)
movq -0x30(%rbp), %rax
movl 0x8(%rax), %eax
movq -0x70(%rbp), %rcx
movq 0x8(%rcx), %rcx
cmpl 0x8(%rcx), %eax
jge 0x742c
movq -0x70(%rbp), %rax
movq 0x8(%rax), %rax
movl 0x8(%rax), %ecx
movq -0x30(%rbp), %rax
movl %ecx, 0x8(%rax)
jmp 0x742e
movq -0x70(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x70(%rbp)
jmp 0x73ce
movl -0x64(%rbp), %edi
movq -0x30(%rbp), %rax
movl 0x8(%rax), %esi
callq 0x75f0
movl %eax, %ecx
movq -0x30(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x30(%rbp), %rax
movb $0x0, 0xc(%rax)
movq -0x30(%rbp), %rax
movq %rax, -0x8(%rbp)
movq -0x8(%rbp), %rax
addq $0x80, %rsp
popq %rbp
retq