#include "stdafx.h"

#include <Compiler.h>

#include "../BasicCompiler_Common/common.h"
#include "Opcode.h"

void OpcodeOthers(const char *Command){
	int i,i2;

	char leftTerm[8192];
	int lastParePos = 0;
	for(i=0;;i++){
		if(Command[i]=='\"'){
			//ダブルクォートは不正なのでエラー扱い
			leftTerm[i]=0;
			compiler.errorMessenger.Output(3,leftTerm,cp);
			return;
		}

		if(Command[i]=='('){
			lastParePos = i;
			i2=GetStringInPare(leftTerm+i,Command+i);
			i+=i2-1;
			continue;
		}
		if(Command[i]=='['){
			i2=GetStringInBracket(leftTerm+i,Command+i);
			i+=i2-1;
			continue;
		}
		if(Command[i]=='\0'){
			leftTerm[i] = 0;
			break;
		}

		if( IsNumCalcMark( Command, i ) ){
			leftTerm[i] = 0;
			break;
		}

		leftTerm[i]=Command[i];
	}
	if(!(
		IsVariableTopChar(leftTerm[0])||
		leftTerm[0]=='.'||
		(leftTerm[0]==1&&leftTerm[1]==ESC_PSMEM)
		)){
		compiler.errorMessenger.Output(1,NULL,cp);
		return;
	}


	if(Command[i]=='\0' && lastParePos == 0){
		//////////////////////////////
		// パラメータ無しのマクロ検索
		//////////////////////////////

		const UserProc *pUserProc=GetSubHash(Command);

		//GetSubHash内でエラー提示が行われた場合
		if(pUserProc==(UserProc *)-1) return;

		if(pUserProc==0){
			char temporary[VN_SIZE];
			lstrcpy(temporary,Command);

			CharUpper(temporary);
			pUserProc=GetSubHash(temporary);

			//GetSubHash内でエラー提示が行われた場合
			if(pUserProc==(UserProc *)-1) return;
		}

		if(pUserProc){
			if( !pUserProc->IsMacro() ){
				compiler.errorMessenger.Output(10,Command,cp);
			}

			Opcode_CallProc("",pUserProc,0,"");

			return;
		}
	}
	else if(IsNumCalcMark(Command,i)){
		//代入演算
		OpcodeCalc(Command);
		return;
	}

	if( pobj_reg ){
		compiler.errorMessenger.OutputFatalError();
	}
	pobj_reg=new CRegister(REG_RAX);

	Type resultType;
	bool isLiteral, isNeedHeapFreeStructure = false;
	bool result = TermOpe( leftTerm, Type(), resultType, isLiteral, isNeedHeapFreeStructure, NULL, true );

	delete pobj_reg;
	pobj_reg = NULL;

	if( result ){

		/////////////////////
		// 戻り値の処理
		/////////////////////

		if( resultType.IsStruct() ){
			//mov r14,rax
			compiler.codeGenerator.op_mov_RR(REG_R14,REG_RAX);

			FreeTempObject(REG_R14,&resultType.GetClass());
		}

		return;
	}

	// どこにも当てはまらなかったため、失敗
	compiler.errorMessenger.Output(1,NULL,cp);
}

void Judgment(char *buffer){
	int reg=REG_RAX;
	Type resultType;
	if( !NumOpe(&reg,buffer,Type(DEF_BOOLEAN),resultType) ){
		return;
	}

	int offset;

	if(resultType.IsDouble()){
		double dbl=0;
		offset=compiler.GetObjectModule().dataTable.Add( dbl );

		//comisd xmm0,qword ptr[data table offset]
		compiler.codeGenerator.PutOld(
			(char)0x66,
			(char)0x0F,
			(char)0x2F,
			(char)0x04,
			(char)0x25
		);
		compiler.codeGenerator.PutOld(
			(long)offset,
			Schedule::DataTable
		);
	}
	else if(resultType.IsSingle()){
		float flt=0;
		offset=compiler.GetObjectModule().dataTable.Add( flt );

		//comiss xmm0,dword ptr[data table offset]
		compiler.codeGenerator.PutOld(
			(char)0x0F,
			(char)0x2F,
			(char)0x04,
			(char)0x25
		);
		compiler.codeGenerator.PutOld(
			(long)offset,
			Schedule::DataTable
		);
	}
	else{
		//整数型

		//cmp rax,0
		compiler.codeGenerator.op_cmp_value(resultType.GetSize(),REG_RAX,0);
	}
}

void OpcodeIf(char *Parameter){
	for(int i=0;;i++){
		if(Parameter[i]=='\0'){
			compiler.errorMessenger.Output(21,NULL,cp);
			return;
		}
		if(Parameter[i]==1&&Parameter[i+1]==ESC_THEN){
			Parameter[i]=0;
			break;
		}
	}

	//条件式を実行してフラグをセット
	Judgment(Parameter);

	//je (endif、または else まで条件ジャンプ)
	const PertialSchedule *pIfPertialSchedule = compiler.codeGenerator.op_je( 0, sizeof(long), true );


	/////////////////////////
	// If内をコード化
	/////////////////////////

	//レキシカルスコープをレベルアップ
	compiler.codeGenerator.lexicalScopes.Start(
		compiler.codeGenerator.GetNativeCodeSize(),
		LexicalScope::SCOPE_TYPE_IF
	);

	int i2=CompileBuffer(ESC_ENDIF,0);

	//レキシカルスコープをレベルダウン
	compiler.codeGenerator.lexicalScopes.End();


	if(i2==ESC_ELSE){
		//jmp (endifまで)
		const PertialSchedule *pTempPertialSchedule = compiler.codeGenerator.op_jmp( 0, sizeof(long), true );

		compiler.codeGenerator.opfix_JmpPertialSchedule( pIfPertialSchedule );



		/////////////////////////
		// Else内をコード化
		/////////////////////////

		//レキシカルスコープをレベルアップ
		compiler.codeGenerator.lexicalScopes.Start(
			compiler.codeGenerator.GetNativeCodeSize(),
			LexicalScope::SCOPE_TYPE_IF
		);

		CompileBuffer(ESC_ENDIF,0);

		//レキシカルスコープをレベルダウン
		compiler.codeGenerator.lexicalScopes.End();


		compiler.codeGenerator.opfix_JmpPertialSchedule( pTempPertialSchedule );
	}
	else{
		compiler.codeGenerator.opfix_JmpPertialSchedule( pIfPertialSchedule );
	}
}

int GetLabelAddress(char *LabelName,int LineNum){
	if(LabelName){
		BOOST_FOREACH( const GotoLabel &label, compiler.codeGenerator.gotoLabels )
		{
			if( label.name.size() > 0 )
			{
				if( label.name == LabelName )
				{
					return label.address;
				}
			}
		}
	}
	else{
		BOOST_FOREACH( const GotoLabel &label, compiler.codeGenerator.gotoLabels )
		{
			if( label.name.size() == 0 )
			{
				if( label.line == LineNum )
				{
					return label.address;
				}
			}
		}
	}
	return -1;
}
void OpcodeGoto(char *Parameter){
	extern HANDLE hHeap;
	int i,LineNum;

	if(Parameter[0]=='*'){
		i=GetLabelAddress(Parameter+1,0);

		if( i == -1 )
		{
			//jmp ...(schedule)
			compiler.codeGenerator.op_jmp_goto_schedule( (const std::string)(Parameter + 1), 0, cp );
		}
		else
		{
			//jmp ...
			compiler.codeGenerator.op_jmp(
				i-compiler.codeGenerator.GetNativeCodeSize(),
				sizeof(long),
				false,
				true
			);
		}
	}
	else{
		LineNum=atoi(Parameter);
		i=GetLabelAddress(0,LineNum);

		if( i == -1 )
		{
			//jmp ...(schedule)
			compiler.codeGenerator.op_jmp_goto_schedule( "", LineNum, cp );
		}
		else
		{
			//jmp ...
			compiler.codeGenerator.op_jmp(
				i-compiler.codeGenerator.GetNativeCodeSize(),
				sizeof(long),
				false,
				true
			);
		}
	}
}
void OpcodeWhile(char *Parameter){
	extern HANDLE hHeap;

	//Continueアドレスのバックアップとセット
	compiler.codeGenerator.ContinueAreaBegin();

	if(!Parameter[0]) compiler.errorMessenger.Output(10,"While",cp);

	//条件式を実行してフラグをセット
	Judgment(Parameter);

	//je (Wend まで)
	const PertialSchedule *pWhilePertialSchedule = compiler.codeGenerator.op_je( 0, sizeof(long), true );

	//レキシカルスコープをレベルアップ
	compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_TYPE_WHILE );

	//While内をコンパイル
	CompileBuffer(0,COM_WEND);

	compiler.codeGenerator.lexicalScopes.CallDestructorsOfScopeEnd();

	//jmp ...
	compiler.codeGenerator.op_jmp_continue();

	//レキシカルスコープをレベルダウン
	compiler.codeGenerator.lexicalScopes.End();

	compiler.codeGenerator.opfix_JmpPertialSchedule( pWhilePertialSchedule );

	//Continueアドレスを復元
	compiler.codeGenerator.ContinueAreaEnd();
}

char szNextVariable[VN_SIZE];
void OpcodeFor(char *Parameter){
	extern HANDLE hHeap;
	Type resultType;
	int i,i2;
	char temporary[VN_SIZE],variable[VN_SIZE],JudgeNum[VN_SIZE],StepNum[VN_SIZE];
	bool isError = false;

	//第１パラメータを取得
	i=GetOneParameter(Parameter,0,temporary);
	if(!Parameter[i]){
		compiler.errorMessenger.Output(12,"For",cp);
		isError = true;
		goto ErrorStep;
	}

	for(i2=0;;i2++){
		if(temporary[i2]=='='){
			variable[i2]=0;

			//カウンタ初期化
			OpcodeCalc(temporary);
			break;
		}
		if(temporary[i2]=='\0'){
			compiler.errorMessenger.Output(12,"For",cp);
			isError = true;
			goto ErrorStep;
		}
		variable[i2]=temporary[i2];
	}

	//jmp ...
	const PertialSchedule *pTempPertialSchedule = compiler.codeGenerator.op_jmp( 0, sizeof(long), true );

	//Continueアドレスのバックアップとセット
	compiler.codeGenerator.ContinueAreaBegin();

	//第２パラメータを取得（to〜）
	i=GetOneParameter(Parameter,i,JudgeNum);

	//第３パラメータを取得（step〜）
	if(Parameter[i]){
		i=GetOneParameter(Parameter,i,StepNum);
		if(Parameter[i]) compiler.errorMessenger.Output(12,"For",cp);
	}
	else lstrcpy(StepNum,"1");

	//カウンタを増加させる
	sprintf(temporary,"%s=(%s)+(%s)",variable,variable,StepNum);
	OpcodeCalc(temporary);

	compiler.codeGenerator.opfix_JmpPertialSchedule( pTempPertialSchedule );

	//増加か減少かを区別する
	sprintf(temporary,"(%s)>=0",StepNum);

	int reg;
	reg=REG_RAX;
	if( !NumOpe(&reg,temporary,Type(),resultType) ){
		return;
	}

	//cmp rax,0
	compiler.codeGenerator.op_cmp_value(resultType.GetSize(),REG_RAX,0);

	//je [カウンタ減少の場合の判定]
	pTempPertialSchedule = compiler.codeGenerator.op_je( 0, sizeof(long), true );

	//判定（カウンタ増加の場合）
	sprintf(temporary,"%s<=(%s)",variable,JudgeNum);

	reg=REG_RAX;
	NumOpe(&reg,temporary,Type(),Type());

	//jmp [カウンタ減少の場合の判定を飛び越す]
	const PertialSchedule *pTempPertialSchedule2 = compiler.codeGenerator.op_jmp( 0, sizeof(long), true );

	//jeジャンプ先のオフセット値
	compiler.codeGenerator.opfix_JmpPertialSchedule( pTempPertialSchedule );

	//判定（カウンタ減少の場合）
	sprintf(temporary,"%s>=(%s)",variable,JudgeNum);

	reg=REG_RAX;
	NumOpe(&reg,temporary,Type(),resultType);

	//jmpジャンプ先のオフセット値
	compiler.codeGenerator.opfix_JmpPertialSchedule( pTempPertialSchedule2 );

	//cmp rax,0
	compiler.codeGenerator.op_cmp_value(resultType.GetSize(),REG_RAX,0);

ErrorStep:

	//je ...
	pTempPertialSchedule = compiler.codeGenerator.op_je( 0, sizeof(long), true );

	//レキシカルスコープをレベルアップ
	compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_TYPE_FOR );

	//For内をコンパイル
	CompileBuffer(0,COM_NEXT);

	compiler.codeGenerator.lexicalScopes.CallDestructorsOfScopeEnd();

	if(szNextVariable[0]){
		if(lstrcmp(szNextVariable,variable)!=0){
			compiler.errorMessenger.Output(55,szNextVariable,cp);
		}
	}

	//jmp ...
	compiler.codeGenerator.op_jmp_continue();

	//レキシカルスコープをレベルダウン
	compiler.codeGenerator.lexicalScopes.End();

	//jeジャンプ先のオフセット値
	compiler.codeGenerator.opfix_JmpPertialSchedule( pTempPertialSchedule );

	//Continueアドレスを復元
	compiler.codeGenerator.ContinueAreaEnd();
}

void OpcodeForeach( const char *Parameter )
{
	Type resultType;
	char temporary[VN_SIZE],variable[VN_SIZE],collectionVar[VN_SIZE];
	bool isError = false;

	//レキシカルスコープをレベルアップ
	compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_TYPE_FOR );

	//第１パラメータを取得
	int i = 0;
	GetCustomToken( variable, Parameter, i, ESC_IN, true );
	if(!Parameter[i]){
		compiler.errorMessenger.Output(12,"Foreach",cp);
		isError = true;
		goto ErrorStep;
	}
	i++;

	//第２パラメータを取得（in〜）
	lstrcpy( collectionVar, Parameter + i );

	if( !GetVarType( variable, resultType, false ) )
	{
		Type collectionType;
		if( !NumOpe_GetType( collectionVar, Type(), collectionType ) )
		{
			isError = true;
			goto ErrorStep;
		}

		// 未定義の場合は自動的に定義する
		sprintf(temporary,"%s=Nothing%c%c%s", variable, 1, ESC_AS, collectionType.GetActualGenericType(0).GetClass().GetFullName().c_str() );
		OpcodeDim(temporary,DIMFLAG_INITDEBUGVAR);
	}

	// Resetメソッドを呼び出す
	sprintf( temporary, "%s.Reset()", collectionVar );
	Compile( temporary );

	//Continueアドレスのバックアップとセット
	compiler.codeGenerator.ContinueAreaBegin();

	// MoveNextメソッドを呼び出す
	sprintf( temporary, "%s.MoveNext()", collectionVar );
	int reg = REG_RAX;
	NumOpe(&reg,temporary,Type(),resultType);

	//cmp rax,0
	compiler.codeGenerator.op_cmp_value(resultType.GetSize(),REG_RAX,0);

ErrorStep:

	//je ...
	const PertialSchedule *pTempPertialSchedule = compiler.codeGenerator.op_je( 0, sizeof(long), true );

	if( !isError )
	{
		// Currentプロパティから現在の値を取得
		sprintf( temporary, "%s=%s.Current", variable, collectionVar );
		Compile( temporary );
	}

	//For内をコンパイル
	CompileBuffer(0,COM_NEXT);

	compiler.codeGenerator.lexicalScopes.CallDestructorsOfScopeEnd();

	if(szNextVariable[0]){
		if(lstrcmp(szNextVariable,variable)!=0){
			compiler.errorMessenger.Output(55,szNextVariable,cp);
		}
	}

	if( !isError )
	{
		//jmp ...
		compiler.codeGenerator.op_jmp_continue();
	}

	//レキシカルスコープをレベルダウン
	compiler.codeGenerator.lexicalScopes.End();

	//jeジャンプ先のオフセット値
	compiler.codeGenerator.opfix_JmpPertialSchedule( pTempPertialSchedule );

	//Continueアドレスを復元
	compiler.codeGenerator.ContinueAreaEnd();
}

void OpcodeDo(char *Parameter){
	extern HANDLE hHeap;
	int i,i2,i3;

	if(Parameter[0]) compiler.errorMessenger.Output(10,"Do",cp);

	//Continueアドレスのバックアップとセット
	compiler.codeGenerator.ContinueAreaBegin();

	//レキシカルスコープをレベルアップ
	compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_TYPE_DO );

	//Do内をコンパイル
	CompileBuffer(0,COM_LOOP);

	compiler.codeGenerator.lexicalScopes.CallDestructorsOfScopeEnd();

	const PertialSchedule *pDoPertialSchedule = NULL;

	extern char *basbuf;
	char temporary[VN_SIZE];
	for(i=cp-1;;i--){
		if(IsCommandDelimitation(basbuf[i])){
			i+=3;
			if(!(basbuf[i]=='0'||basbuf[i]=='1')){
				//無条件ループ
				break;
			}
			i3=i;

			for(i+=2,i2=0;;i++,i2++){
				if(IsCommandDelimitation(basbuf[i])){
					temporary[i2]=0;
					break;
				}
				temporary[i2]=basbuf[i];
			}

			//条件式を実行してフラグをセット
			Judgment(temporary);

			if(basbuf[i3]=='0'){
				//While

				//je 5（ループ終了）
				pDoPertialSchedule = compiler.codeGenerator.op_je( 0, sizeof(char), true );
			}
			else if(basbuf[i3]=='1'){
				//Until

				//jne 5（ループ終了）
				pDoPertialSchedule = compiler.codeGenerator.op_jne( 0, sizeof(char), true );
			}
			break;
		}
	}

	//jmp ...
	compiler.codeGenerator.op_jmp_continue();

	if( pDoPertialSchedule )
	{
		compiler.codeGenerator.opfix_JmpPertialSchedule( pDoPertialSchedule );
	}

	//jmp ...
	const PertialSchedule *pTempPertialSchedule = compiler.codeGenerator.op_jmp( 0, sizeof(long), true );

	//レキシカルスコープをレベルダウン
	compiler.codeGenerator.lexicalScopes.End();

	//jmpジャンプ先のオフセット値
	compiler.codeGenerator.opfix_JmpPertialSchedule( pTempPertialSchedule );

	//Continueアドレスを復元
	compiler.codeGenerator.ContinueAreaEnd();
}
void OpcodeContinue(void){
	//jmp ...(Continue addr)
	compiler.codeGenerator.op_jmp_continue();
}

void OpcodeExitSub(void){
	if( compiler.IsGlobalAreaCompiling() ){
		compiler.errorMessenger.Output(12,"Exit Sub/Function",cp);
		return;
	}

	//未解放のローカルオブジェクトのデストラクタを呼び出す
	compiler.codeGenerator.lexicalScopes.CallDestructorsOfReturn();

	//jmp ...(End Sub/Function)
	compiler.codeGenerator.op_jmp_exitsub();
}

//Caseスケジュール
class SelectSchedule
{
public:
	SelectSchedule( int typeSize )
		: typeSize( typeSize )
		, nowCaseSchedule( 0 )
	{
	}

	PertialSchedules casePertialSchedules;
	int typeSize;
	int nowCaseSchedule;
};
std::vector<SelectSchedule> selectSchedules;

void OpcodeSelect( const char *lpszParms )
{
	extern HANDLE hHeap;
	extern char *basbuf;
	int i,i2,i3,NowCaseCp;
	char temporary[VN_SIZE];
	
	int reg1=REG_RAX;
	Type type1;
	bool result = NumOpe(&reg1,lpszParms,Type(), type1 );

	selectSchedules.push_back( SelectSchedule( type1.GetSize() ) );

	if( result )
	{
		if( selectSchedules.back().typeSize < sizeof(long) ){
			selectSchedules.back().typeSize = sizeof(long);
		}

		if(type1.IsDouble()){
			//movsd qword ptr[rsp+offset],xmm_reg		※スタックフレームを利用
			pobj_sf->push(reg1,sizeof(double));
		}
		else if(type1.IsSingle()){
			//movss dword ptr[rsp+offset],xmm_reg		※スタックフレームを利用
			pobj_sf->push(reg1,sizeof(float));
		}
		else{
			ExtendTypeTo64(type1.GetBasicType(),reg1);

			//mov qword ptr[rsp+offset],reg     ※スタックフレームを利用
			pobj_sf->push(reg1);
		}

		for(i=cp;;i++){
			if(basbuf[i]=='\0'){
				selectSchedules.pop_back();
				compiler.errorMessenger.Output(22,"Select",cp);
				return;
			}
			if(basbuf[i]==1&&basbuf[i+1]==ESC_SELECTCASE){
				for(i2=0;;i++){
					if(basbuf[i]==1&&basbuf[i+1]==ESC_SELECTCASE) i2++;
					if(basbuf[i]==1&&basbuf[i+1]==ESC_ENDSELECT){
						i2--;
						if(i2==0) break;
					}
				}
				continue;
			}
			if(basbuf[i]==1&&basbuf[i+1]==ESC_ENDSELECT) break;

			if(basbuf[i]==1&&basbuf[i+1]==ESC_CASE){
				NowCaseCp=i;

				i++;
				while(1){
					for(i++,i2=0;;i++,i2++){
						if(basbuf[i]=='\"'){
							i3=GetStringInQuotation(temporary+i2,basbuf+i);
							i+=i3-1;
							i2+=i3-1;
							continue;
						}
						if(basbuf[i]=='('){
							i3=GetStringInPare(temporary+i2,basbuf+i);
							i+=i3-1;
							i2+=i3-1;
							continue;
						}
						if(basbuf[i]=='['){
							i3=GetStringInBracket(temporary+i2,basbuf+i);
							i+=i3-1;
							i2+=i3-1;
							continue;
						}

						if(IsCommandDelimitation(basbuf[i])){
							temporary[i2]=0;
							break;
						}
						if(basbuf[i]==','){
							temporary[i2]=0;
							break;
						}

						temporary[i2]=basbuf[i];
					}

					//エラー用
					i2=cp;
					cp=NowCaseCp;

					int reg2=REG_RDX;
					Type type2;
					if( !NumOpe(&reg2,temporary,type1,type2) ){
						return;
					}

					cp=i2;

					if(type1.IsObject()){
						std::vector<const UserProc *> subs;
						type1.GetClass().GetDynamicMethods().Enum( CALC_EQUAL, subs );
						if( subs.size() == 0 ){
							return;
						}

						Parameters params;
						params.push_back( new Parameter( "", Type( type2 ) ) );

						//オーバーロードを解決
						const UserProc *pUserProc = OverloadSolution( "==", subs, params, Type( DEF_BOOLEAN ), type1 );

						delete params[0];

						if(!pUserProc){
							//エラー
							return;
						}


						//実体オブジェクト
						if(reg2!=REG_RDX){
							//mov rdx,reg2
							compiler.codeGenerator.op_mov_RR(REG_RDX,reg2);
						}

						//mov rcx,qword ptr[rsp+offset]		※スタックフレームから参照
						pobj_sf->ref(REG_RCX);

						//call operator_proc	※ ==演算子
						compiler.codeGenerator.op_call(pUserProc);

						//test rax,rax
						compiler.codeGenerator.op_test(REG_RAX,REG_RAX);

						//jne ...
						selectSchedules.back().casePertialSchedules.push_back(
							compiler.codeGenerator.op_jne( 0, sizeof(long), true )
						);
					}
					else{
						if(type1.IsDouble()){
							int xmm_reg;
							if(IsXmmReg(reg2)) xmm_reg=reg2;
							else xmm_reg=REG_XMM5;
							ChangeTypeToXmm_Double(type2.GetBasicType(),xmm_reg,reg2);

							//movsd xmm4,qword ptr[rsp+offset]	※スタックフレームから参照
							pobj_sf->ref(REG_XMM4,sizeof(double));

							//comiss xmm_reg1,xmm_reg2
							compiler.codeGenerator.op_comisd(xmm_reg,REG_XMM4);
						}
						else if(type1.IsSingle()){
							int xmm_reg;
							if(IsXmmReg(reg2)) xmm_reg=reg2;
							else xmm_reg=REG_XMM5;
							ChangeTypeToXmm_Single(type2.GetBasicType(),xmm_reg,reg2);

							//movss xmm4,dword ptr[rsp+offset]	※スタックフレームから参照
							pobj_sf->ref(REG_XMM4,sizeof(float));

							//comiss xmm_reg1,xmm_reg2
							compiler.codeGenerator.op_comiss(xmm_reg,REG_XMM4);
						}
						else{
							//その他整数型

							i2=NeutralizationType(type1.GetBasicType(),-1,type2.GetBasicType(),-1);

							//mov r14,qword ptr[rsp+offset]		※スタックフレームから参照
							pobj_sf->ref(REG_R14);

							//cmp reg2,r14
							compiler.codeGenerator.op_cmp_reg(Type(i2).GetSize(),reg2,REG_R14);
						}

						//je ...
						selectSchedules.back().casePertialSchedules.push_back(
							compiler.codeGenerator.op_je( 0, sizeof(long), true )
						);
					}

					if(basbuf[i]!=',') break;
				}
			}
			if(basbuf[i]==1&&basbuf[i+1]==ESC_CASEELSE){
				//jmp ...
				selectSchedules.back().casePertialSchedules.push_back(
					compiler.codeGenerator.op_jmp( 0, sizeof(long), true )
				);
			}
		}

		//スタックフレームを1スペースだけ解除
		pobj_sf->pop(REG_NON);
	}

	//レキシカルスコープをレベルアップ
	compiler.codeGenerator.lexicalScopes.Start( compiler.codeGenerator.GetNativeCodeSize(), LexicalScope::SCOPE_TYPE_SELECT );

	//Select Case内をコンパイル
	CompileBuffer(ESC_ENDSELECT,0);

	//jmp EndSelect
	selectSchedules.back().casePertialSchedules.push_back(
		compiler.codeGenerator.op_jmp( 0, sizeof(long), true )
	);

	//最終スケジュール
	for(i=selectSchedules.back().nowCaseSchedule;i<(int)selectSchedules.back().casePertialSchedules.size();i++){
		compiler.codeGenerator.opfix_JmpPertialSchedule( selectSchedules.back().casePertialSchedules[i] );
	}

	//レキシカルスコープをレベルダウン
	compiler.codeGenerator.lexicalScopes.End();

	selectSchedules.pop_back();
}
void OpcodeCase(char *Parameter){
	int i;

	if(selectSchedules.back().typeSize==-1){
		compiler.errorMessenger.Output(30,"Case",cp);
		return;
	}

	//jmp EndSelect
	selectSchedules.back().casePertialSchedules.push_back(
		compiler.codeGenerator.op_jmp( 0, sizeof(long), true )
	);

	i=0;
	while(1){
		//Caseスケジュール
		compiler.codeGenerator.opfix_JmpPertialSchedule( selectSchedules.back().casePertialSchedules[selectSchedules.back().nowCaseSchedule] );
		selectSchedules.back().nowCaseSchedule++;

		i=JumpOneParameter(Parameter,i);
		if(Parameter[i]=='\0') break;
	}
}

void OpcodeGosub(char *Parameter){
	compiler.errorMessenger.Output(-1,"Gosub 〜 Returnステートメントは64ビットコンパイラで利用することはできません。",cp);
}
void OpcodeReturn(char *Parameter){
	if( compiler.IsGlobalAreaCompiling() ){
		compiler.errorMessenger.Output(62,NULL,cp);
	}
	else{
		//戻り値をセット
		if(Parameter[0]){
			const UserProc &proc = compiler.GetCompilingUserProc();

			const char *temp = "_System_ReturnValue";
			if(proc.GetName()[0]==1&&proc.GetName()[1]==ESC_OPERATOR)
			{
			}
			else{
				temp=proc.GetName().c_str();
			}

			char temporary[VN_SIZE];
			sprintf(temporary,"%s=%s",temp,Parameter);
			OpcodeCalc(temporary);
		}

		//プロシージャを抜け出す（C言語のreturnと同様の処理を行う）
		OpcodeExitSub();
	}
}


////////////
// ポインタ
////////////

void OpcodeSetPtrData(char *Parameter,int type){
	int i;
	char temporary[VN_SIZE];

	if(Parameter[0]=='('){
		i=JumpStringInPare(Parameter,1);
		if(Parameter[i+1]=='\0'){
			for(i=0;;i++){
				Parameter[i]=Parameter[i+1];
				if(Parameter[i]=='\0') break;
			}
			Parameter[i-1]=0;
		}
	}

	//第１パラメータを取得
	i=GetOneParameter(Parameter,0,temporary);
	if(!Parameter[i]){
		compiler.errorMessenger.Output(1,NULL,cp);
		return;
	}

	int reg_ptr=REG_RAX;
	Type resultType;
	if( !NumOpe(&reg_ptr,temporary,Type(),resultType) ){
		return;
	}
	if(!resultType.IsWhole()){
		compiler.errorMessenger.Output(11,Parameter,cp);
		return;
	}

	//結果を格納しているレジスタをブロッキング
	pobj_BlockReg->lock(reg_ptr);

	//第２パラメータを取得
	i=GetOneParameter(Parameter,i,temporary);
	if(Parameter[i]){
		compiler.errorMessenger.Output(1,NULL,cp);
		return;
	}

	int temp_reg=REG_NON;
	if( !NumOpe(&temp_reg,temporary,Type(),resultType) ){
		return;
	}

	//レジスタのブロッキングを解除
	pobj_BlockReg->clear();

	if(type==DEF_DOUBLE){
		ChangeTypeToXmm_Double(resultType.GetBasicType(),REG_XMM0,temp_reg);

		//movsd qword ptr[reg_ptr],xmm0
		compiler.codeGenerator.op_movsd_MR(REG_XMM0,reg_ptr,0,MOD_BASE);
	}
	else if(type==DEF_SINGLE){
		ChangeTypeToXmm_Single(resultType.GetBasicType(),REG_XMM0,temp_reg);

		//movss dword ptr[reg_ptr],xmm0
		compiler.codeGenerator.op_movss_MR(REG_XMM0,reg_ptr,0,MOD_BASE);
	}
	else{
		ChangeTypeToWhole(resultType,Type(type),REG_RCX,temp_reg);

		//mov ptr[reg_ptr],rcx
		compiler.codeGenerator.op_mov_MR(Type(type).GetSize(),REG_RCX,reg_ptr,0,MOD_BASE);
	}
}
