// File: exrd[P]neteruhsp/neteruhsp/main.cc
// Function: main
int main( int argc, const char* argv[] )
{
	using namespace neteruhsp;

	// オプション
	bool has_error = false;
	const char* filename = nullptr;
	bool show_script = false;
	bool show_preprocessed_script = false;
	bool show_ast = false;
	bool show_execute_code = false;
	bool show_help = false;

	// オプション解析
	for( int i=1/* 0飛ばし */; i<argc; ++i )
	{
		const auto arg = argv[i];
		if ( arg[0] == '-' )
		{
			switch( arg[1] )
			{
				case 'f':
					if ( i+1 < argc )
					{
						++i;
						filename = argv[i];
					}
					else
					{
						fprintf( stderr, "ERROR : cannot read script file path\n" );
						has_error = true;
					}
					break;
				case 's':
					show_script = true;
					break;
				case 'p':
					show_preprocessed_script = true;
					break;
				case 'a':
					show_ast = true;
					break;
				case 'e':
					show_execute_code = true;
					break;
				case 'h':
					show_help = true;
					break;
				default:
					fprintf( stderr, "ERROR : unknown argument :%s\n", arg );
					has_error = true;
					break;
			}
		}
		else
		{
			fprintf( stderr, "ERROR : cannot parse argument :%s\n", arg );
			has_error = true;
			break;
		}
	}

	if ( filename == nullptr )
	{
		fprintf( stderr, "ERROR : have to specify script file\n" );
		has_error = true;
	}

	if ( show_help || has_error )
	{
		printf(
			"neteruhsp : commandline tool options\n"
			"  <bin> [<options>...] -f <SCRIPT_FILE>\n"
			"    -f : specify file path to execute\n"
			"\n"
			"  options are followings\n"
			"    -s : show loaded script file contents\n"
			"    -p : show preprocessed script contents\n"
			"    -a : show abstract-syntax-tree constructed from loaded script\n"
			"    -e : show instruction code for execution\n"
			"    -h : show (this) help\n"
		);
		fflush( stdout );
		fflush( stderr );
		return ( has_error ? -1 : 0 );
	}

	// システムここから
	initialize_system();

	// ファイル読み込み
	size_t script_size = 0;
	char* script = nullptr;
	{
		FILE* file = fopen( filename, "r" );
		if ( file == nullptr )
		{
			printf( "ERROR : cannot read such file %s\n", filename );
			return -1;
		}

		fseek( file, 0, SEEK_END );
		const size_t initial_size = ftell( file );

		size_t buffer_size = initial_size +4;// 初期バッファ
		script = reinterpret_cast<char*>( xmalloc( buffer_size +1 ) );

		fseek( file, 0, SEEK_SET );

		for( ; ; )
		{
			const auto c = fgetc(file);
			if ( c == EOF )
			{ break; }

			const auto ch = static_cast<char>( c );
			if ( buffer_size <= script_size )
			{
				buffer_size *= 2;
				script = reinterpret_cast<char*>( xrealloc( script, buffer_size ) );
			}
			script[script_size++] = ch;
		}
		script[script_size] = '\0';

		fclose( file );
	}
	assert( script != nullptr );

	if ( show_script )
	{
		printf( "====LOADED SCRIPT FILE(%d bytes)\n----begin----\n%s\n----end----\n", static_cast<int>( script_size ), script );
	}

	// 実行
	{
		{
			auto env =create_execute_environment();

			load_arg_t la;
			la.dump_preprocessed_ = show_preprocessed_script;
			la.dump_ast_ = show_ast;
			load_script( env, script, &la );

			if ( show_execute_code )
			{
				printf( "====Instruction Code for execution\n" );
				dump_code( env->execute_code_ );
			}

			execute( env );
			destroy_execute_environment( env );
		}

		printf(
			"====\n"
			">>Execution finished, press ENTER key to exit\n"
		);
		fflush( stdout );
		getchar();
	}

	xfree( script );
	uninitialize_system();

	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movb $0x0, -0x11(%rbp)
movq $0x0, -0x20(%rbp)
movb $0x0, -0x21(%rbp)
movb $0x0, -0x22(%rbp)
movb $0x0, -0x23(%rbp)
movb $0x0, -0x24(%rbp)
movb $0x0, -0x25(%rbp)
movl $0x1, -0x2c(%rbp)
movl -0x2c(%rbp), %eax
cmpl -0x8(%rbp), %eax
jge 0x34ec
movq -0x10(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x2d, %eax
jne 0x34ba
movq -0x38(%rbp), %rax
movsbl 0x1(%rax), %eax
addl $-0x61, %eax
movl %eax, %ecx
movq %rcx, -0x80(%rbp)
subl $0x12, %eax
ja 0x3498
movq -0x80(%rbp), %rax
leaq 0xebd7(%rip), %rcx      # 0x12004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl -0x2c(%rbp), %eax
addl $0x1, %eax
cmpl -0x8(%rbp), %eax
jge 0x345c
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
movq -0x10(%rbp), %rax
movslq -0x2c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x20(%rbp)
jmp 0x3478
movq 0x18b7d(%rip), %rax     # 0x1bfe0
movq (%rax), %rdi
leaq 0xebe3(%rip), %rsi      # 0x12050
movb $0x0, %al
callq 0x3220
movb $0x1, -0x11(%rbp)
jmp 0x34b8
movb $0x1, -0x21(%rbp)
jmp 0x34b8
movb $0x1, -0x22(%rbp)
jmp 0x34b8
movb $0x1, -0x23(%rbp)
jmp 0x34b8
movb $0x1, -0x24(%rbp)
jmp 0x34b8
movb $0x1, -0x25(%rbp)
jmp 0x34b8
movq 0x18b41(%rip), %rax     # 0x1bfe0
movq (%rax), %rdi
movq -0x38(%rbp), %rdx
leaq 0xebc9(%rip), %rsi      # 0x12076
movb $0x0, %al
callq 0x3220
movb $0x1, -0x11(%rbp)
jmp 0x34dc
movq 0x18b1f(%rip), %rax     # 0x1bfe0
movq (%rax), %rdi
movq -0x38(%rbp), %rdx
leaq 0xebc5(%rip), %rsi      # 0x12094
movb $0x0, %al
callq 0x3220
movb $0x1, -0x11(%rbp)
jmp 0x34ec
jmp 0x34de
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x33e0
cmpq $0x0, -0x20(%rbp)
jne 0x350f
movq 0x18ae6(%rip), %rax     # 0x1bfe0
movq (%rax), %rdi
leaq 0xebb3(%rip), %rsi      # 0x120b7
movb $0x0, %al
callq 0x3220
movb $0x1, -0x11(%rbp)
testb $0x1, -0x25(%rbp)
jne 0x351b
testb $0x1, -0x11(%rbp)
je 0x355f
leaq 0xebba(%rip), %rdi      # 0x120dc
movb $0x0, %al
callq 0x3050
movq 0x18a90(%rip), %rax     # 0x1bfc0
movq (%rax), %rdi
callq 0x3180
movq 0x18aa1(%rip), %rax     # 0x1bfe0
movq (%rax), %rdi
callq 0x3180
movb -0x11(%rbp), %dl
xorl %eax, %eax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
testb $0x1, %dl
cmovnel %ecx, %eax
movl %eax, -0x4(%rbp)
jmp 0x3744
callq 0x3750
movq $0x0, -0x40(%rbp)
movq $0x0, -0x48(%rbp)
movq -0x20(%rbp), %rdi
leaq 0xf76c(%rip), %rsi      # 0x12ceb
callq 0x3190
movq %rax, -0x50(%rbp)
cmpq $0x0, -0x50(%rbp)
jne 0x35ad
movq -0x20(%rbp), %rsi
leaq 0xecae(%rip), %rdi      # 0x12248
movb $0x0, %al
callq 0x3050
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x3744
movq -0x50(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x2, %edx
callq 0x3170
movq -0x50(%rbp), %rdi
callq 0x3030
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rdi
addq $0x1, %rdi
callq 0x3800
movq %rax, -0x48(%rbp)
movq -0x50(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x3170
movq -0x50(%rbp), %rdi
callq 0x3240
movl %eax, -0x64(%rbp)
cmpl $-0x1, -0x64(%rbp)
jne 0x360c
jmp 0x3653
movl -0x64(%rbp), %eax
movb %al, -0x65(%rbp)
movq -0x60(%rbp), %rax
cmpq -0x40(%rbp), %rax
ja 0x3638
movq -0x60(%rbp), %rax
shlq %rax
movq %rax, -0x60(%rbp)
movq -0x48(%rbp), %rdi
movq -0x60(%rbp), %rsi
callq 0x3960
movq %rax, -0x48(%rbp)
movb -0x65(%rbp), %dl
movq -0x48(%rbp), %rax
movq -0x40(%rbp), %rcx
movq %rcx, %rsi
addq $0x1, %rsi
movq %rsi, -0x40(%rbp)
movb %dl, (%rax,%rcx)
jmp 0x35f8
movq -0x48(%rbp), %rax
movq -0x40(%rbp), %rcx
movb $0x0, (%rax,%rcx)
movq -0x50(%rbp), %rdi
callq 0x3160
cmpq $0x0, -0x48(%rbp)
je 0x3671
jmp 0x3690
leaq 0xebf2(%rip), %rdi      # 0x1226a
leaq 0xebfd(%rip), %rsi      # 0x1227c
movl $0x88, %edx
leaq 0xec03(%rip), %rcx      # 0x1228e
callq 0x30f0
testb $0x1, -0x21(%rbp)
je 0x36ae
movq -0x40(%rbp), %rax
movl %eax, %esi
movq -0x48(%rbp), %rdx
leaq 0xec04(%rip), %rdi      # 0x122ab
movb $0x0, %al
callq 0x3050
callq 0xbe50
movq %rax, -0x70(%rbp)
movb -0x22(%rbp), %al
andb $0x1, %al
movb %al, -0x72(%rbp)
movb -0x23(%rbp), %al
andb $0x1, %al
movb %al, -0x71(%rbp)
movq -0x70(%rbp), %rdi
movq -0x48(%rbp), %rsi
leaq -0x72(%rbp), %rdx
callq 0xc120
testb $0x1, -0x24(%rbp)
je 0x36f9
leaq 0xec05(%rip), %rdi      # 0x122ea
movb $0x0, %al
callq 0x3050
movq -0x70(%rbp), %rax
movq 0x20(%rax), %rdi
callq 0x10db0
movq -0x70(%rbp), %rdi
xorl %esi, %esi
callq 0xd740
movq -0x70(%rbp), %rdi
callq 0xbec0
leaq 0xebfa(%rip), %rdi      # 0x1230e
movb $0x0, %al
callq 0x3050
movq 0x1889e(%rip), %rax     # 0x1bfc0
movq (%rax), %rdi
callq 0x3180
callq 0x3200
movq -0x48(%rbp), %rdi
callq 0x3900
callq 0x3830
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x80, %rsp
popq %rbp
retq