// File: /workspace/github_c_makefile_star2_O0/hsjoihs[P]c-compiler/parse_analyze_toplevel.c
// Function: parse_toplevel_definition
static struct Toplevel
parse_toplevel_definition(struct AnalyzerState *ptr_ps,
                          const struct Token **ptr_tokvec)
{
	const struct Token *tokvec2 = *ptr_tokvec;

	int is_extern_global_var = 0;
	if (tokvec2[0].kind == RES_EXTERN) {
		tokvec2++;
		is_extern_global_var = 1;
	}

	int is_static_function = 0;
	if (tokvec2[0].kind == RES_STATIC) {
		tokvec2++;
		is_static_function = 1;
	}

	*ptr_tokvec = tokvec2;

	struct Type *optional_ptr_type =
	    try_parse_type_specifier_and_semicolon(ptr_tokvec);

	if (optional_ptr_type) {
		struct Toplevel d;
		d.category = TOPLEVEL_VAR_DEFINITION;
		d.declarator_type = *optional_ptr_type;
		/* d.size_of_declarator_type need not be set; it is not a real variable
		 */

		record_if_global_struct_or_enum_declaration(ptr_ps, &d.declarator_type);
		d.declarator_name = 0;
		return d;
	}

	const char *declarator_name;
	struct Type declarator_type =
	    parse_type_specifier_and_declarator(&tokvec2, &declarator_name);
	record_if_global_struct_or_enum_declaration(ptr_ps, &declarator_type);

	if (declarator_type.type_category != FN) {

		expect_and_consume(&tokvec2, SEMICOLON,
		                   "semicolon at the end of variable definition");

		struct Type *ptr_type = calloc(1, sizeof(struct Type));
		*ptr_type = declarator_type;
		insert(ptr_ps->global_vars_type_map, declarator_name, ptr_type);

		*ptr_tokvec = tokvec2;

		struct Toplevel d;
		d.category = TOPLEVEL_VAR_DEFINITION;
		d.declarator_name = declarator_name;
		d.declarator_type = declarator_type;
		d.size_of_declarator_type = size_of(ptr_ps, &declarator_type);
		d.is_extern_global_var = is_extern_global_var;
		return d;
	}

	struct Vector /*<TypeAndIdent>*/ param_infos = declarator_type.param_infos;
	enum ParamInfosValidity param_infos_validity =
	    declarator_type.param_infos_validity;
	struct Type *derived_from = declarator_type.derived_from;
	struct Type ret_type = *derived_from;

	ptr_ps->scope_chain.outer = 0; /* most outer scope */
	ptr_ps->scope_chain.var_table = init_map();
	ptr_ps->newest_offset = 0;
	ptr_ps->func_ret_type = ret_type;
	ptr_ps->current_function_name = declarator_name;

	const struct Type *ptr_old_func_info =
	    lookup(ptr_ps->func_info_map, declarator_name);

	struct Type *ptr_func_info = calloc(1, sizeof(struct Type));
	*ptr_func_info = declarator_type;

	if (!ptr_old_func_info) {
		insert(ptr_ps->func_info_map, declarator_name, ptr_func_info);
	} else {
		expect_type(ptr_ps, &declarator_type, ptr_old_func_info,
		            "conflicting function definition");
		if (ptr_old_func_info->param_infos_validity == INVALID &&
		    declarator_type.param_infos_validity != INVALID) {
			insert(ptr_ps->func_info_map, declarator_name, ptr_func_info);
		}
	}

	if (tokvec2[0].kind == SEMICOLON) { /* function prototype */
		++tokvec2;
		*ptr_tokvec = tokvec2;

		struct Toplevel def;
		def.category = TOPLEVEL_FUNCTION_DECLARATION;
		return def;
	}

	struct Vector /*<LocalVarInfo>*/ offsets_and_types = init_vector();

	struct Toplevel def;
	def.category = TOPLEVEL_FUNCTION_DEFINITION;
	def.declarator_name = declarator_name;
	def.func.is_static_function = is_static_function;
	def.func.ret_type = ret_type;
	if (is_struct_or_union(&ret_type)) {
		enum SystemVAbiClass abi_class =
		    system_v_abi_class_of(ptr_ps, &ret_type);
		def.func.abi_class = abi_class;
		def.func.ret_struct_or_union_size = size_of(ptr_ps, &ret_type);
		if (abi_class == MEMORY_CLASS) {
			const struct Type type = ptr_to_type(&ret_type);
			int hidden_var_offset = push_offset_and_type(
			    ptr_ps, &type, &offsets_and_types, "@hidden");
			def.func.hidden_var_offset = hidden_var_offset;
		}
	}

	def.func.is_va = 0;
	switch (param_infos_validity) {
	case VALID:
	case VA_ARGS: {
		for (int counter = 0; counter < param_infos.length; ++counter) {

			const struct TypeAndIdent *ptr_param_info =
			    param_infos.vector[counter];
			struct TypeAndIdent param_info = *ptr_param_info;
			const struct Type type = param_info.type;

			if (counter > 5) { /* silently fails when there is 6 params and
				                  1 implicit param*/
				unsupported("7-or-more parameters");
			}

			push_offset_and_type(ptr_ps, &type, &offsets_and_types,
			                     param_info.ident_str);
		}

		if (param_infos_validity == VA_ARGS) {
			def.func.is_va = 1;
		}
		break;
	}

	case INVALID:
		break;
	}

	struct Statement sta = parse_compound_statement(ptr_ps, &tokvec2);
	*ptr_tokvec = tokvec2;
	/* parse finished */

	def.func.sta = sta;
	def.func.offsets_and_types = offsets_and_types;
	def.func.capacity = -ptr_ps->newest_offset;
	return def;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x5d0, %rsp            # imm = 0x5D0
movq %rdi, -0x5c8(%rbp)
movq %rdi, -0x5c0(%rbp)
movq %rsi, -0x8(%rbp)
movq %rdx, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
movl $0x0, -0x1c(%rbp)
movq -0x18(%rbp), %rax
cmpl $0x46, (%rax)
jne 0x2bef
movq -0x18(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x18(%rbp)
movl $0x1, -0x1c(%rbp)
movl $0x0, -0x20(%rbp)
movq -0x18(%rbp), %rax
cmpl $0x47, (%rax)
jne 0x2c12
movq -0x18(%rbp), %rax
addq $0x20, %rax
movq %rax, -0x18(%rbp)
movl $0x1, -0x20(%rbp)
movq -0x18(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
movq -0x10(%rbp), %rdi
callq 0xc0a0
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
je 0x2c78
movq -0x5c8(%rbp), %rdi
movl $0x0, (%rdi)
addq $0x10, %rdi
movq -0x28(%rbp), %rsi
movl $0x50, %edx
callq 0x10e0
movq -0x5c8(%rbp), %rsi
movq -0x8(%rbp), %rdi
addq $0x10, %rsi
callq 0x3150
movq -0x5c8(%rbp), %rax
movq $0x0, 0x8(%rax)
jmp 0x3139
leaq -0x80(%rbp), %rdi
leaq -0x18(%rbp), %rsi
leaq -0x30(%rbp), %rdx
callq 0xc390
movq -0x8(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x3150
cmpl $0x3, -0x80(%rbp)
je 0x2d54
leaq -0x18(%rbp), %rdi
movl $0x1a, %esi
leaq 0x10a0d(%rip), %rdx     # 0x136bd
callq 0xb190
movl $0x1, %edi
movl $0x50, %esi
callq 0x10b0
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rdi
leaq -0x80(%rbp), %rsi
movl $0x50, %edx
callq 0x10e0
movq -0x8(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x30(%rbp), %rsi
movq -0x88(%rbp), %rdx
callq 0xcb50
movq -0x5c8(%rbp), %rdi
movq -0x18(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
movl $0x0, (%rdi)
movq -0x30(%rbp), %rax
movq %rax, 0x8(%rdi)
addq $0x10, %rdi
leaq -0x80(%rbp), %rsi
movl $0x50, %edx
callq 0x10e0
movq -0x8(%rbp), %rdi
leaq -0x80(%rbp), %rsi
callq 0x2570
movl %eax, %ecx
movq -0x5c8(%rbp), %rax
movl %ecx, 0x468(%rax)
movl -0x1c(%rbp), %ecx
movl %ecx, 0x46c(%rax)
jmp 0x3139
movq -0x68(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0x90(%rbp)
movl -0x58(%rbp), %eax
movl %eax, -0x9c(%rbp)
movq -0x78(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq -0xa8(%rbp), %rsi
leaq -0xf8(%rbp), %rdi
movl $0x50, %edx
callq 0x10e0
movq -0x8(%rbp), %rax
movq $0x0, 0x8(%rax)
callq 0xccc0
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq %rcx, (%rax)
movq -0x8(%rbp), %rax
movl $0x0, 0x70(%rax)
movq -0x8(%rbp), %rdi
addq $0x20, %rdi
leaq -0xf8(%rbp), %rsi
movl $0x50, %edx
callq 0x10e0
movq -0x30(%rbp), %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x98(%rax)
movq -0x8(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x30(%rbp), %rsi
callq 0xcc00
movq %rax, -0x100(%rbp)
movl $0x1, %edi
movl $0x50, %esi
callq 0x10b0
movq %rax, -0x108(%rbp)
movq -0x108(%rbp), %rdi
leaq -0x80(%rbp), %rsi
movl $0x50, %edx
callq 0x10e0
cmpq $0x0, -0x100(%rbp)
jne 0x2e4b
movq -0x8(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x30(%rbp), %rsi
movq -0x108(%rbp), %rdx
callq 0xcb50
jmp 0x2e93
movq -0x8(%rbp), %rdi
movq -0x100(%rbp), %rdx
leaq -0x80(%rbp), %rsi
leaq 0x10888(%rip), %rcx     # 0x136e9
callq 0x6630
movq -0x100(%rbp), %rax
cmpl $0x0, 0x28(%rax)
jne 0x2e91
cmpl $0x0, -0x58(%rbp)
je 0x2e91
movq -0x8(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x30(%rbp), %rsi
movq -0x108(%rbp), %rdx
callq 0xcb50
jmp 0x2e93
movq -0x18(%rbp), %rax
cmpl $0x1a, (%rax)
jne 0x2ec5
movq -0x5c8(%rbp), %rax
movq -0x18(%rbp), %rcx
addq $0x20, %rcx
movq %rcx, -0x18(%rbp)
movq -0x18(%rbp), %rdx
movq -0x10(%rbp), %rcx
movq %rdx, (%rcx)
movl $0x2, (%rax)
jmp 0x3139
callq 0x61d0
movq -0x5c8(%rbp), %rdi
movq %rax, -0x118(%rbp)
movq %rdx, -0x110(%rbp)
movl $0x1, (%rdi)
movq -0x30(%rbp), %rax
movq %rax, 0x8(%rdi)
movl -0x20(%rbp), %eax
movl %eax, 0x454(%rdi)
addq $0x60, %rdi
addq $0x3a0, %rdi            # imm = 0x3A0
leaq -0xf8(%rbp), %rsi
movl $0x50, %edx
callq 0x10e0
leaq -0xf8(%rbp), %rdi
callq 0xb250
cmpl $0x0, %eax
je 0x2fc8
movq -0x8(%rbp), %rdi
leaq -0xf8(%rbp), %rsi
callq 0x28c0
movl %eax, %ecx
movq -0x5c8(%rbp), %rax
movl %ecx, -0x11c(%rbp)
movl -0x11c(%rbp), %ecx
movl %ecx, 0x458(%rax)
movq -0x8(%rbp), %rdi
leaq -0xf8(%rbp), %rsi
callq 0x2570
movl %eax, %ecx
movq -0x5c8(%rbp), %rax
movl %ecx, 0x45c(%rax)
cmpl $0x1, -0x11c(%rbp)
jne 0x2fc6
leaq -0x170(%rbp), %rdi
leaq -0xf8(%rbp), %rsi
callq 0xb8a0
movq -0x8(%rbp), %rdi
leaq -0x170(%rbp), %rsi
leaq -0x118(%rbp), %rdx
leaq 0x10763(%rip), %rcx     # 0x13709
callq 0x31f0
movl %eax, %ecx
movq -0x5c8(%rbp), %rax
movl %ecx, -0x174(%rbp)
movl -0x174(%rbp), %ecx
movl %ecx, 0x460(%rax)
jmp 0x2fc8
movq -0x5c8(%rbp), %rax
movl $0x0, 0x464(%rax)
movl -0x9c(%rbp), %eax
movl %eax, -0x5cc(%rbp)
testl %eax, %eax
je 0x30ca
jmp 0x2fef
movl -0x5cc(%rbp), %eax
decl %eax
subl $0x1, %eax
ja 0x30cc
jmp 0x3002
movl $0x0, -0x178(%rbp)
movl -0x178(%rbp), %eax
cmpl -0x98(%rbp), %eax
jge 0x30ae
movq -0x90(%rbp), %rax
movslq -0x178(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x180(%rbp)
movq -0x180(%rbp), %rsi
leaq -0x1d8(%rbp), %rdi
movl $0x58, %edx
callq 0x10e0
leaq -0x1d8(%rbp), %rsi
leaq -0x228(%rbp), %rdi
movl $0x50, %edx
callq 0x10e0
cmpl $0x5, -0x178(%rbp)
jle 0x307c
leaq 0x1069a(%rip), %rdi     # 0x13711
callq 0xb1f0
movq -0x8(%rbp), %rdi
movq -0x188(%rbp), %rcx
leaq -0x228(%rbp), %rsi
leaq -0x118(%rbp), %rdx
callq 0x31f0
movl -0x178(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x178(%rbp)
jmp 0x300c
cmpl $0x2, -0x9c(%rbp)
jne 0x30c8
movq -0x5c8(%rbp), %rax
movl $0x1, 0x464(%rax)
jmp 0x30cc
jmp 0x30cc
movq -0x8(%rbp), %rsi
leaq -0x5b8(%rbp), %rdi
leaq -0x18(%rbp), %rdx
callq 0x45d0
movq -0x5c8(%rbp), %rdi
movq -0x18(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, (%rax)
addq $0x60, %rdi
leaq -0x5b8(%rbp), %rsi
movl $0x390, %edx            # imm = 0x390
callq 0x10e0
movq -0x5c8(%rbp), %rax
movq -0x118(%rbp), %rcx
movq %rcx, 0x3f0(%rax)
movq -0x110(%rbp), %rcx
movq %rcx, 0x3f8(%rax)
movq -0x8(%rbp), %rdx
xorl %ecx, %ecx
subl 0x70(%rdx), %ecx
movl %ecx, 0x450(%rax)
movq -0x5c0(%rbp), %rax
addq $0x5d0, %rsp            # imm = 0x5D0
popq %rbp
retq
nopl (%rax)