// File: baziotis[P]minijava-cpp/parse.cpp
// Function: parse_main_class()
static MainClass parse_main_class() {
    MainClass main_class;
    // Note: Most gymnastics are for error reporting.
    // TODO: Some errors below are probably fatal, so we should
    // stop there.
    if (match_token(TOK::CLASS)) {  // "class"
        main_class.id = token.id;
        if (match_token(TOK::ID)) {  // Identifier
            expect_token_in_rule(TOK::LBRACE, "MainClass declaration");    // "{"
            expect_token_in_rule(TOK::PUBLIC, "MainClass declaration");    // "public"
            expect_token_in_rule(TOK::STATIC, "MainClass declaration");    // "static"
            expect_token_in_rule(TOK::VOID, "MainClass declaration");      // "void"
            if (!is_token(TOK::ID) || token.id != main_method_string) {
                syntax_error("Expected identifier `main` in MainClass declaration to"
                             " start the declaration of the main method.");
                goto Lerror;
            }
            // Advance anyway
            next_token();
            expect_token_in_rule(TOK::LPAR, "`main` method declaration");      // "("
            if (!match_token(TOK::STRING)) {
                syntax_error("`main` method of MainClass can only have one"
                             " argument, of String[] type.");
                // Advance anyway
                next_token();
            }
            expect_token_in_rule(TOK::LBRACKET, "MainClass declaration");  // "["
            expect_token_in_rule(TOK::RBRACKET, "MainClass declaration");  // "]"
            expect_token_in_rule(TOK::ID, "MainClass declaration");        // "Identifier"
            if (is_token(TOK::COMMA)) {
                syntax_error_no_ln("`main` method of MainClass can only have one"
                             " argument, of String[] type.");
                skip_tokens(TOK::RPAR);
            } else {
                // ")"
                expect_token_in_rule(TOK::RPAR, "`main` method of MainClass declaration");
            }
            // "{"
            expect_token_in_rule(TOK::LBRACE, "`main` method of MainClass declaration");
            // Parse VarDeclarations
            while (starts_local()) {
                parse_local_and_push(&main_class.vars);
                expect_token_in_rule(TOK::SEMI, "var declaration");
            }
            while (starts_statement(token.kind)) {
                parse_stmt_and_push(&main_class.stmts);
            }
            // "}" - close main
            expect_token_in_rule(TOK::RBRACE, "`main` method of MainClass declaration");
            expect_token_in_rule(TOK::RBRACE, "MainClass declaration");  // "}" - close class
        } else {
            syntax_error("MainClass name was expected, but `", token.kind,
                         "` was encountered.");
            goto Lerror;
        }
    } else {
        syntax_error("`class` keyword was expected, in order to start the "
                     "MainClass. But `", token.kind, "` was encountered.");
        goto Lerror;
    }
    return main_class;
Lerror:
    main_class.make_undefined();
    return main_class;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x10, %rsp
movq %rdi, -0x10(%rbp)
movq %rdi, %rax
movq %rax, -0x8(%rbp)
callq 0xaa90
movl $0x16, %edi
callq 0x82c0
testb $0x1, %al
jne 0x7deb
jmp 0x7fef
movq -0x10(%rbp), %rax
leaq 0x1c8b2(%rip), %rcx     # 0x246a8
movq 0x8(%rcx), %rcx
movq %rcx, 0x8(%rax)
movl $0x8, %edi
callq 0x82c0
testb $0x1, %al
jne 0x7e11
jmp 0x7fcf
movl $0x7, %edi
leaq 0x12e47(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
movl $0xc, %edi
leaq 0x12e34(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
movl $0xf, %edi
leaq 0x12e21(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
movl $0x10, %edi
leaq 0x12e0e(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
movl $0x8, %edi
callq 0x8070
testb $0x1, %al
jne 0x7e6d
jmp 0x7e81
leaq 0x1c834(%rip), %rax     # 0x246a8
movq 0x8(%rax), %rax
cmpq 0x1cbd9(%rip), %rax     # 0x24a58
je 0x7e92
leaq 0x12d07(%rip), %rdi     # 0x1ab8f
callq 0x83d0
jmp 0x800f
callq 0x4370
movl $0x3, %edi
leaq 0x12d4d(%rip), %rsi     # 0x1abf0
xorl %edx, %edx
callq 0x8300
movl $0x11, %edi
callq 0x82c0
testb $0x1, %al
jne 0x7ec9
leaq 0x12d4b(%rip), %rdi     # 0x1ac0a
callq 0x83d0
callq 0x4370
movl $0x24, %edi
leaq 0x12d8f(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
movl $0x1b, %edi
leaq 0x12d7c(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
movl $0x8, %edi
leaq 0x12d69(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
movl $0x1c, %edi
callq 0x8070
testb $0x1, %al
jne 0x7f12
jmp 0x7f2f
leaq 0x12cf1(%rip), %rdi     # 0x1ac0a
callq 0x8400
movl $0x19, %edi
movl $0x1, %esi
callq 0x8450
jmp 0x7f42
movl $0x19, %edi
leaq 0x12d18(%rip), %rsi     # 0x1ac53
xorl %edx, %edx
callq 0x8300
movl $0x7, %edi
leaq 0x12d05(%rip), %rsi     # 0x1ac53
xorl %edx, %edx
callq 0x8300
callq 0x8560
testb $0x1, %al
jne 0x7f60
jmp 0x7f82
movq -0x10(%rbp), %rdi
addq $0x10, %rdi
callq 0x85d0
movl $0x1e, %edi
leaq 0x12d01(%rip), %rsi     # 0x1ac7a
xorl %edx, %edx
callq 0x8300
jmp 0x7f55
jmp 0x7f84
leaq 0x1c71d(%rip), %rax     # 0x246a8
movl (%rax), %edi
callq 0x8610
testb $0x1, %al
jne 0x7f98
jmp 0x7fa7
movq -0x10(%rbp), %rdi
addq $0x28, %rdi
callq 0x8640
jmp 0x7f84
movl $0x1a, %edi
leaq 0x12ca0(%rip), %rsi     # 0x1ac53
xorl %edx, %edx
callq 0x8300
movl $0x1a, %edi
leaq 0x12c9e(%rip), %rsi     # 0x1ac64
xorl %edx, %edx
callq 0x8300
jmp 0x7fed
leaq 0x1c6d2(%rip), %rax     # 0x246a8
movl (%rax), %esi
leaq 0x12cab(%rip), %rdi     # 0x1ac8a
leaq 0x12cc7(%rip), %rdx     # 0x1acad
callq 0x8680
jmp 0x800f
jmp 0x800d
leaq 0x1c6b2(%rip), %rax     # 0x246a8
movl (%rax), %esi
leaq 0x12cc1(%rip), %rdi     # 0x1acc0
leaq 0x12ca7(%rip), %rdx     # 0x1acad
callq 0x8680
jmp 0x800f
jmp 0x8018
movq -0x10(%rbp), %rdi
callq 0xab50
movq -0x8(%rbp), %rax
addq $0x10, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)