// File: /workspace/github_c_makefile_star2_O3/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 $0x58, %rsp
movl %esi, %r15d
movq %rdi, %r13
callq 0x937c
testq %rax, %rax
je 0x87e0
leal 0x1(%r15), %eax
movl %eax, 0xc(%rsp)
leaq 0x4208(%rip), %r12      # 0xc2fe
leaq 0x30(%rsp), %rbp
leaq 0x31b1(%rip), %rbx      # 0xb2b3
movq %r15, 0x10(%rsp)
movq %r13, 0x20(%rsp)
movq %r12, %rdi
callq 0x93f7
testq %rax, %rax
je 0x816d
movq %rax, %r14
movl 0x130(%rax), %ecx
movl $0x20, %esi
movq %rbp, %rdi
leaq 0x34a0(%rip), %rdx      # 0xb5d1
xorl %eax, %eax
callq 0x20a0
movl $0x3, 0x108(%r14)
movq %rbp, %rdi
callq 0x21c0
movq %rax, 0x128(%r14)
movq %rax, 0x118(%r14)
movq %rax, %rdi
callq 0x2080
movl %eax, 0x120(%r14)
jmp 0x81f1
movl $0x1a, %edi
callq 0x93a5
testq %rax, %rax
je 0x819f
movq %rax, %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0x9210
testl %eax, %eax
jne 0x81e9
movq 0x110(%r14), %r14
testq %r14, %r14
jne 0x817f
xorl %r14d, %r14d
jmp 0x81e9
movl $0x1b, %edi
callq 0x93a5
testq %rax, %rax
je 0x8204
movq %rax, %r14
movq %r14, %rdi
movl $0x1c, %esi
callq 0x90d3
testb %al, %al
jne 0x81d1
movq 0x110(%r14), %r14
testq %r14, %r14
jne 0x81b1
xorl %r14d, %r14d
movq %r14, %rdi
movl $0x1c, %esi
callq 0x90d3
testb %al, %al
je 0x81e9
movq 0x110(%r14), %r14
movq %r14, %rdi
callq 0x955f
callq 0x937c
testq %rax, %rax
jne 0x810c
jmp 0x87e0
callq 0x937c
movq %rax, %r14
movq %rax, %rdi
leaq 0x40f1(%rip), %rsi      # 0xc307
callq 0x9210
testl %eax, %eax
je 0x831b
testq %r14, %r14
je 0x885a
movq 0x110(%r14), %rdi
callq 0x892e
movq %rax, %r12
movq %rax, %rdi
leaq 0x40d3(%rip), %rsi      # 0xc318
callq 0x9210
testl %eax, %eax
je 0x84ae
testq %r12, %r12
je 0x88a2
movq 0x110(%r12), %rdi
callq 0x892e
movq %rax, %r12
movq 0x110(%rax), %r14
movq %r14, %rdi
leaq 0x3348(%rip), %rsi      # 0xb5c4
callq 0x9210
testl %eax, %eax
je 0x8598
movq $0x0, 0x30(%rsp)
movq 0x110(%r14), %rdi
callq 0x892e
testq %rax, %rax
je 0x855e
movq %rax, %r13
movq %rbp, %r15
movq %r13, %rdi
leaq 0x45be(%rip), %rsi      # 0xc875
callq 0x9210
testl %eax, %eax
jne 0x8564
movq %r13, %rdi
callq 0x9134
movq %rax, (%r15)
movq %rax, %r15
addq $0x110, %r15            # imm = 0x110
movq 0x110(%r13), %rdi
callq 0x892e
movq %rax, %r13
movq %rax, %rdi
leaq 0x2f28(%rip), %rsi      # 0xb21a
callq 0x9210
testl %eax, %eax
je 0x8564
movq 0x110(%r13), %rdi
callq 0x892e
movq %rax, %r13
testq %rax, %rax
jne 0x82ad
xorl %r13d, %r13d
jmp 0x8564
callq 0x937c
movq %rax, %r12
movq %r13, %rdi
movq %rax, %rsi
callq 0x496e
testq %rax, %rax
je 0x8554
movq %rax, %r14
cmpl $0x3, (%rax)
jne 0x88ba
movq 0xa0(%r14), %rdi
callq 0x9190
movq %rax, 0x18(%rsp)
callq 0x9545
cmpq $0x0, 0xb8(%r14)
je 0x863e
movq 0x110(%r12), %rdi
callq 0x892e
movq %rax, %r12
movq %rax, %rdi
leaq 0x3243(%rip), %rsi      # 0xb5c4
callq 0x9210
testl %eax, %eax
je 0x88ea
movq 0x110(%r12), %r13
xorl %eax, %eax
callq 0x47d2
movq %rax, 0x28(%rsp)
movq 0xb8(%r14), %r14
testq %r14, %r14
movq 0x18(%rsp), %r15
leaq 0x3f46(%rip), %r12      # 0xc2fe
je 0x86cb
movq %r14, %rdi
leaq 0x44ad(%rip), %rsi      # 0xc875
callq 0x9210
testl %eax, %eax
jne 0x86cb
movq $0x0, 0x30(%rsp)
movq %r13, %rdi
callq 0x892e
testq %rax, %rax
je 0x8444
movq %rax, %r13
movq %rbp, %r15
leaq 0x447d(%rip), %r12      # 0xc875
movq %r13, %rdi
movq %r12, %rsi
callq 0x9210
testl %eax, %eax
jne 0x843d
movq %r13, %rdi
leaq 0x2e09(%rip), %rsi      # 0xb21a
callq 0x9210
testl %eax, %eax
jne 0x843d
movq %r13, %rdi
callq 0x9134
movq %rax, (%r15)
addq $0x110, %rax            # imm = 0x110
movq 0x110(%r13), %r13
movq %rax, %r15
testq %r13, %r13
jne 0x83f8
xorl %r13d, %r13d
movq 0x30(%rsp), %r12
jmp 0x844a
xorl %r12d, %r12d
xorl %r13d, %r13d
movq %r14, %rdi
callq 0x91d7
movq %rax, %r15
xorl %edi, %edi
movq %r12, %rsi
callq 0x43e5
movq 0x28(%rsp), %rdi
movq %r15, %rsi
movq %rax, %rdx
callq 0x488d
movq %r13, %rdi
leaq 0x43fc(%rip), %rsi      # 0xc875
callq 0x9210
testl %eax, %eax
jne 0x86bf
movq 0x110(%r13), %r13
movq 0x110(%r14), %r14
testq %r14, %r14
leaq 0x3e60(%rip), %r12      # 0xc2fe
movq 0x18(%rsp), %r15
jne 0x83be
jmp 0x86cb
movq %r12, %rdi
leaq 0x3e85(%rip), %rsi      # 0xc33d
callq 0x9210
testl %eax, %eax
jne 0x870a
movq %r12, %rdi
leaq 0x3f16(%rip), %rsi      # 0xc3e5
callq 0x9210
testl %eax, %eax
je 0x87ef
movq 0x110(%r12), %rdi
callq 0x892e
movq %rax, %r14
movq %r13, %rdi
movq %rax, %rsi
callq 0x496e
movq %r13, %r15
movq %rax, %r13
movq 0x110(%r14), %rdi
callq 0x892e
movq %rax, %rdi
callq 0x955f
testq %r13, %r13
je 0x864a
movq %r15, %rdi
movl 0xc(%rsp), %esi
callq 0x80c5
callq 0x937c
movq %rax, %rdi
leaq 0x3eb6(%rip), %rsi      # 0xc3eb
callq 0x9210
testl %eax, %eax
movq %r15, %r13
je 0x867b
callq 0x9545
callq 0x8a4c
jmp 0x867b
callq 0x9527
jmp 0x86b3
xorl %r13d, %r13d
movq %rbp, %r15
movq %r13, %rdi
leaq 0x4307(%rip), %rsi      # 0xc875
callq 0x9210
testl %eax, %eax
je 0x8598
movq %r13, %rdi
callq 0x9134
movq %rax, (%r15)
movq 0x110(%r13), %rdi
callq 0x892e
movq %rax, %r14
movq 0x30(%rsp), %r13
jmp 0x859b
xorl %r13d, %r13d
movq %r14, %rdi
callq 0x892e
testq %rax, %rax
je 0x888a
movq %rax, %r14
movq $0x0, 0x30(%rsp)
movq %rbp, %r15
movq %r14, %rdi
movq %rbx, %rsi
callq 0x9210
testl %eax, %eax
jne 0x85ed
movq %r14, %rdi
callq 0x9134
movq %rax, (%r15)
addq $0x110, %rax            # imm = 0x110
movq 0x110(%r14), %r14
movq %rax, %r15
testq %r14, %r14
jne 0x85bb
xorl %r14d, %r14d
movq %r14, %rdi
movq %rbx, %rsi
callq 0x9210
testl %eax, %eax
je 0x8872
movq 0x110(%r14), %rdi
callq 0x955f
movq %r12, %rdi
callq 0x91d7
movq %rax, %r14
movq 0x30(%rsp), %rsi
movq %r13, %rdi
callq 0x43e5
movq 0x20(%rsp), %r13
movq %r13, %rdi
movq %r14, %rsi
movq %rax, %rdx
callq 0x488d
movq 0x10(%rsp), %r15
jmp 0x86b3
movq 0x18(%rsp), %rdi
callq 0x9590
jmp 0x86b3
callq 0x8a4c
callq 0x937c
movq %rax, %rdi
leaq 0x3d8d(%rip), %rsi      # 0xc3eb
callq 0x9210
testl %eax, %eax
movq %r15, %r13
je 0x867b
callq 0x9545
movq %r13, %rdi
movl 0xc(%rsp), %esi
callq 0x80c5
callq 0x937c
movq %rax, %r14
movq %rax, %rdi
leaq 0x3d63(%rip), %rsi      # 0xc3f0
callq 0x9210
testl %eax, %eax
movq 0x10(%rsp), %r15
je 0x88d2
movq 0x110(%r14), %rdi
callq 0x892e
movq %rax, %rdi
callq 0x955f
leaq 0x3c44(%rip), %r12      # 0xc2fe
jmp 0x81f1
leaq 0x3c38(%rip), %r12      # 0xc2fe
movq 0x18(%rsp), %r15
movq %r13, %rdi
leaq 0x41a0(%rip), %rsi      # 0xc875
callq 0x9210
testl %eax, %eax
je 0x88db
movq 0x110(%r13), %rdi
callq 0x955f
movq %r15, %rdi
movq 0x28(%rsp), %rsi
callq 0x95e0
movq 0x10(%rsp), %r15
movq 0x20(%rsp), %r13
jmp 0x81f1
movq 0x110(%r12), %rdi
callq 0x892e
movq %rax, %r14
movq %rax, %rdi
movl $0x18, %esi
callq 0x90d3
testb %al, %al
je 0x8740
movq %r14, %rdi
movq %rbp, %rsi
callq 0x2b09
movq 0x30(%rsp), %rsi
jmp 0x87d3
movq %r14, %rdi
leaq 0x3612(%rip), %rsi      # 0xbd5c
callq 0x9210
testl %eax, %eax
je 0x88f3
movq %r14, %r15
movq 0x110(%r14), %r14
testq %r14, %r14
je 0x8849
movq %r14, %r13
movq %r13, %rdi
leaq 0x2917(%rip), %rsi      # 0xb08e
callq 0x9210
testl %eax, %eax
jne 0x8791
movq 0x110(%r13), %r13
testq %r13, %r13
jne 0x876d
jmp 0x8849
movq %r14, %rdi
movq %r13, %rsi
callq 0x89f6
movq %rax, %r14
movq 0x110(%r13), %rdi
callq 0x955f
leaq 0x8bae(%rip), %rax      # 0x11360
movq (%rax), %rdi
testq %rdi, %rdi
je 0x8902
movq %r14, %rsi
callq 0x8972
movq %rax, %rsi
movq 0x10(%rsp), %r15
movq 0x20(%rsp), %r13
movq %r12, %rdi
callq 0x2b5a
jmp 0x86b3
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3bfa(%rip), %rsi      # 0xc3f0
movq %r12, %rdi
callq 0x9210
testl %eax, %eax
je 0x8813
testl %r15d, %r15d
jne 0x8833
leaq 0x3c1c(%rip), %rsi      # 0xc42a
jmp 0x8909
leaq 0x3bd1(%rip), %rsi      # 0xc3eb
movq %r12, %rdi
callq 0x9210
testl %eax, %eax
je 0x8911
testl %r15d, %r15d
je 0x8925
movq %r12, %rdi
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x955f
leaq 0x3af8(%rip), %rsi      # 0xc348
movq %r15, %rdi
xorl %eax, %eax
callq 0x470c
leaq 0x3d33(%rip), %rdi      # 0xc594
leaq 0x3aa1(%rip), %rsi      # 0xc309
movl $0x5f, %edx
callq 0x46d0
leaq 0x3aa6(%rip), %rdi      # 0xc31f
leaq 0x3a89(%rip), %rsi      # 0xc309
movl $0x70, %edx
callq 0x46d0
leaq 0x3d03(%rip), %rdi      # 0xc594
leaq 0x3a71(%rip), %rsi      # 0xc309
movl $0x68, %edx
callq 0x46d0
leaq 0x3ceb(%rip), %rdi      # 0xc594
leaq 0x3a59(%rip), %rsi      # 0xc309
movl $0x62, %edx
callq 0x46d0
leaq 0x3ba6(%rip), %rdi      # 0xc467
leaq 0x3a41(%rip), %rsi      # 0xc309
movl $0xd4, %edx
callq 0x46d0
leaq 0x3b1d(%rip), %rsi      # 0xc3f6
jmp 0x8909
leaq 0x3bb6(%rip), %rsi      # 0xc498
movq %r13, %rdi
jmp 0x8853
leaq 0x3b97(%rip), %rsi      # 0xc488
jmp 0x8909
leaq 0x3aae(%rip), %rsi      # 0xc3a8
movq %r14, %rdi
jmp 0x8853
leaq 0x3a71(%rip), %rsi      # 0xc37a
movq %r12, %rdi
jmp 0x8853
callq 0x9527
leaq 0x3b38(%rip), %rsi      # 0xc455
movq %rax, %rdi
jmp 0x8853
leaq 0x3b14(%rip), %rsi      # 0xc440
jmp 0x8909