// File: /workspace/github_c_makefile_star2_O1/hikalium[P]compilium/preprocessor.c
// Function: PreprocessBlock
static void PreprocessBlock(struct Node *replacement_list, int level) {
  struct Node *t;
  while (PeekToken()) {
    if ((t = ConsumeTokenStr("__LINE__"))) {
      char s[32];
      snprintf(s, sizeof(s), "%d", t->line);
      t->token_type = kTokenIntegerConstant;
      t->begin = t->src_str = strdup(s);
      t->length = strlen(t->begin);
      continue;
    }
    if ((t = ReadToken(kTokenLineComment))) {
      while (t && !IsEqualTokenWithCStr(t, "\n")) t = t->next_token;
      RemoveTokensTo(t);
      continue;
    }
    if ((t = ReadToken(kTokenBlockCommentBegin))) {
      while (t && !IsTokenWithType(t, kTokenBlockCommentEnd)) t = t->next_token;
      if (IsTokenWithType(t, kTokenBlockCommentEnd)) t = t->next_token;
      RemoveTokensTo(t);
      continue;
    }
    if (IsEqualTokenWithCStr((t = PeekToken()), "#")) {
      assert(t);
      t = SkipDelimiterTokensInLogicalLine(t->next_token);
      if (IsEqualTokenWithCStr(t, "define")) {
        assert(t);
        t = SkipDelimiterTokensInLogicalLine(t->next_token);
        struct Node *from = t;
        t = t->next_token;
        struct Node *ident_list = TryReadIdentListWrappedByParens(&t);
        t = SkipDelimiterTokensInLogicalLine(t);
        assert(t);
        struct Node *to_token_head = NULL;
        struct Node **to_token_last_holder = &to_token_head;
        while (t && !IsEqualTokenWithCStr(t, "\n")) {
          *to_token_last_holder = DuplicateToken(t);
          to_token_last_holder = &(*to_token_last_holder)->next_token;
          t = t->next_token;
        }
        assert(IsEqualTokenWithCStr(t, "\n"));
        RemoveTokensTo(t->next_token);
        PushKeyValueToList(replacement_list, CreateTokenStr(from),
                           CreateMacroReplacement(ident_list, to_token_head));
        continue;
      }
      if (IsEqualTokenWithCStr(t, "include")) {
        struct Node *token_include = t;
        const char *fname = NULL;
        const char *path = NULL;
        t = SkipDelimiterTokensInLogicalLine(t->next_token);
        if (IsTokenWithType(t, kTokenStringLiteral)) {
          char *tmp_fname = CreateTokenStr(t);
          tmp_fname++;  // Remove open "
          tmp_fname[strlen(tmp_fname) - 1] = 0;  // Remove close "
          fname = tmp_fname;
          RemoveTokensTo(t->next_token);
          path = CreateJoinedString(
              "./", fname);  // TODO: Make this relative to source, not cwd.
        } else if (IsEqualTokenWithCStr(t, "<")) {
          struct Node *markL = t;
          t = t->next_token;
          struct Node *begin = t;
          while (t && !IsEqualTokenWithCStr(t, ">")) {
            t = t->next_token;
          }
          if (!t) {
            ErrorWithToken(markL,
                           "Unexpected EOF. > is expected to match with this.");
          }
          struct Node *end = t;
          fname = CreateStrFromTokenRange(begin, end);
          RemoveTokensTo(end->next_token);
          if (!include_path) {
            ErrorWithToken(token_include,
                           "Include path is not provided in compiler args");
          }
          path = CreateJoinedString(include_path, fname);
        } else {
          ErrorWithToken(t, "Expected < or \" here");
        }
        assert(path);
        fprintf(stderr, "Include from: %s\n", path);
        FILE *fp = fopen(path, "rb");
        if (!fp) {
          ErrorWithToken(token_include, "File not found: %s", path);
        }
        const char *include_input = ReadFile(fp);
        InsertTokens(Tokenize(include_input));
        fclose(fp);
        continue;
      }
      if (IsEqualTokenWithCStr(t, "ifdef")) {
        struct Node *ifdef_token = t;
        t = SkipDelimiterTokensInLogicalLine(t->next_token);
        struct Node *e;
        bool cond = (e = GetNodeByTokenKey(replacement_list, t));
        // defined
        t = SkipDelimiterTokensInLogicalLine(t->next_token);
        RemoveTokensTo(t);
        if (cond) {
          PreprocessBlock(replacement_list, level + 1);
          if (IsEqualTokenWithCStr(PeekToken(), "else")) {
            RemoveCurrentToken();
            PreprocessRemoveBlock();
          }
        } else {
          PreprocessRemoveBlock();
          if (IsEqualTokenWithCStr(PeekToken(), "else")) {
            RemoveCurrentToken();
            PreprocessBlock(replacement_list, level + 1);
          }
        }
        t = PeekToken();
        if (!IsEqualTokenWithCStr(t, "endif")) {
          ErrorWithToken(ifdef_token,
                         "Unexpected eof. Expected #endif to match with this.");
        }
        t = SkipDelimiterTokensInLogicalLine(t->next_token);
        RemoveTokensTo(t);
        continue;
      }
      if (IsEqualTokenWithCStr(t, "endif")) {
        if (level == 0) {
          ErrorWithToken(t, "Unexpected endif here");
        }
        RemoveTokensTo(t);
        return;
      }
      if (IsEqualTokenWithCStr(t, "else")) {
        if (level == 0) {
          ErrorWithToken(t, "Unexpected else here");
        }
        RemoveTokensTo(t);
        return;
      }
      ErrorWithToken(NextToken(), "Not a valid macro");
    }
    struct Node *e;
    if ((e = GetNodeByTokenKey(replacement_list, (t = PeekToken())))) {
      assert(e->type == kNodeMacroReplacement);
      struct Node *rep = DuplicateTokenSequence(e->value);
      RemoveCurrentToken();
      if (!e->arg_expr_list) {
        // ident replace macro case
        InsertTokens(rep);
        continue;
      }
      // function-like macro case
      t = SkipDelimiterTokensInLogicalLine(t->next_token);
      if (!IsEqualTokenWithCStr(t, "(")) ErrorWithToken(t, "Expected ( here");
      t = t->next_token;
      struct Node *it;
      struct Node *arg_rep_list = AllocList();
      for (it = e->arg_expr_list; it; it = it->next_token) {
        if (IsEqualTokenWithCStr(it, ")")) break;
        struct Node *arg_token_head = NULL;
        struct Node **arg_token_last_holder = &arg_token_head;
        t = SkipDelimiterTokensInLogicalLine(t);
        for (; t; t = t->next_token) {
          if (IsEqualTokenWithCStr(t, ")") || IsEqualTokenWithCStr(t, ","))
            break;
          *arg_token_last_holder = DuplicateToken(t);
          arg_token_last_holder = &(*arg_token_last_holder)->next_token;
        }
        PushKeyValueToList(arg_rep_list, CreateTokenStr(it),
                           CreateMacroReplacement(NULL, arg_token_head));
        if (IsEqualTokenWithCStr(t, ")")) break;
        t = t->next_token;
      }
      if (!IsEqualTokenWithCStr(t, ")")) ErrorWithToken(t, "Expected ) here");
      RemoveTokensTo(t->next_token);
      // Insert & replace args
      InsertTokensWithIdentReplace(rep, arg_rep_list);
      continue;
    }
    NextToken();
  }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rsi, 0x18(%rsp)
movq %rdi, %r13
callq 0x93e4
testq %rax, %rax
je 0x8850
movq 0x18(%rsp), %rax
incl %eax
movl %eax, 0xc(%rsp)
leaq 0x4193(%rip), %rbp      # 0xc302
leaq 0x20(%rsp), %r15
leaq 0x3138(%rip), %rbx      # 0xb2b3
leaq 0x344f(%rip), %r12      # 0xb5d1
movq %r13, (%rsp)
movq %rbp, %rdi
callq 0x945f
testq %rax, %rax
je 0x81e0
movq %rax, %r14
movl 0x130(%rax), %ecx
movl $0x20, %esi
movq %r15, %rdi
movq %r12, %rdx
xorl %eax, %eax
callq 0x20a0
movl $0x3, 0x108(%r14)
movq %r15, %rdi
callq 0x21c0
movq %rax, 0x128(%r14)
movq %rax, 0x118(%r14)
movq %rax, %rdi
callq 0x2080
movl %eax, 0x120(%r14)
jmp 0x825e
movl $0x1a, %edi
callq 0x940d
testq %rax, %rax
je 0x820f
movq %rax, %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0x9278
testl %eax, %eax
jne 0x8256
movq 0x110(%r14), %r14
testq %r14, %r14
jne 0x81f2
jmp 0x8256
movl $0x1b, %edi
callq 0x940d
testq %rax, %rax
je 0x8271
movq %rax, %r14
movq %r14, %rdi
movl $0x1c, %esi
callq 0x913f
testb %al, %al
jne 0x823e
movq 0x110(%r14), %r14
testq %r14, %r14
jne 0x8221
movq %r14, %rdi
movl $0x1c, %esi
callq 0x913f
testb %al, %al
je 0x8256
movq 0x110(%r14), %r14
movq %r14, %rdi
callq 0x95c7
callq 0x93e4
testq %rax, %rax
jne 0x8186
jmp 0x8850
callq 0x93e4
movq %rax, %r14
movq %rax, %rdi
leaq 0x4088(%rip), %rsi      # 0xc30b
callq 0x9278
testl %eax, %eax
je 0x8389
testq %r14, %r14
je 0x88ce
movq 0x110(%r14), %rdi
callq 0x8998
movq %rax, %r12
movq %rax, %rdi
leaq 0x406a(%rip), %rsi      # 0xc31c
callq 0x9278
testl %eax, %eax
je 0x8534
testq %r12, %r12
je 0x8916
movq 0x110(%r12), %rdi
callq 0x8998
movq %rax, %r12
movq 0x110(%rax), %r14
movq %r14, %rdi
leaq 0x32db(%rip), %rsi      # 0xb5c4
callq 0x9278
testl %eax, %eax
je 0x861f
movq $0x0, 0x20(%rsp)
movq 0x110(%r14), %rdi
callq 0x8998
testq %rax, %rax
je 0x85e4
movq %rax, %r13
movq %r15, %rbp
movq %r13, %rdi
leaq 0x4555(%rip), %rsi      # 0xc879
callq 0x9278
testl %eax, %eax
jne 0x85ea
movq %r13, %rdi
callq 0x91a0
movq %rax, (%rbp)
movq %rax, %rbp
addq $0x110, %rbp            # imm = 0x110
movq 0x110(%r13), %rdi
callq 0x8998
movq %rax, %r13
movq %rax, %rdi
leaq 0x2eba(%rip), %rsi      # 0xb21a
callq 0x9278
testl %eax, %eax
je 0x85ea
movq 0x110(%r13), %rdi
callq 0x8998
movq %rax, %r13
testq %rax, %rax
jne 0x831a
xorl %r13d, %r13d
jmp 0x85ea
callq 0x93e4
movq %rax, %r12
movq %r13, %rdi
movq %rax, %rsi
callq 0x49a2
testq %rax, %rax
je 0x85da
movq %rax, %r14
cmpl $0x3, (%rax)
jne 0x892e
movq 0xa0(%r14), %rdi
callq 0x91fc
movq %rax, %r13
callq 0x95ad
cmpq $0x0, 0xb8(%r14)
je 0x86c7
movq %r13, 0x40(%rsp)
movq 0x110(%r12), %rdi
callq 0x8998
movq %rax, %r12
movq %rax, %rdi
leaq 0x31d2(%rip), %rsi      # 0xb5c4
callq 0x9278
testl %eax, %eax
je 0x8958
movq 0x110(%r12), %r12
xorl %eax, %eax
callq 0x4806
movq %rax, 0x10(%rsp)
movq 0xb8(%r14), %r14
testq %r14, %r14
movq (%rsp), %r13
je 0x84fc
movq %r14, %rdi
leaq 0x4448(%rip), %rsi      # 0xc879
callq 0x9278
testl %eax, %eax
jne 0x84fc
movq $0x0, 0x20(%rsp)
movq %r12, %rdi
callq 0x8998
movq %rax, %r12
testq %rax, %rax
je 0x84a2
movq %r15, %r13
movq %r12, %rdi
leaq 0x4415(%rip), %rsi      # 0xc879
callq 0x9278
testl %eax, %eax
jne 0x84a2
movq %r12, %rdi
leaq 0x2da3(%rip), %rsi      # 0xb21a
callq 0x9278
testl %eax, %eax
jne 0x84a2
movq %r12, %rdi
callq 0x91a0
movq %rax, (%r13)
addq $0x110, %rax            # imm = 0x110
movq 0x110(%r12), %r12
movq %rax, %r13
testq %r12, %r12
jne 0x845a
movq %r14, %rdi
callq 0x923f
movq %rax, %r13
movq 0x20(%rsp), %rsi
xorl %edi, %edi
callq 0x43d9
movq 0x10(%rsp), %rdi
movq %r13, %rsi
movq %rax, %rdx
callq 0x48c1
movq %r12, %rdi
leaq 0x43a6(%rip), %rsi      # 0xc879
callq 0x9278
testl %eax, %eax
jne 0x84e4
movq 0x110(%r12), %r12
movq (%rsp), %r13
testl %eax, %eax
jne 0x84fc
movq 0x110(%r14), %r14
testq %r14, %r14
jne 0x8427
movq %r12, %rdi
leaq 0x4373(%rip), %rsi      # 0xc879
callq 0x9278
testl %eax, %eax
je 0x894f
movq 0x110(%r12), %rdi
callq 0x95c7
movq 0x40(%rsp), %rdi
movq 0x10(%rsp), %rsi
callq 0x9648
jmp 0x874a
movq %r12, %rdi
leaq 0x3e03(%rip), %rsi      # 0xc341
callq 0x9278
testl %eax, %eax
jne 0x8756
movq %r12, %rdi
leaq 0x3e94(%rip), %rsi      # 0xc3e9
callq 0x9278
testl %eax, %eax
je 0x885f
movq 0x110(%r12), %rdi
callq 0x8998
movq %rax, %r14
movq %r13, %rdi
movq %rax, %rsi
callq 0x49a2
movq %r13, %rbp
movq %rax, %r13
movq 0x110(%r14), %rdi
callq 0x8998
movq %rax, %rdi
callq 0x95c7
testq %r13, %r13
je 0x86df
movq %rbp, %rdi
movl 0xc(%rsp), %esi
callq 0x8139
callq 0x93e4
movq %rax, %rdi
leaq 0x3e34(%rip), %rsi      # 0xc3ef
callq 0x9278
testl %eax, %eax
movq %rbp, %r13
je 0x8710
callq 0x95ad
callq 0x8ab4
jmp 0x8710
callq 0x958f
jmp 0x874a
xorl %r13d, %r13d
movq %r15, %rbp
movq %r13, %rdi
leaq 0x4285(%rip), %rsi      # 0xc879
callq 0x9278
testl %eax, %eax
je 0x861f
movq %r13, %rdi
callq 0x91a0
movq %rax, (%rbp)
movq 0x110(%r13), %rdi
callq 0x8998
movq %rax, %r14
movq 0x20(%rsp), %r13
jmp 0x8622
xorl %r13d, %r13d
movq %r14, %rdi
callq 0x8998
testq %rax, %rax
je 0x88fe
movq %rax, %r14
movq $0x0, 0x20(%rsp)
movq %r15, %rbp
movq %r14, %rdi
movq %rbx, %rsi
callq 0x9278
testl %eax, %eax
jne 0x8672
movq %r14, %rdi
callq 0x91a0
movq %rax, (%rbp)
addq $0x110, %rax            # imm = 0x110
movq 0x110(%r14), %r14
movq %rax, %rbp
testq %r14, %r14
jne 0x8642
movq %r14, %rdi
movq %rbx, %rsi
callq 0x9278
testl %eax, %eax
je 0x88e6
movq 0x110(%r14), %rdi
callq 0x95c7
movq %r12, %rdi
callq 0x923f
movq %rax, %r14
movq 0x20(%rsp), %rsi
movq %r13, %rdi
callq 0x43d9
movq (%rsp), %r13
movq %r13, %rdi
movq %r14, %rsi
movq %rax, %rdx
callq 0x48c1
leaq 0x3c40(%rip), %rbp      # 0xc302
jmp 0x874a
movq %r13, %rdi
callq 0x95f8
leaq 0x2efb(%rip), %r12      # 0xb5d1
movq (%rsp), %r13
jmp 0x825e
callq 0x8ab4
callq 0x93e4
movq %rax, %rdi
leaq 0x3cfc(%rip), %rsi      # 0xc3ef
callq 0x9278
testl %eax, %eax
movq %rbp, %r13
je 0x8710
callq 0x95ad
movq %r13, %rdi
movl 0xc(%rsp), %esi
callq 0x8139
callq 0x93e4
movq %rax, %r14
movq %rax, %rdi
leaq 0x3cd2(%rip), %rsi      # 0xc3f4
callq 0x9278
testl %eax, %eax
leaq 0x3bd2(%rip), %rbp      # 0xc302
je 0x8946
movq 0x110(%r14), %rdi
callq 0x8998
movq %rax, %rdi
callq 0x95c7
leaq 0x2e80(%rip), %r12      # 0xb5d1
jmp 0x825e
movq 0x110(%r12), %rdi
callq 0x8998
movq %rax, %r14
movq %rax, %rdi
movl $0x18, %esi
callq 0x913f
testb %al, %al
je 0x878c
movq %r14, %rdi
movq %r15, %rsi
callq 0x2abe
movq 0x20(%rsp), %rsi
jmp 0x8843
movq %r14, %rdi
leaq 0x35ca(%rip), %rsi      # 0xbd60
callq 0x9278
testl %eax, %eax
je 0x8972
movq %r14, 0x10(%rsp)
movq 0x110(%r14), %r14
testq %r14, %r14
sete %bpl
je 0x88bd
movq %r14, %rdi
leaq 0x28c8(%rip), %rsi      # 0xb08e
callq 0x9278
movq %r14, %r13
testl %eax, %eax
jne 0x87f7
movq 0x110(%r13), %r13
testq %r13, %r13
sete %bpl
je 0x88bd
movq %r13, %rdi
leaq 0x289e(%rip), %rsi      # 0xb08e
callq 0x9278
jmp 0x87ce
testb %bpl, %bpl
jne 0x88bd
movq %r14, %rdi
movq %r13, %rsi
callq 0x8a5e
movq %rax, %r14
movq 0x110(%r13), %rdi
callq 0x95c7
leaq 0x8b3f(%rip), %rax      # 0x11360
movq (%rax), %rdi
testq %rdi, %rdi
je 0x8961
movq %r14, %rsi
callq 0x89da
movq %rax, %rsi
movq (%rsp), %r13
leaq 0x3abf(%rip), %rbp      # 0xc302
movq %r12, %rdi
callq 0x2b0f
jmp 0x874a
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3b8e(%rip), %rsi      # 0xc3f4
movq %r12, %rdi
callq 0x9278
testl %eax, %eax
je 0x8885
cmpl $0x0, 0x18(%rsp)
jne 0x88a7
leaq 0x3bae(%rip), %rsi      # 0xc42e
jmp 0x8968
leaq 0x3b63(%rip), %rsi      # 0xc3ef
movq %r12, %rdi
callq 0x9278
testl %eax, %eax
je 0x897e
cmpl $0x0, 0x18(%rsp)
je 0x898f
movq %r12, %rdi
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x95c7
leaq 0x3a88(%rip), %rsi      # 0xc34c
movq 0x10(%rsp), %rdi
jmp 0x896b
leaq 0x3cc3(%rip), %rdi      # 0xc598
leaq 0x3a31(%rip), %rsi      # 0xc30d
movl $0x5f, %edx
callq 0x4704
leaq 0x3a36(%rip), %rdi      # 0xc323
leaq 0x3a19(%rip), %rsi      # 0xc30d
movl $0x70, %edx
callq 0x4704
leaq 0x3c93(%rip), %rdi      # 0xc598
leaq 0x3a01(%rip), %rsi      # 0xc30d
movl $0x68, %edx
callq 0x4704
leaq 0x3c7b(%rip), %rdi      # 0xc598
leaq 0x39e9(%rip), %rsi      # 0xc30d
movl $0x62, %edx
callq 0x4704
leaq 0x3b36(%rip), %rdi      # 0xc46b
leaq 0x39d1(%rip), %rsi      # 0xc30d
movl $0xd4, %edx
callq 0x4704
leaq 0x3aad(%rip), %rsi      # 0xc3fa
jmp 0x8968
leaq 0x3b46(%rip), %rsi      # 0xc49c
jmp 0x8968
leaq 0x3b2d(%rip), %rsi      # 0xc48c
jmp 0x8968
leaq 0x3a16(%rip), %rsi      # 0xc37e
movq %r12, %rdi
xorl %eax, %eax
callq 0x4740
leaq 0x3a33(%rip), %rsi      # 0xc3ac
movq %r14, %rdi
jmp 0x896b
callq 0x958f
leaq 0x3acf(%rip), %rsi      # 0xc459
movq %rax, %rdi
jmp 0x896b
leaq 0x3aae(%rip), %rsi      # 0xc444
jmp 0x8968