// File: AshOlogn[P]ash-language-interpreter/src/parser.cpp
// Function: parseFunction(unsigned int, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>)
Function* parseFunction(uint32_t startLine, uint32_t secondStartLine, string functionName) {

	//now create a Function struct
	Function* function = (Function*) malloc(sizeof(Function));
	function->returnFlag = (bool*) malloc(sizeof(bool));
	function->returnValue = (ParseData*) malloc(sizeof(ParseData));

	//assign the global returnFlag and returnValue pointers to this function
	returnFlag.push_back(function->returnFlag);
	returnValue.push_back(function->returnValue);

	//now read in arguments enclosed in parentheses
	Token* leftParenToken = consume(); //consume (

	//if the next token is not a parenthesis, throw an error
	if(leftParenToken->type != LEFT_PAREN) {

		uint32_t endLine = (leftParenToken->type == END) ? secondStartLine : leftParenToken->line+1;

		if(leftParenToken->type == END) {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected '(' to begin function parameter list"); 
		} else {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), leftParenToken->lexeme, "Expected '(' to begin function parameter list");
		}
	}

	//first scan to figure out how many arguments must be allocated in Function
	uint32_t currentIndex = 0;
	uint32_t argCount = 0;

	uint32_t currentErrorLine = leftParenToken->line+1;
	while(peekAhead(currentIndex)->type != RIGHT_PAREN) {

		//make sure you have a type then variable
		if(!isTypeTokenType(peekAhead(currentIndex)->type)) {

			Token* tempTypeToken = peekAhead(currentIndex);	
			uint32_t endLine = (tempTypeToken->type == END) ? currentErrorLine : tempTypeToken->line+1;

			if(tempTypeToken->type == END) {
				throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected function parameter type");
			} else {
				throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), tempTypeToken->lexeme, "Expected function parameter type");
			}
		}
		currentErrorLine = peekAhead(currentIndex)->line+1;
		currentIndex++;

		//could be an array type
		if(peekAhead(currentIndex)->type == LEFT_BRACKET) {

			currentErrorLine = peekAhead(currentIndex)->line+1;
			currentIndex++;

			//next token must be ']'
			if(peekAhead(currentIndex)->type != RIGHT_BRACKET) {

				uint32_t endLine = (peekAhead(currentIndex)->type == END) ? currentErrorLine : peekAhead(currentIndex)->line+1;

				if(peekAhead(currentIndex)->type == END) {
					throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected closing ']' in array type");		
				} else {
					throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), peekAhead(currentIndex)->lexeme, "Expected closing ']' in array type");						
				}
			}

			currentErrorLine = peekAhead(currentIndex)->line+1;
			currentIndex++;
		}

		//make sure parameter name follows type
		if(peekAhead(currentIndex)->type != VARIABLE) {

			Token* tempVariableToken = peekAhead(currentIndex);
			uint32_t endLine = (tempVariableToken->type == END) ? currentErrorLine : tempVariableToken->line+1;

			if(tempVariableToken->type == END) {
				throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected function parameter name");
			} else {
				throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), tempVariableToken->lexeme, "Expected function parameter name");
			}
		}
		currentErrorLine = peekAhead(currentIndex)->line+1;
		currentIndex++;
		argCount++;

		//if next token is not closing parenthesis, it must be a comma
		Token* nextToken = peekAhead(currentIndex);				
		if(nextToken->type != RIGHT_PAREN && nextToken->type != COMMA) {

			uint32_t endLine = (nextToken->type == END) ? currentErrorLine : nextToken->line+1;

			if(nextToken->type == END) {
				throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected ',' separating arguments or ')' terminating argument list");
			} else {
				throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), nextToken->lexeme, "Expected ',' separating arguments or ')' terminating argument list"); 
			} 

		} else if(nextToken->type == COMMA) {
			currentErrorLine = nextToken->line+1;
			currentIndex++; //"consume" COMMA token
		}
	}

	//now allocate memory for argument names and types
	function->numArgs = argCount;
	ParseDataType* argTypes = new ParseDataType[argCount];
	ParseDataType* argSubTypes = new ParseDataType[argCount];
	char** argNames = (char**) malloc(sizeof(char*) * argCount);

	//keep track of variable line numbers
	uint32_t typeLines[argCount];
	uint32_t varLines[argCount];

	//now read in arguments for real
	uint32_t argIndex = 0;
	while(peek()->type != RIGHT_PAREN) {

		//read in parameter type
		Token* currTypeToken = consume();

		//could be an array type
		if(peek()->type == LEFT_BRACKET) {

			argTypes[argIndex] = ARRAY_T;
			argSubTypes[argIndex] = typeTokenConversion(currTypeToken->type);

			consume(); //consume '['
			typeLines[argIndex] = consume()->line+1;

		} else {

			argTypes[argIndex] = typeTokenConversion(currTypeToken->type);
			argSubTypes[argIndex] = INVALID_T;
			typeLines[argIndex] = currTypeToken->line+1;
		}

		//read in parameter name
		Token* currVarToken = consume();
		const char* aName = currVarToken->lexeme;
		argNames[argIndex] = copyString(aName);
		varLines[argIndex] = currVarToken->line+1;

		argIndex++;
		if(argIndex < argCount)
			consume(); //consume ,
	}
	leftParenToken = consume(); //consume ')' token

	function->argTypes = argTypes;
	function->argSubTypes = argSubTypes;
	function->argNames = argNames;

	//now get the return type
	Token* rightArrowToken = consume(); //consume ->
	if(rightArrowToken->type != RIGHTARROW) {
		
		uint32_t endLine = (rightArrowToken->line == END) ? leftParenToken->line+1 : rightArrowToken->line+1;

		if(rightArrowToken->line == END) {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected -> followed by return type");
		} else {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), rightArrowToken->lexeme, "Expected -> followed by return type");
		}
	}

	//make sure following token is a return type
	Token* returnTypeToken = consume();
	if(!isTypeTokenType(returnTypeToken->type)) {

		uint32_t endLine = (returnTypeToken->type == END) ? rightArrowToken->line+1 : returnTypeToken->line+1;

		if(returnTypeToken->type == END) {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected function return type"); 
		} else {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), returnTypeToken->lexeme, "Expected function return type"); 
		}
	}

	returnType.push_back(typeTokenConversion(returnTypeToken->type));
	function->returnType = typeTokenConversion(returnTypeToken->type);

	//just declare function up front with dummy data and Function public interface data
	//(to allow for recursive definitions)
	ParseData dummyFunctionData;
	dummyFunctionData.type = FUN_T;
	dummyFunctionData.value.allocated = function;
	symbolTable->declare(functionName, dummyFunctionData);

	//now declare the variables just for scope-checking purposes
	//and enter a new scope (in both tables) for function body
	symbolTable->enterNewScope();
	NewAssignmentStatementNode* dummy;

	for(uint32_t i = 0; i < argCount; i++) {
		//this construction declares variable as well
		string argName(argNames[i]);
		dummy = new NewAssignmentStatementNode(argName, argTypes[i], symbolTable, typeLines[i], varLines[i]);
	}

	//now store AbstractStatementNode* vector representing function body
	//make sure the body is braced
	Token* leftBraceToken = consume(); //consume {
	if(leftBraceToken->type != LEFT_BRACE) {

		uint32_t endLine = (leftBraceToken->type == END) ? returnTypeToken->line+1 : leftBraceToken->line+1;

		if(leftBraceToken->type == END) {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), "Expected '{' followed by function body");
		} else {
			throw ParseSyntaxError(startLine, endLine, getCodeLineBlock(startLine-1, endLine-1), leftBraceToken->lexeme, "Expected '{' followed by function body");
		}
	}

	//represents statements in body
	vector<AbstractStatementNode*>* body = new vector<AbstractStatementNode*>();

	while(peek()->type != RIGHT_BRACE) {
		body->push_back(addStatement());  
	}
	consume(); //consume }

	//leave scope
	symbolTable->leaveScope();
	function->body = body;

	//reset global pointers
	returnFlag.pop_back();
	returnValue.pop_back();
	returnType.pop_back();

	return function;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x3c0, %rsp            # imm = 0x3C0
movq %rdx, -0x1a8(%rbp)
movl %edi, -0x4(%rbp)
movl %esi, -0x8(%rbp)
movq %rdx, -0x10(%rbp)
movl $0x40, %edi
callq 0x4310
movq %rax, -0x18(%rbp)
movl $0x1, %edi
callq 0x4310
movq %rax, %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x38(%rax)
movl $0x10, %edi
callq 0x4310
movq %rax, %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x30(%rax)
movq -0x18(%rbp), %rsi
addq $0x38, %rsi
leaq 0x243dd(%rip), %rdi     # 0x543b0
callq 0x3a150
movq -0x18(%rbp), %rsi
addq $0x30, %rsi
leaq 0x243e1(%rip), %rdi     # 0x543c8
callq 0x3a1c0
callq 0x2fe10
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rax
cmpl $0x0, (%rax)
je 0x3016c
movq -0x20(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x30016
movl -0x8(%rbp), %eax
movl %eax, -0x1ac(%rbp)
jmp 0x30026
movq -0x20(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x1ac(%rbp)
movl -0x1ac(%rbp), %eax
movl %eax, -0x24(%rbp)
movq -0x20(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x300d0
movl $0x28, %edi
callq 0x4130
movq %rax, -0x1c8(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x1c0(%rbp)
movl -0x24(%rbp), %esi
movl %esi, -0x1bc(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x1b8(%rbp)
jmp 0x30071
movq -0x1b8(%rbp), %rcx
movl -0x1bc(%rbp), %edx
movl -0x1c0(%rbp), %esi
movq -0x1c8(%rbp), %rdi
leaq 0x14636(%rip), %r8      # 0x446c8
callq 0x3a230
jmp 0x30099
movq -0x1c8(%rbp), %rdi
leaq 0x23601(%rip), %rsi     # 0x536a8
leaq -0x2913e(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x1c8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x1e0(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x1d8(%rbp)
movl -0x24(%rbp), %esi
movl %esi, -0x1d4(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x1d0(%rbp)
jmp 0x30105
movq -0x1d0(%rbp), %rcx
movl -0x1d4(%rbp), %edx
movl -0x1d8(%rbp), %esi
movq -0x1e0(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x1459a(%rip), %r9      # 0x446c8
callq 0x3a2a0
jmp 0x30135
movq -0x1e0(%rbp), %rdi
leaq 0x23565(%rip), %rsi     # 0x536a8
leaq -0x291da(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x1e0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x0, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
movq -0x20(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x38(%rbp), %edi
callq 0x2fe80
cmpl $0x1, (%rax)
je 0x3087f
movl -0x38(%rbp), %edi
callq 0x2fe80
movl (%rax), %edi
callq 0x7f00
testb $0x1, %al
jne 0x30325
movl -0x38(%rbp), %edi
callq 0x2fe80
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x301cf
movl -0x40(%rbp), %eax
movl %eax, -0x1e4(%rbp)
jmp 0x301df
movq -0x48(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x1e4(%rbp)
movl -0x1e4(%rbp), %eax
movl %eax, -0x4c(%rbp)
movq -0x48(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x30289
movl $0x28, %edi
callq 0x4130
movq %rax, -0x200(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x1f8(%rbp)
movl -0x4c(%rbp), %esi
movl %esi, -0x1f4(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x1f0(%rbp)
jmp 0x3022a
movq -0x1f0(%rbp), %rcx
movl -0x1f4(%rbp), %edx
movl -0x1f8(%rbp), %esi
movq -0x200(%rbp), %rdi
leaq 0x144ab(%rip), %r8      # 0x446f6
callq 0x3a230
jmp 0x30252
movq -0x200(%rbp), %rdi
leaq 0x23448(%rip), %rsi     # 0x536a8
leaq -0x292f7(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x200(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x218(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x210(%rbp)
movl -0x4c(%rbp), %esi
movl %esi, -0x20c(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x208(%rbp)
jmp 0x302be
movq -0x208(%rbp), %rcx
movl -0x20c(%rbp), %edx
movl -0x210(%rbp), %esi
movq -0x218(%rbp), %rdi
movq -0x48(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x1440f(%rip), %r9      # 0x446f6
callq 0x3a2a0
jmp 0x302ee
movq -0x218(%rbp), %rdi
leaq 0x233ac(%rip), %rsi     # 0x536a8
leaq -0x29393(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x218(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl -0x38(%rbp), %edi
callq 0x2fe80
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
movl -0x38(%rbp), %edi
callq 0x2fe80
cmpl $0x2, (%rax)
jne 0x3051f
movl -0x38(%rbp), %edi
callq 0x2fe80
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
movl -0x38(%rbp), %edi
callq 0x2fe80
cmpl $0x3, (%rax)
je 0x30505
movl -0x38(%rbp), %edi
callq 0x2fe80
cmpl $0x4e, (%rax)
jne 0x30393
movl -0x40(%rbp), %eax
movl %eax, -0x21c(%rbp)
jmp 0x303a7
movl -0x38(%rbp), %edi
callq 0x2fe80
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x21c(%rbp)
movl -0x21c(%rbp), %eax
movl %eax, -0x50(%rbp)
movl -0x38(%rbp), %edi
callq 0x2fe80
cmpl $0x4e, (%rax)
jne 0x30455
movl $0x28, %edi
callq 0x4130
movq %rax, -0x238(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x230(%rbp)
movl -0x50(%rbp), %esi
movl %esi, -0x22c(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x228(%rbp)
jmp 0x303f6
movq -0x228(%rbp), %rcx
movl -0x22c(%rbp), %edx
movl -0x230(%rbp), %esi
movq -0x238(%rbp), %rdi
leaq 0x14300(%rip), %r8      # 0x44717
callq 0x3a230
jmp 0x3041e
movq -0x238(%rbp), %rdi
leaq 0x2327c(%rip), %rsi     # 0x536a8
leaq -0x294c3(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x238(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x250(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x248(%rbp)
movl -0x50(%rbp), %esi
movl %esi, -0x244(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x240(%rbp)
jmp 0x3048a
movl -0x38(%rbp), %edi
callq 0x2fe80
movq %rax, -0x258(%rbp)
jmp 0x3049b
movq -0x240(%rbp), %rcx
movl -0x244(%rbp), %edx
movl -0x248(%rbp), %esi
movq -0x250(%rbp), %rdi
movq -0x258(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x14250(%rip), %r9      # 0x44717
callq 0x3a2a0
jmp 0x304ce
movq -0x250(%rbp), %rdi
leaq 0x231cc(%rip), %rsi     # 0x536a8
leaq -0x29573(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x250(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl -0x38(%rbp), %edi
callq 0x2fe80
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
movl -0x38(%rbp), %edi
callq 0x2fe80
cmpl $0x3b, (%rax)
je 0x306a6
movl -0x38(%rbp), %edi
callq 0x2fe80
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x30550
movl -0x40(%rbp), %eax
movl %eax, -0x25c(%rbp)
jmp 0x30560
movq -0x58(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x25c(%rbp)
movl -0x25c(%rbp), %eax
movl %eax, -0x5c(%rbp)
movq -0x58(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x3060a
movl $0x28, %edi
callq 0x4130
movq %rax, -0x278(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x270(%rbp)
movl -0x5c(%rbp), %esi
movl %esi, -0x26c(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x268(%rbp)
jmp 0x305ab
movq -0x268(%rbp), %rcx
movl -0x26c(%rbp), %edx
movl -0x270(%rbp), %esi
movq -0x278(%rbp), %rdi
leaq 0x1416e(%rip), %r8      # 0x4473a
callq 0x3a230
jmp 0x305d3
movq -0x278(%rbp), %rdi
leaq 0x230c7(%rip), %rsi     # 0x536a8
leaq -0x29678(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x278(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x290(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x288(%rbp)
movl -0x5c(%rbp), %esi
movl %esi, -0x284(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x280(%rbp)
jmp 0x3063f
movq -0x280(%rbp), %rcx
movl -0x284(%rbp), %edx
movl -0x288(%rbp), %esi
movq -0x290(%rbp), %rdi
movq -0x58(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x140d2(%rip), %r9      # 0x4473a
callq 0x3a2a0
jmp 0x3066f
movq -0x290(%rbp), %rdi
leaq 0x2302b(%rip), %rsi     # 0x536a8
leaq -0x29714(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x290(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl -0x38(%rbp), %edi
callq 0x2fe80
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
movl -0x38(%rbp), %edi
callq 0x2fe80
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
cmpl $0x1, (%rax)
je 0x30859
movq -0x68(%rbp), %rax
cmpl $0x2b, (%rax)
je 0x30859
movq -0x68(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x30703
movl -0x40(%rbp), %eax
movl %eax, -0x294(%rbp)
jmp 0x30713
movq -0x68(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x294(%rbp)
movl -0x294(%rbp), %eax
movl %eax, -0x6c(%rbp)
movq -0x68(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x307bd
movl $0x28, %edi
callq 0x4130
movq %rax, -0x2b0(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x2a8(%rbp)
movl -0x6c(%rbp), %esi
movl %esi, -0x2a4(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x2a0(%rbp)
jmp 0x3075e
movq -0x2a0(%rbp), %rcx
movl -0x2a4(%rbp), %edx
movl -0x2a8(%rbp), %esi
movq -0x2b0(%rbp), %rdi
leaq 0x13fdc(%rip), %r8      # 0x4475b
callq 0x3a230
jmp 0x30786
movq -0x2b0(%rbp), %rdi
leaq 0x22f14(%rip), %rsi     # 0x536a8
leaq -0x2982b(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x2b0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x2c8(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x2c0(%rbp)
movl -0x6c(%rbp), %esi
movl %esi, -0x2bc(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x2b8(%rbp)
jmp 0x307f2
movq -0x2b8(%rbp), %rcx
movl -0x2bc(%rbp), %edx
movl -0x2c0(%rbp), %esi
movq -0x2c8(%rbp), %rdi
movq -0x68(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x13f40(%rip), %r9      # 0x4475b
callq 0x3a2a0
jmp 0x30822
movq -0x2c8(%rbp), %rdi
leaq 0x22e78(%rip), %rsi     # 0x536a8
leaq -0x298c7(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x2c8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movq -0x68(%rbp), %rax
cmpl $0x2b, (%rax)
jne 0x30878
movq -0x68(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
jmp 0x3087a
jmp 0x30187
movl -0x3c(%rbp), %ecx
movq -0x18(%rbp), %rax
movl %ecx, (%rax)
movl -0x3c(%rbp), %eax
movl %eax, %edi
shlq $0x2, %rdi
callq 0x4030
movq %rax, -0x78(%rbp)
movl -0x3c(%rbp), %eax
movl %eax, %edi
shlq $0x2, %rdi
callq 0x4030
movq %rax, -0x80(%rbp)
movl -0x3c(%rbp), %eax
movl %eax, %edi
shlq $0x3, %rdi
callq 0x4310
movq %rax, -0x88(%rbp)
movl -0x3c(%rbp), %eax
movq %rsp, %rcx
movq %rcx, -0x90(%rbp)
leaq 0xf(,%rax,4), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0x2d8(%rbp)
movq %rcx, %rsp
movq %rax, -0x98(%rbp)
movl -0x3c(%rbp), %eax
leaq 0xf(,%rax,4), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0x2d0(%rbp)
movq %rcx, %rsp
movq %rax, -0xa0(%rbp)
movl $0x0, -0xa4(%rbp)
callq 0x2fe60
cmpl $0x1, (%rax)
je 0x30a62
callq 0x2fe10
movq %rax, -0xb0(%rbp)
callq 0x2fe60
cmpl $0x2, (%rax)
jne 0x30998
movq -0x78(%rbp), %rax
movl -0xa4(%rbp), %ecx
movl $0xc, (%rax,%rcx,4)
movq -0xb0(%rbp), %rax
movl (%rax), %edi
callq 0xb5e0
movl %eax, %edx
movq -0x80(%rbp), %rax
movl -0xa4(%rbp), %ecx
movl %edx, (%rax,%rcx,4)
callq 0x2fe10
callq 0x2fe10
movq %rax, %rcx
movq -0x2d8(%rbp), %rax
movl 0x10(%rcx), %edx
addl $0x1, %edx
movl -0xa4(%rbp), %ecx
movl %edx, (%rax,%rcx,4)
jmp 0x309e3
movq -0xb0(%rbp), %rax
movl (%rax), %edi
callq 0xb5e0
movl %eax, %esi
movq -0x2d8(%rbp), %rax
movq -0x78(%rbp), %rcx
movl -0xa4(%rbp), %edx
movl %esi, (%rcx,%rdx,4)
movq -0x80(%rbp), %rcx
movl -0xa4(%rbp), %edx
movl $0x11, (%rcx,%rdx,4)
movq -0xb0(%rbp), %rcx
movl 0x10(%rcx), %edx
addl $0x1, %edx
movl -0xa4(%rbp), %ecx
movl %edx, (%rax,%rcx,4)
callq 0x2fe10
movq %rax, -0xb8(%rbp)
movq -0xb8(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rdi
callq 0x2fb10
movq %rax, %rsi
movq -0x2d0(%rbp), %rax
movq -0x88(%rbp), %rcx
movl -0xa4(%rbp), %edx
movq %rsi, (%rcx,%rdx,8)
movq -0xb8(%rbp), %rcx
movl 0x10(%rcx), %edx
addl $0x1, %edx
movl -0xa4(%rbp), %ecx
movl %edx, (%rax,%rcx,4)
movl -0xa4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa4(%rbp)
movl -0xa4(%rbp), %eax
cmpl -0x3c(%rbp), %eax
jae 0x30a5d
callq 0x2fe10
jmp 0x30921
callq 0x2fe10
movq %rax, -0x20(%rbp)
movq -0x78(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x80(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x88(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x18(%rax)
callq 0x2fe10
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
cmpl $0x2d, (%rax)
je 0x30c36
movq -0xc8(%rbp), %rax
cmpl $0x4e, 0x10(%rax)
jne 0x30acd
movq -0x20(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x2dc(%rbp)
jmp 0x30ae0
movq -0xc8(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x2dc(%rbp)
movl -0x2dc(%rbp), %eax
movl %eax, -0xcc(%rbp)
movq -0xc8(%rbp), %rax
cmpl $0x4e, 0x10(%rax)
jne 0x30b94
movl $0x28, %edi
callq 0x4130
movq %rax, -0x2f8(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x2f0(%rbp)
movl -0xcc(%rbp), %esi
movl %esi, -0x2ec(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x2e8(%rbp)
jmp 0x30b35
movq -0x2e8(%rbp), %rcx
movl -0x2ec(%rbp), %edx
movl -0x2f0(%rbp), %esi
movq -0x2f8(%rbp), %rdi
leaq 0x13c48(%rip), %r8      # 0x4479e
callq 0x3a230
jmp 0x30b5d
movq -0x2f8(%rbp), %rdi
leaq 0x22b3d(%rip), %rsi     # 0x536a8
leaq -0x29c02(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x2f8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x310(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x308(%rbp)
movl -0xcc(%rbp), %esi
movl %esi, -0x304(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x300(%rbp)
jmp 0x30bcc
movq -0x300(%rbp), %rcx
movl -0x304(%rbp), %edx
movl -0x308(%rbp), %esi
movq -0x310(%rbp), %rdi
movq -0xc8(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x13ba6(%rip), %r9      # 0x4479e
callq 0x3a2a0
jmp 0x30bff
movq -0x310(%rbp), %rdi
leaq 0x22a9b(%rip), %rsi     # 0x536a8
leaq -0x29ca4(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x310(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
callq 0x2fe10
movq %rax, -0xd8(%rbp)
movq -0xd8(%rbp), %rax
movl (%rax), %edi
callq 0x7f00
testb $0x1, %al
jne 0x30de1
movq -0xd8(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x30c79
movq -0xc8(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x314(%rbp)
jmp 0x30c8c
movq -0xd8(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x314(%rbp)
movl -0x314(%rbp), %eax
movl %eax, -0xdc(%rbp)
movq -0xd8(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x30d3f
movl $0x28, %edi
callq 0x4130
movq %rax, -0x330(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x328(%rbp)
movl -0xdc(%rbp), %esi
movl %esi, -0x324(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x320(%rbp)
jmp 0x30ce0
movq -0x320(%rbp), %rcx
movl -0x324(%rbp), %edx
movl -0x328(%rbp), %esi
movq -0x330(%rbp), %rdi
leaq 0x13ac1(%rip), %r8      # 0x447c2
callq 0x3a230
jmp 0x30d08
movq -0x330(%rbp), %rdi
leaq 0x22992(%rip), %rsi     # 0x536a8
leaq -0x29dad(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x330(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x348(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x340(%rbp)
movl -0xdc(%rbp), %esi
movl %esi, -0x33c(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x338(%rbp)
jmp 0x30d77
movq -0x338(%rbp), %rcx
movl -0x33c(%rbp), %edx
movl -0x340(%rbp), %esi
movq -0x348(%rbp), %rdi
movq -0xd8(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x13a1f(%rip), %r9      # 0x447c2
callq 0x3a2a0
jmp 0x30daa
movq -0x348(%rbp), %rdi
leaq 0x228f0(%rip), %rsi     # 0x536a8
leaq -0x29e4f(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x348(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movq -0xd8(%rbp), %rax
movl (%rax), %edi
callq 0xb5e0
movl %eax, -0xe0(%rbp)
leaq 0x235e4(%rip), %rdi     # 0x543e0
leaq -0xe0(%rbp), %rsi
callq 0x3a310
movq -0xd8(%rbp), %rax
movl (%rax), %edi
callq 0xb5e0
movq -0x1a8(%rbp), %rsi
movl %eax, %ecx
movq -0x18(%rbp), %rax
movl %ecx, 0x28(%rax)
movl $0xd, -0xf0(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0xe8(%rbp)
movq 0x235ce(%rip), %rax     # 0x54410
movq %rax, -0x358(%rbp)
leaq -0x110(%rbp), %rdi
movq %rdi, -0x350(%rbp)
callq 0x40f0
movq -0x358(%rbp), %rdi
movq -0x350(%rbp), %rsi
movups -0xf0(%rbp), %xmm0
movaps %xmm0, -0x120(%rbp)
movl -0x120(%rbp), %edx
movq -0x118(%rbp), %rcx
callq 0x2bda0
jmp 0x30e8c
leaq -0x110(%rbp), %rdi
callq 0x4170
movq 0x23571(%rip), %rdi     # 0x54410
callq 0x2bd00
movl $0x0, -0x12c(%rbp)
movl -0x12c(%rbp), %eax
cmpl -0x3c(%rbp), %eax
jae 0x31059
movq -0x88(%rbp), %rax
movl -0x12c(%rbp), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, -0x368(%rbp)
leaq -0x151(%rbp), %rdi
movq %rdi, -0x360(%rbp)
callq 0x4430
movq -0x368(%rbp), %rsi
movq -0x360(%rbp), %rdx
leaq -0x150(%rbp), %rdi
callq 0x4350
jmp 0x30f04
leaq -0x151(%rbp), %rdi
callq 0x4290
movl $0x48, %edi
callq 0x4260
movq %rax, -0x370(%rbp)
jmp 0x30f23
movb $0x1, -0x179(%rbp)
leaq -0x178(%rbp), %rdi
leaq -0x150(%rbp), %rsi
callq 0x40f0
jmp 0x30f3f
movq -0x370(%rbp), %rdi
movq -0x2d0(%rbp), %rax
movq -0x2d8(%rbp), %r8
movq -0x78(%rbp), %rcx
movl -0x12c(%rbp), %edx
movl %edx, %esi
movl (%rcx,%rsi,4), %edx
movq 0x234a6(%rip), %rcx     # 0x54410
movl (%r8,%rsi,4), %r8d
movl (%rax,%rsi,4), %r9d
leaq -0x178(%rbp), %rsi
callq 0x2acc0
jmp 0x30f80
movq -0x370(%rbp), %rax
movb $0x0, -0x179(%rbp)
movq %rax, -0x128(%rbp)
leaq -0x178(%rbp), %rdi
callq 0x4170
leaq -0x150(%rbp), %rdi
callq 0x4170
movl -0x12c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x12c(%rbp)
jmp 0x30eae
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
leaq -0x110(%rbp), %rdi
callq 0x4170
jmp 0x312c8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
leaq -0x151(%rbp), %rdi
callq 0x4290
jmp 0x312c8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
jmp 0x31048
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
jmp 0x3102f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
leaq -0x178(%rbp), %rdi
callq 0x4170
testb $0x1, -0x179(%rbp)
jne 0x3103a
jmp 0x31046
movq -0x370(%rbp), %rdi
callq 0x4240
jmp 0x31048
leaq -0x150(%rbp), %rdi
callq 0x4170
jmp 0x312c8
callq 0x2fe10
movq %rax, -0x188(%rbp)
movq -0x188(%rbp), %rax
cmpl $0x4, (%rax)
je 0x311fe
movq -0x188(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x31096
movq -0xd8(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x374(%rbp)
jmp 0x310a9
movq -0x188(%rbp), %rax
movl 0x10(%rax), %eax
addl $0x1, %eax
movl %eax, -0x374(%rbp)
movl -0x374(%rbp), %eax
movl %eax, -0x18c(%rbp)
movq -0x188(%rbp), %rax
cmpl $0x4e, (%rax)
jne 0x3115c
movl $0x28, %edi
callq 0x4130
movq %rax, -0x390(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x388(%rbp)
movl -0x18c(%rbp), %esi
movl %esi, -0x384(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x380(%rbp)
jmp 0x310fd
movq -0x380(%rbp), %rcx
movl -0x384(%rbp), %edx
movl -0x388(%rbp), %esi
movq -0x390(%rbp), %rdi
leaq 0x136c2(%rip), %r8      # 0x447e0
callq 0x3a230
jmp 0x31125
movq -0x390(%rbp), %rdi
leaq 0x22575(%rip), %rsi     # 0x536a8
leaq -0x2a1ca(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x390(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x28, %edi
callq 0x4130
movq %rax, -0x3a8(%rbp)
movl -0x4(%rbp), %edi
movl %edi, -0x3a0(%rbp)
movl -0x18c(%rbp), %esi
movl %esi, -0x39c(%rbp)
decl %edi
decl %esi
callq 0x2feb0
movq %rax, -0x398(%rbp)
jmp 0x31194
movq -0x398(%rbp), %rcx
movl -0x39c(%rbp), %edx
movl -0x3a0(%rbp), %esi
movq -0x3a8(%rbp), %rdi
movq -0x188(%rbp), %rax
movq 0x18(%rax), %r8
leaq 0x13620(%rip), %r9      # 0x447e0
callq 0x3a2a0
jmp 0x311c7
movq -0x3a8(%rbp), %rdi
leaq 0x224d3(%rip), %rsi     # 0x536a8
leaq -0x2a26c(%rip), %rdx    # 0x6f70
callq 0x43f0
movq -0x3a8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30(%rbp)
movl %eax, -0x34(%rbp)
callq 0x41d0
jmp 0x312c8
movl $0x18, %edi
callq 0x4260
movq %rax, %rdi
movq %rdi, -0x3b0(%rbp)
xorl %esi, %esi
movl $0x18, %edx
callq 0x4160
movq -0x3b0(%rbp), %rdi
callq 0x3a340
movq -0x3b0(%rbp), %rax
movq %rax, -0x198(%rbp)
callq 0x2fe60
cmpl $0x5, (%rax)
je 0x31271
movq -0x198(%rbp), %rax
movq %rax, -0x3b8(%rbp)
callq 0x312e0
movq -0x3b8(%rbp), %rdi
movq %rax, -0x1a0(%rbp)
leaq -0x1a0(%rbp), %rsi
callq 0x3a360
jmp 0x31238
callq 0x2fe10
movq 0x23193(%rip), %rdi     # 0x54410
callq 0x2bd70
movq -0x198(%rbp), %rcx
movq -0x18(%rbp), %rax
movq %rcx, 0x20(%rax)
leaq 0x23118(%rip), %rdi     # 0x543b0
callq 0x3a390
leaq 0x23124(%rip), %rdi     # 0x543c8
callq 0x3a3c0
leaq 0x23130(%rip), %rdi     # 0x543e0
callq 0x3a3f0
movq -0x18(%rbp), %rax
movq -0x90(%rbp), %rcx
movq %rcx, %rsp
movq %rbp, %rsp
popq %rbp
retq
movq -0x30(%rbp), %rdi
callq 0x4420
nopw %cs:(%rax,%rax)