// File: /workspace/github_cpp_makefile_star2_O2/Bartor[P]kompilator/main.cpp
// Function: main
int main(int argc, char **argv) {
    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

    if (argc < 2) {
        std::cerr << "[i] Usage: compiler <source> [destination] [optimize=(0|1)]" << std::endl;
        return 1;
    }

    FILE *source = fopen(argv[1], "r");
    if (!source) {
        std::cerr << "[e] Can't open " << argv[1] << std::endl;
        return 1;
    }

    bool optimize = true, verbose = false;
    for (int i = 0; i < argc; i++) {
        if (argv[i][0] == '-' && argv[i][1] == 'v') verbose = true;
        if (argv[i][0] == '-' && argv[i][1] == 'o') optimize = false;
    }

    std::cout << "[i] Compiling file " << argv[1] << (optimize ? " with optimization" : " without optimization") << std::endl;

    std::cout << "[i] Parsing... " << std::endl;

    yyin = source;
    yyparse();

    std::cout << "   [i] done" << std::endl;

    if (commands == nullptr) commands = new CommandList();
    if (declarations == nullptr) declarations = new DeclarationList();

    Program *program = new Program(*declarations, *commands, *constants);

    if (verbose) std::cout << "-=- A S T -=-" << std::endl;
    if (verbose) std::cout << program->toString() << std::endl;

    if (optimize) {
        std::cout << "[i] AST Optimization... " << std::endl;
        if (verbose) std::cout << std::endl;
        ASTOptimizer *astOptimizer = new ASTOptimizer(program);
        astOptimizer->optimize(verbose);
        if (verbose) std::cout << std::endl;
        std::cout << "   [i] done" << std::endl;

        if (verbose) std::cout << "-=- OPTIMIZED A S T -=-" << std::endl;
        if (verbose) std::cout << program->toString() << std::endl;
    }

    AbstractAssembler *assembler = new AbstractAssembler(*program);

    std::cout << "[i] Compiling... " << std::endl;
    if (verbose) std::cout << std::endl;

    try {
        InstructionList &assembled = assembler->assemble(verbose);

        std::cout << "   [i] done" << std::endl;

        if (verbose) std::cout << std::endl << "-=- A S M -=-" << std::endl;

        std::ofstream output;
        output.open(argv[2] ? argv[2] : "a.out");

        for (const auto &ins : assembled.getInstructions()) {
            if (!ins->stub) {
                if (verbose) std::cout << std::setbase(10) << ins->getAddress() << ": " << ins->toAssemblyCode(true) << std::endl;
                if (!optimize) output << ins->toAssemblyCode(true) << std::endl;
            }
        }

        if (optimize) {
            std::cout << "[i] ASM Optimization... " << std::endl;
            if (verbose) std::cout << std::endl;
            PeepholeOptimizer *peepholeOptimizer = new PeepholeOptimizer(assembled);

            peepholeOptimizer->optimize(verbose);
            assembled.seal(false);

            if (verbose) std::cout << std::endl;
            std::cout << "   [i] done" << std::endl;

            if (verbose) std::cout << std::endl << "-=- OPTIMIZED A S M -=-" << std::endl;

            for (const auto &ins : assembled.getInstructions()) {
                if (!ins->stub) {
                    if (verbose) std::cout << std::setbase(10) << ins->getAddress() << ": " << ins->toAssemblyCode(true) << std::endl;
                    output << ins->toAssemblyCode(true) << std::endl;
                }
            }
            output.close();
        }

        std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

        if (warning) {
            std::cout << "[w] Compiled with warnings in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " ms" << std::endl;

        } else {
            std::cout << "[i] Compiled successfully in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " ms" << std::endl;
        }

    } catch (std::string errorMessage) {
        std::cout << "   [e] " << errorMessage << std::endl;
        std::cout << "[e] Aborting" << std::endl;
        return 1;
    } catch (char const *errorMessage) {
        std::cout << "   [e] " << errorMessage << std::endl;
        std::cout << "[e] Aborting" << std::endl;
        return 1;
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x248, %rsp            # imm = 0x248
movq %rsi, %r14
movl %edi, %r15d
callq 0x5270
cmpl $0x1, %r15d
jg 0x15f3c
movq 0xa0c0(%rip), %rdi      # 0x1fff0
leaq 0x2b37(%rip), %rsi      # 0x18a6e
jmp 0x16181
movq %rax, -0x48(%rbp)
movq 0x8(%r14), %rdi
leaq 0x2642(%rip), %rsi      # 0x1858d
callq 0x5210
testq %rax, %rax
je 0x16167
movq %rax, %rbx
movl %r15d, %eax
movb $0x1, %r15b
xorl %ecx, %ecx
xorl %edi, %edi
cmpq %rcx, %rax
je 0x15f8f
movq (%r14,%rcx,8), %rdx
cmpb $0x2d, (%rdx)
jne 0x15f8a
movb 0x1(%rdx), %dl
cmpb $0x76, %dl
sete %sil
orb %sil, %dil
cmpb $0x6f, %dl
setne %dl
andb %dl, %r15b
incq %rcx
jmp 0x15f66
movq %rdi, -0x38(%rbp)
movq 0xa02e(%rip), %r12      # 0x1ffc8
leaq 0x2b19(%rip), %rsi      # 0x18aba
movq %r12, %rdi
callq 0x51b0
movq 0x8(%r14), %rsi
movq %rax, %rdi
callq 0x51b0
leaq 0x2b12(%rip), %rcx      # 0x18ace
leaq 0x2b1e(%rip), %rsi      # 0x18ae1
testb $0x1, %r15b
cmovneq %rcx, %rsi
movq %rax, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq 0x2b15(%rip), %rsi      # 0x18af7
movq %r12, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq 0xa29f(%rip), %rax      # 0x20298
movq %rbx, (%rax)
callq 0x572c
leaq 0x2aff(%rip), %rsi      # 0x18b07
movq %r12, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq 0xa249(%rip), %r12      # 0x20268
movq (%r12), %rbx
testq %rbx, %rbx
jne 0x16051
pushq $0x20
popq %rdi
callq 0x51c0
movq %rax, %rbx
leaq 0x92c6(%rip), %rax      # 0x1f300
addq $0x10, %rax
movq %rax, (%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rbx)
andq $0x0, 0x18(%rbx)
movq %rbx, (%r12)
leaq 0xa208(%rip), %r13      # 0x20260
movq (%r13), %r12
testq %r12, %r12
jne 0x1608e
pushq $0x20
popq %rdi
callq 0x51c0
movq %rax, %r12
leaq 0x955d(%rip), %rax      # 0x1f5d0
addq $0x10, %rax
movq %rax, (%r12)
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%r12)
andq $0x0, 0x18(%r12)
movq %r12, (%r13)
pushq $0x18
popq %rdi
callq 0x51c0
leaq 0xa1d3(%rip), %rcx      # 0x20270
movq (%rcx), %rcx
movq %r12, (%rax)
movq %rbx, 0x8(%rax)
movq %rax, -0x30(%rbp)
movq %rcx, 0x10(%rax)
movq -0x38(%rbp), %r13
testb $0x1, %r13b
je 0x16109
movq 0x9f08(%rip), %rbx      # 0x1ffc8
leaq 0x2a4c(%rip), %rsi      # 0x18b13
movq %rbx, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq -0x268(%rbp), %r12
movq %r12, %rdi
movq -0x30(%rbp), %rsi
callq 0x9586
movq %rbx, %rdi
movq %r12, %rsi
callq 0x5190
movq %rax, %rdi
callq 0x5100
leaq -0x268(%rbp), %rdi
callq 0x5418
testb $0x1, %r15b
je 0x16220
movq 0x9eae(%rip), %rdi      # 0x1ffc8
leaq 0x2a00(%rip), %rsi      # 0x18b21
callq 0x51b0
movq %rax, %rdi
callq 0x5100
testb $0x1, %r13b
je 0x16196
movq 0x9e8d(%rip), %rbx      # 0x1ffc8
movq %rbx, %rdi
callq 0x5100
pushq $0x8
popq %rdi
callq 0x51c0
movq -0x30(%rbp), %rcx
movq %rcx, (%rax)
pushq $0x1
popq %rsi
movq %rax, %rdi
callq 0x14078
movq %rbx, %rdi
callq 0x5100
jmp 0x161af
movq 0x9e82(%rip), %rdi      # 0x1fff0
leaq 0x2935(%rip), %rsi      # 0x18aaa
callq 0x51b0
movq 0x8(%r14), %rsi
movq %rax, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
pushq $0x1
popq %rax
jmp 0x1660f
pushq $0x8
popq %rdi
callq 0x51c0
movq -0x30(%rbp), %rcx
movq %rcx, (%rax)
movq %rax, %rdi
xorl %esi, %esi
callq 0x14078
movq 0x9e12(%rip), %rdi      # 0x1ffc8
leaq 0x294a(%rip), %rsi      # 0x18b07
callq 0x51b0
movq %rax, %rdi
callq 0x5100
testb $0x1, %r13b
je 0x16220
movq 0x9df1(%rip), %rbx      # 0x1ffc8
leaq 0x295c(%rip), %rsi      # 0x18b3a
movq %rbx, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq -0x268(%rbp), %r12
movq %r12, %rdi
movq -0x30(%rbp), %rsi
callq 0x9586
movq %rbx, %rdi
movq %r12, %rsi
callq 0x5190
movq %rax, %rdi
callq 0x5100
leaq -0x268(%rbp), %rdi
callq 0x5418
pushq $0x38
popq %rdi
callq 0x51c0
movq %rax, %r12
movq %rax, %rdi
movq -0x30(%rbp), %rsi
callq 0x1679c
movq 0x9d8a(%rip), %rdi      # 0x1ffc8
leaq 0x290d(%rip), %rsi      # 0x18b52
callq 0x51b0
movq %rax, %rdi
callq 0x5100
testb $0x1, %r13b
je 0x16264
movq 0x9d69(%rip), %rdi      # 0x1ffc8
callq 0x5100
movzbl %r13b, %esi
andl $0x1, %esi
movq %r12, %rdi
movl %esi, -0x3c(%rbp)
callq 0x115bc
movq %rax, %rbx
movq 0x9d48(%rip), %rdi      # 0x1ffc8
leaq 0x2880(%rip), %rsi      # 0x18b07
callq 0x51b0
movq %rax, %rdi
callq 0x5100
testb $0x1, %r13b
je 0x162bd
movq 0x9d27(%rip), %rdi      # 0x1ffc8
callq 0x5100
leaq 0x28b7(%rip), %rsi      # 0x18b64
movq %rax, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq -0x268(%rbp), %rdi
callq 0x5350
movq 0x10(%r14), %rax
testq %rax, %rax
leaq 0x289b(%rip), %rsi      # 0x18b72
cmovneq %rax, %rsi
leaq -0x268(%rbp), %rdi
pushq $0x10
popq %rdx
callq 0x5040
movq %rbx, -0x30(%rbp)
movq %rbx, %rdi
callq 0x14d9e
movq (%rax), %r12
movq 0x8(%rax), %r13
leaq -0x68(%rbp), %rbx
cmpq %r13, %r12
je 0x163ca
movq (%r12), %rdi
cmpb $0x0, 0x10(%rdi)
jne 0x163c1
testb $0x1, -0x38(%rbp)
je 0x1638c
movq 0x9ca3(%rip), %rdx      # 0x1ffc8
movq (%rdx), %rax
movq -0x18(%rax), %rax
movl 0x18(%rdx,%rax), %ecx
andl $-0x4b, %ecx
orl $0x2, %ecx
movl %ecx, 0x18(%rdx,%rax)
movq (%rdi), %rax
callq *0x8(%rax)
movq 0x9c81(%rip), %rdi      # 0x1ffc8
movq %rax, %rsi
callq 0x50b0
movq %rax, %rdi
leaq 0x2336(%rip), %rsi      # 0x1868f
callq 0x51b0
movq %rax, %r14
movq (%r12), %rsi
movq (%rsi), %rax
movq %rbx, %rdi
pushq $0x1
popq %rdx
callq *0x10(%rax)
movq %r14, %rdi
movq %rbx, %rsi
callq 0x5190
movq %rax, %rdi
callq 0x5100
movq %rbx, %rdi
callq 0x5418
testb $0x1, %r15b
jne 0x163c1
movq (%r12), %rsi
movq (%rsi), %rax
movq %rbx, %rdi
pushq $0x1
popq %rdx
callq *0x10(%rax)
leaq -0x268(%rbp), %rdi
movq %rbx, %rsi
callq 0x5190
movq %rax, %rdi
callq 0x5100
movq %rbx, %rdi
callq 0x5418
addq $0x8, %r12
jmp 0x16301
testb $0x1, %r15b
movq -0x38(%rbp), %rbx
movq -0x30(%rbp), %r14
je 0x16562
movq 0x9be5(%rip), %rdi      # 0x1ffc8
leaq 0x278e(%rip), %rsi      # 0x18b78
callq 0x51b0
movq %rax, %rdi
callq 0x5100
testb $0x1, %bl
je 0x16408
movq 0x9bc5(%rip), %rdi      # 0x1ffc8
callq 0x5100
pushq $0x8
popq %rdi
callq 0x51c0
movq %r14, (%rax)
movq %rax, %rdi
movl -0x3c(%rbp), %esi
callq 0x1479c
movq %r14, %rdi
xorl %esi, %esi
callq 0x14e1e
testb $0x1, %bl
je 0x16439
movq 0x9b94(%rip), %rdi      # 0x1ffc8
callq 0x5100
movq 0x9b88(%rip), %rdi      # 0x1ffc8
leaq 0x26c0(%rip), %rsi      # 0x18b07
callq 0x51b0
movq %rax, %rdi
callq 0x5100
testb $0x1, %bl
je 0x1647c
movq 0x9b68(%rip), %rdi      # 0x1ffc8
callq 0x5100
leaq 0x2725(%rip), %rsi      # 0x18b91
movq %rax, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
movq %r14, %rdi
callq 0x14d9e
movq (%rax), %r14
movq 0x8(%rax), %r13
leaq -0x68(%rbp), %rbx
pushq $0x1
popq %r12
cmpq %r13, %r14
je 0x16556
movq (%r14), %rsi
cmpb $0x0, 0x10(%rsi)
jne 0x1654d
testb $0x1, -0x38(%rbp)
je 0x16522
movq 0x9b12(%rip), %rdx      # 0x1ffc8
movq (%rdx), %rax
movq -0x18(%rax), %rax
movl 0x18(%rdx,%rax), %ecx
andl $-0x4b, %ecx
orl $0x2, %ecx
movl %ecx, 0x18(%rdx,%rax)
movq (%rsi), %rax
movq %rsi, %rdi
callq *0x8(%rax)
movq 0x9aed(%rip), %rdi      # 0x1ffc8
movq %rax, %rsi
callq 0x50b0
movq %rax, %rdi
leaq 0x21a2(%rip), %rsi      # 0x1868f
callq 0x51b0
movq %rax, %r15
movq (%r14), %rsi
movq (%rsi), %rax
movq %rbx, %rdi
movl %r12d, %edx
callq *0x10(%rax)
movq %r15, %rdi
movq %rbx, %rsi
callq 0x5190
movq %rax, %rdi
callq 0x5100
movq %rbx, %rdi
callq 0x5418
movq (%r14), %rsi
movq (%rsi), %rax
movq %rbx, %rdi
movl %r12d, %edx
callq *0x10(%rax)
leaq -0x268(%rbp), %rdi
movq %rbx, %rsi
callq 0x5190
movq %rax, %rdi
callq 0x5100
movq %rbx, %rdi
callq 0x5418
addq $0x8, %r14
jmp 0x16493
leaq -0x268(%rbp), %rdi
callq 0x52a0
callq 0x5270
movq %rax, %rbx
cmpb $0x1, 0x9e31(%rip)      # 0x203a2
jne 0x165bb
movq 0x9a4e(%rip), %rdi      # 0x1ffc8
leaq 0x2628(%rip), %rsi      # 0x18ba9
callq 0x51b0
movq %rax, %rdi
subq -0x48(%rbp), %rbx
movl $0xf4240, %ecx          # imm = 0xF4240
movq %rbx, %rax
cqto
idivq %rcx
movq %rax, %rsi
callq 0x51a0
leaq 0x261f(%rip), %rsi      # 0x18bc8
movq %rax, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
jmp 0x16601
movq 0x9a06(%rip), %rdi      # 0x1ffc8
leaq 0x2603(%rip), %rsi      # 0x18bcc
callq 0x51b0
movq %rax, %rdi
subq -0x48(%rbp), %rbx
movl $0xf4240, %ecx          # imm = 0xF4240
movq %rbx, %rax
cqto
idivq %rcx
movq %rax, %rsi
callq 0x51a0
leaq 0x25d7(%rip), %rsi      # 0x18bc8
movq %rax, %rdi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq -0x268(%rbp), %rdi
callq 0x52c0
xorl %eax, %eax
addq $0x248, %rsp            # imm = 0x248
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x16683
jmp 0x1663b
jmp 0x16683
jmp 0x16683
jmp 0x1665c
movq %rax, %rbx
pushq $0x38
popq %rsi
movq %r12, %rdi
callq 0x51d0
jmp 0x1664a
movq %rax, %rbx
leaq -0x268(%rbp), %rdi
callq 0x5418
movq %rbx, %rdi
callq 0x5390
jmp 0x16683
jmp 0x16683
jmp 0x16683
jmp 0x16683
jmp 0x16683
movq %rdx, %r14
movq %rax, %rbx
jmp 0x16695
jmp 0x16672
jmp 0x16683
jmp 0x16683
jmp 0x16683
jmp 0x16683
jmp 0x16672
jmp 0x16672
movq %rdx, %r14
movq %rax, %rbx
leaq -0x68(%rbp), %rdi
callq 0x5418
jmp 0x16689
movq %rdx, %r14
movq %rax, %rbx
leaq -0x268(%rbp), %rdi
callq 0x52c0
cmpl $0x2, %r14d
jne 0x1670d
movq %rbx, %rdi
callq 0x5250
leaq -0x268(%rbp), %rdi
movq %rax, %rsi
callq 0x5290
movq %rbx, %rdi
callq 0x50d0
movq 0x9907(%rip), %rdi      # 0x1ffc8
leaq 0xe8c(%rip), %rsi       # 0x17554
callq 0x51b0
leaq -0x268(%rbp), %rsi
movq %rax, %rdi
callq 0x5190
movq %rax, %rdi
callq 0x5100
movq 0x98dd(%rip), %rdi      # 0x1ffc8
leaq 0xe74(%rip), %rsi       # 0x17566
callq 0x51b0
movq %rax, %rdi
callq 0x5100
leaq -0x268(%rbp), %rdi
callq 0x5418
jmp 0x16763
cmpl $0x1, %r14d
jne 0x1664a
movq %rbx, %rdi
callq 0x50d0
movq %rax, %rbx
movq 0x989f(%rip), %rdi      # 0x1ffc8
leaq 0xe24(%rip), %rsi       # 0x17554
callq 0x51b0
movq %rax, %rdi
movq %rbx, %rsi
callq 0x51b0
movq %rax, %rdi
callq 0x5100
movq 0x9879(%rip), %rdi      # 0x1ffc8
leaq 0xe10(%rip), %rsi       # 0x17566
callq 0x51b0
movq %rax, %rdi
callq 0x5100
callq 0x5320
jmp 0x1618e
movq %rax, %rbx
callq 0x5320
jmp 0x1664a
movq %rax, %rbx
leaq -0x268(%rbp), %rdi
callq 0x5418
callq 0x5320
jmp 0x1664a
movq %rax, %rdi
callq 0xa8e7
nop