// File: /workspace/github_c_makefile_star2_O2/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 0xb5ed
movq %rax, %rbp
leaq 0xb8(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x74e5
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 0x561d(%rip), %r13      # 0xd5b0
leaq 0x55ca(%rip), %r15      # 0xd564
movl $0x0, 0x3c(%rsp)
movq %r12, %rdi
movq %r14, %rsi
callq 0x74e5
movl 0x58(%rsp), %eax
leal -0x42(%rax), %ecx
cmpl $0x12, %ecx
ja 0x7fec
movslq (%r15,%rcx,4), %rcx
addq %r15, %rcx
jmpq *%rcx
cmpl $0x0, (%rbp)
leaq 0x5789(%rip), %rsi      # 0xd756
jne 0x7fde
jmp 0x7fe8
cmpl $0x0, 0x8(%rbp)
leaq 0x579e(%rip), %rsi      # 0xd77a
je 0x7fe8
movq %rbx, %rdi
xorl %eax, %eax
callq 0x35e4
movl 0x58(%rsp), %eax
addl $-0x35, %eax
cmpl $0x1f, %eax
ja 0x82cb
movslq (%r13,%rax,4), %rax
addq %r13, %rax
jmpq *%rax
movq %r14, %rdi
callq 0x8441
movq %rax, %rbx
leaq 0x88(%rsp), %rdi
movq %r14, %rsi
callq 0x74e5
movups 0x88(%rsp), %xmm0
movups 0x98(%rsp), %xmm1
movups 0xa8(%rsp), %xmm2
movups %xmm2, 0x20(%rsp)
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x76dd
movq %r14, %rdi
movq %rax, %rsi
callq 0x7673
testq %rbx, %rbx
je 0x8161
movl 0x8(%rbp), %eax
movl %eax, 0x8(%rbx)
movq 0x10(%rbp), %rax
movq %rax, 0x10(%rbx)
jmp 0x8156
cmpl $0x1, 0x10(%rbp)
leaq 0x5729(%rip), %rsi      # 0xd7a3
je 0x7fde
movl $0x1, 0x10(%rbp)
jmp 0x82a7
cmpl $0x1, 0x14(%rbp)
leaq 0x5729(%rip), %rsi      # 0xd7c0
je 0x7fde
movl $0x1, 0x14(%rbp)
jmp 0x82a7
movl $0x1, 0xc(%rbp)
jmp 0x82a7
movl (%rbp), %eax
cmpl $0x7, %eax
je 0x8256
cmpl $0x6, %eax
je 0x8244
testl %eax, %eax
jne 0x8272
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 0x8287
movl $0x5, (%rbp)
jmp 0x82a7
movq 0x60(%r14), %rdi
movq 0x78(%rsp), %rsi
callq 0xb822
cmpl $0x0, (%rbp)
jne 0x82cb
testq %rax, %rax
je 0x82cb
movq 0x10(%rax), %rcx
cmpl $0x1, 0x8(%rcx)
jne 0x82cb
movq 0x8(%rax), %rdi
callq 0xb949
movq %rax, %rbx
movq %rax, %rcx
movq %rcx, %rax
movq 0x18(%rcx), %rcx
testq %rcx, %rcx
jne 0x8138
andl $0x0, 0x8(%rax)
movl 0x8(%rbp), %ecx
movl %ecx, 0x8(%rax)
movq 0x10(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq %rbp, %rdi
callq 0xb8ba
movq %rbx, %rbp
leaq 0x60(%rsp), %rbx
jmp 0x82a7
movabsq $0x200000006, %rax      # imm = 0x200000006
jmp 0x81ae
movl $0x1, 0x8(%rbp)
jmp 0x82a7
movl $0x3, 0x8(%rbp)
jmp 0x82a7
movabsq $0x100000006, %rax      # imm = 0x100000006
jmp 0x81ae
andl $0x0, 0xc(%rbp)
jmp 0x82a7
movabsq $0x400000007, %rax      # imm = 0x400000007
movq %rax, (%rbp)
jmp 0x82a7
movl 0x3c(%rsp), %eax
cmpl $0x1, %eax
ja 0x8213
movl $0x4, 0x4(%rbp)
jmp 0x82a0
movl $0x2, 0x8(%rbp)
jmp 0x82a7
movl $0x5, 0x8(%rbp)
jmp 0x82a7
movl 0x3c(%rsp), %eax
cmpl $0x1, %eax
je 0x8221
testl %eax, %eax
jne 0x822a
movl $0x8, 0x4(%rbp)
jmp 0x823b
movq %r14, %rdi
callq 0x85f0
jmp 0x82a7
movl $0x4, 0x8(%rbp)
jmp 0x82a7
cmpl $0x2, %eax
jne 0x828f
movl $0x8, 0x4(%rbp)
jmp 0x82a0
movl $0x10, 0x4(%rbp)
jmp 0x823b
movq %rbx, %rdi
leaq 0x55d1(%rip), %rsi      # 0xd805
xorl %eax, %eax
callq 0x35e4
movl $0x7, (%rbp)
jmp 0x82a7
movl 0x3c(%rsp), %eax
cmpl $0x1, %eax
jne 0x82b4
movl $0x8, 0x4(%rbp)
jmp 0x8287
cmpl $0x8, 0x4(%rbp)
jne 0x8272
movl 0x3c(%rsp), %eax
testl %eax, %eax
je 0x82c2
jle 0x8287
movq %rbx, %rdi
leaq 0x5595(%rip), %rsi      # 0xd805
jmp 0x827c
movq %rbx, %rdi
leaq 0x55b1(%rip), %rsi      # 0xd82d
xorl %eax, %eax
callq 0x35e4
movl 0x3c(%rsp), %eax
incl %eax
movl %eax, 0x3c(%rsp)
jmp 0x82a7
movq %rbx, %rdi
leaq 0x5547(%rip), %rsi      # 0xd7e0
xorl %eax, %eax
callq 0x35e4
movl $0x6, (%rbp)
movq %r14, %rdi
callq 0x7522
jmp 0x7fa2
jle 0x8287
movq %rbx, %rdi
leaq 0x5520(%rip), %rsi      # 0xd7e0
jmp 0x827c
movl $0x10, 0x4(%rbp)
jmp 0x8287
cmpl $0x0, (%rbp)
jne 0x830d
movl 0x3c(%rsp), %eax
testl %eax, %eax
je 0x82f3
cmpl $0x3, %eax
jl 0x8306
leaq 0x54fb(%rip), %rsi      # 0xd7e0
leaq 0x40(%rsp), %rdi
xorl %eax, %eax
callq 0x35e4
jmp 0x8306
leaq 0x554a(%rip), %rsi      # 0xd844
leaq 0x40(%rsp), %rdi
xorl %eax, %eax
callq 0x36cc
movl $0x6, (%rbp)
movq %rbp, %rax
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq