// File: brianquinlan[P]brainfuck-jit/bf_main.cpp
// Function: main
int main(int argc, char *argv[]) {
  unique_ptr<BrainfuckRunner> bf(new BrainfuckInterpreter());
  string bf_file;

  for (int i = 1; i < argc; ++i) {
    if (argv[i] == string("-h") ||
        argv[i] == string("-help") ||
        argv[i] == string("--help") ||
        argv[i] == string("-?")) {
      printf(USAGE, argv[0], argv[0]);
      return 0;
    }
  }

  vector<string> files;
  for (int i = 1; i < argc; ++i) {
    string arg(argv[i]);
    if (arg.find("--") == 0) {
      if (arg.find("--mode=") == 0) {
        if (arg == "--mode=cag") {
          unique_ptr<BrainfuckRunner> compile_and_go(
              new BrainfuckCompileAndGo());
          bf = std::move(compile_and_go);
        } else if (arg == "--mode=i") {
          unique_ptr<BrainfuckRunner> interpreter(new BrainfuckInterpreter());
          bf = std::move(interpreter);
        } else if (arg == "--mode=jit") {
          unique_ptr<BrainfuckRunner> jit(new BrainfuckJIT());
          bf = std::move(jit);
        } else {
          fprintf(stderr, "Unexpected mode: %s\n", arg.c_str());
          return 1;
        }
      } else {
        fprintf(stderr, "Unexpected argument: %s\n", arg.c_str());
        return 1;
      }
    } else {
      files.push_back(arg);
    }
  }

  if (files.size() != 1) {
    fputs("You need to specify exactly one Brainfuck file\n", stderr);
    printf(USAGE, argv[0], argv[0]);
    return 1;
  }

  return run_brainfuck_program(bf.get(), files[0]);
}

// Assembly:
subq $0x218, %rsp            # imm = 0x218
movl $0x0, 0x214(%rsp)
movl %edi, 0x210(%rsp)
movq %rsi, 0x208(%rsp)
movl $0x48, %edi
callq 0x3250
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0xc0(%rsp)
callq 0x8670
jmp 0x3a10
movq 0xc0(%rsp), %rsi
leaq 0x200(%rsp), %rdi
callq 0x4490
leaq 0x1d0(%rsp), %rdi
callq 0x3330
movl $0x1, 0x1cc(%rsp)
movl 0x1cc(%rsp), %eax
cmpl 0x210(%rsp), %eax
jge 0x3f80
movq 0x208(%rsp), %rax
movslq 0x1cc(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0xb0(%rsp)
leaq 0x1a7(%rsp), %rdi
movq %rdi, 0xb8(%rsp)
callq 0x33d0
movq 0xb8(%rsp), %rdx
movb $0x0, 0x17e(%rsp)
movb $0x0, 0x17d(%rsp)
movb $0x0, 0x156(%rsp)
movb $0x0, 0x155(%rsp)
movb $0x0, 0x12e(%rsp)
movb $0x0, 0x12d(%rsp)
leaq 0xa5f3(%rip), %rsi      # 0xe0b4
leaq 0x1a8(%rsp), %rdi
callq 0x3320
jmp 0x3ad0
movq 0xb0(%rsp), %rdi
leaq 0x1a8(%rsp), %rsi
callq 0x44c0
movb %al, 0xaf(%rsp)
jmp 0x3aee
movb 0xaf(%rsp), %cl
movb $0x1, %al
testb $0x1, %cl
movb %al, 0xae(%rsp)
jne 0x3caa
jmp 0x3b09
movq 0x208(%rsp), %rax
movslq 0x1cc(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x98(%rsp)
leaq 0x17f(%rsp), %rdi
movq %rdi, 0xa0(%rsp)
callq 0x33d0
movq 0xa0(%rsp), %rdx
movb $0x1, 0x17e(%rsp)
leaq 0xa567(%rip), %rsi      # 0xe0b8
leaq 0x180(%rsp), %rdi
callq 0x3320
jmp 0x3b60
movq 0x98(%rsp), %rdi
movb $0x1, 0x17d(%rsp)
leaq 0x180(%rsp), %rsi
callq 0x44c0
movb %al, 0x97(%rsp)
jmp 0x3b86
movb 0x97(%rsp), %cl
movb $0x1, %al
testb $0x1, %cl
movb %al, 0xae(%rsp)
jne 0x3caa
jmp 0x3ba1
movq 0x208(%rsp), %rax
movslq 0x1cc(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x80(%rsp)
leaq 0x157(%rsp), %rdi
movq %rdi, 0x88(%rsp)
callq 0x33d0
movq 0x88(%rsp), %rdx
movb $0x1, 0x156(%rsp)
leaq 0xa4ce(%rip), %rsi      # 0xe0b7
leaq 0x158(%rsp), %rdi
callq 0x3320
jmp 0x3bf8
movq 0x80(%rsp), %rdi
movb $0x1, 0x155(%rsp)
leaq 0x158(%rsp), %rsi
callq 0x44c0
movb %al, 0x7f(%rsp)
jmp 0x3c1b
movb 0x7f(%rsp), %cl
movb $0x1, %al
testb $0x1, %cl
movb %al, 0xae(%rsp)
jne 0x3caa
jmp 0x3c2f
movq 0x208(%rsp), %rax
movslq 0x1cc(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x68(%rsp)
leaq 0x12f(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x33d0
movq 0x70(%rsp), %rdx
movb $0x1, 0x12e(%rsp)
leaq 0xa450(%rip), %rsi      # 0xe0be
leaq 0x130(%rsp), %rdi
callq 0x3320
jmp 0x3c7d
movq 0x68(%rsp), %rdi
movb $0x1, 0x12d(%rsp)
leaq 0x130(%rsp), %rsi
callq 0x44c0
movb %al, 0x67(%rsp)
jmp 0x3c9d
movb 0x67(%rsp), %al
movb %al, 0xae(%rsp)
jmp 0x3caa
movb 0xae(%rsp), %al
movb %al, 0x66(%rsp)
testb $0x1, 0x12d(%rsp)
jne 0x3cc1
jmp 0x3cce
leaq 0x130(%rsp), %rdi
callq 0x3160
testb $0x1, 0x12e(%rsp)
jne 0x3cda
jmp 0x3ce7
leaq 0x12f(%rsp), %rdi
callq 0x3280
testb $0x1, 0x155(%rsp)
jne 0x3cf3
jmp 0x3d00
leaq 0x158(%rsp), %rdi
callq 0x3160
testb $0x1, 0x156(%rsp)
jne 0x3d0c
jmp 0x3d19
leaq 0x157(%rsp), %rdi
callq 0x3280
testb $0x1, 0x17d(%rsp)
jne 0x3d25
jmp 0x3d32
leaq 0x180(%rsp), %rdi
callq 0x3160
testb $0x1, 0x17e(%rsp)
jne 0x3d3e
jmp 0x3d4b
leaq 0x17f(%rsp), %rdi
callq 0x3280
leaq 0x1a8(%rsp), %rdi
callq 0x3160
leaq 0x1a7(%rsp), %rdi
callq 0x3280
movb 0x66(%rsp), %al
testb $0x1, %al
jne 0x3d72
jmp 0x3f68
movq 0x208(%rsp), %rax
movq (%rax), %rdx
leaq 0xa3ec(%rip), %rdi      # 0xe170
xorl %eax, %eax
movq %rdx, %rsi
callq 0x3050
jmp 0x3d90
movl $0x0, 0x214(%rsp)
movl $0x1, 0x128(%rsp)
jmp 0x443e
movq 0xc0(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
callq 0x3210
jmp 0x4481
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x3f3d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x3f30
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x3f15
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x3efa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x3edf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x3ec4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x3ea9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
testb $0x1, 0x12d(%rsp)
jne 0x3e9a
jmp 0x3ea7
leaq 0x130(%rsp), %rdi
callq 0x3160
jmp 0x3ea9
testb $0x1, 0x12e(%rsp)
jne 0x3eb5
jmp 0x3ec2
leaq 0x12f(%rsp), %rdi
callq 0x3280
jmp 0x3ec4
testb $0x1, 0x155(%rsp)
jne 0x3ed0
jmp 0x3edd
leaq 0x158(%rsp), %rdi
callq 0x3160
jmp 0x3edf
testb $0x1, 0x156(%rsp)
jne 0x3eeb
jmp 0x3ef8
leaq 0x157(%rsp), %rdi
callq 0x3280
jmp 0x3efa
testb $0x1, 0x17d(%rsp)
jne 0x3f06
jmp 0x3f13
leaq 0x180(%rsp), %rdi
callq 0x3160
jmp 0x3f15
testb $0x1, 0x17e(%rsp)
jne 0x3f21
jmp 0x3f2e
leaq 0x17f(%rsp), %rdi
callq 0x3280
jmp 0x3f30
leaq 0x1a8(%rsp), %rdi
callq 0x3160
leaq 0x1a7(%rsp), %rdi
callq 0x3280
jmp 0x4467
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x4467
jmp 0x3f6a
movl 0x1cc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1cc(%rsp)
jmp 0x3a3d
leaq 0x110(%rsp), %rdi
callq 0x44f0
movl $0x1, 0x10c(%rsp)
movl 0x10c(%rsp), %eax
cmpl 0x210(%rsp), %eax
jge 0x435f
movq 0x208(%rsp), %rax
movslq 0x10c(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x50(%rsp)
leaq 0xe7(%rsp), %rdi
movq %rdi, 0x58(%rsp)
callq 0x33d0
movq 0x50(%rsp), %rsi
movq 0x58(%rsp), %rdx
leaq 0xe8(%rsp), %rdi
callq 0x3320
jmp 0x3ff0
leaq 0xe7(%rsp), %rdi
callq 0x3280
leaq 0xe8(%rsp), %rdi
leaq 0xa0b5(%rip), %rsi      # 0xe0c1
xorl %eax, %eax
movl %eax, %edx
callq 0x3430
cmpq $0x0, %rax
jne 0x42f3
leaq 0xe8(%rsp), %rdi
leaq 0xa096(%rip), %rsi      # 0xe0c4
xorl %eax, %eax
movl %eax, %edx
callq 0x3430
cmpq $0x0, %rax
jne 0x42a7
leaq 0xa084(%rip), %rsi      # 0xe0cc
leaq 0xe8(%rsp), %rdi
callq 0x4500
movb %al, 0x4f(%rsp)
jmp 0x405b
movb 0x4f(%rsp), %al
testb $0x1, %al
jne 0x4068
jmp 0x4120
movl $0x20, %edi
callq 0x3250
movq %rax, 0x40(%rsp)
jmp 0x4079
movq 0x40(%rsp), %rdi
callq 0x6790
jmp 0x4085
movq 0x40(%rsp), %rsi
leaq 0xd8(%rsp), %rdi
callq 0x4490
leaq 0x200(%rsp), %rdi
leaq 0xd8(%rsp), %rsi
callq 0x4530
leaq 0xd8(%rsp), %rdi
callq 0x4560
jmp 0x42a5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
leaq 0xe7(%rsp), %rdi
callq 0x3280
jmp 0x442f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x434d
movq 0x40(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
callq 0x3210
jmp 0x434d
leaq 0x9fb0(%rip), %rsi      # 0xe0d7
leaq 0xe8(%rsp), %rdi
callq 0x4500
movb %al, 0x3f(%rsp)
jmp 0x413a
movb 0x3f(%rsp), %al
testb $0x1, %al
jne 0x4144
jmp 0x41bd
movl $0x48, %edi
callq 0x3250
movq %rax, 0x30(%rsp)
jmp 0x4155
movq 0x30(%rsp), %rdi
callq 0x8670
jmp 0x4161
movq 0x30(%rsp), %rsi
leaq 0xd0(%rsp), %rdi
callq 0x4490
leaq 0x200(%rsp), %rdi
leaq 0xd0(%rsp), %rsi
callq 0x4530
leaq 0xd0(%rsp), %rdi
callq 0x4560
jmp 0x42a3
movq 0x30(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
callq 0x3210
jmp 0x434d
leaq 0x9f1c(%rip), %rsi      # 0xe0e0
leaq 0xe8(%rsp), %rdi
callq 0x4500
movb %al, 0x2f(%rsp)
jmp 0x41d7
movb 0x2f(%rsp), %al
testb $0x1, %al
jne 0x41e1
jmp 0x4257
movl $0x48, %edi
callq 0x3250
movq %rax, 0x20(%rsp)
jmp 0x41f2
movq 0x20(%rsp), %rdi
callq 0xb4a0
jmp 0x41fe
movq 0x20(%rsp), %rsi
leaq 0xc8(%rsp), %rdi
callq 0x4490
leaq 0x200(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0x4530
leaq 0xc8(%rsp), %rdi
callq 0x4560
jmp 0x42a1
movq 0x20(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
callq 0x3210
jmp 0x434d
movq 0xfd82(%rip), %rax      # 0x13fe0
movq (%rax), %rax
movq %rax, 0x18(%rsp)
leaq 0xe8(%rsp), %rdi
callq 0x3100
movq 0x18(%rsp), %rdi
movq %rax, %rdx
leaq 0x9e69(%rip), %rsi      # 0xe0eb
movb $0x0, %al
callq 0x3360
movl $0x1, 0x214(%rsp)
movl $0x1, 0x128(%rsp)
jmp 0x4317
jmp 0x42a3
jmp 0x42a5
jmp 0x42f1
movq 0xfd32(%rip), %rax      # 0x13fe0
movq (%rax), %rax
movq %rax, 0x10(%rsp)
leaq 0xe8(%rsp), %rdi
callq 0x3100
movq 0x10(%rsp), %rdi
movq %rax, %rdx
leaq 0x9e2e(%rip), %rsi      # 0xe100
movb $0x0, %al
callq 0x3360
movl $0x1, 0x214(%rsp)
movl $0x1, 0x128(%rsp)
jmp 0x4317
jmp 0x430c
leaq 0x110(%rsp), %rdi
leaq 0xe8(%rsp), %rsi
callq 0x45c0
jmp 0x430a
jmp 0x430c
movl $0x0, 0x128(%rsp)
leaq 0xe8(%rsp), %rdi
callq 0x3160
movl 0x128(%rsp), %eax
testl %eax, %eax
jne 0x4420
jmp 0x4335
jmp 0x4337
movl 0x10c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x10c(%rsp)
jmp 0x3f98
leaq 0xe8(%rsp), %rdi
callq 0x3160
jmp 0x442f
leaq 0x110(%rsp), %rdi
callq 0x4630
cmpq $0x1, %rax
je 0x43d6
movq 0xfc67(%rip), %rax      # 0x13fe0
movq (%rax), %rsi
leaq 0x9d96(%rip), %rdi      # 0xe119
callq 0x32c0
jmp 0x438a
movq 0x208(%rsp), %rax
movq (%rax), %rdx
leaq 0x9dd4(%rip), %rdi      # 0xe170
xorl %eax, %eax
movq %rdx, %rsi
callq 0x3050
jmp 0x43a8
movl $0x1, 0x214(%rsp)
movl $0x1, 0x128(%rsp)
jmp 0x4420
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1f8(%rsp)
movl %eax, 0x1f4(%rsp)
jmp 0x442f
leaq 0x200(%rsp), %rdi
callq 0x4650
movq %rax, (%rsp)
xorl %eax, %eax
movl %eax, %esi
leaq 0x110(%rsp), %rdi
callq 0x4680
movq (%rsp), %rdi
movq %rax, %rsi
callq 0x3540
movl %eax, 0xc(%rsp)
jmp 0x440a
movl 0xc(%rsp), %eax
movl %eax, 0x214(%rsp)
movl $0x1, 0x128(%rsp)
leaq 0x110(%rsp), %rdi
callq 0x46a0
jmp 0x443e
leaq 0x110(%rsp), %rdi
callq 0x46a0
jmp 0x4467
leaq 0x1d0(%rsp), %rdi
callq 0x3160
leaq 0x200(%rsp), %rdi
callq 0x4560
movl 0x214(%rsp), %eax
addq $0x218, %rsp            # imm = 0x218
retq
leaq 0x1d0(%rsp), %rdi
callq 0x3160
leaq 0x200(%rsp), %rdi
callq 0x4560
movq 0x1f8(%rsp), %rdi
callq 0x33c0
nop