// File: /workspace/github_c_makefile_star2_O1/Yamsman[P]scc/src/parse.c
// Function: parse_decl_spec
s_type *parse_decl_spec(lexer *lx) {
	s_type *type = type_new(TYPE_UNDEF);

	/*
	 * Loop and process specifiers
	 */
	int from_typedef = 0;
	int is_long = 0, is_signed = 0, is_unsigned = 0;
	s_pos begin = lex_peek(lx).loc;
	for (;;) {
		token t = lex_peek(lx);

		//Check for conflicts
		switch (t.type) {
			case TOK_KW_VOID: case TOK_KW_CHAR: case TOK_KW_SHORT:
			case TOK_KW_INT: case TOK_KW_FLOAT: case TOK_KW_DOUBLE:
			case TOK_KW_STRUCT: case TOK_KW_UNION: case TOK_KW_ENUM:
				if (type->kind != TYPE_UNDEF) {
					c_error(&t.loc, "Multiple data types in declaration\n");
				}
				break;
			case TOK_KW_EXTERN: case TOK_KW_STATIC: case TOK_KW_AUTO:
			case TOK_KW_REGISTER: case TOK_KW_TYPEDEF:
				if (type->s_class != CLASS_UNDEF) {
					c_error(&t.loc, "Multiple storage classes in declaration\n");
				}
				break;
			case TOK_KW_SIGNED:
				if (is_signed > 0)
					c_error(&t.loc, "Duplicate 'signed' qualifier\n");
				break;
			case TOK_KW_UNSIGNED:
				if (is_unsigned > 0)
					c_error(&t.loc, "Duplicate 'unsigned' qualifier\n");
				break;
			case TOK_KW_CONST:
				if (type->is_const == 1)
					c_error(&t.loc, "Duplicate 'const' qualifier\n");
				break;
			case TOK_KW_VOLATILE:
				if (type->is_volatile == 1)
					c_error(&t.loc, "Duplicate 'volatile' qualifier\n");
				break;
		} 

		//Check for a user defined type
		if (t.type == TOK_IDENT) {
			symbol *td = symtable_search(lx->stb, t.dat.sval);
			if (type->kind != TYPE_UNDEF) goto ts_end;
			if (td == NULL || td->btype->s_class != CLASS_TYPEDEF) goto ts_end;

			//Clone the predefined type
			s_type *usr_type = type_clone(td->type);
			s_type *usr_btype = usr_type;
			while (usr_btype->ref != NULL)
				usr_btype = usr_btype->ref;
			usr_btype->s_class = CLASS_UNDEF;

			//Copy over class/qualifiers if needed
			usr_btype->s_class = type->s_class;
			usr_btype->is_const = type->is_const;
			usr_btype->is_volatile = type->is_volatile;
			
			type_del(type);
			type = usr_type;
			lex_adv(lx);
			continue;
		} 

		//Process specifier
		s_type *su_type;
		switch (t.type) {
			case TOK_KW_VOID: 	type->kind = TYPE_VOID; break;
			case TOK_KW_CHAR: 	type->kind = TYPE_INT; type->size = 1; break;
			case TOK_KW_SHORT: 	type->kind = TYPE_INT; type->size = 2; break;
			case TOK_KW_FLOAT:	type->kind = TYPE_FLOAT; type->size = 4; break;
			case TOK_KW_TYPEDEF:	type->s_class = CLASS_TYPEDEF;	break;
			case TOK_KW_EXTERN:	type->s_class = CLASS_EXTERN;	break;
			case TOK_KW_STATIC:	type->s_class = CLASS_STATIC;	break;
			case TOK_KW_AUTO:	type->s_class = CLASS_AUTO; 	break;
			case TOK_KW_REGISTER:	type->s_class = CLASS_REGISTER;	break;
			case TOK_KW_SIGNED:	type->is_signed = 1;		break;
			case TOK_KW_UNSIGNED:	type->is_signed = 0;		break;
			case TOK_KW_CONST:	type->is_const = 1;		break;
			case TOK_KW_VOLATILE:	type->is_volatile = 1;		break;
			case TOK_KW_INT: 	
				if (is_long == 0 || is_long == 1)
					type->size = 4;
				else if (is_long == 2)
					type->size = 8;
				else
					c_error(&t.loc, "Too many 'long' for data type 'int'\n");
				type->kind = TYPE_INT;
				break;
			case TOK_KW_DOUBLE:
				if (is_long == 0)
					type->size = 8;
				else if (is_long == 1)
					type->size = 16;
				else
					c_error(&t.loc, "Too many 'long' for data type 'double'\n");
				type->kind = TYPE_FLOAT;
				break;
			case TOK_KW_LONG:
				//Either set the data type to int, or modify the current type
				if (type->kind == TYPE_UNDEF) {
					type->size = 4;
					if (is_long > 0)
						type->size = 8;
				} else if (type->kind == TYPE_INT) {
					if (is_long == 1)
						type->size = 8;
					else if (is_long > 1)
						c_error(&t.loc,
							"Too many 'long' for data type 'int'\n");
				} else if (type->kind == TYPE_FLOAT && type->size == 8) {
					if (is_long == 0)
						type->size = 16;
					else if (is_long > 0)
						c_error(&t.loc,
							"Too many 'long' for data type 'double'\n");
				} else {
					c_error(&t.loc, "Invalid use of 'long'\n");
				}
				is_long++;
				break;
			case TOK_KW_STRUCT:
			case TOK_KW_UNION:
				//Read struct/union type
				su_type = parse_sdef(lx);
				lex_unget(lx, make_tok_node(lex_peek(lx)));
				if (su_type == NULL) break;

				//Merge with current type
				su_type->s_class = type->s_class;
				su_type->is_const = type->is_const;
				su_type->is_volatile = type->is_volatile;
				type_del(type);
				type = su_type; 
				break;
			case TOK_KW_ENUM:
				parse_edef(lx);
				break;
			default:
				goto ts_end;
		}
		lex_adv(lx);
	}

	/*
	 * Error checking
	 */
	//Warning for no specified data type (unless 'long' is specified)
ts_end:	if (type->kind == TYPE_UNDEF) {
		if (is_long == 0)
			c_warn(&begin, "Declaration defaults to 'int'\n");
		if (is_long > 2)
			c_error(&begin, "Too many 'long' for data type 'int'\n");
		type->kind = TYPE_INT;
	}

	//Ensure signed/unsigned is only used with integer data types
	if (is_signed == 1 && type->kind != TYPE_INT)
		c_error(&begin, "Improper usage of 'signed' qualifier\n");
	if (is_unsigned == 1 && type->kind != TYPE_INT)
		c_error(&begin, "Improper usage of 'unsigned' qualifier\n");

	return type;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movq %rdi, %r14
xorl %edi, %edi
callq 0xbfcd
movq %rax, %r13
leaq 0xa8(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x7a57
movq 0x18(%rbx), %rax
movq %rax, 0x40(%rsp)
movups 0x8(%rbx), %xmm0
movaps %xmm0, 0x30(%rsp)
leaq 0x50(%rsp), %rbp
leaq 0x5f23(%rip), %r15      # 0xe564
xorl %ebx, %ebx
leaq 0x48(%rsp), %rdi
movq %r14, %rsi
callq 0x7a57
movl 0x48(%rsp), %eax
addl $-0x42, %eax
cmpl $0x12, %eax
ja 0x8690
movslq (%r15,%rax,4), %rax
addq %r15, %rax
jmpq *%rax
cmpl $0x0, (%r13)
je 0x8690
movq %rbp, %rdi
leaq 0x60e0(%rip), %rsi      # 0xe756
jmp 0x8689
cmpl $0x0, 0x8(%r13)
je 0x8690
movq %rbp, %rdi
leaq 0x60f1(%rip), %rsi      # 0xe77a
xorl %eax, %eax
callq 0x3250
movl $0x5, %r12d
movl 0x48(%rsp), %eax
addl $-0x35, %eax
cmpl $0x1f, %eax
ja 0x8998
leaq 0x5f03(%rip), %rcx      # 0xe5b0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl %ebx, %ebp
movq %r14, %rdi
callq 0x8b37
movq %rax, %rbx
leaq 0x78(%rsp), %rdi
movq %r14, %rsi
callq 0x7a57
movups 0x78(%rsp), %xmm0
movups 0x88(%rsp), %xmm1
movups 0x98(%rsp), %xmm2
movups %xmm2, 0x20(%rsp)
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x7ca7
movq %r14, %rdi
movq %rax, %rsi
callq 0x7c3b
xorl %r12d, %r12d
testq %rbx, %rbx
je 0x872b
movl 0x8(%r13), %eax
movl %eax, 0x8(%rbx)
movl 0x10(%r13), %eax
movl %eax, 0x10(%rbx)
movl 0x14(%r13), %eax
movl %eax, 0x14(%rbx)
movq %r13, %rdi
callq 0xc2c4
movq %rbx, %r13
movl %ebp, %ebx
leaq 0x50(%rsp), %rbp
jmp 0x8990
cmpl $0x1, 0x10(%r13)
jne 0x8690
movq %rbp, %rdi
leaq 0x6057(%rip), %rsi      # 0xe7a3
jmp 0x8689
cmpl $0x1, 0x14(%r13)
jne 0x8690
movq %rbp, %rdi
leaq 0x605a(%rip), %rsi      # 0xe7c0
jmp 0x8689
movl $0x1, 0x10(%r13)
jmp 0x898d
movl $0x3, 0x8(%r13)
jmp 0x898d
movq %r14, %rdi
callq 0x8ceb
jmp 0x898d
movl $0x2, 0x8(%r13)
jmp 0x898d
movl $0x1, 0x14(%r13)
jmp 0x898d
movabsq $0x100000006, %rax      # imm = 0x100000006
jmp 0x88ce
movl $0x1, 0x8(%r13)
jmp 0x898d
movl (%r13), %eax
cmpl $0x7, %eax
je 0x8946
cmpl $0x6, %eax
je 0x8937
testl %eax, %eax
jne 0x895f
xorl %eax, %eax
testl %ebx, %ebx
setg %al
leal 0x4(,%rax,4), %eax
movl %eax, 0x4(%r13)
jmp 0x8970
movq 0x60(%r14), %rdi
movq 0x68(%rsp), %rsi
callq 0xc219
cmpl $0x0, (%r13)
setne %cl
testq %rax, %rax
sete %dl
orb %cl, %dl
jne 0x8998
movq 0x10(%rax), %rcx
cmpl $0x1, 0x8(%rcx)
jne 0x8998
movl %ebx, %ebp
movq 0x8(%rax), %rdi
callq 0xc35c
movq %rax, %rbx
movq %rax, %rcx
movq %rcx, %rax
movq 0x18(%rcx), %rcx
testq %rcx, %rcx
jne 0x8840
movl $0x0, 0x8(%rax)
movl 0x8(%r13), %ecx
movl %ecx, 0x8(%rax)
movl 0x10(%r13), %ecx
movl %ecx, 0x10(%rax)
movl 0x14(%r13), %ecx
movl %ecx, 0x14(%rax)
movq %r13, %rdi
callq 0xc2c4
movl $0x3, %r12d
jmp 0x8728
movl $0x5, (%r13)
jmp 0x898d
movabsq $0x400000007, %rax      # imm = 0x400000007
jmp 0x88ce
cmpl $0x1, %ebx
je 0x8912
testl %ebx, %ebx
jne 0x891c
movl $0x8, 0x4(%r13)
jmp 0x892d
movl $0x4, 0x8(%r13)
jmp 0x898d
movl $0x5, 0x8(%r13)
jmp 0x898d
movabsq $0x200000006, %rax      # imm = 0x200000006
movq %rax, (%r13)
jmp 0x898d
cmpl $0x1, %ebx
ja 0x8903
movl $0x4, 0x4(%r13)
jmp 0x8985
movl $0x0, 0xc(%r13)
jmp 0x898d
movl $0x1, 0xc(%r13)
jmp 0x898d
cmpl $0x2, %ebx
jne 0x8974
movl $0x8, 0x4(%r13)
jmp 0x8985
movl $0x10, 0x4(%r13)
jmp 0x892d
movq %rbp, %rdi
leaq 0x5edf(%rip), %rsi      # 0xe805
xorl %eax, %eax
callq 0x3250
movl $0x7, (%r13)
jmp 0x898d
cmpl $0x1, %ebx
jne 0x89ad
movl $0x8, 0x4(%r13)
jmp 0x8970
cmpl $0x8, 0x4(%r13)
jne 0x895f
testl %ebx, %ebx
je 0x89bb
jle 0x8970
movq %rbp, %rdi
leaq 0x5ea8(%rip), %rsi      # 0xe805
jmp 0x8969
movq %rbp, %rdi
leaq 0x5ec4(%rip), %rsi      # 0xe82d
xorl %eax, %eax
callq 0x3250
incl %ebx
jmp 0x898d
movq %rbp, %rdi
leaq 0x5e62(%rip), %rsi      # 0xe7e0
xorl %eax, %eax
callq 0x3250
movl $0x6, (%r13)
xorl %r12d, %r12d
movq %r14, %rdi
callq 0x7a94
testl %r12d, %r12d
je 0x8643
cmpl $0x3, %r12d
je 0x8643
jmp 0x89c5
jle 0x8970
movq %rbp, %rdi
leaq 0x5e27(%rip), %rsi      # 0xe7e0
jmp 0x8969
movl $0x10, 0x4(%r13)
jmp 0x8970
cmpl $0x5, %r12d
jne 0x8a09
cmpl $0x0, (%r13)
jne 0x8a09
testl %ebx, %ebx
jne 0x89e9
leaq 0x5e67(%rip), %rsi      # 0xe844
leaq 0x30(%rsp), %rdi
xorl %eax, %eax
callq 0x3338
cmpl $0x3, %ebx
jl 0x8a01
leaq 0x5deb(%rip), %rsi      # 0xe7e0
leaq 0x30(%rsp), %rdi
xorl %eax, %eax
callq 0x3250
movl $0x6, (%r13)
movq %r13, %rax
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq