// File: /workspace/github_c_makefile_star2_O3/hsjoihs[P]c-compiler/codegen.c
// Function: print_statement
void print_statement(struct PrinterState *ptr_prs,
                     const struct Statement *ref_sta)
{
	if (ref_sta->category != DECLARATION_STATEMENT) {
		for (int j = 0; j < ref_sta->labels.length; j++) {
			const struct SourceLabel *ptr_label = ref_sta->labels.vector[j];

			if (ptr_label->category == IDENT_LABEL) {
				const struct SourceLabelAndAssemblyLabel *p =
				    lookup(ptr_prs->source_label_to_assembly_label,
				           ptr_label->ident_str);
				if (!p) {
					fprintf(stderr,
					        "****************************\n"
					        "* INTERNAL COMPILER ERROR @ %s\n"
					        "* Lookup failed; cannot find an identifier `%s`\n"
					        "****************************\n",
					        __func__, ptr_label->ident_str);
					exit(EXIT_FAILURE);
				}
				gen_label(p->assembly_label);
				continue;
			}

			if (!ptr_prs->is_inside_switch) {
				simple_error(
				    "`default` or `case` was detected, but is not inside "
				    "`switch`.\n");
			}
			for (int k = 0; k < ptr_prs->case_default_vec.length; k++) {
				const struct SourceLabelAndAssemblyLabel *ptr_ll =
				    ptr_prs->case_default_vec.vector[k];
				if (is_label_compatible(&ptr_ll->source_label, ptr_label)) {
					gen_label(ptr_ll->assembly_label);
				}
			}
		}
	}
	switch (ref_sta->category) {
	case DECLARATION_STATEMENT: {
		/* do nothing */
		return;
	}
	case BREAK_STATEMENT: {
		if (ptr_prs->break_label_name == -1) {
			simple_error("invalid `break`; no loop, no switch\n");
		} else {
			gen_jump(ptr_prs->break_label_name, "break");
		}
		return;
	}
	case EXPRESSION_STATEMENT: {
		print_expression(ptr_prs, &ref_sta->expr1);
		gen_discard();
		return;
	}
	case RETURN_STATEMENT: {

		print_expression_or_addr_of_struct_or_union(ptr_prs, &ref_sta->expr1,
		                                            "returning a struct");

		/* the first occurrence of return within a function */
		if (ptr_prs->return_label_name == -1) {
			int ret_label = get_new_label_name(ptr_prs);
			ptr_prs->return_label_name = ret_label;
			gen_jump(ret_label, "return");
		} else {
			gen_jump(ptr_prs->return_label_name, "return");
		}

		return;
	}
	case GOTO_STATEMENT: {
		const char *destination = ref_sta->destination;
		const struct SourceLabelAndAssemblyLabel *p =
		    lookup(ptr_prs->source_label_to_assembly_label, destination);
		if (!p) {
			fprintf(stderr, "undefined label `%s` used in `goto`\n",
			        destination);
			exit(EXIT_FAILURE);
		}
		gen_jump(p->assembly_label, "goto");
		return;
	}
	case CONTINUE_STATEMENT: {
		if (ptr_prs->continue_label_name == -1) {
			simple_error("invalid `continue`; no loop\n");
		} else {
			gen_jump(ptr_prs->continue_label_name, "continue");
		}
		return;
	}
	case COMPOUND_STATEMENT: {
		struct Vector /*<Statement>*/ vec = ref_sta->statement_vector;

		for (int counter = 0; counter != vec.length; ++counter) {
			const struct Statement *ptr_ith = vec.vector[counter];
			print_statement(ptr_prs, ptr_ith);
		}
		return;
	}
	case IF_ELSE_STATEMENT: {
		int label1 = get_new_label_name(ptr_prs);
		int label2 = get_new_label_name(ptr_prs);
		const struct Expr expr = ref_sta->expr1;
		print_expression(ptr_prs, &expr);

		gen_if_zero_jmp_nbyte(
		    size_of_basic(&expr.details.type, "condition of `if`"), label1, 0);
		gen_discard();

		const struct Statement *ptr_inner_s =
		    ref_sta->statement_vector.vector[0];
		print_statement(ptr_prs, ptr_inner_s);

		gen_jump(label2, "if statement");
		gen_label(label1);
		gen_discard();

		const struct Statement *ptr_inner_s2 =
		    ref_sta->statement_vector.vector[1];
		print_statement(ptr_prs, ptr_inner_s2);
		gen_label(label2);

		return;
	}
	case SWITCH_STATEMENT: {
		codegen_switch(ptr_prs, ref_sta);
		return;
	}
	case IF_STATEMENT: {

		int label1 = get_new_label_name(ptr_prs);
		int label2 = get_new_label_name(ptr_prs);
		const struct Expr expr = ref_sta->expr1;
		print_expression(ptr_prs, &expr);

		gen_if_zero_jmp_nbyte(
		    size_of_basic(&expr.details.type, "condition of `if`"), label1, 0);
		gen_discard();

		print_statement(ptr_prs, ref_sta->inner_statement);

		gen_jump(label2, "if statement");
		gen_label(label1);
		gen_discard();

		gen_label(label2);

		return;
	}
	case DO_WHILE_STATEMENT: {
		int stashed_break_label = ptr_prs->break_label_name;
		int stashed_continue_label = ptr_prs->continue_label_name;
		int label1 = get_new_label_name(ptr_prs);
		int break_label = get_new_label_name(ptr_prs);
		int cont_label = get_new_label_name(ptr_prs);
		ptr_prs->break_label_name = break_label;
		ptr_prs->continue_label_name = cont_label;

		gen_label(label1);
		print_statement(ptr_prs, ref_sta->inner_statement);

		gen_label(cont_label);

		const struct Expr expr = ref_sta->expr1;
		print_expression(ptr_prs, &expr);

		gen_discard();
		gen_if_nonzero_jmp_nbyte(
		    size_of_basic(&expr.details.type, "condition of do-while"), label1,
		    -8);
		gen_label(break_label);

		ptr_prs->break_label_name = stashed_break_label;
		ptr_prs->continue_label_name = stashed_continue_label;

		return;
	}

	case WHILE_STATEMENT: {
		const struct Expr expr = ref_sta->expr1;

		int stashed_break_label = ptr_prs->break_label_name;
		int stashed_continue_label = ptr_prs->continue_label_name;

		int label1 = get_new_label_name(ptr_prs);
		int break_label = get_new_label_name(ptr_prs);
		int cont_label = get_new_label_name(ptr_prs);
		ptr_prs->break_label_name = break_label;
		ptr_prs->continue_label_name = cont_label;

		gen_label(label1);

		print_expression(ptr_prs, &expr);

		gen_discard();
		gen_if_zero_jmp_nbyte(
		    size_of_basic(&expr.details.type, "condition of `while`"),
		    break_label, -8);

		print_statement(ptr_prs, ref_sta->inner_statement);

		gen_label(cont_label);
		gen_jump(label1, "for(part4)");
		gen_label(break_label);

		ptr_prs->break_label_name = stashed_break_label;
		ptr_prs->continue_label_name = stashed_continue_label;

		return;
	}
	case FOR_STATEMENT: {
		int stashed_break_label = ptr_prs->break_label_name;
		int stashed_continue_label = ptr_prs->continue_label_name;
		int label1 = get_new_label_name(ptr_prs);
		int break_label = get_new_label_name(ptr_prs);
		int cont_label = get_new_label_name(ptr_prs);
		ptr_prs->break_label_name = break_label;
		ptr_prs->continue_label_name = cont_label;

		print_expression(ptr_prs, &ref_sta->expr1); /* expression1 */
		gen_discard();
		gen_label(label1);
		print_expression(ptr_prs, &ref_sta->expr2); /* expression2 */

		gen_discard();
		gen_if_zero_jmp_nbyte(
		    size_of_basic(&ref_sta->expr2.details.type, "condition of `for`"),
		    break_label, -8);

		print_statement(ptr_prs, ref_sta->inner_statement);
		gen_label(cont_label);
		print_expression(ptr_prs, &ref_sta->expr3);
		gen_discard();
		gen_jump(label1, "for(part4)");
		gen_label(break_label);

		ptr_prs->break_label_name = stashed_break_label;
		ptr_prs->continue_label_name = stashed_continue_label;

		return;
	}
	}
	fprintf(
	    stderr,
	    "****************************\n"
	    "* INTERNAL COMPILER ERROR @ %s\n"
	    "* Unexpected value of StatementCategory: `ref_sta->category` is %d\n"
	    "****************************\n",
	    __func__, ref_sta->category);
	exit(EXIT_FAILURE);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x118, %rsp            # imm = 0x118
movq %rdi, %rbx
movl (%rsi), %edi
cmpl $0xa, %edi
jne 0x2498
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rsi, %r14
cmpl $0x0, 0x378(%rsi)
jle 0x2545
xorl %r12d, %r12d
movq 0x380(%r14), %rax
movq (%rax,%r12,8), %r15
cmpl $0x2, (%r15)
jne 0x24db
movq 0x38(%rbx), %rdi
movq 0x8(%r15), %rsi
callq 0xa39c
testq %rax, %rax
je 0x2972
movl (%rax), %edi
callq 0xac74
jmp 0x252f
cmpl $0x0, 0x24(%rbx)
je 0x297a
movl 0x28(%rbx), %eax
testl %eax, %eax
jle 0x252f
xorl %r13d, %r13d
movq 0x30(%rbx), %rcx
movq (%rcx,%r13,8), %rcx
movl 0x8(%rcx), %edx
cmpl $0x1, %edx
je 0x250b
testl %edx, %edx
jne 0x2524
cmpl $0x0, (%r15)
jne 0x2524
jmp 0x251a
cmpl $0x1, (%r15)
jne 0x2524
movl 0xc(%rcx), %edx
cmpl 0x4(%r15), %edx
jne 0x2524
movl (%rcx), %edi
callq 0xac74
movl 0x28(%rbx), %eax
incq %r13
movslq %eax, %rcx
cmpq %rcx, %r13
jl 0x24ef
incq %r12
movslq 0x378(%r14), %rax
cmpq %rax, %r12
jl 0x24ab
movl (%r14), %edi
cmpl $0xc, %edi
ja 0x29a6
movl %edi, %eax
leaq 0xbaad(%rip), %rcx      # 0xe004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl 0x8(%r14), %r15d
testq %r15, %r15
je 0x2486
movq 0x10(%r14), %r14
xorl %r12d, %r12d
movq (%r14,%r12,8), %rsi
movq %rbx, %rdi
callq 0x2468
incq %r12
cmpq %r12, %r15
jne 0x2574
jmp 0x2486
movq %rbx, %rdi
movq %r14, %rsi
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xcf58
movq 0x8(%rbx), %rax
movq %rax, -0x30(%rbp)
movl (%rbx), %r13d
leal 0x1(%r13), %r12d
movl %r12d, -0x34(%rbp)
leal 0x2(%r13), %r15d
addl $0x3, %r13d
movl %r13d, (%rbx)
movl %r15d, 0x8(%rbx)
movl %r13d, 0xc(%rbx)
leaq 0x18(%r14), %rsi
movq %rbx, %rdi
callq 0x4e8f
callq 0xadc9
movl %r12d, %edi
callq 0xac74
leaq 0x118(%r14), %r12
movq %rbx, %rdi
movq %r12, %rsi
callq 0x4e8f
callq 0xadc9
leaq 0xbbee(%rip), %rsi      # 0xe1f4
movq %r12, %rdi
callq 0x95dd
movl %eax, %edi
movl %r15d, %esi
movl $0xfffffff8, %edx       # imm = 0xFFFFFFF8
callq 0xab15
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r13d, %edi
callq 0xac74
addq $0x218, %r14            # imm = 0x218
movq %rbx, %rdi
movq %r14, %rsi
callq 0x4e8f
callq 0xadc9
leaq 0xbb97(%rip), %rsi      # 0xe1e9
movl -0x34(%rbp), %edi
jmp 0x287f
movq 0x388(%r14), %r14
movq 0x38(%rbx), %rdi
movq %r14, %rsi
callq 0xa39c
testq %rax, %rax
je 0x2986
movl (%rax), %edi
leaq 0xbaf5(%rip), %rsi      # 0xe174
jmp 0x295c
movl 0xc(%rbx), %edi
cmpl $-0x1, %edi
je 0x298e
leaq 0xbaff(%rip), %rsi      # 0xe196
jmp 0x295c
movl (%rbx), %r15d
leal 0x1(%r15), %r12d
addl $0x2, %r15d
movl %r15d, (%rbx)
leaq 0x18(%r14), %rsi
leaq -0x138(%rbp), %r13
movl $0x100, %edx            # imm = 0x100
movq %r13, %rdi
callq 0x1100
movq %rbx, %rdi
movq %r13, %rsi
callq 0x4e8f
leaq 0xbacb(%rip), %rsi      # 0xe19f
movq %r13, %rdi
callq 0x95dd
movl %eax, %edi
movl %r12d, %esi
xorl %edx, %edx
callq 0xab15
callq 0xadc9
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
leaq 0xbaae(%rip), %rsi      # 0xe1b1
movl %r15d, %edi
callq 0xaac7
movl %r12d, %edi
callq 0xac74
callq 0xadc9
jmp 0x27a9
movl (%rbx), %r15d
leal 0x1(%r15), %r12d
addl $0x2, %r15d
movl %r15d, (%rbx)
leaq 0x18(%r14), %rsi
leaq -0x138(%rbp), %r13
movl $0x100, %edx            # imm = 0x100
movq %r13, %rdi
callq 0x1100
movq %rbx, %rdi
movq %r13, %rsi
callq 0x4e8f
leaq 0xba4a(%rip), %rsi      # 0xe19f
movq %r13, %rdi
callq 0x95dd
movl %eax, %edi
movl %r12d, %esi
xorl %edx, %edx
callq 0xab15
callq 0xadc9
movq 0x10(%r14), %rax
movq (%rax), %rsi
movq %rbx, %rdi
callq 0x2468
leaq 0xba2d(%rip), %rsi      # 0xe1b1
movl %r15d, %edi
callq 0xaac7
movl %r12d, %edi
callq 0xac74
callq 0xadc9
movq 0x10(%r14), %rax
movq 0x8(%rax), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r15d, %edi
callq 0xac74
jmp 0x2486
addq $0x18, %r14
leaq 0xb97b(%rip), %rdx      # 0xe13c
movq %rbx, %rdi
movq %r14, %rsi
callq 0x587e
movl 0x4(%rbx), %edi
cmpl $-0x1, %edi
jne 0x27dd
movl (%rbx), %edi
incl %edi
movl %edi, (%rbx)
movl %edi, 0x4(%rbx)
leaq 0xfb37(%rip), %rsi      # 0x1231b
jmp 0x295c
leaq 0x18(%r14), %rsi
leaq -0x138(%rbp), %rdi
movl $0x100, %edx            # imm = 0x100
callq 0x1100
movq 0x8(%rbx), %rax
movq %rax, -0x30(%rbp)
movl (%rbx), %r13d
leal 0x1(%r13), %r12d
leal 0x2(%r13), %r15d
addl $0x3, %r13d
movl %r13d, (%rbx)
movl %r15d, 0x8(%rbx)
movl %r13d, 0xc(%rbx)
movl %r12d, %edi
callq 0xac74
movq %rbx, %rdi
leaq -0x138(%rbp), %rsi
callq 0x4e8f
callq 0xadc9
leaq 0xb991(%rip), %rsi      # 0xe1d4
leaq -0x138(%rbp), %rdi
callq 0x95dd
movl %eax, %edi
movl %r15d, %esi
movl $0xfffffff8, %edx       # imm = 0xFFFFFFF8
callq 0xab15
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r13d, %edi
callq 0xac74
leaq 0xb96d(%rip), %rsi      # 0xe1e9
movl %r12d, %edi
callq 0xaac7
jmp 0x2913
movq 0x8(%rbx), %rax
movq %rax, -0x30(%rbp)
movl (%rbx), %r13d
leal 0x1(%r13), %r12d
leal 0x2(%r13), %r15d
addl $0x3, %r13d
movl %r13d, (%rbx)
movl %r15d, 0x8(%rbx)
movl %r13d, 0xc(%rbx)
movl %r12d, %edi
callq 0xac74
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r13d, %edi
callq 0xac74
addq $0x18, %r14
leaq -0x138(%rbp), %r13
movl $0x100, %edx            # imm = 0x100
movq %r13, %rdi
movq %r14, %rsi
callq 0x1100
movq %rbx, %rdi
movq %r13, %rsi
callq 0x4e8f
callq 0xadc9
leaq 0xb8c2(%rip), %rsi      # 0xe1be
movq %r13, %rdi
callq 0x95dd
movl %eax, %edi
movl %r12d, %esi
movl $0xfffffff8, %edx       # imm = 0xFFFFFFF8
callq 0xaba6
movl %r15d, %edi
callq 0xac74
movq -0x30(%rbp), %rax
movq %rax, 0x8(%rbx)
jmp 0x2486
addq $0x18, %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x4e8f
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xadc9
movl 0x8(%rbx), %edi
cmpl $-0x1, %edi
je 0x299a
leaq 0xb7da(%rip), %rsi      # 0xe136
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xaac7
movq %r15, %rdi
callq 0x11f4
leaq 0xb751(%rip), %rdi      # 0xe0d2
callq 0x9546
movq %r14, %rdi
callq 0x11a0
leaq 0xb7e4(%rip), %rdi      # 0xe179
callq 0x9546
leaq 0xb770(%rip), %rdi      # 0xe111
callq 0x9546
callq 0x11c7