// File: /workspace/github_c_makefile_star2_O1/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 %rsi, %r14
movq %rdi, %rbx
cmpl $0xa, (%rsi)
je 0x2533
cmpl $0x0, 0x378(%r14)
jle 0x2533
xorl %r12d, %r12d
movq 0x380(%r14), %rax
movq (%rax,%r12,8), %r15
cmpl $0x2, (%r15)
jne 0x24cc
movq 0x38(%rbx), %rdi
movq 0x8(%r15), %rsi
callq 0xa32d
testq %rax, %rax
je 0x296f
movl (%rax), %edi
callq 0xac08
jmp 0x2520
cmpl $0x0, 0x24(%rbx)
je 0x2977
cmpl $0x0, 0x28(%rbx)
jle 0x2520
xorl %r13d, %r13d
movq 0x30(%rbx), %rax
movq (%rax,%r13,8), %rax
movl 0x8(%rax), %ecx
cmpl $0x1, %ecx
je 0x24fe
testl %ecx, %ecx
jne 0x2514
cmpl $0x0, (%r15)
je 0x250d
cmpl $0x1, %ecx
jne 0x2514
cmpl $0x1, (%r15)
jne 0x2514
movl 0xc(%rax), %ecx
cmpl 0x4(%r15), %ecx
jne 0x2514
movl (%rax), %edi
callq 0xac08
incq %r13
movslq 0x28(%rbx), %rax
cmpq %rax, %r13
jl 0x24df
incq %r12
movslq 0x378(%r14), %rax
cmpq %rax, %r12
jl 0x249c
movl (%r14), %edi
cmpq $0xc, %rdi
ja 0x29a3
leaq 0xbabd(%rip), %rax      # 0xe004
movslq (%rax,%rdi,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movl 0x8(%r14), %r15d
testq %r15, %r15
je 0x2913
movq 0x10(%r14), %r14
xorl %r12d, %r12d
movq (%r14,%r12,8), %rsi
movq %rbx, %rdi
callq 0x2468
incq %r12
cmpq %r12, %r15
jne 0x2564
jmp 0x2913
movq %rbx, %rdi
movq %r14, %rsi
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xcf9c
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 0x4cdb
callq 0xad5d
movl %r12d, %edi
callq 0xac08
leaq 0x118(%r14), %r12
movq %rbx, %rdi
movq %r12, %rsi
callq 0x4cdb
callq 0xad5d
leaq 0xbbfe(%rip), %rsi      # 0xe1f4
movq %r12, %rdi
callq 0x9529
movl %eax, %edi
movl %r15d, %esi
movl $0xfffffff8, %edx       # imm = 0xFFFFFFF8
callq 0xaaa9
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r13d, %edi
callq 0xac08
addq $0x218, %r14            # imm = 0x218
movq %rbx, %rdi
movq %r14, %rsi
callq 0x4cdb
callq 0xad5d
leaq 0xbba7(%rip), %rsi      # 0xe1e9
movl -0x34(%rbp), %edi
jmp 0x286f
movq 0x388(%r14), %r14
movq 0x38(%rbx), %rdi
movq %r14, %rsi
callq 0xa32d
testq %rax, %rax
je 0x2983
movl (%rax), %edi
leaq 0xbb05(%rip), %rsi      # 0xe174
jmp 0x2959
movl 0xc(%rbx), %edi
cmpl $-0x1, %edi
je 0x298b
leaq 0xbb0f(%rip), %rsi      # 0xe196
jmp 0x2959
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 0x4cdb
leaq 0xbadb(%rip), %rsi      # 0xe19f
movq %r13, %rdi
callq 0x9529
movl %eax, %edi
movl %r12d, %esi
xorl %edx, %edx
callq 0xaaa9
callq 0xad5d
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
leaq 0xbabe(%rip), %rsi      # 0xe1b1
movl %r15d, %edi
callq 0xaa5b
movl %r12d, %edi
callq 0xac08
callq 0xad5d
jmp 0x2799
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 0x4cdb
leaq 0xba5a(%rip), %rsi      # 0xe19f
movq %r13, %rdi
callq 0x9529
movl %eax, %edi
movl %r12d, %esi
xorl %edx, %edx
callq 0xaaa9
callq 0xad5d
movq 0x10(%r14), %rax
movq (%rax), %rsi
movq %rbx, %rdi
callq 0x2468
leaq 0xba3d(%rip), %rsi      # 0xe1b1
movl %r15d, %edi
callq 0xaa5b
movl %r12d, %edi
callq 0xac08
callq 0xad5d
movq 0x10(%r14), %rax
movq 0x8(%rax), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r15d, %edi
callq 0xac08
jmp 0x2913
addq $0x18, %r14
leaq 0xb98b(%rip), %rdx      # 0xe13c
movq %rbx, %rdi
movq %r14, %rsi
callq 0x566e
movl 0x4(%rbx), %edi
cmpl $-0x1, %edi
jne 0x27cd
movl (%rbx), %edi
incl %edi
movl %edi, (%rbx)
movl %edi, 0x4(%rbx)
leaq 0xfc92(%rip), %rsi      # 0x12466
jmp 0x2959
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 0xac08
movq %rbx, %rdi
leaq -0x138(%rbp), %rsi
callq 0x4cdb
callq 0xad5d
leaq 0xb9a1(%rip), %rsi      # 0xe1d4
leaq -0x138(%rbp), %rdi
callq 0x9529
movl %eax, %edi
movl %r15d, %esi
movl $0xfffffff8, %edx       # imm = 0xFFFFFFF8
callq 0xaaa9
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r13d, %edi
callq 0xac08
leaq 0xb97d(%rip), %rsi      # 0xe1e9
movl %r12d, %edi
callq 0xaa5b
jmp 0x2903
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 0xac08
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x2468
movl %r13d, %edi
callq 0xac08
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 0x4cdb
callq 0xad5d
leaq 0xb8d2(%rip), %rsi      # 0xe1be
movq %r13, %rdi
callq 0x9529
movl %eax, %edi
movl %r12d, %esi
movl $0xfffffff8, %edx       # imm = 0xFFFFFFF8
callq 0xab3a
movl %r15d, %edi
callq 0xac08
movq -0x30(%rbp), %rax
movq %rax, 0x8(%rbx)
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
addq $0x18, %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x4cdb
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xad5d
movl 0x8(%rbx), %edi
cmpl $-0x1, %edi
je 0x2997
leaq 0xb7dd(%rip), %rsi      # 0xe136
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xaa5b
movq %r15, %rdi
callq 0x11a0
leaq 0xb754(%rip), %rdi      # 0xe0d2
callq 0x9492
movq %r14, %rdi
callq 0x11d2
leaq 0xb7e7(%rip), %rdi      # 0xe179
callq 0x9492
leaq 0xb773(%rip), %rdi      # 0xe111
callq 0x9492
callq 0x11f9