// File: /workspace/github_c_makefile_star2_O2/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
cmpl $0xa, (%rsi)
jne 0x12df
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rsi, %r14
movq %rdi, %rbx
xorl %r15d, %r15d
movslq 0x378(%r14), %rax
cmpq %rax, %r15
jge 0x137d
movq 0x380(%r14), %rax
movq (%rax,%r15,8), %r12
cmpl $0x2, (%r12)
jne 0x132d
movq 0x38(%rbx), %rdi
movq 0x8(%r12), %rsi
callq 0x92a8
testq %rax, %rax
je 0x179e
movl (%rax), %edi
callq 0x9b55
incq %r15
jmp 0x12e8
cmpl $0x0, 0x24(%rbx)
je 0x17ca
xorl %r13d, %r13d
movslq 0x28(%rbx), %rax
cmpq %rax, %r13
jge 0x1328
movq 0x30(%rbx), %rax
movq (%rax,%r13,8), %rax
movl 0x8(%rax), %ecx
cmpl $0x1, %ecx
je 0x1360
testl %ecx, %ecx
jne 0x1378
cmpl $0x0, (%r12)
jne 0x1378
jmp 0x1371
cmpl $0x1, (%r12)
jne 0x1378
movl 0xc(%rax), %ecx
cmpl 0x4(%r12), %ecx
jne 0x1378
movl (%rax), %edi
callq 0x9b55
incq %r13
jmp 0x133a
movl (%r14), %ecx
cmpq $0xc, %rcx
ja 0x180b
leaq 0xbc73(%rip), %rax      # 0xd004
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movl 0x8(%r14), %r15d
movq 0x10(%r14), %r14
xorl %r12d, %r12d
cmpq %r12, %r15
je 0x12cd
movq (%r14,%r12,8), %rsi
movq %rbx, %rdi
callq 0x12b4
incq %r12
jmp 0x13a5
movq %rbx, %rdi
movq %r14, %rsi
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xbc80
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 0x3b8f
callq 0x9caa
movl %r12d, %edi
callq 0x9b55
leaq 0x118(%r14), %r12
movq %rbx, %rdi
movq %r12, %rsi
callq 0x3b8f
callq 0x9caa
leaq 0xbdbc(%rip), %rsi      # 0xd1f4
movq %r12, %rdi
callq 0x81de
pushq $-0x8
popq %rdx
movl %eax, %edi
movl %r15d, %esi
callq 0x9a17
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x12b4
movl %r13d, %edi
callq 0x9b55
addq $0x218, %r14            # imm = 0x218
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3b8f
callq 0x9caa
leaq 0xbd67(%rip), %rsi      # 0xd1e9
movl -0x34(%rbp), %edi
jmp 0x16ad
movq 0x388(%r14), %r14
movq 0x38(%rbx), %rdi
movq %r14, %rsi
callq 0x92a8
testq %rax, %rax
je 0x17d6
movl (%rax), %edi
leaq 0xbcc5(%rip), %rsi      # 0xd174
jmp 0x1788
movl 0xc(%rbx), %edi
cmpl $-0x1, %edi
je 0x17f3
leaq 0xbccf(%rip), %rsi      # 0xd196
jmp 0x1788
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 0x3b8f
leaq 0xbc9b(%rip), %rsi      # 0xd19f
movq %r13, %rdi
callq 0x81de
movl %eax, %edi
movl %r12d, %esi
xorl %edx, %edx
callq 0x9a17
callq 0x9caa
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x12b4
leaq 0xbc7e(%rip), %rsi      # 0xd1b1
movl %r15d, %edi
callq 0x99c9
movl %r12d, %edi
callq 0x9b55
callq 0x9caa
jmp 0x15d9
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 0x3b8f
leaq 0xbc1a(%rip), %rsi      # 0xd19f
movq %r13, %rdi
callq 0x81de
movl %eax, %edi
movl %r12d, %esi
xorl %edx, %edx
callq 0x9a17
callq 0x9caa
movq 0x10(%r14), %rax
movq (%rax), %rsi
movq %rbx, %rdi
callq 0x12b4
leaq 0xbbfd(%rip), %rsi      # 0xd1b1
movl %r15d, %edi
callq 0x99c9
movl %r12d, %edi
callq 0x9b55
callq 0x9caa
movq 0x10(%r14), %rax
movq 0x8(%rax), %rsi
movq %rbx, %rdi
callq 0x12b4
movl %r15d, %edi
callq 0x9b55
jmp 0x12cd
addq $0x18, %r14
leaq 0xbb4b(%rip), %rdx      # 0xd13c
movq %rbx, %rdi
movq %r14, %rsi
callq 0x4536
movl 0x4(%rbx), %edi
cmpl $-0x1, %edi
jne 0x160d
movl (%rbx), %edi
incl %edi
movl %edi, (%rbx)
movl %edi, 0x4(%rbx)
leaq 0xfd27(%rip), %rsi      # 0x1133b
jmp 0x1788
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 0x9b55
movq %rbx, %rdi
leaq -0x138(%rbp), %rsi
callq 0x3b8f
callq 0x9caa
leaq 0xbb61(%rip), %rsi      # 0xd1d4
leaq -0x138(%rbp), %rdi
callq 0x81de
pushq $-0x8
popq %rdx
movl %eax, %edi
movl %r15d, %esi
callq 0x9a17
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x12b4
movl %r13d, %edi
callq 0x9b55
leaq 0xbb3f(%rip), %rsi      # 0xd1e9
movl %r12d, %edi
callq 0x99c9
jmp 0x173f
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 0x9b55
movq 0x318(%r14), %rsi
movq %rbx, %rdi
callq 0x12b4
movl %r13d, %edi
callq 0x9b55
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 0x3b8f
callq 0x9caa
leaq 0xba94(%rip), %rsi      # 0xd1be
movq %r13, %rdi
callq 0x81de
pushq $-0x8
popq %rdx
movl %eax, %edi
movl %r12d, %esi
callq 0x9ab3
movl %r15d, %edi
callq 0x9b55
movq -0x30(%rbp), %rax
movq %rax, 0x8(%rbx)
jmp 0x12cd
addq $0x18, %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3b8f
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x9caa
movl 0x8(%rbx), %edi
cmpl $-0x1, %edi
je 0x17ff
leaq 0xb9ae(%rip), %rsi      # 0xd136
addq $0x118, %rsp            # imm = 0x118
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x99c9
movq 0x14853(%rip), %rax     # 0x15ff8
movq (%rax), %rdi
movq 0x8(%r12), %rcx
leaq 0xb884(%rip), %rsi      # 0xd038
leaq 0xb907(%rip), %rdx      # 0xd0c2
xorl %eax, %eax
callq 0x10f0
pushq $0x1
popq %rdi
callq 0x1170
leaq 0xb901(%rip), %rdi      # 0xd0d2
callq 0x814d
movq 0x1481b(%rip), %rax     # 0x15ff8
movq (%rax), %rdi
leaq 0xb968(%rip), %rsi      # 0xd14f
movq %r14, %rdx
xorl %eax, %eax
callq 0x10f0
jmp 0x17c2
leaq 0xb97f(%rip), %rdi      # 0xd179
callq 0x814d
leaq 0xb90b(%rip), %rdi      # 0xd111
callq 0x814d
movq 0x147e6(%rip), %rax     # 0x15ff8
movq (%rax), %rdi
leaq 0xb9eb(%rip), %rsi      # 0xd207
leaq 0xb89f(%rip), %rdx      # 0xd0c2
xorl %eax, %eax
callq 0x10f0
jmp 0x17c2