// File: baziotis[P]minijava-cpp/parse.cpp
// Function: parse_stmt()
static Statement *parse_stmt() {
    // The contract is that if the caller called this function,
    // then a statement _must_ follow. In other words, the caller
    // is responsible to check whether a statement follows.
    // The caller is also responsible for checking whether
    // an UndefinedStatement was returned.
    if (!starts_statement(token.kind)) {
        syntax_error("Expected `{`, `Identifier`, `if`, `while`"
                     " or `System.out.println` to start a statement, found:",
                     " `", token, "`");
        Statement *s = new UndefinedStatement;
        s->loc = loc;
        return s;
    }

    Statement *s = NULL;
    switch (token.kind) {
    case TOK::LBRACE:
    {
        next_token();
        BlockStatement *b = new BlockStatement;
        b->loc = loc;
        b->block = parse_stmt_block();
        expect_token(TOK::RBRACE);
        s = b;
    } break;
    case TOK::ID:
    {
        next_token();
        const char *id = token.id;
        Statement *s2 = NULL;
        if (match_token(TOK::ASGN)) {
            AssignmentStatement *asgn_stmt = new AssignmentStatement;
            asgn_stmt->loc = loc;
            asgn_stmt->id = id;
            asgn_stmt->rhs = parse_expr();
            if (asgn_stmt->rhs->kind == EXPR::UNDEFINED) {
                syntax_error_no_ln("RHS expression of assignment to `", id, "` is invalid");
                skip_tokens(TOK::SEMI);
                goto Lerror;
            }
            expect_token_in_rule(TOK::SEMI, "assignment statement");
            s2 = asgn_stmt;
        } else if (match_token(TOK::LBRACKET)) {
            ArrayAssignmentStatement *arr_as = new ArrayAssignmentStatement;
            arr_as->loc = loc;
            arr_as->id = id;
            arr_as->index = parse_expr();
            expect_token_in_rule(TOK::RBRACKET, "array assignment statement");
            if (!expect_token_in_rule(TOK::ASGN, "array assignment statement")) {
                goto Lerror;
            }
            arr_as->rhs = parse_expr();
            if (arr_as->rhs->kind == EXPR::UNDEFINED) {
                syntax_error_no_ln("RHS expression of array assignment to `", id, "` is invalid");
                skip_tokens(TOK::SEMI);
                goto Lerror;
            }
            expect_token_in_rule(TOK::SEMI, "array assignment statement");
            s2 = arr_as;
        } else {
            // Make a poinsoned statement
            syntax_error("Expected either `=` or `[` following id: `", id, "`");
            goto Lerror;
        }
        s = s2;
    } break;
    case TOK::IF:
    {
        next_token();
        IfStatement *if_stmt = new IfStatement;
        if_stmt->loc = loc;
        expect_token_in_rule(TOK::LPAR, "if statement");
        if_stmt->cond = parse_expr();
        if (if_stmt->cond->kind == EXPR::UNDEFINED) {
            syntax_error_no_ln("Condition expression of `if` is invalid");
            skip_tokens(TOK::RPAR);
            goto Lerror;
        }
        expect_token_in_rule(TOK::RPAR, "if statement");
        if_stmt->then = parse_stmt();
        if (!expect_token_in_rule(TOK::ELSE, "if statement")) {
            goto Lerror;
        } 
        if_stmt->else_= parse_stmt();
        s = if_stmt;
    } break;
    case TOK::WHILE:
    {
        next_token();
        WhileStatement *while_stmt = new WhileStatement;
        while_stmt->loc = loc;
        expect_token_in_rule(TOK::LPAR, "while statement");
        while_stmt->cond = parse_expr();
        if (while_stmt->cond->kind == EXPR::UNDEFINED) {
            syntax_error_no_ln("Condition expression of `while` is invalid");
            skip_tokens(TOK::RPAR);
            goto Lerror;
        }
        expect_token_in_rule(TOK::RPAR, "while statement");
        while_stmt->body = parse_stmt();
        s = while_stmt;
    } break;
    case TOK::PRINT:
    {
        next_token();
        PrintStatement *prnt = new PrintStatement;
        prnt->loc = loc;
        expect_token_in_rule(TOK::LPAR, "System.out.println");
        prnt->to_print = parse_expr();
        if (prnt->to_print->kind == EXPR::UNDEFINED) {
            syntax_error_no_ln("Expression inside System.out.println is invalid");
            skip_tokens(TOK::SEMI);
            goto Lerror;
        }
        expect_token_in_rule(TOK::RPAR, "System.out.println");
        expect_token_in_rule(TOK::SEMI, "System.out.println");
        s = prnt;
    } break;
    default: assert(0);
    }
    assert(s);
    return s;
Lerror:
    s = new UndefinedStatement;
    s->loc = loc;
    return s;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
leaq 0x1b5b6(%rip), %rax     # 0x246a8
movl (%rax), %edi
callq 0x8610
testb $0x1, %al
jne 0x9198
leaq 0x1b5a0(%rip), %rax     # 0x246a8
movups (%rax), %xmm0
movaps %xmm0, -0x20(%rbp)
movl -0x20(%rbp), %edx
movq -0x18(%rbp), %rcx
leaq 0x11dec(%rip), %rdi     # 0x1af09
leaq 0x11c08(%rip), %rsi     # 0x1ad2c
leaq 0x11c02(%rip), %r8      # 0x1ad2d
callq 0x8de0
movl $0x10, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xa0(%rbp)
callq 0xae60
jmp 0x914e
movq -0xa0(%rbp), %rax
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rax
leaq 0x1b53c(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
movq -0x28(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x9874
movq -0xa0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x10, %esi
callq 0x2120
jmp 0x9881
movq $0x0, -0x40(%rbp)
leaq 0x1b501(%rip), %rax     # 0x246a8
movl (%rax), %eax
addl $-0x7, %eax
movl %eax, %ecx
movq %rcx, -0xa8(%rbp)
subl $0x4, %eax
ja 0x97c1
movq -0xa8(%rbp), %rax
leaq 0x11910(%rip), %rcx     # 0x1aadc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
callq 0x4370
movl $0x28, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xb0(%rbp)
callq 0xaea0
jmp 0x91f8
movq -0xb0(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
leaq 0x1b492(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
leaq -0x60(%rbp), %rdi
callq 0x9890
movq -0x48(%rbp), %rax
movq -0x60(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq -0x58(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq -0x50(%rbp), %rcx
movq %rcx, 0x20(%rax)
movl $0x1a, %edi
xorl %esi, %esi
callq 0x98d0
movq -0x48(%rbp), %rax
movq %rax, -0x40(%rbp)
jmp 0x97e0
movq -0xb0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x28, %esi
callq 0x2120
jmp 0x9881
callq 0x4370
leaq 0x1b429(%rip), %rax     # 0x246a8
movq 0x8(%rax), %rax
movq %rax, -0x68(%rbp)
movq $0x0, -0x70(%rbp)
movl $0x18, %edi
callq 0x82c0
testb $0x1, %al
jne 0x92a2
jmp 0x9372
movl $0x20, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xb8(%rbp)
callq 0xaef0
jmp 0x92c0
movq -0xb8(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rax
leaq 0x1b3ca(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
movq -0x68(%rbp), %rcx
movq -0x78(%rbp), %rax
movq %rcx, 0x10(%rax)
callq 0x9990
movq %rax, %rcx
movq -0x78(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x78(%rbp), %rax
movq 0x18(%rax), %rax
cmpl $0x0, 0x4(%rax)
jne 0x9352
movq -0x68(%rbp), %rsi
leaq 0x11c58(%rip), %rdi     # 0x1af68
leaq 0x11d44(%rip), %rdx     # 0x1b05b
callq 0x9d90
movl $0x1e, %edi
movl $0x1, %esi
callq 0x8450
jmp 0x9812
movq -0xb8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x20, %esi
callq 0x2120
jmp 0x9881
movl $0x1e, %edi
leaq 0x11c32(%rip), %rsi     # 0x1af90
xorl %edx, %edx
callq 0x8300
movq -0x78(%rbp), %rax
movq %rax, -0x70(%rbp)
jmp 0x94af
movl $0x24, %edi
callq 0x82c0
testb $0x1, %al
jne 0x9385
jmp 0x9491
movl $0x28, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xc0(%rbp)
callq 0xaf30
jmp 0x93a3
movq -0xc0(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rax
leaq 0x1b2e7(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
movq -0x68(%rbp), %rcx
movq -0x80(%rbp), %rax
movq %rcx, 0x10(%rax)
callq 0x9990
movq %rax, %rcx
movq -0x80(%rbp), %rax
movq %rcx, 0x18(%rax)
movl $0x1b, %edi
leaq 0x11ba4(%rip), %rsi     # 0x1af8a
xorl %edx, %edx
callq 0x8300
movl $0x18, %edi
leaq 0x11b91(%rip), %rsi     # 0x1af8a
xorl %edx, %edx
callq 0x8300
testb $0x1, %al
jne 0x942b
jmp 0x9812
movq -0xc0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x28, %esi
callq 0x2120
jmp 0x9881
callq 0x9990
movq %rax, %rcx
movq -0x80(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x80(%rbp), %rax
movq 0x20(%rax), %rax
cmpl $0x0, 0x4(%rax)
jne 0x9474
movq -0x68(%rbp), %rsi
leaq 0x11b51(%rip), %rdi     # 0x1afa5
leaq 0x11c00(%rip), %rdx     # 0x1b05b
callq 0x9d90
movl $0x1e, %edi
movl $0x1, %esi
callq 0x8450
jmp 0x9812
movl $0x1e, %edi
leaq 0x11b0a(%rip), %rsi     # 0x1af8a
xorl %edx, %edx
callq 0x8300
movq -0x80(%rbp), %rax
movq %rax, -0x70(%rbp)
jmp 0x94ad
movq -0x68(%rbp), %rsi
leaq 0x11b31(%rip), %rdi     # 0x1afcd
leaq 0x1188a(%rip), %rdx     # 0x1ad2d
callq 0x9df0
jmp 0x9812
jmp 0x94af
movq -0x70(%rbp), %rax
movq %rax, -0x40(%rbp)
jmp 0x97e0
callq 0x4370
movl $0x28, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xc8(%rbp)
callq 0xaf70
jmp 0x94df
movq -0xc8(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rax
leaq 0x1b1a5(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
movl $0x3, %edi
leaq 0x11aec(%rip), %rsi     # 0x1aff8
xorl %edx, %edx
callq 0x8300
callq 0x9990
movq %rax, %rcx
movq -0x88(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x88(%rbp), %rax
movq 0x10(%rax), %rax
cmpl $0x0, 0x4(%rax)
jne 0x9579
leaq 0x11ac7(%rip), %rdi     # 0x1b005
callq 0x8400
movl $0x19, %edi
movl $0x1, %esi
callq 0x8450
jmp 0x9812
movq -0xc8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x28, %esi
callq 0x2120
jmp 0x9881
movl $0x19, %edi
leaq 0x11a73(%rip), %rsi     # 0x1aff8
xorl %edx, %edx
callq 0x8300
callq 0x90e0
movq %rax, %rcx
movq -0x88(%rbp), %rax
movq %rcx, 0x18(%rax)
movl $0xd, %edi
leaq 0x11a4d(%rip), %rsi     # 0x1aff8
xorl %edx, %edx
callq 0x8300
testb $0x1, %al
jne 0x95bb
jmp 0x9812
callq 0x90e0
movq %rax, %rcx
movq -0x88(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x88(%rbp), %rax
movq %rax, -0x40(%rbp)
jmp 0x97e0
callq 0x4370
movl $0x30, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xd0(%rbp)
callq 0xafb0
jmp 0x9601
movq -0xd0(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
leaq 0x1b083(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
movl $0x3, %edi
leaq 0x119ff(%rip), %rsi     # 0x1b02d
xorl %edx, %edx
callq 0x8300
callq 0x9990
movq %rax, %rcx
movq -0x90(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x90(%rbp), %rax
movq 0x10(%rax), %rax
cmpl $0x0, 0x4(%rax)
jne 0x969b
leaq 0x119dd(%rip), %rdi     # 0x1b03d
callq 0x8400
movl $0x19, %edi
movl $0x1, %esi
callq 0x8450
jmp 0x9812
movq -0xd0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x30, %esi
callq 0x2120
jmp 0x9881
movl $0x19, %edi
leaq 0x11986(%rip), %rsi     # 0x1b02d
xorl %edx, %edx
callq 0x8300
callq 0x90e0
movq %rax, %rcx
movq -0x90(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x90(%rbp), %rax
movq %rax, -0x40(%rbp)
jmp 0x97e0
callq 0x4370
movl $0x18, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xd8(%rbp)
callq 0xb000
jmp 0x96f4
movq -0xd8(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rax
leaq 0x1af90(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
movl $0x3, %edi
leaq 0x10723(%rip), %rsi     # 0x19e44
xorl %edx, %edx
callq 0x8300
callq 0x9990
movq %rax, %rcx
movq -0x98(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x98(%rbp), %rax
movq 0x10(%rax), %rax
cmpl $0x0, 0x4(%rax)
jne 0x978e
leaq 0x11915(%rip), %rdi     # 0x1b068
callq 0x8400
movl $0x1e, %edi
movl $0x1, %esi
callq 0x8450
jmp 0x9812
movq -0xd8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x18, %esi
callq 0x2120
jmp 0x9881
movl $0x19, %edi
leaq 0x106aa(%rip), %rsi     # 0x19e44
xorl %edx, %edx
callq 0x8300
movl $0x1e, %edi
leaq 0x10697(%rip), %rsi     # 0x19e44
xorl %edx, %edx
callq 0x8300
movq -0x98(%rbp), %rax
movq %rax, -0x40(%rbp)
jmp 0x97e0
leaq 0x121ba(%rip), %rdi     # 0x1b982
leaq 0x118c9(%rip), %rsi     # 0x1b098
movl $0x1c4, %edx            # imm = 0x1C4
leaq 0x118c7(%rip), %rcx     # 0x1b0a2
callq 0x20d0
cmpq $0x0, -0x40(%rbp)
je 0x97e9
jmp 0x9808
leaq 0xfbfc(%rip), %rdi      # 0x193ec
leaq 0x118a1(%rip), %rsi     # 0x1b098
movl $0x1c6, %edx            # imm = 0x1C6
leaq 0x1189f(%rip), %rcx     # 0x1b0a2
callq 0x20d0
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x9874
movl $0x10, %edi
callq 0xae40
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0xe0(%rbp)
callq 0xae60
jmp 0x9830
movq -0xe0(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
leaq 0x1ae5a(%rip), %rcx     # 0x246a0
movl (%rcx), %ecx
movl %ecx, 0xc(%rax)
movq -0x40(%rbp), %rax
movq %rax, -0x8(%rbp)
jmp 0x9874
movq -0xe0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
movl $0x10, %esi
callq 0x2120
jmp 0x9881
movq -0x8(%rbp), %rax
addq $0xe0, %rsp
popq %rbp
retq
movq -0x30(%rbp), %rdi
callq 0x21c0
nopw (%rax,%rax)