// File: /workspace/github_c_makefile_star2_O2/ryvnf[P]czc/main.c
// Function: main
int main(int argc, char **argv)
{
    char *out = NULL;

    struct arg_list *gcc_args = arg_list_new("gcc");
    struct arg_list **gcc_args_tailp = &gcc_args->next;
    struct arg_list *src_files = NULL;
    struct arg_list **src_files_tailp = &src_files;

    // Colors are disabled to make messages from 'gcc' consistent with other
    // messages which doesn't have color.
    *gcc_args_tailp = arg_list_new("-fno-diagnostics-color");
    gcc_args_tailp = &(*gcc_args_tailp)->next;

    // We don't want warnings from GCC to leak through.  Will still output
    // errors if the generated code does not compile.
    *gcc_args_tailp = arg_list_new("-w");
    gcc_args_tailp = &(*gcc_args_tailp)->next;

    // Tell GCC that the source has been preprocessed.  This is to avoid having
    // to escape trigraphs in the generated C code.
    *gcc_args_tailp = arg_list_new("-fpreprocessed");
    gcc_args_tailp = &(*gcc_args_tailp)->next;

    int input_file_count = 0;

    enum {
        TO_EXE,
        TO_C,
        TO_ASM,
        TO_OBJ,
        AST_PRINT
    } mode = TO_EXE;

    for (int i = 1; i < argc; ++i) {
        if (argv[i][0] == '-') {
            if (strcmp(argv[i], "--print-ast") == 0) {
                mode = AST_PRINT;
                continue;
            }
            if (strcmp(argv[i], "--to-c") == 0) {
                mode = TO_C;
                *gcc_args_tailp = arg_list_new(argv[i]);
                gcc_args_tailp = &(*gcc_args_tailp)->next;
                continue;
            }

            switch (argv[i][1]) {
                // These options require thir arguments to be in the option
                // flag.  Their arguments can be anything.  They are copied
                // directly to the GCC command-line.
                case 'O':
                case 'f':
                    *gcc_args_tailp = arg_list_new(argv[i]);
                    gcc_args_tailp = &(*gcc_args_tailp)->next;
                    break;

                // The '-o' option doesn't require its arguments to be in the
                // option flag.  So if the flag doesn't have an argument, parse
                // the next argv element as argument for the option.  The
                // option gets added to the GCC command-line, but it also sets
                // the variable 'out'.
                case 'o':
                    *gcc_args_tailp = arg_list_new(argv[i]);
                    gcc_args_tailp = &(*gcc_args_tailp)->next;

                    if (argv[i][2] != '\0') {
                        out = argv[i] + 1;
                    } else {
                        if ((out = argv[++i]) == NULL)
                            missing_arg_for_opt(argv[i - 1]);
                        *gcc_args_tailp = arg_list_new(argv[i]);
                        gcc_args_tailp = &(*gcc_args_tailp)->next;
                    }

                    break;

                // These options doesn't require their arguments to be in the
                // option flag.  So if the flag doesn't have an argument, parse
                // the next argv element as argument for the option.  The
                // options are copied directly to the GCC command-line.
                case 'l':
                case 'L':
                    *gcc_args_tailp = arg_list_new(argv[i]);
                    gcc_args_tailp = &(*gcc_args_tailp)->next;

                    if (argv[i][2] == '\0') {
                        if (argv[++i] == NULL)
                            missing_arg_for_opt(argv[i - 1]);
                        *gcc_args_tailp = arg_list_new(argv[i]);
                        gcc_args_tailp = &(*gcc_args_tailp)->next;
                    }
                    break;

                case 'c':
                    mode = TO_OBJ;
                    if (argv[i][2] != '\0')
                        unrecognized_opt(argv[i]);

                    *gcc_args_tailp = arg_list_new(argv[i]);
                    gcc_args_tailp = &(*gcc_args_tailp)->next;
                    break;

                case 'S':
                    mode = TO_ASM;
                    if (argv[i][2] != '\0')
                        unrecognized_opt(argv[i]);

                    *gcc_args_tailp = arg_list_new(argv[i]);
                    gcc_args_tailp = &(*gcc_args_tailp)->next;
                    break;

                default:
                    unrecognized_opt(argv[i]);
            }
            continue;
        }

        // Arguments left are input files.  These are interpreted differently
        // depending on their extension, like .o for object files passed to the
        // linker or .s for assembly files passed to the assembler.  Only .z
        // and .zc files are recognized as source files for the language, all
        // other file types are passed directly to the GCC command-line.
        const char *ext = get_file_ext(argv[i]);
        input_file_count++;

        if (ext == NULL || (strcmp(ext, "z") != 0 &&
                    strcmp(ext, "zc") != 0 && strcmp(ext, "Z") != 0 &&
                    strcmp(ext, "ZC") != 0)) {
            *gcc_args_tailp = arg_list_new(argv[i]);
            gcc_args_tailp = &(*gcc_args_tailp)->next;
            continue;
        }

        *src_files_tailp = arg_list_new(argv[i]);
        src_files_tailp = &(*src_files_tailp)->next;
    }

    if (input_file_count == 0) {
        fatal(NULL, "no input files");
        exit(1);
    }


    if (out != NULL && input_file_count != 1 && mode != TO_EXE) {
        fatal(NULL, "cannot specify '-o' with '-c', '-S', or '-C' with "
                "multiple files\n");
        exit(1);
    }

    if (src_files != NULL) {
        if (mode == TO_C) {
            gen_c(src_files, out);
        } else if (mode == AST_PRINT) {
            print_ast_files(src_files);
        } else {
            invoke_gcc(src_files, gcc_args, gcc_args_tailp);
        }
    } else {
        invoke_gcc(src_files, gcc_args, gcc_args_tailp);
    }

    arg_list_del(src_files);
    arg_list_del(gcc_args);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rsi, %r14
movl %edi, 0x1c(%rsp)
leaq 0x41aa(%rip), %rdi      # 0xc59f
callq 0x80ce
movq %rax, %r15
leaq 0x30(%rsp), %rax
movq %rax, 0x20(%rsp)
andq $0x0, (%rax)
leaq 0x4198(%rip), %rdi      # 0xc5aa
callq 0x80ce
movq %rax, %rbx
movq %r15, 0x28(%rsp)
movq %rax, 0x8(%r15)
leaq 0x4197(%rip), %rdi      # 0xc5c1
callq 0x80ce
movq %rax, %r12
movq %rax, 0x8(%rbx)
leaq 0x4187(%rip), %rdi      # 0xc5c4
callq 0x80ce
movq %rax, %r15
movq %rax, 0x8(%r12)
addq $0x8, %r15
pushq $0x1
popq %r13
xorl %ebx, %ebx
movl $0x0, 0xc(%rsp)
movq $0x0, 0x10(%rsp)
cmpl 0x1c(%rsp), %r13d
jge 0x8641
movslq %r13d, %rbp
movq (%r14,%rbp,8), %r12
cmpb $0x2d, (%r12)
jne 0x84ee
movq %r12, %rdi
leaq 0x414b(%rip), %rsi      # 0xc5d3
callq 0x2100
testl %eax, %eax
je 0x8518
movq %r12, %rdi
leaq 0x4140(%rip), %rsi      # 0xc5df
callq 0x2100
testl %eax, %eax
je 0x851c
movzbl 0x1(%r12), %eax
cmpl $0x4c, %eax
je 0x857e
cmpl $0x4f, %eax
je 0x8549
cmpl $0x53, %eax
je 0x85b0
cmpl $0x63, %eax
je 0x85d5
cmpl $0x6f, %eax
je 0x85fa
cmpl $0x6c, %eax
je 0x857e
cmpl $0x66, %eax
je 0x8549
jmp 0x86c3
movq %r12, %rdi
callq 0x8094
incl %ebx
testq %rax, %rax
je 0x8549
movzbl (%rax), %ecx
cmpl $0x5a, %ecx
je 0x8537
cmpl $0x7a, %ecx
jne 0x8549
cmpb $0x0, 0x1(%rax)
je 0x8563
cmpb $0x63, 0x1(%rax)
je 0x8543
jmp 0x8549
pushq $0x4
jmp 0x8530
movq %r12, %rdi
callq 0x80ce
movq %rax, (%r15)
addq $0x8, %rax
movq %rax, %r15
pushq $0x1
popq %rax
movl %eax, 0xc(%rsp)
jmp 0x855b
cmpb $0x0, 0x1(%rax)
je 0x8563
cmpb $0x43, 0x1(%rax)
jne 0x8549
cmpb $0x0, 0x2(%rax)
je 0x8563
movq %r12, %rdi
callq 0x80ce
movq %rax, (%r15)
addq $0x8, %rax
movq %rax, %r15
incl %r13d
jmp 0x8465
movq %r12, %rdi
callq 0x80ce
movq 0x20(%rsp), %rcx
movq %rax, (%rcx)
addq $0x8, %rax
movq %rax, 0x20(%rsp)
jmp 0x855b
movq %r12, %rdi
callq 0x80ce
movq %rax, (%r15)
movq %rax, %r15
addq $0x8, %r15
movq (%r14,%rbp,8), %rdi
cmpb $0x0, 0x2(%rdi)
jne 0x855b
movq 0x8(%r14,%rbp,8), %rax
testq %rax, %rax
je 0x86e4
incl %r13d
jmp 0x8639
cmpb $0x0, 0x2(%r12)
jne 0x86c3
movq %r12, %rdi
callq 0x80ce
movq %rax, (%r15)
addq $0x8, %rax
movq %rax, %r15
pushq $0x2
jmp 0x8530
cmpb $0x0, 0x2(%r12)
jne 0x86c3
movq %r12, %rdi
callq 0x80ce
movq %rax, (%r15)
addq $0x8, %rax
movq %rax, %r15
pushq $0x3
jmp 0x8530
movq %r12, %rdi
callq 0x80ce
movq %rax, (%r15)
movq %rax, %r15
addq $0x8, %r15
movq (%r14,%rbp,8), %rdi
cmpb $0x0, 0x2(%rdi)
je 0x8623
incq %rdi
movq %rdi, 0x10(%rsp)
jmp 0x855b
movq 0x8(%r14,%rbp,8), %rax
testq %rax, %rax
je 0x86e4
incl %r13d
movq %rax, 0x10(%rsp)
movq %rax, %rdi
jmp 0x854c
testl %ebx, %ebx
je 0x86cb
movq 0x10(%rsp), %rsi
testq %rsi, %rsi
setne %al
cmpl $0x1, %ebx
setne %cl
andb %al, %cl
movl 0xc(%rsp), %edx
testl %edx, %edx
setne %al
andb %cl, %al
cmpb $0x1, %al
movq 0x28(%rsp), %r14
je 0x86d4
movq 0x30(%rsp), %rbx
testq %rbx, %rbx
je 0x868e
movq %rbx, %rdi
cmpl $0x4, %edx
je 0x869d
cmpl $0x1, %edx
jne 0x8690
callq 0x8110
jmp 0x86a2
xorl %edi, %edi
movq %r14, %rsi
movq %r15, %rdx
callq 0x8205
jmp 0x86a2
callq 0x81c5
movq %rbx, %rdi
callq 0x80aa
movq %r14, %rdi
callq 0x80aa
xorl %eax, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r12, %rdi
callq 0x806c
leaq 0x3f14(%rip), %rsi      # 0xc5e6
jmp 0x86db
leaq 0x3f1a(%rip), %rsi      # 0xc5f5
xorl %edi, %edi
xorl %eax, %eax
callq 0x4a05
callq 0x8080
nopl (%rax)