//--------------------------------------------------------------------------------------
//
// X-BASIC'
//	コンパイラ：式評価
//
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "XB.h"
#include "code2code.h"
#include <alloca.h>

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

// 式の最適化処理
// prmAdrsLen	項群先頭	a1
// sikis		式群先頭	a2
// numOfSiki0	式数		d5	最適化後の数を返す
uwPARAMTYPE Optimizer(SWord *numOfSiki0,uwCODE *sikis,PRM_ADRS prmAdrsLen[])
{	// 最適化	1208
	DBG_Func();
	
	SWord	numOfSiki=*numOfSiki0;

	DBG_printf3("prmAdrsLen=%p/sikis(%d個)=%p\n",prmAdrsLen,numOfSiki,sikis);
	
	// Optimizerは式(sikis)の並び替えをする
	//	code=*siki
	// code==CODE_SIKIの時=式には値が付属する(prmAdrsLen.adrs～len)が、それは式を並べ直した結果、定数演算であった場合のみ展開する
	// オリジナルには変数(演算子)定数でも高速化処理が入っていたが、iOS版では一切削除した
	
	uwCODE *sikis0=sikis;
	
	DBG_prints("\n式に順番付け : ");	// 1212
	int no=0;
	int i;
	for (i=0;i<numOfSiki;i++) {
		if (*sikis==CODE_SIKI) {
			*sikis=no++;	// 「値」に番号づけ	1216
		}
		DBG_printf1("$%04x,",*sikis);
		sikis++;
	}
	// これでsikisは一番後ろに移動する
	DBG_printf1(" → sikis=%p\n",sikis);
// v2.3!!
	uwCODE *sikie=sikis; // 最終+1
	
	// オリジナルでは(sp)スタックをそのまま使っている
	#define	MAX_CODESTACK	(MAX_SOUREC1LINE/2)	// 適当;ソース1行にn式記述には最低でも値n+演算子(n-1)バイトなので余裕を持って確保
	uwPARAMTYPE	*codeStack=(uwPARAMTYPE *)alloca(sizeof(uwPARAMTYPE)*MAX_CODESTACK); // スタックからメモリを動的に確保する関数(解放不要)
//	uwPARAMTYPE	codeStack[MAX_CODESTACK];
	SWord	codeStackPointer=MAX_CODESTACK;	// スタックは後ろから前に格納されるから(--してから格納)
	#define	pushCode(w)		codeStack[--codeStackPointer]=w
	#define	pushCodeN(w)	codeStack[  codeStackPointer]=w	// スタックポインタを動かさない
	#define	popCode()		codeStack[codeStackPointer++]
	#define	popCodeN()		codeStack[codeStackPointer  ]	// スタックポインタを動かさない
	DBG_printf1("\n\n最初codeStackPointer=%d\n",codeStackPointer);
	
	// 1221
	REGISTER	p;	// .l/.w単位の読み書きがあるため
	uwCODE		code;
	SLong		num1,num2;
	uwPARAMTYPE	prm1,prm2,prm0; // prm0は中間作業用
	//
	DBG_printsn("-- Optimizerループ --");
	#ifdef CORE_DEBUG
	int j;
	#endif
	SWord num=numOfSiki; // numOfSikiはループ中で変化するが、このforループの回数は変化させてはいけないから
	for (i=0;i<num;i++) { // 最適化loop:	1225
		code=*--sikis;	// 後ろから読んでいく
		DBG_printf4("-----\n%d/%d : siki(%p)=$%04x\n",i,num,sikis,code);
		// code=d6 , siki=a2 , prmAdrsLen=a1
		// codeは、代入(0x0000)の場合、番号(0x0000,0x0001～)になってる
		
		if (code<CODE_OPERATOR) {
			// 最適化_値	1230
			nslog(@"最適化_値:code=%d",code);
			p.wp=prmAdrsLen[code].adrs;	// その項の内容のアドレス	1233
			prm1=*p.wp;
			DBG_printf2("ステートメント\nprmAdrsLen=%p 値:prm1=$%04x",p.wp,prm1);
			if (_maskNo(prm1)==_CONSTANT) {	// 1235
				DBG_printsn(";定数");
				code=_type2MathType(code);	// xx00=T_型 → MATH_TYPE : これでスタック上_CONSTANTは出てこなくなる	1240
			} else {
				DBG_printsn(";定数でない");
				code=_NOT_CONST;	// 定数でない:0xff00	1237
			}
			code|=_getType(prm1);	// 型を戻す;上記2式がともに下位8ビットを0にするのでこれでいける
			// 1234
			DBG_printf2("push(--%d)=$%04x\n",codeStackPointer,code);
			pushCode(code);	// スタックに積む;値番号(<0:定数でない)+型
			continue;
		}
		
		// 最適化_演算子	1249
		uwTYPE type1;
		DBG_printsn("最適化_演算子");
		code&=~(CODE_ATRB_NOMOVE);		// 移動済み印を消す
		uwCODE cal=_getOperator(code);
		// d2=cal d6=code
		DBG_printf1("cal=$%04x\n",cal);
		switch (cal) { // 単項演算子処理
			case NOT:	// not
			case SIGN:	// minus
				// 一項演算子	1723
				DBG_printsn("単項演算子");
				prm1=popCodeN();		// スタックから取り出す	d0
				DBG_printf2("pop(%d) → $%04x\n",codeStackPointer,prm1);
				//
				type1=_getType(prm1);	// d0.b
				if (type1==T_STR) {
					// 文字列にnot/minusは使えない
					Error(ERR_MISMATCH_FORMULA_TYPE);
				}
				// 1727
				DBG_printf2("type1=$%02x(T_FLOAT=$%02x)\n",type1,T_FLOAT);
				if (type1!=T_FLOAT) {
					// int/charである	1729
					DBG_printf1("int/char prm1=$%04x\n",prm1);
					// 定数なら$00_型、// 変数なら$ff_型でくる
					if (!_isNotConstant(prm1)) {	//	(SWord)prm1>=0
						DBG_printsn("int/char一項定数");
						// 一項定数	1743
						// int/charの定数演算はコンパイラで演算してしまう
						int no=_getNo(prm1);		// 値番号
						p.wp=prmAdrsLen[no].adrs;	// その項の内容のアドレス
						p.wp++;	// CODE_SIKI.w,num.lなので、CODE_SIKIを飛ばす
						// 1748
						num1=readLong(p.lp);
						if (cal==NOT) {
							nslog(@"NOT");
							num1=~num1;
						} else { // minus
							nslog(@"負号");
							num1=-num1;
						}
						//１ずらし:	1756
						storeLong(p.lp,num1); // *p.lp=num1;	// 演算結果を入れる
						// 1758
						DBG_printf1("計算結果=%d\n",(int)num1);
						DBG_printf1("1項ずらし:numOfSiki=%d",numOfSiki);
#if 0
						memcpy(sikis,&sikis[1],&sikis0[numOfSiki+1]-&sikis[1]);
						numOfSiki--; // 1項消すから
#else	//!! v2.3	デバッグ
						numOfSiki--; // 1項消すから	d5
						memcpy(sikis,&sikis[1],(int)sikie-(int)sikis);
#endif
						#ifdef CORE_DEBUG
						DBG_printf2("→%d/i=%d\n",numOfSiki,i);
						DBG_printf("1項削除後の式:");
						for (j=0;j<numOfSiki;j++) {
							DBG_printf("$%04x,",*(sikis0+j));
						}
						DBG_printf("\n");
						#endif
						// 1765
						continue;
					} // 定数でない
					DBG_printsn("int/charだが定数でない単項演算子");
				} else {
					DBG_printsn("float1項演算子");
				#if 1	// float1項演算子の畳込み処理追加
					DBG_printf1("float prm1=$%04x\n",prm1);
					// 定数なら$00_型、// 変数なら$ff_型でくる
					if (!_isNotConstant(prm1)) {	//	(SWord)prm1>=0
						DBG_printsn("float一項定数");
						// 一項定数
						// floatの定数演算はコンパイラで演算してしまう
						int no=_getNo(prm1);		// 値番号
						p.wp=prmAdrsLen[no].adrs;	// その項の内容のアドレス
						p.wp++;						// CODE_SIKI.w,num.lなので、CODE_SIKIを飛ばす
						DOUBLE_LONG dl;
						readDOUBLE_LONG(&dl,p.dp);	// dl=*p.dp;
						if (cal==NOT) {
							dl.d=~((SLong)dl.d);
						} else { // minus
							dl.d=-dl.d;
						}
						// 1ずらし:	1756
						readDOUBLE_LONG(p.dp,&dl);	// *p.dp=dl; // 演算結果を入れる
						DBG_printf1("計算結果=%f\n",dl.d);
						//
						DBG_printf1("1項ずらし:numOfSiki=%d",numOfSiki);
						memcpy(sikis,&sikis[1],&sikis0[numOfSiki+1]-&sikis[1]);
						numOfSiki--; // 1項消すから
						#ifdef CORE_DEBUG
						DBG_printf2("→%d/i=%d\n",numOfSiki,i);
						DBG_printf("1項削除後の式:");
						for (j=0;j<numOfSiki;j++) {
							DBG_printf("$%04x,",*(sikis0+j));
						}
						DBG_printf("\n");
						#endif
						// 1765
						continue;
					} // 定数でない
				#endif
					DBG_printsn("floatだが定数でない単項演算子");
				}
				// floatまたはintでも定数でないとき	1732
				if (cal==NOT) {	// not 1738
					DBG_printsn("int化してnot");
					// notはintでのみ実行可能なので、intへの変換を指示しておく
					code=_changeType(code,T_INT);	// int 型
				} else {		// minus 1734
					DBG_printsn("負号");
					// 負号はfloatでも実行できるので型を維持する
					code=_changeType(code,type1);	// 型
				}
				// 1736/1740
				DBG_printf2("%p<-$%04x\n",sikis,code);
				*sikis=code;	// 登録
				continue;
		} // ↑単項演算子終わり

		// 二項演算子: 1257
		DBG_printsn("二項演算子");
		prm1=popCode();		// 前	d0.w
		prm2=popCodeN();	// 後	d1.w
		DBG_printf2("pop(%d++) → $%04x\n",codeStackPointer-1,prm1); // popする前のspを表示
		DBG_printf2("pop(%d)   → $%04x\n",codeStackPointer  ,prm2);
		// 次の演算は、現在のスタックから取り出される2つの数値を持って行われる。
		// ただし、2つ目は後で演算結果に書き換えられるのでスタックポインタは動かさない。
		
			   type1=_getType(prm1);	// d0.b
		uwTYPE type2=_getType(prm2);	// d1.b
		int fNotConstant1=_isNotConstant(prm1);
		int fNotConstant2=_isNotConstant(prm2);
		#ifdef CORE_DEBUG
		DBG_printf("$%04x(型:$%02x)%s : 演算=$%04x: $%04x(型:$%02x)%s\n"
					,prm1,type1,(fNotConstant1? "":";定数")
					,cal
					,prm2,type2,(fNotConstant2? "":";定数")
		);
		#endif
		
		if (type1==T_STR) {
			DBG_printsn("type1=文字列");
			if (type2==T_STR) {
				// 二項STR	1704
				DBG_printsn("type2=文字列");
				code=_changeType(code,type1);	// 型	1705
				if (cal==ADD) {		// '+'	1706
					// 1708
					*sikis=code;	// 登録	1708
					continue;		// 		1709
				}
				// 1710
				if (cal<EQU || cal>=NOT) {
					// 文字列では算術演算子、ビット演算子は使えない
					// 型違い
					Error(ERR_MISMATCH_FORMULA_TYPE);
				}
				// 1715
				code=_changeType(code,T_INT);		// int型			1715
				*sikis=code;						// 登録			1716
				pushCodeN(_notConstType(T_INT));	// 定数でないint	1717
				DBG_printf2("push(%d)=$%04x\n",codeStackPointer,_notConstType(T_INT));
				continue;	// 1718
			}
			// 型違い	1712 → 1264
			Error(ERR_MISMATCH_FORMULA_TYPE);
		}
		
		// 1267
		uwTYPE type=type1; // 一時的に書き換えるので	d3
		if (type1!=type2) {
			// 型不一致
			DBG_printsn("型不一致による調整");
			// 1270
			if (type2==T_STR) {
				// 文字列はいかなる型変換も出来ない
				Error(ERR_MISMATCH_FORMULA_TYPE);
			}
			// float:intは相互変換により処理可能にさせる
			// 1272
			if (type1!=T_FLOAT) {
				// 1274
				if (type2!=T_FLOAT) {
					// 1276
					type1=T_INT;
					type =T_INT;
				} else {
					// 1279
					type=type2;
				}
			}
		}
		
		// 型一致	1281
		DBG_printsn("型一致");
		// 演算子の下位8ビットに型を入れる(もう優先順位は必要ないので)
		code=_changeType(code,type);	//	1282
		// スタック(prm2分)上も更新				1283
		prm0=_changeType(prm2,type);
		pushCodeN(prm0);
		DBG_printf2("更新push(%d)=$%04x;下位8=型\n",codeStackPointer,prm0);
		//
		if (cal==IDIV || cal==MOD || cal>=SHR) {
			DBG_printsn("int専用演算子");
			// floatが来てる時は整数に変換して計算させるためコードを変換する
			// 1292
			nslog(@"code=$%04x->",code);
			code=_changeType(code,T_INT);		// int型専用の演算子
			nslog(@"code=$%04x",code);
			// 1283のpushを上書きする
			pushCodeN(_notConstType(T_INT));	// 定数でないint	1293	enumの中で整数演算子を使うと、これのため定数でないと判断されてエラーが出てしまう
			DBG_printf2("push(%d)=$%04x\n",codeStackPointer,_notConstType(T_INT));
		}
		// 1296
		*sikis=code;
		DBG_printf2("*sikis(%p)<-$%04x\n",sikis,code);

		// 1299
		if (!fNotConstant2 && !fNotConstant1) {
			// 両方とも定数(1304)
			DBG_printsn("両方とも定数");
			// コンパイラで演算してしまう
			if (type1==T_FLOAT || type2==T_FLOAT) {
				DBG_printsn("どちらかfloat");
				// 二項定数float(1501)
				if (cal==IDIV || cal==MOD || cal>=SHR) { // \ , mod , sh? 関係・論理
					// 二項定数float演算しない	1498
					DBG_printf1("二項定数float演算しない:cal=$%04x\n",cal);
					pushCodeN(_notConstType(T_FLOAT));	// 定数でない、float型
					DBG_printf2("push(%d)=$%04x\n",codeStackPointer,_notConstType(T_FLOAT));
					continue;	// 1500
				}
				// 1508
				if (type1==T_FLOAT) {
					// 1510
					DBG_printf1("1項目float:prm1=$%04x\n",prm1);
					pushCodeN(prm1);	// float登録
					DBG_printf2("push(%d)=$%04x\n",codeStackPointer,prm1);
				}
				// 1516
				DOUBLE_LONG dl1,dl2;
				//
				p.wp=prmAdrsLen[_getNo(prm2)].adrs;
				p.wp++;	// CODE_SIKI.w,num.lなので、CODE_SIKIを飛ばす
				if (type2==T_FLOAT) {
					// 1518
					DBG_printsn("2項目float");
					readDOUBLE_LONG(&dl2,p.dp);	// dl2=*p.dp;
				} else { // 第二項int:	1522
					DBG_printsn("2項目int");
					SLong num2=readLong(p.lp); // 符号付きにしないといけないので
					dl2.d=(double)(num2);	// 第二項
				}
				DBG_printf1("2項目=%f\n",dl2.d);
				p.wp=prmAdrsLen[_getNo(prm1)].adrs;
				p.wp++;	// CODE_SIKI.w,num.lなので、CODE_SIKIを飛ばす
				if (type1==T_FLOAT) {
					// 1534
					DBG_printsn("1項目float");
					readDOUBLE_LONG(&dl1,p.dp);	// dl1=*p.dp;
				} else { //	第一項int
					// 1538
					DBG_printsn("1項目int");
					SLong num1=readLong(p.lp); // 符号付きにしないといけないので
					dl1.d=(double)(num1);	// 第１項
				}
				DBG_printf1("1項目=%f\n",dl1.d);
				// 1545
				DBG_printf1("code=$%04x\n",code);
				switch (cal) { // float演算子処理
					case NOP:
					case IDIV:
					case MOD:
						DBG_printf1("NOP/IDIV/MOD:code=$%04x\n",code);
						break;
					
					case MUL:
						DBG_printf1("MUL:code=$%04x\n",code);
						dl1.d*=dl2.d;
						break;
						
					case DIV:
						DBG_printf1("DIV:code=$%04x\n",code);
						dl1.d/=dl2.d;
						break;

					case ADD:
						DBG_printf1("ADD:code=$%04x\n",code);
						dl1.d+=dl2.d;
						break;
						
					case SUB:
						DBG_printf1("SUB:code=$%04x\n",code);
						dl1.d-=dl2.d;
						break;
				}
				// 1568
				cal=popCodeN();
				DBG_printf2("pop(%d) → $%04x\n",codeStackPointer,cal);
				cal=_getOperator(cal);
				sikis[2]=cal;
				p.wp=prmAdrsLen[cal].adrs;
				p.wp++;	// CODE_SIKI.w,num.lなので、CODE_SIKIを飛ばす
				readDOUBLE_LONG(p.dp,&dl1); // *p.dp=dl1;
			} else { // 二項定数int
				// 両方ともint定数 1580
				DBG_printf2("両方ともint定数:prm1=%d:prm2=%d\n",_getNo(prm1),_getNo(prm2));
				// 両方ともint定数
				p.wp=prmAdrsLen[_getNo(prm1)].adrs;
				p.wp++;	// CODE_SIKI.w,num.lなので、CODE_SIKIを飛ばす
				num1=readLong(p.lp);	// 第一項
				// 1586
				p.wp=prmAdrsLen[_getNo(prm2)].adrs;
				p.wp++;	// CODE_SIKI.w,num.lなので、CODE_SIKIを飛ばす
				num2=readLong(p.lp);	// 第２項
				DBG_printf2("第1項=%d,第2項=%d\n",(int)num1,(int)num2);
				//
				switch (cal) { // 演算実行
					case NOT:
					case NOP:
						// dummy
						break;
					
					case MUL:
						DBG_printsn("MUL");
						num1*=num2;
						break;
						
					case DIV:
					case IDIV:
						DBG_printsn("I/DIV");
						if (num2==0) {
							Error(ERR_ZERO_DIVIDE);
						}
						num1/=num2;
						break;
						
					case MOD:
						DBG_printsn("MOD");
						if (num2==0) {
							Error(ERR_ZERO_DIVIDE);
						}
						num1%=num2;
						break;
						
					case ADD:
						DBG_printsn("ADD");
						num1+=num2;
						break;
						
					case SUB:
						DBG_printsn("SUB");
						num1-=num2;
						break;
						
					case SHR:
						DBG_printsn("SHR");
						// シフト数に負数を与えた場合は逆シフトする
						if (num2<0) {
							num1<<=(-num2);
						} else {
							num1>>=num2;
						}
						break;
						
					case SHL:
						DBG_printsn("SHL");
						// シフト数に負数を与えた場合は逆シフトする
						if (num2<0) {
							num1>>=(-num2);
						} else {
							num1<<=num2;
						}
						break;
						
					case EQU:
						DBG_printsn("EQU");
						if (num1==num2) {
							num1=BASIC_YES;
						} else {
							num1=BASIC_NO;
						}
						break;
						
					case NOTEQU:
						DBG_printsn("NOTEQU");
						if (num1!=num2) {
							num1=BASIC_YES;
						} else {
							num1=BASIC_NO;
						}
						break;
						
					case SMALL:
						DBG_printsn("SMALL");
						if (num1<num2) {
							num1=BASIC_YES;
						} else {
							num1=0;
						}
						break;
						
					case LARGE:
						DBG_printsn("LARGE");
						if (num1>num2) {
							num1=BASIC_YES;
						} else {
							num1=BASIC_NO;
						}
						break;
						
					case SMALLEQU:
						DBG_printsn("SMALLEQU");
						if (num1<=num2) {
							num1=BASIC_YES;
						} else {
							num1=BASIC_NO;
						}
						break;
						
					case LARGEEQU:
						DBG_printsn("LARGEEQU");
						if (num1>=num2) {
							num1=BASIC_YES;
						} else {
							num1=BASIC_NO;
						}
						break;

					case AND:// Sand
						DBG_printsn("AND");
						num1&=num2;
						break;
						
					case OR:// Sor
						DBG_printsn("OR");
						num1|=num2;
						break;
						
					case XOR:// Sxor
						DBG_printsn("XOR");
						num1^=num2;
						break;
				}
				// ２ずらし	1683
				storeLong(p.lp,num1); // *p.lp=num1; // 演算結果を書き戻す(num2の位置)
				DBG_printf1("計算結果=%d\n",(int)num1);
			}
			// ２ずらしf:	1685
			DBG_printf1("2項ずらし:numOfSiki=%d",numOfSiki);
			// 消えるのは、演算子と第1数値
			//       ↓siki0
			//「例1」8504 8504 0000 8101 0001 0002 0003
			//						↑siki +1   +2   +3
			//						+-----------+~~~~~~
			//    → 8504 8504 0000 0002 0003		8101 0001 が消える
			//
			//「例2」8504 0500 0000 0002 0003
			//			 ↑siki +1   +2   +3
			//			 +-----------+~~~~~~
			//    → 8504 0002 0003		0005 0000 が消える
			
			// 移動する領域の算出
			// 現在の項数:numOfSiki
			// 式全体  領域アドレス:sikis0   ～&sikis0[numOfSiki]
			// 移動対象領域アドレス:&sikis[2]～&sikis0[numOfSiki] → sikis
			// 前にずらす
			memcpy(sikis,&sikis[2],(int)&sikis0[numOfSiki]-(int)&sikis[2]);
			numOfSiki-=2; // 2項消すから
			#ifdef CORE_DEBUG
			DBG_printf2("→%d/i=%d\n",numOfSiki,i);
			DBG_printf("2項削除後の式:");
			for (j=0;j<numOfSiki;j++) {
				DBG_printf("$%04x,",*(sikis0+j));
			}
			DBG_printf("\n");
			#endif
		} else { // if (!fNotConstant2 && !fNotConstant1) の else
			// どちらかが定数でない	1696
			DBG_printsn("どちらかが定数でない");
			prm0=popCodeN();
			DBG_printf2("pop(%d) → $%04x\n",codeStackPointer,prm0);
			prm0=_notConstType(_getType(prm0));	// 定数でないに変更
			pushCodeN(prm0);
			DBG_printf2("push(%d)=$%04x\n",codeStackPointer,prm0);
		}
	} // for
	//
	*numOfSiki0=numOfSiki; // 最適化後の式の数を返す
	prm1=popCode();	// スタックから出す
	DBG_printf2("pop++(%d) → $%04x\n",codeStackPointer-1,prm1);
	DBG_printsn("Optimizer(End)\n\n");
	return (prm1);
}

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

// 式評価
// msType0	  = 型(MATH_*)
// kekkaSiki0 = 結果の中間コードを書き込む領域のアドレス(通常internalCode)
// len0		  = 書き込んだ長さ(バイト)
// リターン値 : 変数の型
uwMATHTYPE interpretMath(uwMATHTYPE msType0,uwCODE *(*kekkaSiki0),SLong *len0)
{	// math解釈	585

	DBG_Func();
	DBG2_printf2("要求型msType0=$%04x%s\n",msType0,(msType0==MATH_VOID? "=無指定":""));
	DBG2_printName(source,16);
	
	/* ワーク割り当て
													ワーク			 制御変数
							+-----------+		TopSikis+-----------+
	次の演算子格納位置			|sikis	.p	|--------------→| [0x100]	|sikis.w	=	[演算子.w]
							+-----------+	  TopPrmAdrs+-----------+
	次のparam格納位置			|prmAdrs.p	|--------------→| [0x100]	|prmAdrs	=	[アドレス.p+長さ.l]
							+-----------+		TopParam+-----------+					↓
							|param	.p	|--------------→| [0x100]	|param		=	パラメーターそのもの
							+-----------+				+-----------+
							|siki0	.p	|<-siki
							+-----------+
	*/	// いったんローカルに式を展開し、呼び出し側にコピーして返す
	uwCODE		TopSikis[  0x100];
	uwCODE		TopParam[  0x100];
	PRM_ADRS	TopPrmAdrs[0x100];
	// $c(a4)=kekkaSiki
	//
	uwCODE	code;
	SWord	len;
	SLong	lenL;
	int		floop;
	//
	uwCODE	 *kekkaSiki
	#ifdef CORE_DEBUG
	=*kekkaSiki0
	#endif
	;
	uwCODE	 *sikis		=TopSikis;		// uwCODE sikis[]	0(a4)	a0
	uwCODE	 *param		=TopParam;		// uwCODE param[]	8(a4)	a2
	PRM_ADRS *prmAdrsLen=TopPrmAdrs;	//  				4(a4)	a1
	int		 i			=0;				// prmAdrsLen[i]
	DBG2_printf1("kekkaSiki0=%p\n"	,kekkaSiki);
	DBG_printf1("sikis=%p\n"	 	,sikis);
	DBG_printf1("param=%p\n"	 	,param);
	DBG_printf1("prmAdrsLen=%p\n"	,prmAdrsLen);
	//
	do {	// 608
		DBG_printf1("--式評価ループ%d--\n",i);

		// OperatorCheck : not と - は先頭に有っても良い
		code=operatorCheck();	// 611
	  IM2:;
		DBG_printsn("一項演算子チェック(前側)");
#if 1	// 連続単項演算子バグ修正版
		switch (code) {	// 618～
			case CODE_SUB:	// 624
				DBG_prints("負号に変換:");
				code=CODE_SIGN;	// 負号に置き換え	624
			case CODE_NOT:	// not	626
				DBG_printf2("単項演算子:%p<-$%04x\n",sikis,code);
				*sikis++=code;	// 演算子(CODE_NOT)	628
			case CODE_ADD:	// 先頭の+は正号なので無視するだけ	618
				// 連続チェック
				{
				DBG_printsn("単項演算子連続チェック");
				UByte *source0=source;
				code=operatorCheck();
				if (code!=CODE_NONE) {
					// 演算子が続くので連続評価へ
					DBG_printsn("演算子が続くので連続評価へ");
					goto IM2;
				}
				// 演算子はないのでsourceを戻して後ろの式を評価へ
				DBG_printsn("演算子はないので後ろの式評価へ");
				source=source0;
				}
				break;
			//
			case CODE_NONE:	// 演算子なし	617
				break;
			//
			case CODE_PROGRAMEND:
				nslog(@"プログラム終了または改行がいきなり来た");		// 616
				Error(ERR_SYNTAX_FORMULA);
			//
			default:
				nslog(@"式の先頭に +/-,not 以外は使えない");
				Error(ERR_SYNTAX_FORMULA);
		}
#else
		// オリジナルと同等
		switch (code) {	// 618～
			case CODE_SUB:	// 624
				DBG_prints("単項演算子:-;負号に変換:");
				code=CODE_SIGN;	// 負号に置き換え	624
				*sikis++=code;	// 演算子		628
				break;
			case CODE_NOT:	// 620
				nslog(@"単項演算子:NOT");
				// 626
				*sikis++=code;	// 演算子(CODE_NOT)	628
				break;
			
			case CODE_ADD:	// 先頭の+は正号なので無視するだけ	618
				break;

			case CODE_NONE:	// 演算子なし	617
				break;
			//
			case CODE_PROGRAMEND:
				nslog(@"プログラム終了または改行がいきなり来た");	//616
				Error(ERR_SYNTAX_FORMULA);
			//
			default:
				nslog(@"式の先頭に +/-,not 以外は使えない");
				Error(ERR_SYNTAX_FORMULA);
		}
#endif
		DBG_printsn("式チェック");
		// 633 : 解釈loop
		SLong num;
		DOUBLE_LONG dl;
		ULong words;
		uwTYPE type=T_INT; // &型付き数字の場合のため
		switch (firstCheckSouceInLine()) {	// まず、空白を飛ばして、先頭の文字を見る。
			case EOL:
				nslog(@"改行またはプログラム終了");
				Error(ERR_SYNTAX_FORMULA);
			
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9': // 数字
			case '.': // 小数点	1018
				type=checkImmidiate();		// type = T_FLOAT/T_INT
			case '&': // 型付き数字	1014
				{
				nslog(@"定数");
				// 即値=定数指定
				num=getNumConstant(type,&dl);
				nslog(@"getNumConstant:次の1文字:source=%02x",*source);
			ENUM1: // enum定数として見つかった時はここに飛んでくる
				*sikis++=CODE_SIKI;			// 式	1026
				prmAdrsLen[i].adrs=param;	// paramの格納位置
				DBG_printf3("param=%p/prmAdrsLen[%d]=%p\n",param,i,&prmAdrsLen[i]);
				*param++=(_CONSTANT|type);	// 1033
//				words=withWord(SZ_WORD);
				if (type==T_FLOAT) {
					// 1044
					DBG_printf1("float=%.15f(15桁)\n",dl.d);	// .数値は小数点以下の桁数
//					DBG_printf1("float=%f\n",dl.d);
					DOUBLE_LONG *dp=(DOUBLE_LONG *)param;
					readDOUBLE_LONG(dp, &dl); // *dp=dl;
					words=withWord(SZ_DOUBLE_LONG);	// param書き込み長(WORD単位);dl分
					if (*source=='#') source++;
				} else {
					DBG_printf1("int=%d\n",(int)num);
					storeLong(param, num);			// *(ULong *)param=num;
					words=withWord(SZ_LONG);		// param書き込み長(WORD単位);num分
				}
				param+=words; 				// -1は最初のtype分(すでに++されているので)
				prmAdrsLen[i].lenL=words+1;	// 項の長さも記録(type+param)
				}
				// 1055
				break; // goto OperatorCheck;

			case '\'': // ' = 一文字定数	979
				DBG_printsn("一文字定数");
				source++; // 'を飛ばす
				SLong lc=getSjisOrUtf8(&source,fsjisInRun); // SHIFT-JIS
				if (*source++!='\'') {
					nslog(@"'で括られてない");
					Error(ERR_SYNTAX_FORMULA);
				}
				// iOS
				//type=T_INT;
				*sikis++	=CODE_SIKI;		// 式
				prmAdrsLen[i].adrs=param;
				DBG_printf3("param=%p/prmAdrsLen[%d]=%p\n",param,i,&prmAdrsLen[i]);
				*param++=(_CONSTANT|T_INT);	// 定数を示す
				param=(uwCODE *)storeLong(param, lc);
				prmAdrsLen[i].lenL=withWord(SZ_WORD+SZ_LONG);	// 長さ
				break; // goto OperatorCheck;
			
			case '\"': // str定数	952
				DBG_printsn("str定数");
				*sikis++	=CODE_SIKI;		// 式
				prmAdrsLen[i].adrs=param;
				DBG_printf3("param=%p/prmAdrsLen[%d]=%p\n",param,i,&prmAdrsLen[i]);
				*param++=(_CONSTANT|T_STR);	// 文字列定数を示す
				// 文字列はここではコード変換しない（print出力時に行う）
				words=sourceStringCopy((UByte *)param);	// (source)"～" を (param) に書き移す ; wordsは.w単位
				DBG_printName((UByte *)param,words*SZ_WORD);
				param+=words;
				DBG_printf2("～param=%p(len=%d.w)\n",param,(int)words);
				prmAdrsLen[i].lenL=withWord(SZ_WORD)+words;	// 長さ
				break; // goto OperatorCheck;
			
			case '(': // 括弧がついてる＝関数/配列/()内式	654
				// 657
				DBG2_printf1("(がある:source=%p\n",source);
				DBG_printsn("関数/配列/()内式による再帰呼び出し\n");
				source++; // '('を飛ばす	658
				#ifdef CORE_DEBUG
				uwCODE *param0=param;
				#endif
				prmAdrsLen[i].adrs=param; // ここから格納する
				DBG_printf3("param=%p/prmAdrsLen[%d]=%p\n",param,i,&prmAdrsLen[i]);
				interpretMath(MATH_VOID,&param,&lenL); // paramは移動する	再帰	661
				#ifdef CORE_DEBUG
				DBG_printf("()内式解釈終了:param=%p～%p(%zu:lenL=%d)\n\n",param0,param,calcAdrsOffset(param,param0),(int)lenL);
				#endif
				*sikis++=CODE_SIKI;	// 式
				prmAdrsLen[i].lenL=withWord(lenL);
				//
				// 括弧がちゃんと終わっているか？
				if (*source++!=')') {
					nslog(@"')'で終わってない");
					Error(ERR_SYNTAX_FORMULA);
				}
				break; // goto OperatorCheck;
				
			default:	// 684
				DBG_printsn("その他(関数/変数)");
				// ハッシュ値を計算しながら、文字数を数える
				uwHash hash;
				UByte *name=source;
				UByte c=calcHash(source,&len,&hash,&source);	// 687
				DBG_printName(name,len);
				if (len<=0) {
					// ここに来るのは、関数で引数があるべきところにないとき
					Error(ERR_NOT_ENOUGH_FUNC_PARAM);
				}
				double fnum;
				int fenum;
				if (getEnum(name,hash,len,&num,&fnum,&fenum)) {
					nslog(@"enum定数として見つかった");
					switch (fenum) {
						case ENUM_INT:
							dl.l[LL]=num;
							dl.l[HL]=0;
							type=T_INT;
							break;
						case ENUM_FLOAT:
							dl.d=fnum;
							type=T_FLOAT;
							break;
					}
					goto ENUM1;
				}
				// 関数/変数のチェック
				uwRETURNTYPE rettype=FuncNotFound; // 変数かどうかチェックへ飛ばすため
				uwCODE 	*paramTable;
				swVarCNT paramCnt;
				swFuncNO fno;
				uwPARAMTYPE prmType=PARAM_INT; // 警告回避のため
				if (c=='(') { // 関数	701
					DBG2_printsn("関数チェック");
					rettype=functionCheck(name,hash,len,&paramCnt,&paramTable,&fno);	// 707
				}
				switch (rettype) {
					case FuncNotFound: // 該当関数なし
						// 変数かどうかチェック:	778
						{ // 変数宣言用
						swVarNO no;
						sbVarSTAT stat;
						DIM1 *dimInfo;
						DBG_printsn("変数チェック");
						uwMATHTYPE msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);
						switch (msType) {
							case MATH_NONE:
								// 未宣言変数
								nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
								Error(ERR_UNDEFINED_VARIABLE);
							//
							case MATH_STR:
								if (*source!='[') break; // 普通変数参照判定へ
								// 文字列ポインタ	898
								source++; // '['を飛ばす
								if (stat&VARIABLE_DIM) {
									nslog(@"配列が来ている");
									Error(ERR_SYNTAX_FORMULA);
								}
								if (stat&VARIABLE_SYSTEM) {
									nslog(@"system変数が来ている");
									Error(ERR_SYNTAX_FORMULA);
								}
								
								prmType=(CODE_ATRB_STR|CODE_ATRB_VARIABLE)|T_CHAR; // グローバル
								if (_isStatLocal(stat)) { // ローカル
									prmType|=CODE_ATRB_LOCAL;
								}
								//
								*sikis++=CODE_SIKI;			// 式
								prmAdrsLen[i].adrs=param;	// a1
								DBG_printf3("param=%p/prmAdrsLen[%d]=%p\n",param,i,&prmAdrsLen[i]);
								*param++=prmType;			// 922 a2	????
								DBG_printsn("文字列ポインタによる再帰呼び出し");
								interpretMath(MATH_INT,&param,&lenL); // 再帰	929
								*param++=no;			// 変数番号
								if (*source++!=']') {	// 括弧がちゃんと終わっているか？
									nslog(@"']’で閉じてない");
									Error(ERR_SYNTAX_FORMULA);
								}
								lenL/=SZ_WORD;
								lenL+=2;					// .w*2=prmType+no分
								prmAdrsLen[i].lenL=lenL;	// param書き込み長さ(.w単位)
								//
								goto OperatorCheck;
						} // switch (msType)
						
						// 普通変数参照判定		803
						if (!(stat&VARIABLE_DIM)) {
							// 普通の変数参照	874
							DBG_printsn("普通変数");
							*sikis++	=CODE_SIKI;		// 式
							prmAdrsLen[i].adrs=param;
							DBG_printf3("param=%p/prmAdrsLen[%d]=%p\n",param,i,&prmAdrsLen[i]);
							//
							prmType=CODE_ATRB_VARIABLE|_mathType2Type(msType);	// 変数を示す | MATH_* → T_*
							if (_isStatLocal(stat)) {	// ローカル
								prmType|=CODE_ATRB_LOCAL;
							}
							*param++=prmType;
							*param++=no;
							prmAdrsLen[i].lenL=2;	// .w*2=prmType+no分
							DBG_printf2("変数:番号=%d,CODE_ATRB=$%04x\n",no,prmType);
						} else {
							// 配列の場合	807
							DBG_printsn("配列");
							//
							*sikis++=CODE_SIKI;		// 式
							prmAdrsLen[i].adrs=param;
							DBG_printf3("param=%p/prmAdrsLen[%d]=%p\n",param,i,&prmAdrsLen[i]);
							//
							// dimInfo = その配列情報
							prmType=_mathType2Type(dimInfo->msType);			// 型(MATH_*→T_*)
							prmType|=(CODE_ATRB_VARIABLE|CODE_ATRB_POINTER);	// 配列を示す
							if (_isStatLocal(stat)) { // ローカル
								prmType|=CODE_ATRB_LOCAL;
							}
							*param++=prmType;	// [配列の印 ＋ 型]
							*param++=no;		// 配列番号
							//
							DBG_printf2("配列:番号=%d,型=$%04x\n",no,prmType);
							//
							if (*source!='(') { // 833
								nslog(@"'('がない");
								Error(ERR_SYNTAX_FORMULA);
							}
							
							len=0;	// 要素数情報の長さ
							swJigen jigen=dimInfo->jigen;	// 次元
							while (jigen-->0) {
								source++; // 最初は(、後は,を飛ばす
								DBG_printsn("要素数による再帰呼び出し");
								interpretMath(MATH_INT,&param,&lenL); // 再帰	843
								len+=lenL;
								// 要素数は,で区切られる
								if (*source!=',') {
									if (jigen>1) { // まだ必要なのにもう指定がない
										// 添え字の個数が少ない
										Error(ERR_ARRAY_COUNT_NOT_ENOUGHT);
									}
									break; // 848
								}
								// ==','
								if (jigen==0) {
									// 最後の次元分まで読んだのにまだ , があるとき
									DBG_printsn("最後の次元分まで読んだのにまだ , がある");
									// 添え字の個数が多い
									Error(ERR_ARRAY_COUNT_TOO_MUCH);
								}
							}
							if (*source++!=')') { // 854
								nslog(@"')'で終わってない");
								Error(ERR_SYNTAX_FORMULA);
							}
							len+=(SZ_WORD*2);	// prmType+no
							prmAdrsLen[i].lenL=withWord(len);	// 長さ(.w単位)
						}
						} // 変数宣言用
						goto OperatorCheck;
					
					// 728あたり
					case VOID_RET: // void
						Error(ERR_VOID_HAS_NO_RETURN_VALUE);
					
					case FLOAT_RET: // float関数
						prmType=CODE_ATRB_FUNC|T_FLOAT;
						break;	// 関数の処理へ
					case INT_RET: // int関数
						prmType=CODE_ATRB_FUNC|T_INT;
						break;	// 関数の処理へ
					case CHAR_RET: // char関数
						prmType=CODE_ATRB_FUNC|T_CHAR;
						break;	// 関数の処理へ
					case STR_RET: // str関数
						prmType=CODE_ATRB_FUNC|T_STR;
						break;	// 関数の処理へ
					
					default:
						// 念のため
						nslog(@"interpretMath");
						Error(ERR_SYSTEM);
				} // switch (rettype)
				// ↑で*_ret以外のcaseで処理されたものは、ここには来ない(OperatorCheckへ飛ぶから)
				// ここ来るのは_retのみのはず
				
				// 関数の処理(742)
				DBG_printsn("\n～～～～～関数の引数部解釈");
				*sikis++  =CODE_SIKI;		// 式
				prmAdrsLen[i].adrs=param;	// a3
				*param++  =prmType;			// 関数印＋型
				DBG_printf2("param=%p<-code:$%04x\n",param,prmType);
				//
				len=interpretFunctions(param,paramTable,paramCnt,fno);	// 756
				//
				DBG_printsn("関数の引数部解釈終了");
				len+=SZ_WORD;	// prmType分
				prmAdrsLen[i].lenL=withWord(len);	// .w単位
				param+=withWord(len);
				#ifdef CORE_DEBUG
				DBG_printf("パラメーター数:%d個\nパラメーター\n",(int)prmAdrsLen[i].lenL);
				{
				uwCODE *sikis0=prmAdrsLen[i].adrs;
				int j;
				for (j=0;j<prmAdrsLen[i].lenL;j++) {
					DBG_printf("%p : $%04x\n",sikis0,*sikis0);
					sikis0++;
				}
				}
				DBG_printf("\n");
				#endif
				break; // goto OperatorCheck;
		}
	OperatorCheck:
		// 後に演算子が続くか
		nslog(@"後に演算子が続くか:次の1文字=%02x",*source);
		// 演算子チェック 1066
		code=operatorCheck();
		floop=YES;
		switch (code) {
			case CODE_PROGRAMEND:
			case CODE_NONE:
				// 数式コード化終了	1074
				nslog(@"数式コード化終了:次の1文字=%02x",*source);
				floop=NO;
				break;
			
			case CODE_NOT: // 1076
				nslog(@"CODE_NOT");
				Error(ERR_SYNTAX_FORMULA);
			
			default: // 1078
				nslog(@"継続:%p<-$%04x\n",sikis,code);
				*sikis++=code;
				break;
		}
		// 演算子ではないかプログラム終了なら並べ替えへ(ループ終了)
		i++;
	} while (floop); // 演算子があるときはループを回る
	// ここの時点でループ回数=i
	// =prmAdrs[]の格納数!=numOfParams
	// なぜなら、１つのprmAdrsに.lenワード分管理されるから
	// 基本的に、再帰呼び出しがない限り１ループで１つの項が解釈される
	// 再帰呼び出しがあった場合は、１ループで複数の項が解釈される
	
	// 演算子優先順位による並べ替え	1095
	uwCODE *sikis0;
	SWord numOfSiki=withWord(calcAdrsOffset(sikis,TopSikis)); // 格納した式の数

#ifdef CORE_DEBUG
	{
	// 読み取り結果の表示
	DBG_printf("読み取り結果\nnumOfSiki=%d : ",numOfSiki);
	int j;
	sikis0=(uwCODE *)TopSikis;
	for (j=0;j<numOfSiki;j++) {
		DBG_printf("$%04x,",*sikis0);
		sikis0++;
	}
	//
	DBG_printf("\nTopParam=%p～param=%p\n",TopParam,param);
	SWord numOfParams=withWord(calcAdrsOffset(param,TopParam)); // 格納したパラメーターの数
	DBG_printf("numOfParams=%d\n",numOfParams);
	sikis0=(uwCODE *)TopParam;
	for (j=0;j<numOfParams;j++) {
		DBG_printf("%p\t$%04x\n",sikis0,*sikis0);
		sikis0++;
	}
	//
	DBG_printf("TopParamAdrs=%p/%d個\n",TopPrmAdrs,i);
	PRM_ADRS *prmAdrs0=(PRM_ADRS *)TopPrmAdrs;
	DBG2_dump2("prmAdrs",prmAdrs0,numOfParams*sizeof(PRM_ADRS),"a");
	for (j=0;j<i;j++) {
		DBG_printf("%p(%d)\n",prmAdrs0[j].adrs,(int)prmAdrs0[j].lenL);
	}
	}
#endif

// siki=*a4.lp	a1
//	xb.xでは1100行でd4=6;=numOfSiki-1になってる

	DBG_printsn("演算子優先順位による並べ替え");	// 1095
	SWord num=numOfSiki;
	if (--num>0) {	// １つの時は処理しなくて良いから V2.3!!
		// 式がある時
		do {	//	並べ替えloop:	1105
			code=*--sikis;	// 後ろから読む
			// a1=siki , d2=code
			DBG2_printf1("{$%04x}",code);
			if (_isDainyu(code)) {	// 代入式2	1107
				DBG2_printsn("代入2なので飛ばす");
				continue;
			}
			switch (code) {
				case CODE_SIKI:	// 代入式	1107
					DBG2_printsn("代入なので飛ばす");
					continue;
				case CODE_NOT:	// not		1108
					DBG2_printsn("notなので飛ばす");
					continue;
				case CODE_SIGN:	// 負号		1110
					DBG2_printsn("負号なので飛ばす");
					continue;
			}
			// 以外の時；２項演算子の時	1113
			DBG2_printsn("2項演算子の入れ替え");
			// d3=d4=num
			sikis0=sikis;			// 1113	a0=sikis0
			for (i=0;i<num;i++) {	// 1115	移動loop
				uwCODE code0=*--sikis0;	// 1116	code0:d1=-(a0:siki0)
				if (code0!=CODE_SIKI) {
					if (code0&CODE_ATRB_NOMOVE) {
						// 移動後のものは抜かさない
						DBG2_printsn("移動後のものは抜かさない");
						goto MOVE_END;
					}
					// d1=code0 > d2=code :: d1>d2 goto MOVE_END
					DBG_printf2("優先順位0=%d,優先順位1=%d\n",_getPriority(code0),_getPriority(code));
					if (_getPriority(code0)>_getPriority(code)) {
						// 優先順位比較
						DBG2_printsn("優先順位比較により抜かさない");
						goto MOVE_END;
					}
				} // 代入式は無条件でずれる 
				DBG2_printf1("←→$%04x",code0);
				*(sikis0+1)=code0;	// 1つ前に入れる
			} // for
			// 1125
			sikis0--;
		MOVE_END:; // 1126
			*(sikis0+1)=(code|CODE_ATRB_NOMOVE); // もう動かさない
		} while (--num>0); // while
	}	// V2.3!!

	// ここでの並び結果はXB.Xと一致している
#ifdef CORE_DEBUG
	{
	DBG_printf("入れ替え結果\n");
	int j;
	sikis0=(uwCODE *)TopSikis;
	for (j=0;j<numOfSiki;j++) {
		DBG_printf("$%04x,",*(sikis0+j));
	}
	DBG_printf("\n\n");
	}
#endif
	
	// 展開	1138
	DBG_printsn("最適化&展開");
	// 先頭から読み直すため
	// a3=*kekkaSiki0
	// 最適化
	sikis=(uwCODE *)TopSikis;
	uwMATHTYPE msTypeS=_type2MathType(Optimizer(&numOfSiki,sikis,TopPrmAdrs));
	
	// 最適化の結果得られる型と指定の型が一致するかどうかを調べる
	DBG_printf2("最適化結果型比較:リターン値=$%04x,指定=$%04x\n",msTypeS,msType0);
	if (msType0==MATH_VOID) { // 1147
		// 1149
		msType0=msTypeS;
	} else {
		// 1151
		if (msType0!=msTypeS) {
			// 1154
			if (msTypeS==MATH_STR || msType0==MATH_STR) {
				DBG_printsn("ERR_MISMATCH_FORMULA_TYPE");
				Error(ERR_MISMATCH_FORMULA_TYPE);
			}
		}
	}
	// 1160
	DBG_printf1("最適化結果展開(interpretMath):numOfSiki=%d\n",numOfSiki);
	kekkaSiki=*kekkaSiki0;
	len=0;
	while (numOfSiki-->0) {	// 1161
		uwCODE code0=*sikis++; // d1=(a2)+
		DBG_printCode(code0);
		if (code0<CODE_OPERATOR) { // ステートメントである	1166
			DBG_prints("ステートメント:");
			param =prmAdrsLen[code0].adrs;	// 項の内容のアドレス
			lenL  =prmAdrsLen[code0].lenL;	// 項の長さ (w単位)
			DBG_printf2("param=%p(%d)\n",param,(int)lenL);
			len+=(SWord)lenL;
			while (lenL-->0) {	// 1171,1173
				DBG_printf1("[%p",kekkaSiki);
				*kekkaSiki++=*param++;	// 1172
				DBG_printf1("<-$%04x]\n",*(param-1));
			}
		} else {
			// 演算子	1177
			// 演算子は、Optimizer()の中で演算子|優先順位が演算子|型に書き換えられている
			DBG_prints("演算子:");
			DBG_printf1("[%p",kekkaSiki);
			*kekkaSiki++=_getType(code0);		// 型
			*kekkaSiki++=_getOperator(code0);	// 演算子
			len+=2;		// 長さ (単位・ワード)
			DBG_printf2("<-型:$%04x,番号:$%04x]\n",_getPriority(code0),_getOperator(code0));
		}
	}
	len*=SZ_WORD;	// 長さをb単位にする
	// リターン値
	*kekkaSiki0=kekkaSiki;
	if (len0!=NULL) *len0=len;
	DBG_printf1("----------------%s(end)\n\n",__FUNCTION__); // １行開ける
	return (msType0);
}

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

// 関数の解釈
// siki0	結果書き込み先アドレス
// param	パラメーターテーブル
// cnt		引数の個数
// fno		関数番号
// リターン値：書き込んだ長さ
ULong interpretFunctions(uwCODE *siki,UWord *param,swVarCNT cnt,swFuncNO fno)
{	// function解釈 1916
	nslog(@"\n-----%s",__FUNCTION__);

	#ifdef CORE_DEBUG
	UWord *siki0;
	DBG_printf("処理前siki=%p\n",siki);
	siki0=siki; // 初期位置
	nslog(@"func(%d);param=%p～%d個 : ",fno,param,cnt);
	int i;
	for (i=0;i<cnt;i++) {
		nslog(@"$%04x,",*(param+i));
	}
	nslog(@"(=PARAM_*)\n");
	#define	storeSiki(code)	nslog(@"[%p<-$%04x]\n",siki,code),*siki++=(code)	// 式の２重評価に注意
	#else	// 本番
	#define	storeSiki(code)	*siki++=(code)
	#endif

	storeSiki(cnt);			// 引数の個数
	ULong bytes=SZ_WORD;	// 書き込んだ長さ(最初)

	// 引数解釈
	#ifdef CORE_DEBUG
	int j=0;
	#endif
	UByte c;
	while (1) {	// 1934
		#ifdef CORE_DEBUG
		nslog(@"\n引数%d個目:",j);
		j++;
		#endif
		
		if (*source!=')') {	// 1935
			source++;	// '(' または ','	1937
		}
		
		// 1940
		// まず、空白を飛ばして、先頭の文字を見る
		c=firstCheckSouceInLine();	// 1941
		//
		uwPARAMTYPE prm=*param++;	// 1946	a2=param
		nslog(@"prm=$%04x(PARAM_*)\n",prm);
		if (prm&PARAM_RETURN) {
			// リターン値だった
			break; // cに文字が入ってる
		}
		
		swStrLEN	len;
		uwHash		hash;
		UByte		*name;
		sbVarSTAT	stat;
		DIM1		*dimInfo;
		swVarNO		no;
		
		if (prm==PARAM_ARRAYext) {	// 配列拡張	1948
			// 拡張配列の引き数	2077
			nslog(@"拡張配列");
			name=source;
			calcHash(source,&len,&hash,&source);	// 2079
			DBGprintName(name,len);
			if (len<=0) {
				Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
			}
			// 2084
			uwMATHTYPE msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);
			if (msType==MATH_NONE) {
				// 未宣言配列	2096
				Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
			}
			
//			nslog(@"dim.mstype=$%04x",dimInfo->msType);
//			nslog(@"dim.jigen =%d",dimInfo->jigen);
//			for (int i=0;i<dimInfo->jigen;i++) {
//				nslog(@"次元%d=%d",i,dimInfo->youso[i]);
//			}
			
			if (!(stat&VARIABLE_DIM)) {
				// 引数がおかしい(配列でない)	2098
				Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
			}
			// 2101
			uwMATHTYPE msType2=*param++;		// 型＋次元		2101
			swJigen jigen=_getJigen(msType2);	// 次元			2103
			msType2=getMathType(msType2);		// 型(MATH_*)	2104
			nslog(@"要求次元=%d,要求型=$%04x",jigen,msType);
			nslog(@"存在次元=%d,存在型=$%04x\n",dimInfo->jigen,msType2);
			if (msType!=msType2) {	// 2106
				// 型が合わない
				Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
			}
			if (jigen!=dimInfo->jigen) {	// 2108
				// 次元が合わない
				Error(ERR_MISMATCH_ARRAY_DIMENSION_AT_PARAM);
			}
			
			msType=(CODE_ATRB_VARIABLE|_mathType2Type(msType));	// 配列の引き数	2111
			if (_isStatLocal(stat)) {
				msType|=CODE_ATRB_LOCAL;	// local 配列の引き数
			}
			storeSiki(msType);	// 引数情報
			storeSiki(no);		// 配列/変数番号
			bytes+=(SZ_WORD*2);	// 上記2つは各.w
			//
			// V2.3
			// 要素数に0が入っているときは、関数の引数として配列が与えられている時である(それ以外では要素数0の配列は作れないから)
			// この引数配列は、呼び出し側によって要素サイズが変化するため、ここではサイズチェックを飛ばす
			UWord yousoFlag=*param++;
			nslog(@"yousoFlag=$%04x\n",yousoFlag);
			int i=0;
			if (dimInfo->youso[0]==0) {
				nslog(@"引数配列である");
				while (jigen-->0) {
					nslog(@"%d. *param=%d:youso=%d\n",i,*param,dimInfo->youso[i]);
					// 要素数比較は飛ばす
					i++;
					param++;
				}
			} else {
				nslog(@"引数配列ではない");
				// 配列の要素数指定フラグの確認
				// bit15=1次元目～bit6=10次元目
				while (jigen-->0) {
					nslog(@"%d. *param=%d:youso=%d\n",i,*param,dimInfo->youso[i]);
					yousoFlag<<=1; // bit=1ならその次元が使われている
					if (yousoFlag&bit(15)) {
						// 配列の要素数指定の大きさがあればチェック
						if (*param!=dimInfo->youso[i]) {
							// 配列の要素数が合わない
							nslog(@"配列の要素数が合わない");
							Error(ERR_MISMATCH_ARRAY_COUNT_AT_PARAM);
						}
					}
					i++;
					param++;
				}
			}
			continue;
		}
		
		//--------------------------
		
		if (prm&PARAM_OMIT) {	// 1953
			// 省略可能な引き数	1955
			if (c==',' || c==')') {
				// 引き数省略:
				DBG_printsn("引数省略");
				storeSiki(CODE_ATRB_NONE);
				bytes+=SZ_WORD;
				continue;
			}
		}

		// 1961
		// 配列とポインターはほぼ共通処理なので、フラグで処理を分ける
		enum {
			AP_ANOTHER=0,
			AP_ARRAY,		// 1
			AP_POINTER,		// 2
		};
		DBG_printf4("prm=$%04x;PARAM_ARRAY1=$%04x,PARAM_ARRAY2=$%04x,PARAM_POINTER=$%04x\n",prm,PARAM_ARRAY1,PARAM_ARRAY2,PARAM_POINTER);
		int fArrayPointer=AP_ANOTHER;
		// 配列はPARAM_POINTERも持っているが、PARAM_ARRAY?優先
		if ((prm&(PARAM_ARRAY2|PARAM_ARRAY1))!=0) fArrayPointer=AP_ARRAY;
		else
		if (prm&PARAM_POINTER) fArrayPointer=AP_POINTER;
		//
		DBG_printf1("fArrayPointer=%d\n",fArrayPointer);
		
		if (fArrayPointer!=AP_ANOTHER) {
			// 配列/ポインタの引き数	2140
			// ということは、必ず「代入出来る」変数名を指定してるはず
			DBG_printsn("配列/ポインタ引数");
			name=source;
			calcHash(source,&len,&hash,&source);	// 2145
			DBG_printName(name,len);
			if (len<=0) { // 2146
				Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
			}
			
			uwMATHTYPE msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);	// 2150
			if (msType==MATH_NONE) {
				// 未宣言配列
				Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
			}
			uwTYPE type=_mathType2Type(msType);
			
			if (fArrayPointer==AP_ARRAY) { // 配列の時
				DBG_printsn("配列引数");
				if (!(stat&VARIABLE_DIM)) {
					// 引数がおかしい(配列でない)
					Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
				}
				switch (dimInfo->jigen) { // 指定された配列の次元
					case 1:
						// 1次元の時
						if (!(prm&PARAM_ARRAY1)) {
							// パラメーターの次元が1次元でなかったらエラー
							Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
						}
						break;
					case 2:
						if (!(prm&PARAM_ARRAY2)) {
							// パラメーターの次元が2次元でなかったらエラー
							Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
						}
						break;
					default:
						// 3次元以上の配列は駄目
						Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
				}
				//
				type|=CODE_ATRB_VARIABLE;	// 配列の引き数
			} else { // ポインタの時
				DBG_printsn("ポインタ引数");
				if (stat&VARIABLE_DIM) {
					// 引数がおかしい(配列が来ている)
					Error(ERR_PARAM_ILLEGAL_IN_FUNCTION);
				}
				//
				type|=CODE_ATRB_VARIABLE|CODE_ATRB_POINTER;	// ポインタの引き数
			}
			checkParamType(prm,msType);
			//
			if (_isStatLocal(stat)) {
				type|=CODE_ATRB_LOCAL;	// local 配列/ポインタの引き数
			}
			storeSiki(type);	// 引数情報
			storeSiki(no);		// 配列/変数番号
			bytes+=(SZ_WORD*2);	// 上記2つ分
		} else { // その他
			// 1968
			DBG_printsn("その他引数");
			uwTYPE pType=setLocalVarCtrlFromBit(prm,NULL);
			DBG_printf2("prmType=$%04x,pType=$%04x\n",prm,pType);
			if (pType==0) {
				Error(ERR_ILLEGAL_PARAM_IN_EXTERNAL_FUNCTION);
			}
			storeSiki(pType);	// 1992
			bytes+=SZ_WORD;		// 2993
			
			#ifdef CORE_DEBUG
			DBG_printsn("interpretFunctions → interpretMath start");
			UWord *siki1=siki;
			DBG_printf2("siki=%p,bytes=%d\n",siki,(int)bytes);
			#endif
			
			// pTypeは_PARAM|T_*なのだが、<<8すると_PARAMが消えるのでMATH_*に変換できる
			SLong lenL;
			interpretMath(_type2MathType(pType),&siki,&lenL);	// 2005
			
			#ifdef CORE_DEBUG
			DBG_printf("interpretMath内 siki=%p～%p(%zu:lenL=%d)\n",siki1,siki,calcAdrsOffset(siki,siki1),(int)lenL);
			DBG_printsn("interpretFunctions<-interpretMath end");
			#endif
			bytes+=lenL;	// 2009
		}
	}
	// fnc_loop_end	2190
	if (c!=')') {
		Error(ERR_TOO_MUTCH_FUNC_PARAM);
	}
	source++; // ')'を飛ばす
	
	storeSiki(fno);	// 関数番号
	DBG_printf1("関数番号=%d\n",fno);
	bytes+=SZ_WORD;	// 書き込んだ長さ

	#ifdef CORE_DEBUG
	DBG_printf("siki=%p～%p(%zu:bytes=%d)\n",siki0,siki,calcAdrsOffset(siki,siki0),(int)bytes);
	#endif
	
	DBG_Func2("(end)");
	
	return (bytes);
}

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