// File: /workspace/github_c_makefile_star2_O3/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 $0xe8, %rsp
movq %rdi, %r14
xorl %edi, %edi
callq 0xbf35
movq %rax, %rbp
leaq 0xb8(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x79dc
movq 0x18(%rbx), %rax
movq %rax, 0x50(%rsp)
movups 0x8(%rbx), %xmm0
movaps %xmm0, 0x40(%rsp)
leaq 0x60(%rsp), %rbx
leaq 0x58(%rsp), %r12
leaq 0x5fd0(%rip), %r13      # 0xe5b0
leaq 0x5f7d(%rip), %r15      # 0xe564
movl $0x0, 0x3c(%rsp)
movq %r12, %rdi
movq %r14, %rsi
callq 0x79dc
movl 0x58(%rsp), %eax
leal -0x42(%rax), %ecx
cmpl $0x12, %ecx
ja 0x8639
movslq (%r15,%rcx,4), %rcx
addq %r15, %rcx
jmpq *%rcx
cmpl $0x0, (%rbp)
leaq 0x613c(%rip), %rsi      # 0xe756
jne 0x862b
jmp 0x8635
cmpl $0x0, 0x8(%rbp)
leaq 0x6151(%rip), %rsi      # 0xe77a
je 0x8635
movq %rbx, %rdi
xorl %eax, %eax
callq 0x3250
movl 0x58(%rsp), %eax
addl $-0x35, %eax
cmpl $0x1f, %eax
ja 0x891e
movslq (%r13,%rax,4), %rax
addq %r13, %rax
jmpq *%rax
movq %r14, %rdi
callq 0x8a94
movq %rax, %rbx
leaq 0x88(%rsp), %rdi
movq %r14, %rsi
callq 0x79dc
movups 0x88(%rsp), %xmm0
movups 0x98(%rsp), %xmm1
movups 0xa8(%rsp), %xmm2
movups %xmm2, 0x20(%rsp)
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x7c14
movq %r14, %rdi
movq %rax, %rsi
callq 0x7ba8
testq %rbx, %rbx
je 0x87b1
movl 0x8(%rbp), %eax
movl %eax, 0x8(%rbx)
movq 0x10(%rbp), %rax
movq %rax, 0x10(%rbx)
jmp 0x87a6
cmpl $0x1, 0x10(%rbp)
leaq 0x60dc(%rip), %rsi      # 0xe7a3
je 0x862b
movl $0x1, 0x10(%rbp)
jmp 0x88fa
cmpl $0x1, 0x14(%rbp)
leaq 0x60dc(%rip), %rsi      # 0xe7c0
je 0x862b
movl $0x1, 0x14(%rbp)
jmp 0x88fa
movl $0x1, 0xc(%rbp)
jmp 0x88fa
movl (%rbp), %eax
cmpl $0x7, %eax
je 0x88a9
cmpl $0x6, %eax
je 0x8897
testl %eax, %eax
jne 0x88c5
xorl %eax, %eax
movl 0x3c(%rsp), %ecx
testl %ecx, %ecx
setg %al
leal 0x4(,%rax,4), %eax
movl %eax, 0x4(%rbp)
movl %ecx, %eax
jmp 0x88da
movl $0x5, (%rbp)
jmp 0x88fa
movq 0x60(%r14), %rdi
movq 0x78(%rsp), %rsi
callq 0xc187
cmpl $0x0, (%rbp)
jne 0x891e
testq %rax, %rax
je 0x891e
movq 0x10(%rax), %rcx
cmpl $0x1, 0x8(%rcx)
jne 0x891e
movq 0x8(%rax), %rdi
callq 0xc2cb
movq %rax, %rbx
movq %rax, %rcx
movq %rcx, %rax
movq 0x18(%rcx), %rcx
testq %rcx, %rcx
jne 0x8785
movl $0x0, 0x8(%rax)
movl 0x8(%rbp), %ecx
movl %ecx, 0x8(%rax)
movq 0x10(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq %rbp, %rdi
callq 0xc233
movq %rbx, %rbp
leaq 0x60(%rsp), %rbx
jmp 0x88fa
movabsq $0x200000006, %rax      # imm = 0x200000006
jmp 0x8801
movl $0x1, 0x8(%rbp)
jmp 0x88fa
movl $0x3, 0x8(%rbp)
jmp 0x88fa
movabsq $0x100000006, %rax      # imm = 0x100000006
jmp 0x8801
movl $0x0, 0xc(%rbp)
jmp 0x88fa
movabsq $0x400000007, %rax      # imm = 0x400000007
movq %rax, (%rbp)
jmp 0x88fa
movl 0x3c(%rsp), %eax
cmpl $0x1, %eax
ja 0x8866
movl $0x4, 0x4(%rbp)
jmp 0x88f3
movl $0x2, 0x8(%rbp)
jmp 0x88fa
movl $0x5, 0x8(%rbp)
jmp 0x88fa
movl 0x3c(%rsp), %eax
cmpl $0x1, %eax
je 0x8874
testl %eax, %eax
jne 0x887d
movl $0x8, 0x4(%rbp)
jmp 0x888e
movq %r14, %rdi
callq 0x8c48
jmp 0x88fa
movl $0x4, 0x8(%rbp)
jmp 0x88fa
cmpl $0x2, %eax
jne 0x88e2
movl $0x8, 0x4(%rbp)
jmp 0x88f3
movl $0x10, 0x4(%rbp)
jmp 0x888e
movq %rbx, %rdi
leaq 0x5f7e(%rip), %rsi      # 0xe805
xorl %eax, %eax
callq 0x3250
movl $0x7, (%rbp)
jmp 0x88fa
movl 0x3c(%rsp), %eax
cmpl $0x1, %eax
jne 0x8907
movl $0x8, 0x4(%rbp)
jmp 0x88da
cmpl $0x8, 0x4(%rbp)
jne 0x88c5
movl 0x3c(%rsp), %eax
testl %eax, %eax
je 0x8915
jle 0x88da
movq %rbx, %rdi
leaq 0x5f42(%rip), %rsi      # 0xe805
jmp 0x88cf
movq %rbx, %rdi
leaq 0x5f5e(%rip), %rsi      # 0xe82d
xorl %eax, %eax
callq 0x3250
movl 0x3c(%rsp), %eax
incl %eax
movl %eax, 0x3c(%rsp)
jmp 0x88fa
movq %rbx, %rdi
leaq 0x5ef4(%rip), %rsi      # 0xe7e0
xorl %eax, %eax
callq 0x3250
movl $0x6, (%rbp)
movq %r14, %rdi
callq 0x7a19
jmp 0x85ef
jle 0x88da
movq %rbx, %rdi
leaq 0x5ecd(%rip), %rsi      # 0xe7e0
jmp 0x88cf
movl $0x10, 0x4(%rbp)
jmp 0x88da
cmpl $0x0, (%rbp)
jne 0x8960
movl 0x3c(%rsp), %eax
testl %eax, %eax
je 0x8946
cmpl $0x3, %eax
jl 0x8959
leaq 0x5ea8(%rip), %rsi      # 0xe7e0
leaq 0x40(%rsp), %rdi
xorl %eax, %eax
callq 0x3250
jmp 0x8959
leaq 0x5ef7(%rip), %rsi      # 0xe844
leaq 0x40(%rsp), %rdi
xorl %eax, %eax
callq 0x3338
movl $0x6, (%rbp)
movq %rbp, %rax
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq