#pragma once

#include "MachineFixed.h"


//変数の種類
#define NON_VAR				0
#define VAR_GLOBAL			1	// Global Variable
#define VAR_REFGLOBAL		2	// Global Refference Variable
#define VAR_LOCAL			3	// Local Variable
#define VAR_REFLOCAL		4	// Local Refference Variable
#define VAR_DIRECTMEM		5	// Direct memory


extern int cp;

#define breakpoint compiler.codeGenerator.PutOld( (char)0xCC );


//プロシージャ
struct PROCEDURE{
	char name[255];
	int address;
	int types[MAX_PARMS];
	_int8 ByVal[MAX_PARMS];
	BOOL ReturnType;
};

//With情報
struct WITHINFO{
	char **ppName;
	int *pWithCp;
	int num;
};


class StackFrame
{
	///////////////////////////
	// スタックフレーム管理
	///////////////////////////

	PertialSchedules pertialSchedules;

	int lowest_sp;			//スタックポインタの最下位位置
	int now_sp;				//スタックポインタ
	int max_parm_size;		//パラメータの最大サイズ

public:
	//コンストラクタ
	StackFrame();

	//デストラクタ
	~StackFrame();

	int GetFrameSize( int localParamSize );
	int GetNowSp();
	void mov_sp( int reg );
	int push(int reg);
	void push(int xmm_reg,int varSize);
	void ref_offset_data( int reg, int sp_offset );
	void ref(int reg);
	void ref(int xmm_reg,int varSize);
	void pop(int reg = REG_NON);
	void pop(int xmm_reg,int varSize);
	void parameter_allocate(int size);
	void RunningSchedule( int stackFrameSize );

	void error_check(void);
};
extern StackFrame *pobj_sf;


class CBlockReg{
	int array_BlockReg[256];
	int num;

public:
	CBlockReg();
	void lock(int reg);
	void unlock(int reg);
	BOOL check(int reg);
	void clear(void);

	//レジスタのバックアップと復旧
	void backup();
	void restore();
};
extern CBlockReg *pobj_BlockReg;
class CRegister{
	////////////////////
	// レジスタ管理
	////////////////////

	//利用可能なレジスタを列挙する関数
	void EnumRegister(int *pRegList,int nMaxList,int *array_reg,int *sp,int AnswerReg);

	int array_UseReg[16],sp_UseReg;

	int array_XmmReg[16];
	int sp_XmmReg;

	int init_sp_reg,init_sp_xmm_reg;

public:
	CRegister(){};
	CRegister(int AnswerReg);
	~CRegister(){};

	//コンパイラにバグがないかをチェックする機構
	void bug_check();

	//汎用レジスタ
	int GetNextReg();
	int GetLockingReg();
	int LockReg();
	int UnlockReg();

	//XMMレジスタ
	int GetNextXmmReg();
	int GetLockingXmmReg();
	int LockXmmReg();
	int UnlockXmmReg();

	//レジスタが利用中かどうかを調べる
	bool IsUsing( int reg );

	//レジスタのバックアップと復旧
	void backup();
	void restore();
};
extern CRegister *pobj_reg;


#define BACKUP_REGISTER_RESOURCE								\
	/* レジスタをスタックフレームにバックアップ */				\
	pobj_BlockReg->backup();									\
	if(pobj_reg) pobj_reg->backup();							\
																\
	/* レジスタブロッキングオブジェクトを退避して再生成 */		\
	CBlockReg *pobj_BlockReg_back;								\
	pobj_BlockReg_back=pobj_BlockReg;							\
	pobj_BlockReg=new CBlockReg;								\
																\
	/* レジスタ管理オブジェクトポインタを退避して0をセット */	\
	CRegister *pobj_reg_back;									\
	pobj_reg_back=pobj_reg;										\
	pobj_reg=0;

#define RESTORE_REGISTER_RESOURCE								\
	/* レジスタブロッキングオブジェクトポインタを復元 */		\
	delete pobj_BlockReg;										\
	pobj_BlockReg=pobj_BlockReg_back;							\
																\
	/* レジスタ管理オブジェクトポインタを復元 */				\
	delete pobj_reg;											\
	pobj_reg=pobj_reg_back;										\
																\
	/* レジスタをスタックフレームから復元 */					\
	if(pobj_reg) pobj_reg->restore();							\
	pobj_BlockReg->restore();



//RSrcSection.cpp
char *GetRSrcSectionBuffer(int *pLen);

//Compile.cpp
void Compile( const char *source );
void ChangeOpcode(char *Command);
void GetGlobalDataForDll(void);
DWORD CompileBuffer(char Return_Sequence,WORD Return_Command);

//Register.cpp
BOOL IsGeneralReg(int reg);
BOOL IsXmmReg(int reg);
BOOL IsVolatileReg(int reg);
void IfR14Push( int reg );

//Compile_Calc.cpp
void SetVariableFromRax( const Type &varType, int CalcType,RELATIVE_VAR *pRelativeVar);
void OpcodeCalc(const char *Command);

//NumOpe.cpp
bool TermOpeOnlyVariable( const char *term, Type &resultType, RELATIVE_VAR &relativeVar, bool isWriteAccess );
bool TermOpe(
			 const char *term,
			 const Type &baseType,
			 Type &resultType,
			 bool &isLiteral,
			 bool &isNeedHeapFreeStructure,
			 bool *pIsClassName = NULL,
			 bool isProcedureCallOnly = false,
			 bool isWriteAccess = false );
bool NumOpe( int *pReg,
		   const char *Command,
		   const Type &baseType,
		   Type &resultType,
		   bool *pbIsNeedHeapFreeStructure = NULL );

//NumOpe_Arithmetic.cpp
BOOL CalcTwoTerm_Arithmetic(int idCalc,int *type,LONG_PTR *index_stack,int *pStackPointer);
BOOL Calc_Mod(int *type,LONG_PTR *index_stack,int *pStackPointer);
BOOL Calc_Divide(int *type,int *pStackPointer,int BaseType);
BOOL Calc_IntDivide(int *type,LONG_PTR *index_stack,int *pStackPointer);
BOOL Calc_MinusMark(int *type,int sp);
BOOL Calc_Power(int *type,int *pStackPointer);
BOOL Calc_Shift(int idCalc,int *type,int *pStackPointer);

//NumOpe_Logical.cpp
BOOL CalcTwoTerm_Logical(int idCalc,int *type,LONG_PTR *index_stack,int *pStackPointer);
BOOL Calc_Not(int *type,int sp);

//NumOpe_Relation.cpp
BOOL CalcTwoTerm_Relational(int idCalc,int *type,LONG_PTR *index_stack,int *pStackPointer);

//NumOpe_TypeOperation.cpp
void ExtendTypeTo64( const Type &oldType, int reg );
void ExtendTypeTo32( const Type &oldType, int reg );
void ExtendTypeTo16( const Type &oldType, int reg );
void ChangeTypeToXmm_Double(int type,int xmm_reg,int general_reg);
void ChangeTypeToXmm_Single(int type,int xmm_reg,int general_reg);
void ChangeTypeToWhole( const Type &oldType, const Type &newType, int reg, int xmm_reg );
void SetOneTermToReg_RealCalc(int TermType,int *pXmmReg);
void SetOneTermToReg_Whole64Calc(int TermType,int *pReg);
void SetOneTermToReg_Whole32Calc(int TermType,int *pReg);
void SetTowTermToReg_RealCalc(int AnswerType,int *type,int sp,int *pXmmReg1,int *pXmmReg2);
void SetTowTermToReg_Whole64Calc(int *type,int sp,int *pReg1,int *pReg2);
void SetTowTermToReg_Whole32Calc(int *type,int sp,int *pReg1,int *pReg2);
BOOL Calc_Cast(int *type,LONG_PTR *index_stack,int *pStackPointer);

//Compile_Set_Var.cpp
BOOL IsUse_r11(RELATIVE_VAR *pRelativeVar);
void SetStructVariableFromRax( const Type &varType, const Type &calcType, RELATIVE_VAR *pRelativeVar,BOOL bUseHeap);
void SetRealVariable(int VarType, int CalcType, RELATIVE_VAR *pRelativeVar);
void SetBooleanVariable(int type,RELATIVE_VAR *pRelative);
void SetWholeVariable(int varSize,int type,RELATIVE_VAR *pRelative);

//increment.cpp
void IncDec(int idCalc, const char *lpszLeft, const char *lpszRight);

//Compile_Calc_PushVar.cpp
void SetXmmReg_DoubleVariable(RELATIVE_VAR *pRelativeVar,int xmm_reg);
void SetXmmReg_SingleVariable(RELATIVE_VAR *pRelativeVar,int xmm_reg);
void SetReg_WholeVariable( const Type &type, RELATIVE_VAR *pRelativeVar,int reg);

//Compile_Object.cpp
void Operator_New( const CClass &classObj, const char *objectSizeStr, const char *parameter,const Type &baseTypeInfo );
void OpcodeDelete(const char *Parameter, bool isSweeping);

//Compile_Var.cpp
bool _member_offset(bool isErrorEnabled, bool isWriteAccess, const Type &classType, const char *member, RELATIVE_VAR *pRelativeVar, Type &resultType, BOOL bPrivateAccess);
void SetThisPtrToReg(int reg);
bool GetVarOffset(bool isErrorEnabled,bool isWriteAccess,const char *NameBuffer,RELATIVE_VAR *pRelativeVar,Type &resultType, Subscripts *pResultSubscripts = NULL );
bool SetInitGlobalData(int offset,const Type &type,const Subscripts &subscripts,const char *InitBuf);
#define DIMFLAG_INITDEBUGVAR			0x01
#define DIMFLAG_NONCALL_CONSTRACTOR		0x02
#define DIMFLAG_STATIC					0x04
#define DIMFLAG_CONST					0x08
void dim( char *VarName, const Subscripts &subscripts, const Type &type, const char *InitBuf,const char *ConstractParameter,DWORD dwFlags);
void SetVarPtrToReg(int reg,RELATIVE_VAR *pRelativeVar);
bool Compile_AddGlobalRootsForGc();

//ParamImpl.cpp
class ParamImpl{
	char *Parms[255];
	std::vector<Type> types;
	int ParmsNum;

	Type leftType;
	Type returnType;

	//一時オブジェクト管理用
	bool useTempObject;
	bool useTempParameters[255];
	bool isNeedFreeStructures[255];
	int StackOffsetOfTempObject[255];

public:
	ParamImpl(const char *buffer);
	ParamImpl(const Parameters &params);
	~ParamImpl();
	void SetLeftType( const Type &type )
	{
		this->leftType = type;
	}
	void SetReturnType( const Type &returnType );

private:
	bool EvaluateOverloadScore( int level, const Parameters &targetParms, const Type &targetResultType, const Type &leftType, const UserProc &userProc, bool &isErrored );

public:
	const UserProc *_OverloadSolution( const char *name, std::vector<const UserProc *> &subs, const Type &leftType, bool isEnabledReturnType );
	const UserProc *OverloadSolution( const char *name, std::vector<const UserProc *> &subs, const Type &leftType, bool isEnabledReturnType = false );

	void ApplyDefaultParameters( const Parameters &params );
	bool ErrorCheck( const std::string &procName, const Parameters &params, int SecondParmNum = -1 );
	void MacroParameterSupport( const Parameters &params );
	void SetStructParameter( int reg, const Type &baseType, const char *expression );
	void SetParameter( const std::string &procName, const Parameters &params, int SecondParmNum = -1, const UserProc *pUserProc = NULL );

	//一時オブジェクトパラメータの生成と破棄
	int NewTempParameters( const std::string &procName, const Parameters &params, int SecondParmNum = -1 );
	void DeleteTempParameters();

	void BackupParameter(int pi_num);
	void RestoreParameter(int pi_num);
};

//CLockParameter.cpp
#define MAX_LOCKPARMS 255
class CDBLockParms{
public:
	int array_LevelCount[MAX_LOCKPARMS];
	CDBLockParms();
	~CDBLockParms();

	void lock(int level);
	void unlock(int level);
};

//Compile_CallProc.cpp
#define PROCFLAG_NEW	1
bool Opcode_CallProcPtr(const char *variable, const char *lpszParms,ProcPointer *pProcPointer);
bool Opcode_CallProc(const char *Parameter,const UserProc *pUserProc,DWORD dwFlags,const char *ObjectName);
bool Opcode_CallDllProc( const char *lpszParms,DllProc *pDllProc);
void Opcode_CallDelegate( const Delegate &dg, const char *methodPtrValueStr, const char *objPtrValueStr, const char *params );

//Compile_ProcOp.cpp
void _compile_proc(const UserProc *pUserProc);

//Compile_Func.cpp
int GetFunctionFromName(char *FuncName);
bool Opcode_CallFunc( const char *Parameter, const int FuncNum, const Type &baseType, Type &resultType, bool isCallOn = true );

//OperatorProc.cpp
void FreeTempObject(int reg,const CClass *pobj_c);
int CallOperatorProc(BYTE idCalc, const Type &baseType, int *type_stack,LONG_PTR *index_stack,bool isNeedHeapFreeStructureStack[],int &sp);
void CallCastOperatorProc(int reg,Type &calcType,BOOL bCalcUseHeap,const Type &toType);
void CallIndexerGetterProc(int reg, const Type &classType, const char *ObjectName,char *Parameter,Type &resultType, DWORD dwProcFlags = 0 );

//Compile_Statement.cpp
void OpcodeOthers(const char *Command);
void OpcodeIf(char *Parameter);
void OpcodeGoto(char *Parameter);
void OpcodeWhile(char *Parameter);
void OpcodeFor(char *Parameter);
void OpcodeForeach(const char *Parameter);
void OpcodeDo(char *Parameter);
void OpcodeContinue(void);
void OpcodeExitSub(void);
void OpcodeSelect( const char *Parameter );
void OpcodeCase(char *Parameter);
void OpcodeGosub(char *Parameter);
void OpcodeReturn(char *Parameter);
void OpcodeSetPtrData(char *Parameter,int type);


//InsertOpcode.cpp
void InsertDimStatement_ToProcHead(char *lpszCommand);


BOOL IsSafeReg(int reg);
