//--------------------------------------------------------------------------------------
//
// X-BASIC'
//	インタープリター(サブルーチン)
//
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "XB.h"
#include <ctype.h>
#include <time.h>
#import "libs.h"
#import "malloc2.h"

//--------------------------------------------------------------------------------------

// Breakチェック
STATE checkBreak(void)
{
	int checkBreakIniOS(void);
	if (checkBreakIniOS()) {
		if (!operationStatus.fbreakoff) {
			return (STATE_BREAK);
		}
	}
	return(STATE_OK);
}

//--------------------------------------------------------------------------------------

// T_*型をVAR_TYPES番号に変換する
VAR_TYPES type2VarTypes(uwTYPE type)
{
	VAR_TYPES typeNo=VAR_INT; // 警告回避のため
	switch (type) {
		case T_INT:
			typeNo=VAR_INT;
			break;
		case T_STR:
			typeNo=VAR_STR;
			break;
		case T_CHAR:
			typeNo=VAR_CHAR;
			break;
		case T_FLOAT:
			typeNo=VAR_FLOAT;
			break;
		case T_VOID:
			typeNo=VAR_VOID;
			break;
	}
	return (typeNo);
}

//--------------------------------------------------------------------------------------

// VAR_CTRLをVAR_CTRL_EXECで読み替えるためのポインタを返す
// グローバル・ローカルも判別する
VAR_CTRL_EXEC *getVarCtrlExec(VAR_TYPES typeNo,uwCODE code)
{
	VAR_CTRL_EXEC *var_ctrl_exec; // 読み替えのため
	if (code&CODE_ATRB_LOCAL) {
		var_ctrl_exec = &localVarCtrlExec[typeNo];
	} else {
		var_ctrl_exec = (VAR_CTRL_EXEC *)&globalVarCtrl[typeNo];
	}
	return (var_ctrl_exec);
}

// VAR_CTRLをVAR_CTRL_EXECで読み替えるためのポインタを返す
// グローバル・ローカルも判別する
VAR_CTRL_EXEC *getVarCtrlExecWithVarNo(VAR_TYPES typeNo,swVarNO *no)
{
	VAR_CTRL_EXEC *var_ctrl_exec; // 読み替えのため
	if (_isLocal(*no)) {
		var_ctrl_exec = &localVarCtrlExec[typeNo];
		*no=getVarNo(*no);
	} else {
		var_ctrl_exec = (VAR_CTRL_EXEC *)&globalVarCtrl[typeNo];
	}
	return (var_ctrl_exec);
}

//--------------------------------------------------------------------------------------

// size分の変数エリアを確保する
// xbasicMain()の先頭で呼び出される
UByte *getVariableArea(ULong size)
{
	nslog(@"%s=%u",__FUNCTION__,(uint)size);
	nslog(@"variableArea=%p〜%p(%d) : variableAreaTop=%p〜%p(%d)",variableArea,variableArea+size-1,(int)size,variableAreaTop,variableAreaTop+variableAreaSize-1,(int)variableAreaSize);
	
	if (variableArea+size>=variableAreaTop+variableAreaSize) {
		nslog(@"変数領域拡大");
		// 次のブロック分の変数領域が確保できないときは拡大する
		// variableAreaTopが変化するかもしれないので、まずvariableAreaの位置を相対で求めておく
		// （元の位置でそのまま拡大できれば変化しないが、拡大できない時は移動されて拡大される）
		psize_t offset=calcAdrsOffset(variableArea,variableAreaTop);
		nslog(@"offset=%zu",offset);
		//
		nslog(@"size=%d : SZ_VARIABLE_AREA=%d",(int)size,SZ_VARIABLE_AREA);
		size=((size+SZ_VARIABLE_AREA-1)/SZ_VARIABLE_AREA)*SZ_VARIABLE_AREA; // SZ_VARIABLE_AREA単位で切り上げで確保
		variableAreaSize+=size;
		variableAreaTop=realloc2(variableAreaTop,variableAreaSize);
		if (variableAreaTop==NULL) {
			// もうこれ以上拡大できない
			nslog(@"変数領域拡大不可");
			IError(ERR_VARIABLE_AREA_OVERFLOW);
		}
		nslog(@"新variableAreaTop=%p",variableAreaTop);
		// variableAreaを新しいワーク内のアドレスに変換する
		variableArea=variableAreaTop+offset;
	}
	// ここで、variableAreaからsize分は確保可能を保証
	return (variableArea);
}

//--------------------------------------------------------------------------------------
// 値取得
//--------------------------------------------------------------------------------------

UByte *nullString(void)
{
	DBG_Func();
	return ((UByte *)""); // 常に空文字列を返す(CのNULLとは違う)
}

UByte *basicVersion(void)
{
extern	NSString *programVersion;
	DBG_Func();
	nslog(@"programVersion=%@",programVersion);
	return (unsStringTocString(programVersion));
}
	
UByte *basicCoreVersion(void)
{
	DBG_Func();
	return ((UByte *)VERSION_CORE);
}

UByte *iOSInterfaceVersion(void)
{
	DBG_Func();
	return ((UByte *)VERSION_IOS_INTERFACE);
}

// 日付を返す
// 文字列内容は機種依存
// YYYY/MM/DD
UByte *dateString(void)
{
#if 0
struct tm {
    int tm_sec;		/* 秒 */
    int tm_min;		/* 分 */
    int tm_hour;	/* 時間 */
    int tm_mday;	/* 日 */
    int tm_mon;		/* 月 */
    int tm_year;	/* 年 */
    int tm_wday;	/* 曜日 */
    int tm_yday;	/* 年内通算日 */
    int tm_isdst;	/* 夏時間 */
};
#endif
	DBG_Func();
	time_t tm;
	time(&tm);
	struct tm *local=localtime(&tm);
	#if 0	// 全体
	sprintf((char *)tmp,"%04d/%02d/%02d %02d:%02d:%02d(%d)\n"
		,local->tm_year+1900
		,local->tm_mon
		,local->tm_mday
		,local->tm_hour
		,local->tm_min
		,local->tm_sec
		,local->tm_wday
	);
	#else
	sprintf((char *)tmp,"%04d/%02d/%02d"
		,local->tm_year+1900
		,local->tm_mon
		,local->tm_mday
	);
	#endif
	nslog(@"%s\n",tmp);
	return ((UByte *)tmp);
}

// 曜日を返す
UByte *dayString(void)
{
	static const char *weekJ[]={"日","月","火","水","木","金","土"};
	static const char *weekE[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
	DBG_Func();
	time_t tm;
	time(&tm);
	struct tm *local=localtime(&tm);
	DBG_printf2("%s/%s\n",weekJ[local->tm_wday],weekE[local->tm_wday]);
	return (operationStatus.fenglish? (UByte *)weekE[local->tm_wday]:(UByte *)weekJ[local->tm_wday]);
}

// 時刻を返す
// hh:mm:ss
UByte *timeString(void)
{
	DBG_Func();
	time_t tm;
	time(&tm);
	struct tm *local=localtime(&tm);
	sprintf((char *)tmp,"%02d:%02d:%02d"
		,local->tm_hour
		,local->tm_min
		,local->tm_sec
	);
	nslog(@"%s\n",tmp);
	return ((UByte *)tmp);
}

//----------------------

// 文字列システム変数
typedef struct {
	UByte* (*exec)(void);
} STR_SYSYTEM_VARIABLE;

static 	STR_SYSYTEM_VARIABLE str_sys[]={
	{basicVersion},
	{basicCoreVersion},
	{iOSInterfaceVersion},
	{dateString},
	{dayString},
	{timeString},
	{nullString},
};

//----------------------------------------------

// 文字列先頭アドレスを返す(a0.l)
UByte *strGet0(uwCODE code)
{
	DBG_Func();
	
	DBG_printCode(code);
	if (_isConstnat(code)) {
		// sg1:	1073
		if (!_isVariable(code)) {
			// 文字列定数そのものを返す
			fnslog("文字列定数");
			UByte *str=internalCode.bp; // 文字列先頭アドレス
			while (*internalCode.bp++!=EOS);
			if (internalCode.l&1) *internalCode.bp++=EOS; // 偶数境界化;念のためEOSを入れておく
			return(str);
		}
	// iOS
	//	code=_clrVariable(code);
		// str_fnc	1076
		fnslog("文字列関数");
		DOUBLE_LONG dl=functionCall(T_STR);
		UByte *bp=strbuf;
		strcpy((char *)bp,dl.cp[LL]);
		strbuf+=operationStatus.sz_str;	// 次のバッファーの位置に移動しておく;文字列長はoperationStatus.sz_str固定
		return (bp);
	}
	// 942
	if (!_isVariable(code)) {
		// str_cal:	1105
		// 文字列定数加算
		fnslog("文字列定数加算");
		code=readInternalCode();
		if (code!=ADD) {
			// strには足し算以外出来ない
			IError(ERR_USE_ONLY_ADD_WITH_STRING);
		}
		// 文字列定数加算
		// 文字列定数の加算時はstrbufから割り付ける。
		// 加算結果を変数に代入しない限りその結果は一時的なものなので、
		// 次のブロックに入るときには消してしまう(次回またそこにきたときに作ればよいだけ)
		DOUBLE_LONG dl=getValue(T_STR);
		UByte *p1=dl.bp[LL];
		dl=getValue(T_STR);
		UByte *p2=dl.bp[LL];
		nslog(@"len str1=%zd",bstrlen(p1)); // EOSを含まないバイト数
		nslog(@"len str2=%zd",bstrlen(p2)); // 同上
		nslog(@"operationStatus.sz_str=%d",operationStatus.sz_str); // EOSを含むバイト数
		
		if (bstrlen(p1)+bstrlen(p2)>=operationStatus.sz_str) {
			// 文字列が長くなりすぎる
			IError(ERR_TOO_LONG_STRING);
		}
		UByte *bp=strbuf;	// strbuf(定数文字列加算用ワーク)
		strcpy((char *)bp,(char *)p1);
		strcat((char *)bp,(char *)p2);
		strbuf+=operationStatus.sz_str;	// 次のバッファーの位置に移動しておく
		return(bp);
	}
	// STR_VAL	945
	if (code&CODE_ATRB_POINTER) {
		//str_dim:	1063
		fnslog("文字列配列");
		//
		slAryNO thno; // 指定された要素番号を全次元での通し番号に直したものが返る
		swVarNO hno=getVarNo(readInternalCode()); // 配列番号
		UByte *bp=dimSetSub(&thno,hno,getVarCtrlExec(VAR_DIM,code));
		// 指定要素内容は((型*)リターン値)[thno]から読み出せばよい
		fnslog("dimSetSubから戻ってきたところ");
#ifdef INTERNAL_TRACE
		if (getinfp()!=NULL) {
			fprintf(getinfp(),"thno=%d/hno=%d\n",(int)thno,hno);
		}
#endif
		return (&bp[thno*operationStatus.sz_str]);
	}
	// 949
	VAR_CTRL_EXEC *var_ctrl_exec=getVarCtrlExec(VAR_STR,code);
	UByte *varAdrs=var_ctrl_exec->varArea;
	swVarNO no=readInternalCode(); // 変数番号
	if (_isSystemVarStr(no)) { // システム変数のとき
		// str_system_var:	954
		nslog(@"文字列システム変数");
		return (str_sys[_getSystemVarStr(no)].exec());
	}
	nslog(@"文字列変数");
	no=getVarNo(no);
	return (&varAdrs[no*operationStatus.sz_str]);
}

//-----------------------------------------------

// int用とchar用をまとめているので、char用の時の変換は呼び出し側で行うこと
SLong charGetSub(uwCODE code)
{	// 386/587

	nslog(@"%s:code=$%04x\n",__FUNCTION__,code);

	if (!_isConstnat(code)) {		// 386/587
		if (!_isVariable(code)) {	// 388/589
			// 定数２項演算
			// 390/591
			fnslog("定数２項演算:calc2Value");
			return (calc2Value(code));
		}
		// CHAR_VAL  404/606
		if (code&CODE_ATRB_POINTER) {	// 405/607
			// char_dim:  424/626
			slAryNO thno; // 指定された要素番号を全次元での通し番号に直したものが返る
			swVarNO hno=getVarNo(readInternalCode()); // 配列番号
			UByte *bp=dimSetSub(&thno,hno,getVarCtrlExec(VAR_DIM,code));
			// 指定要素内容は((型*)リターン値)[thno]から読み出せばよい
			nslog(@"配列:番号=%d\n",(int)thno);
			fnslog2("配列：番号=〜");
			return (bp[thno]);
		}
		// 408/610
		// 元が配列なので、読み替えのためにはいったんポインターに直す必要がある
		VAR_CTRL_EXEC *var_ctrl_exec; // 読み替えのため
		if (code&CODE_ATRB_STR) {	// 408/610
			// 432/634	str_point/2
			// 文字列内1文字取得
			fnslog("文字列内1文字取得");
			SLong num1=intGetValue(); // その位置
			nslog(@"文字列内位置:%d\n",(int)num1);
			if (num1<0) {
				// 位置指定がおかしい
				IError(ERR_ILLEGAL_STRING_POINT);
			}
			if (num1>=operationStatus.sz_str) {
				// 最大文字列長を超えている
				IError(ERR_TOO_LONG_STRING);
			}
			swVarNO no=readInternalCode(); // 変数番号
			nslog(@"変数番号:%d\n",no);
			var_ctrl_exec=getVarCtrlExec(VAR_STR,code);
			UByte *varAdrs=var_ctrl_exec->varArea;
			UByte *bp=&varAdrs[no*operationStatus.sz_str];
			DBG_printf2("bp=%s,len=%ld\n", bp, strlen((char *)bp));
#if 0	// V2.5で封印
			// X-BASIC/68、ぺけ-BASICでは最大文字列長までの範囲内であれば現在の文字列長を超えてもアクセスできる
			if (num1>strlen((char *)bp)-1) {
				// 先頭が[0]なので、[strlen]はEOSの位置に当たる。故に-1までが有効
				// 文字列長を超えている
				IError(ERR_ILLEGAL_STRING_POINT);
			}
#endif
			DBG_printf2("文字:%c[$%02x]\n",bp[num1],bp[num1]);
			return (bp[num1]);
		}
		// 411/613
		fnslog("char変数取得");
		swVarNO no=readInternalCode(); // 文字変数番号
		nslog(@"文字変数番号:%d\n",no);
		var_ctrl_exec=getVarCtrlExec(VAR_CHAR,code);
		UByte *varAdrs=var_ctrl_exec->varArea;
		return ((SLong)varAdrs[no]); // (SLong)str[no]
	}
	// 392
	if (_isVariable(code)) {	// 393
		// char_fnc: 395/597
	// iOS
	//	code=_clrVariable(code);
		DOUBLE_LONG dl=functionCall(T_CHAR);
		return (dl.l[LL]);
	}
	// char_imm	455/657
	return (readInternalCodeL());
}

//-----------------------------------------------

// 内部エラー番号を返す
static
ULong Errno(void)
{
	return (errorNo);
}

#if 0	// v2.2でenum値に変更
static
ULong _Yes(void)
{
	return (BASIC_YES);
}

static
ULong _No(void)
{
	return (BASIC_NO);
}
#endif
	
// 数値システム変数
typedef struct {
	ULong (*exec)(void);
} INT_SYSYTEM_VARIABLE;

static INT_SYSYTEM_VARIABLE int_sys[]={
	{Errno	},
#if 0	// v2.2でenum値に変更
	{_Yes	},
	{_No	},
	{_Yes	},	// true
	{_No	},	// false
#endif
};

// int値取得
SLong intGetSub(uwCODE code)
{	//ig112: 668
	nslog(@"%s:code=$%04x\n",__FUNCTION__,code);
	fnslog2((char *)__FUNCTION__);

	ULong num;
	if (!_isConstnat(code))	{	// 669
		if (!_isVariable(code)) {	// 671
			// ２項演算	673
			fnslog("2項演算:calc2Value");
			return (calc2Value(code));
		}
		code=_clrVariable(code);	// 671

		// int_val2: 676
		if (code&CODE_ATRB_POINTER) {
			// int_dim2: 721
			fnslog("配列");
			//
			slAryNO thno; // 指定された要素番号を全次元での通し番号に直したものが返る
			swVarNO hno=getVarNo(readInternalCode()); // 配列番号
			SLong *lp=(SLong *)dimSetSub(&thno,hno,getVarCtrlExec(VAR_DIM,code));
			lp+=thno;
			// 指定要素内容は((型*)リターン値)[thno]から読み出せばよい
			return (readLong(lp));
		}
		// 680
		// ローカルとグローバルの統合処理
		swVarNO no=readInternalCode(); // 変数番号
		if (_isSystemVarInt(no)) {
			// システム変数(グローバルでしかありえない)
			// int_system_var: 1145
			nslog(@"システム変数");
			return (int_sys[_getSystemVarInt(no)].exec());
		}
		// ローカル変数		709
		// グローバル変数	682
		fnslog("変数");
		VAR_CTRL_EXEC *var_ctrl_exec=getVarCtrlExec(VAR_INT,code);
		ULong *varAdrs=(ULong *)var_ctrl_exec->varArea;
		DBG_printf3("変数アドレス=%p,番号=%d,値=%d\n",varAdrs,getVarNo(no),(int)varAdrs[getVarNo(no)]);
		return (varAdrs[getVarNo(no)]);
	}
	// 代入式	687
	fnslog("代入式");
	if (!_isVariable(code)) {
		// 定数
		// int_imm2: 733
		fnslog("定数");
		num=readInternalCodeL();
	} else {
	// iOS
	//	code=_clrVariable(code);
		// int_fnc2: 690
		fnslog("演算式");
		DOUBLE_LONG dl=functionCall(T_INT);
		num=dl.l[LL];
	}
	nslog(@"num=%d(%s)\n",(int)num,__FUNCTION__);
	return (num);
}

//-----------------------------------------------

// type型の数式を取得する
// リターン値	DOUBLE_LONG
// 	int の時、	.l[LL]
// 	float		.d
// 	str			.l[LL]=a0
//	char		.bp[LL];64bit				(UByte).l[LL];32bit
DOUBLE_LONG getValue(uwTYPE type)
{	// 値get	368
	DBG_Func();

	DOUBLE_LONG dl;
	dl.l[HL]=0;	// .d/.bp以外の時のために未使用領域を消しておく
	uwCODE code=readInternalCode();
	DBG_printf3("要求type=$%04x : code=$%04x;存在type=$%04x\n",type,code,_getType(code));
	// 取得は存在型で行う
	switch (_getType(code)) {
		case T_INT:		// ig111: 466
			fnslog("T_INT取得");
			dl.l[LL]=intGetSub(code);
			break;
		
		case T_CHAR:		//	cg111: 385
			fnslog("T_CHAR取得");
			dl.l[LL]=charGetSub(code)&0xff; // charだから
			break;

		case T_STR:	// sg111: 375
			fnslog("T_STR取得");
			if (type!=T_STR) {
				IError(ERR_MISMATCH_FORMULA_TYPE);
			}
			fnslog2("strGet0前");
			dl.bp[LL]=strGet0(code);
			fnslog2("strGet0後");
			return(dl);
		
		case T_FLOAT:	// fg111: 551
			fnslog("T_FLOAT取得");
			dl=floatGet0(code);
			SLong num=(SLong)dl.d; // 整数値も得ておく(int/charで返すときのため)
			switch (type) {
				case T_STR:
					IError(ERR_MISMATCH_FORMULA_TYPE);
				case T_FLOAT:
					nslog(@"floatGet0()→T_FLOAT=%f",dl.d);
					return(dl);
				//
				case T_INT:
					num=(SLong)dl.d;
					break;
				case T_CHAR:
					num=(SLong)dl.d;
					num&=0xff;
					break;
			}
			// int化して返す
			dl.l[HL]=0;
			dl.l[LL]=num;
			return(dl);
	} // switch

	// T_INT/T_CHARの時のみ来る
	// すでに合っている場合も通る
	switch (type) {
		case T_STR:
			// 型違い
			IError(ERR_MISMATCH_FORMULA_TYPE);

		case T_FLOAT:
			// int/char → float
			nslog(@"int/char → float:$%08x/",(int)dl.l[LL]);
			DBG_printf2("%d → %f\n",(int)dl.l[LL],(double)dl.sl[LL]);
			// 型キャスト時は符号付き変換しないといけない
			dl.d=(double)(dl.sl[LL]);
			break;
		
		case T_INT:
		case T_CHAR:
			nslog(@"int ←→ char");
			// int,char 同士
			break;
	}
	return (dl);
}

//-----------------------------------------------

// intGetValue()は#define定義

ULong intGetValue0(uwTYPE *type0)
{	// int値get 579
	DBG_Func();
	
	SLong num=0; // 警告回避のため
	uwCODE code=readInternalCode();
	uwTYPE type=_getType(code);
	switch (type) { // 581相当
		case T_INT:		//ig112:
			num=intGetSub(code); // 定数または変数
			break;
		
		case T_CHAR:	// cg112 586
			if (_isDainyu(code)) { // 587	code<0
				// 594
				if (!(code&CODE_ATRB_VARIABLE)) {
					// char_imm2:	657
					num=readInternalCodeL();
				} else {
				// iOS
				//	code&=~CODE_ATRB_VARIABLE; // 595
					// char_fnc2:	597
					DOUBLE_LONG dl=functionCall(T_CHAR);
					num=dl.l[LL];
				}
				num&=0xff;	// charだから
			} else {
				// 589～char_val2
				num=charGetSub(code);
			}
			break;
		
		case T_STR: 	// 584
			// 型違い
			IError(ERR_MISMATCH_FORMULA_TYPE);
		
		case T_FLOAT:	// fg112
			{
			DOUBLE_LONG dl=floatGet0(code);
			num=(SLong)dl.d; // 値はintで返すから
			nslog(@"float:%f→%d:int",dl.d,(int)num);
			}
			break;
	}
	if (type0!=NULL) *type0=type; // 型を返す
	return (num);
}

//--------------------------------------------------------------------------------------
// 浮動小数点処理
//--------------------------------------------------------------------------------------

DOUBLE_LONG floatGet0(uwCODE code)
{	// 771
	DBG_Func();

	DOUBLE_LONG dl;

	// $c0xxは関数 : DAINYU|VARIABLE
	if (_isDainyu(code)) { // 772		<0
		// fg1	803
		if (_isVariable(code)) { // 804
			// 806
			nslog(@"浮動小数点関数");
		// iOS
		//	code=_clrVariable(code);
			// float_fnc
			dl=functionCall(T_FLOAT);
			return (dl);
		}
		// 浮動小数点定数	816
		nslog(@"浮動小数点定数");
		readDOUBLE_LONG(&dl, internalCode.dp); // dl=*internalCode.dp;
		internalCode.dp++;
		return (dl);
	}
	// 774
	if (!_isVariable(code)) {
		// float_cal	821
		nslog(@"浮動小数点演算");
		return (float_cal());
	}
	// FLOAT_VAL	777
	if (code&CODE_ATRB_POINTER) {
		// float_dim	795
//		nslog(@"浮動小数点配列");
		//
		slAryNO thno; // 指定された要素番号を全次元での通し番号に直したものが返る
		swVarNO hno=getVarNo(readInternalCode()); // 配列番号
		DOUBLE_LONG *dp=(DOUBLE_LONG *)dimSetSub(&thno,hno,getVarCtrlExec(VAR_DIM,code));
		nslog(@"浮動小数点配列:dp=%p[%d]",dp,(int)thno);
		dp+=thno;
		// 指定要素内容は((型*)リターン値)[thno]から読み出せばよい
		readDOUBLE_LONG(&dl,dp);	// dl=*dp
		nslog(@"=%p:%f",dp,dl.d);
		return (dl);
	}
	// 781
	nslog(@"浮動小数点変数");
	VAR_CTRL_EXEC *var_ctrl_exec=getVarCtrlExec(VAR_FLOAT,code);	// ここは８バイト境界にある
	DOUBLE_LONG *varAdrs=(DOUBLE_LONG *)var_ctrl_exec->varArea;		// varAreaはoffset0
	// 787
	swVarNO no=getVarNo(readInternalCode()); // 変数番号
	readDOUBLE_LONG(&dl,&varAdrs[no]); // dl=varAdrs[no];
	return (dl);
}

//-----------------------------------------------
// 実数演算
//-----------------------------------------------

DOUBLE_LONG float_cal(void)
{
	DBG_Func();
	
	uwCODE cal=readInternalCode();
	nslog(@"cal=$%04x\n",cal);
	
	// 2値を得ておく
	DOUBLE_LONG dl1=getValue(T_FLOAT);
	nslog(@"num1=%f\n",dl1.d);
	DOUBLE_LONG dl2;
	dl2.d=0; // 警告回避のため
	if (cal!=SIGN && cal!=NOT) {
		// 単項演算子以外
		dl2=getValue(T_FLOAT);
		nslog(@"num2=%f\n",dl2.d);
	} // 単項演算子には2項目はないので、読みに行ってはいけない
	
	nslog(@"演算:cal=$%04x\n",cal);
	SLong l1,l2;
	switch (cal) { // これらは単項演算子なので特別処理
		default:
			// floatにない演算:
			IError(ERR_CANT_USE_AT_FLOAT);
		//
		case SIGN:
			dl1.d=-dl1.d;
			break;
		//
		case MUL:
			dl1.d=dl1.d*dl2.d;
			break;
		case ADD:
			dl1.d=dl1.d+dl2.d;
			break;
		case SUB:
			dl1.d=dl1.d-dl2.d;
			break;
		//
		case DIV:
			if (dl2.d==0.0) {
				// 0除算
				IError(ERR_ZERO_DIVIDE);
			}
			dl1.d=dl1.d/dl2.d;
			break;
		case IDIV:
			l2=(SLong)dl2.d;
			if (l2==0) {
				// 0除算
				IError(ERR_ZERO_DIVIDE);
			}
			l1=(SLong)dl1.d;
			dl1.d=(double)(l1/l2);
			break;
		case MOD:
			// 実数の余りも、整数除算で求める
			l2=(SLong)dl2.d;
			if (l2==0) {
				// 0除算
				IError(ERR_ZERO_DIVIDE);
			}
			l1=(SLong)dl1.d;
			dl1.d=(double)(l1%l2);
			break;
	}
	return (dl1);
}

//--------------------------------------------------------------------------------------
// 整数演算
//--------------------------------------------------------------------------------------

// 実数・文字列の比較の時有り
// intは直接比較処理してあるので呼び出さない
// type = 比較する型
CMP_RESULT compare2Value(uwTYPE type)
{	// 二数比較 1382
	DBG_Func();
	switch (type) {
		case T_FLOAT:		//	二比float	1404
			nslog(@"T_FLOAT");
			{
			DOUBLE_LONG dl1=getValue(T_FLOAT);
			DOUBLE_LONG dl2=getValue(T_FLOAT);
			if (dl1.d==dl2.d) return (CMP_EQUAL);
			if (dl1.d> dl2.d) return (CMP_LARGE);
			//  dl1.d< dl2.d
			}
			break;
		case T_CHAR:		// 二比char:	1414
			nslog(@"T_CHAR");
			{
			UByte cnum1=(UByte)intGetValue();
			UByte cnum2=(UByte)intGetValue();
			if (cnum1==cnum2) return (CMP_EQUAL);
			if (cnum1> cnum2) return (CMP_LARGE);
			//  cnum1< cnum2
			}
			break;
		case T_STR:		// 二比str:	1387
			nslog(@"T_STR");
			{
			DOUBLE_LONG dl;
			dl=getValue(T_STR);
			char *p1=dl.cp[LL]; // strcmp()のため
			dl=getValue(T_STR);
			char *p2=dl.cp[LL]; // strcmp()のため
			int ret=strcmp(p1,p2);
			if (ret==0) return(CMP_EQUAL);
			if (ret >0) return(CMP_LARGE);
			}
			break;
	}
	return (CMP_SMALL);
}

//-----------------------------------------------

// int2値を得る
// 単項演算子の時は呼び出さないこと
static uwTYPE getInt2Value(SLong *num1,SLong *num2)
{
	DBG_Func();
	
	uwTYPE type;
	
	*num1=intGetValue0(&type);
	DBG_printf2("num1=%d(type=$%04x)\n",(int)*num1,type);
	
	*num2=intGetValue();
	nslog(@"num2=%d\n",(int)*num2);
	
	return (type);
}

// 2項の演算	int_cal	1186
// 結果としてintを返す2項の演算であって、int2項の演算ではないことに注意
SLong calc2Value(uwCODE code)
{
	nslog(@"%s:code=$%04x\n",__FUNCTION__,code);
	fnslog2((char *)__FUNCTION__);

	uwCODE cal=readInternalCode();
	nslog(@"指定演算子=$%04x\n",cal);

	SLong num1,num2;
	uwTYPE type;

	switch (cal) {
		default: // 念のため;SBASEで発生してしまう
			nslog(@"calc2Value:default:指定演算子=$%04x\n",cal);
			fnslog2("calc2Valie:default");
			IError(ERR_SYSTEM);
		
		// 単項演算子
		case NOT:
			fnslog("NOT");
			num1=intGetValue0(&type);
			DBG_printf2("num1=%d(type=$%04x)\n",(int)num1,type);
			num1=~num1;
			break;
		case SIGN:
			fnslog("SIGN");
			num1=intGetValue0(&type);
			DBG_printf2("num1=%d(type=$%04x)\n",(int)num1,type);
			num1=-num1;
			break;
		
		// 算術演算子
		case DIV:
		case IDIV:
			fnslog("DIV/IDIV");
			getInt2Value(&num1,&num2);
			if (num2==0) {
				// 0除算
				IError(ERR_ZERO_DIVIDE);
			}
			num1/=num2;
			break;
		case MOD:
			fnslog("MOD");
			getInt2Value(&num1,&num2);
			if (num2==0) {
				// 0除算
				IError(ERR_ZERO_DIVIDE);
			}
			num1%=num2;
			break;
		
		case MUL:
			fnslog("MUL");
			getInt2Value(&num1,&num2);
			num1*=num2;
			break;
		case ADD:
			fnslog("ADD");
			getInt2Value(&num1,&num2);
			num1+=num2;
			break;
		case SUB:
			fnslog("SUB");
			getInt2Value(&num1,&num2);
			num1-=num2;
			break;
		case SHR:
			fnslog("SHR");
			getInt2Value(&num1,&num2);
			if (num2<0) {
				// シフト数に負数を与えた場合は逆シフトする
				num1<<=(-num2);
			} else {
				num1>>=num2;
			}
			break;
		case SHL:
			fnslog("SHL");
			getInt2Value(&num1,&num2);
			if (num2<0) {
				// シフト数に負数を与えた場合は逆シフトする
				num1>>=(-num2);
			} else {
				num1<<=num2;
			}
			break;

		// ビット演算子
		case AND:
			fnslog("AND");
			getInt2Value(&num1,&num2);
			num1&=num2;
			break;
		case OR:
			fnslog("OR");
			getInt2Value(&num1,&num2);
			num1|=num2;
			break;
		case XOR:
			fnslog("XOR");
			getInt2Value(&num1,&num2);
			num1^=num2;
			break;

		// ↑ここまでは２項とも整数のみ ; だからgetInt2Value(&num1,&num2)を使える


		// ↓関係演算子は、実数/文字列もある
		case EQU:
		case NOTEQU:
		case SMALL:
		case LARGE:
		case SMALLEQU:
		case LARGEEQU:
		L1:;
			{ // 変数宣言用
			fnslog("関係演算子");
			type=_getType(readInternalCodeN()); // 先に比較する値の型を得ておく
			if (type==T_INT) {
				DBG_prints(";INT;");
				getInt2Value(&num1,&num2);
				switch (cal) {
					case EQU:
						nslog(@"=");
						num1=(num1==num2);
						break;	
					case NOTEQU:
						nslog(@"<>");
						num1=(num1!=num2);
						break;	
					case SMALL:
						nslog(@"<");
						num1=(num1<num2);
						break;	
					case LARGE:
						nslog(@">");
						num1=(num1>num2);
						break;	
					case SMALLEQU:
						nslog(@"<=");
						num1=(num1<=num2);
						break;	
					case LARGEEQU:
						nslog(@">=");
						num1=(num1>=num2);
						break;	
				}
			} else {
				// int以外
				DBG_prints(";INT以外");
				CMP_RESULT ret=compare2Value(type);
				switch (cal) {
					case EQU:
						nslog(@"=");
						num1=(ret==CMP_EQUAL);
						break;	
					case NOTEQU:
						nslog(@"<>");
						num1=(ret!=CMP_EQUAL);
						break;	
					case SMALL:
						nslog(@"<");
						num1=(ret==CMP_SMALL);
						break;	
					case LARGE:
						nslog(@">");
						num1=(ret==CMP_LARGE);
						break;	
					case SMALLEQU:
						nslog(@"<=");
						num1=(ret==CMP_SMALL||ret==CMP_EQUAL);
						break;	
					case LARGEEQU:
						nslog(@">=");
						num1=(ret==CMP_LARGE||ret==CMP_EQUAL);
						break;	
				}
			}
			// basicのtrueは-1だから-num1する
			num1=-num1;
			} // 変数宣言
			break;
	}
	// 結果を返す
	return (num1);
}

//--------------------------------------------------------------------------------------
