// File: /workspace/github_cpp_makefile_star2_O2/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 0x12304(%rip), %r15     # 0x18698
movl (%r15), %edx
leal -0x7(%rdx), %ebx
cmpl $0x5, %ebx
jae 0x6410
callq 0x351d
leaq 0x9425(%rip), %rax      # 0xf7d0
movslq (%rax,%rbx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
pushq $0x28
popq %rdi
callq 0x6f0a
movq %rax, %rbx
leaq 0x1182a(%rip), %rax     # 0x17bf0
addq $0x10, %rax
movq %rax, (%rbx)
leaq 0x10(%rbx), %r12
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rbx)
andq $0x0, 0x20(%rbx)
movl $0x1, 0x8(%rbx)
leaq 0x122a5(%rip), %rax     # 0x18690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
movq %rsp, %r14
movaps %xmm0, (%r14)
andq $0x0, 0x10(%r14)
cmpl $0x1a, (%r15)
je 0x65fa
movq %r14, %rdi
callq 0x5ff8
jmp 0x63fc
movq 0x8(%r15), %rcx
leaq 0x978f(%rip), %rdi      # 0xfbaa
leaq 0x95be(%rip), %rsi      # 0xf9e0
callq 0x6231
jmp 0x6703
pushq $0x18
popq %rdi
callq 0x6f0a
movq %rax, %rbx
leaq 0x1191a(%rip), %rax     # 0x17d58
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x6, 0x8(%rbx)
leaq 0x1223d(%rip), %rax     # 0x18690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
leaq 0x8783(%rip), %rsi      # 0xebe2
pushq $0x3
popq %rdi
callq 0x5d30
callq 0x67e3
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x66a3
leaq 0x8761(%rip), %r14      # 0xebe2
pushq $0x19
popq %rdi
movq %r14, %rsi
callq 0x5d30
pushq $0x1e
popq %rdi
movq %r14, %rsi
jmp 0x65f0
pushq $0x28
popq %rdi
callq 0x6f0a
movq %rax, %rbx
leaq 0x1181f(%rip), %rax     # 0x17cc8
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x4, 0x8(%rbx)
leaq 0x121d2(%rip), %rax     # 0x18690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
leaq 0x97cf(%rip), %rsi      # 0xfc99
pushq $0x3
popq %rdi
callq 0x5d30
callq 0x67e3
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x66b1
leaq 0x97ad(%rip), %r14      # 0xfc99
pushq $0x19
popq %rdi
movq %r14, %rsi
callq 0x5d30
callq 0x6382
movq %rax, 0x18(%rbx)
pushq $0xd
popq %rdi
movq %r14, %rsi
callq 0x5d30
testb %al, %al
je 0x6703
callq 0x6382
movq %rax, 0x20(%rbx)
jmp 0x672c
pushq $0x30
popq %rdi
callq 0x6f0a
movq %rax, %rbx
leaq 0x117dd(%rip), %rax     # 0x17d10
addq $0x10, %rax
movq %rax, (%rbx)
xorps %xmm0, %xmm0
movups %xmm0, 0x20(%rbx)
movl $0x5, 0x8(%rbx)
leaq 0x12141(%rip), %rax     # 0x18690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
leaq 0x9773(%rip), %rsi      # 0xfcce
pushq $0x3
popq %rdi
callq 0x5d30
callq 0x67e3
movq %rax, 0x10(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x66ba
leaq 0x9751(%rip), %rsi      # 0xfcce
pushq $0x19
popq %rdi
callq 0x5d30
callq 0x6382
movq %rax, 0x18(%rbx)
jmp 0x672c
movq 0x8(%r15), %r14
pushq $0x18
popq %rdi
callq 0x5d0d
testb %al, %al
je 0x661a
pushq $0x20
popq %rdi
callq 0x6f0a
movq %rax, %rbx
leaq 0x11683(%rip), %rax     # 0x17c38
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x2, 0x8(%rbx)
leaq 0x120c6(%rip), %rax     # 0x18690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
movq %r14, 0x10(%rbx)
callq 0x67e3
movq %rax, 0x18(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x66e2
leaq 0x9644(%rip), %rsi      # 0xfc31
pushq $0x1e
popq %rdi
callq 0x5d30
jmp 0x672c
movq 0x10(%rsp), %rax
movq %rax, 0x10(%r12)
movaps (%rsp), %xmm0
movups %xmm0, (%r12)
pushq $0x1a
popq %rdi
callq 0x6744
jmp 0x672c
pushq $0x24
popq %rdi
callq 0x5d0d
testb %al, %al
je 0x66ca
pushq $0x28
popq %rdi
callq 0x6f0a
movq %rax, %rbx
leaq 0x11644(%rip), %rax     # 0x17c80
addq $0x10, %rax
movq %rax, (%rbx)
movl $0x3, 0x8(%rbx)
leaq 0x1203f(%rip), %rax     # 0x18690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
movq %r14, 0x10(%rbx)
callq 0x67e3
movq %rax, 0x18(%rbx)
leaq 0x95c1(%rip), %r15      # 0xfc2b
pushq $0x1b
popq %rdi
movq %r15, %rsi
callq 0x5d30
pushq $0x18
popq %rdi
movq %r15, %rsi
callq 0x5d30
testb %al, %al
je 0x6703
callq 0x67e3
movq %rax, 0x20(%rbx)
cmpl $0x0, 0x4(%rax)
je 0x673b
leaq 0x958d(%rip), %rsi      # 0xfc2b
jmp 0x65ed
leaq 0x965f(%rip), %rdi      # 0xfd09
callq 0x5df1
jmp 0x66f8
leaq 0x95ee(%rip), %rdi      # 0xfca6
jmp 0x66c1
leaq 0x961d(%rip), %rdi      # 0xfcde
callq 0x5df1
pushq $0x19
jmp 0x66fa
leaq 0x959d(%rip), %rdi      # 0xfc6e
leaq 0x9309(%rip), %rdx      # 0xf9e1
movq %r14, %rsi
callq 0x6b06
jmp 0x6703
leaq 0x9520(%rip), %rdi      # 0xfc09
leaq 0x960c(%rip), %rdx      # 0xfcfc
movq %r14, %rsi
callq 0x6ab2
pushq $0x1e
popq %rdi
pushq $0x1
popq %rsi
callq 0x5e2c
pushq $0x10
popq %rdi
callq 0x6f0a
movq %rax, %rbx
leaq 0x11493(%rip), %rax     # 0x17ba8
addq $0x10, %rax
movq %rax, (%rbx)
andl $0x0, 0x8(%rbx)
leaq 0x11f69(%rip), %rax     # 0x18690
movl (%rax), %eax
movl %eax, 0xc(%rbx)
movq %rbx, %rax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
leaq 0x9504(%rip), %rdi      # 0xfc46
jmp 0x66e9