// File: /workspace/github_cpp_makefile_star2_O3/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 %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x18, %rsp
leaq 0x137cf(%rip), %r15     # 0x1a698
movl (%r15), %edx
leal -0x7(%rdx), %ebx
cmpl $0x5, %ebx
jae 0x6f73
callq 0x3a62
leaq 0xb85c(%rip), %rax      # 0x12740
movslq (%rax,%rbx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movl $0x28, %edi
movl $0x2, %esi
callq 0x23ef
movq %rax, %rbx
leaq 0x12ce2(%rip), %rax     # 0x19be8
addq $0x10, %rax
movq %rax, (%rbx)
leaq 0x10(%rbx), %r12
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rbx)
xorl %eax, %eax
movq %rax, 0x20(%rbx)
movl $0x1, 0x8(%rbx)
leaq 0x13764(%rip), %rcx     # 0x1a690
movl (%rcx), %ecx
movl %ecx, 0xc(%rbx)
movq %rax, 0x10(%rsp)
movaps %xmm0, (%rsp)
cmpl $0x1a, (%r15)
je 0x6f51
movq %rsp, %r14
movq %r14, %rdi
callq 0x6a6b
cmpl $0x1a, (%r15)
jne 0x6f43
movq 0x10(%rsp), %rax
movq %rax, 0x10(%r12)
movaps (%rsp), %xmm0
movups %xmm0, (%r12)
movl $0x1a, %edi
callq 0x72e0
jmp 0x72d1
movq 0x8(%r15), %rcx
leaq 0xbb9c(%rip), %rdi      # 0x12b1a
leaq 0xb9cb(%rip), %rsi      # 0x12950
callq 0x6c72
jmp 0x729e
movl $0x18, %edi
movl $0x2, %esi
callq 0x23ef
movq %rax, %rbx
leaq 0x12da8(%rip), %rax     # 0x19d50
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x6, 0x8(%rbx)
leaq 0x136d3(%rip), %rax     # 0x1a690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
leaq 0xac45(%rip), %rsi      # 0x11c0e
movl $0x3, %edi
callq 0x6606
callq 0x7423
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x718f
leaq 0xac21(%rip), %r14      # 0x11c0e
movl $0x19, %edi
movq %r14, %rsi
callq 0x6606
movl $0x1e, %edi
movq %r14, %rsi
jmp 0x7244
movl $0x28, %edi
movl $0x2, %esi
callq 0x23ef
movq %rax, %rbx
leaq 0x12ca0(%rip), %rax     # 0x19cc0
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x4, 0x8(%rbx)
leaq 0x1365b(%rip), %rax     # 0x1a690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
leaq 0xbbc8(%rip), %rsi      # 0x12c09
movl $0x3, %edi
callq 0x6606
callq 0x7423
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x71a0
leaq 0xbba4(%rip), %r14      # 0x12c09
movl $0x19, %edi
movq %r14, %rsi
callq 0x6606
callq 0x6eb7
movq %rax, 0x18(%rbx)
movl $0xd, %edi
movq %r14, %rsi
callq 0x6606
testb %al, %al
je 0x729e
callq 0x6eb7
movq %rax, 0x20(%rbx)
jmp 0x72d1
movl $0x30, %edi
movl $0x2, %esi
callq 0x23ef
movq %rax, %rbx
leaq 0x12c51(%rip), %rax     # 0x19d08
addq $0x10, %rax
movq %rax, (%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x20(%rbx)
movl $0x5, 0x8(%rbx)
leaq 0x135bd(%rip), %rax     # 0x1a690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
leaq 0xbb5f(%rip), %rsi      # 0x12c3e
movl $0x3, %edi
callq 0x6606
callq 0x7423
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x71a9
leaq 0xbb3b(%rip), %rsi      # 0x12c3e
movl $0x19, %edi
callq 0x6606
callq 0x6eb7
movq %rax, 0x18(%rbx)
jmp 0x72d1
movq 0x8(%r15), %r14
movl (%r15), %eax
cmpl $0x24, %eax
je 0x71bf
cmpl $0x18, %eax
jne 0x724e
callq 0x3a62
movl $0x20, %edi
movl $0x2, %esi
callq 0x23ef
movq %rax, %rbx
leaq 0x12ade(%rip), %rax     # 0x19c30
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x2, 0x8(%rbx)
leaq 0x13529(%rip), %rax     # 0x1a690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
movq %r14, 0x10(%rbx)
callq 0x7423
movq %rax, 0x18(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x7270
leaq 0xba17(%rip), %rsi      # 0x12ba1
jmp 0x723f
leaq 0xbae3(%rip), %rdi      # 0x12c79
callq 0x675d
jmp 0x728f
leaq 0xba6f(%rip), %rdi      # 0x12c16
jmp 0x71b0
leaq 0xba9e(%rip), %rdi      # 0x12c4e
callq 0x675d
movl $0x19, %edi
jmp 0x7294
callq 0x3a62
movl $0x28, %edi
movl $0x2, %esi
callq 0x23ef
movq %rax, %rbx
leaq 0x12a9b(%rip), %rax     # 0x19c78
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x3, 0x8(%rbx)
leaq 0x1349e(%rip), %rax     # 0x1a690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
movq %r14, 0x10(%rbx)
callq 0x7423
movq %rax, 0x18(%rbx)
leaq 0xb990(%rip), %r15      # 0x12b9b
movl $0x1b, %edi
movq %r15, %rsi
callq 0x6606
movl $0x18, %edi
movq %r15, %rsi
callq 0x6606
testb %al, %al
je 0x729e
callq 0x7423
movq %rax, 0x20(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x7279
leaq 0xb95c(%rip), %rsi      # 0x12b9b
movl $0x1e, %edi
callq 0x6606
jmp 0x72d1
leaq 0xb989(%rip), %rdi      # 0x12bde
leaq 0xb6f5(%rip), %rdx      # 0x12951
movq %r14, %rsi
callq 0x7765
movl $0xa, %edi
callq 0x2160
jmp 0x729e
leaq 0xb902(%rip), %rdi      # 0x12b79
jmp 0x7280
leaq 0xb936(%rip), %rdi      # 0x12bb6
leaq 0xb9e5(%rip), %rdx      # 0x12c6c
movq %r14, %rsi
callq 0x7765
movl $0x1e, %edi
movl $0x1, %esi
callq 0x6811
movl $0x10, %edi
movl $0x2, %esi
callq 0x23ef
movq %rax, %rbx
leaq 0x128e9(%rip), %rax     # 0x19ba0
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x0, 0x8(%rbx)
leaq 0x133c4(%rip), %rax     # 0x1a690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
movq %rbx, %rax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq