//--------------------------------------------------------------------------------------
//
// X-BASIC'
//	コンパイラ：ステートメント
//
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "XB.h"
#include "code2code.h"
#include "libs.h"
#include <ctype.h>

static int fend=NO;	// endがあったかどうか

//--------------------------------------------------------------------------------------
// 各制御構文
//--------------------------------------------------------------------------------------
// ジャンプ系
//-----------------------------------------------

void S_Gosub(uwCODE code)
{
	DBG_Func();
	Error(ERR_NON_SUPPORT_STATEMENT);	// 未サポート
}

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

void S_Goto(uwCODE code)
{
	DBG_Func();
	
	storeInternalCode(code);	// 中間コード書き込み
	
	UByte c=*source;
	if (isdigit(c)) {
		// 行番号でgotoしようとしてる
		// iOS版では行番号はサポートしない
		Error(ERR_NON_SUPPORT_STATEMENT);
	}
	DBG2_printf2("次の文字=%c[$%02x]\n",c,c);
	int			fquart=NO;
	swLabelNO	labelNo=0; // 警告回避のため
	UByte		*name;
	swStrLEN	len;
	uwHash		hash;
	switch (c) {
		case '"': // "label_quote"
			fquart=YES;
		case '*': // *label_star	// オリジナルではこの書き方はエラーになる
			source++;
		default: // label
			// ラベルは前方参照=goto labelが先に出てくる時があるので、ここで未定義の場合は定義する
			// 当然、定義済みの場合はそれを使うだけ
			// 二重定義のチェックはしない
			labelHash(&len,&hash,&name); // ラベル用ハッシュ値計算
			DBG_prints("飛び先ラベル:");
			DBG_printName(name,len);
			labelNo=labelCheckAndDefine(name,len,FLABEL_GOTO,NULL);
			if (fquart) {
				DBG_printsn("\"ラベルの時の閉じチェック");
				c=*source++;
				DBG_printf2("ラベル直後の文字=%c[$%02x]\n",c,c);
				if (c!='"') {
					DBG_printsn("\"でくくられてない？");
					Error(ERR_SYNTAX_LABEL);
				}
			}
			break;
	}
	// ここではgotoBuffCtrlに飛び先を書くべきアドレスを登録するだけで、
	// 実際にそのアドレスに飛び先を書き込むのは、コンパイル終了時にdeterminGotoAdrs()で行う
	// LabelNoはラベルとして定義された順なので、gotoの出てくる順番ではない(要注意)
	DBG_printf2("gotoBuffCtrl<-%d:%p\n",labelNo,internalCode.wp);
	GOTO_CHAIN goto1={labelNo,internalCode.wp};	// 飛び先書き込みアドレス
//	addValueForBufferNoRedundant(&gotoBuffCtrl,&goto1);
	addValueForBuffer(&gotoBuffCtrl,&goto1);
//	dumpBuffer(&gotoBuffCtrl, YES);
	storeInternalCodeP(SZ_VOIDP);	// 飛び先アドレスを後で書き込む場所分飛ばしておく;とりあえず直後の位置を書いておく
}

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

// goto=fromAdrs と 飛び先=toAdrs の間に func がないかどうか調べる
// あったらエラーが発生する
static
void gotoBlockCheck(uwCODE *fromAdrs,uwCODE *toAdrs)
{
	DBG_Func();
	DBG_printf2("元%p～%p間\n",fromAdrs,toAdrs);
	
	SWord cnt=InternalFunctionCount;
	DBG_printf1("内部関数数=%d\n",cnt);
	if (cnt>0) {
		if (fromAdrs>=toAdrs) {
			// 大小関係が逆になる時は入れ替える
			uwCODE *adrs=fromAdrs;
			fromAdrs=toAdrs;
			toAdrs=adrs;
		}
		DBG_printf2("from:%p → to:%p\n",fromAdrs,toAdrs);
		int i=0;
		while (cnt-->0) {
			FUNCTION1 *funcs=&InternalFunctionBuffer[i];
			DBG_printf2("%d:%p\n",i,funcs->exec.func); // i++されてるから
			i++;
			uwCODE *up=(uwCODE *)funcs->exec.func;	// 内部関数の実行アドレス
			if (up>=fromAdrs && up<=toAdrs) {
				// from～toの間にfunc宣言がある
				// 関数ブロックの外に飛び出した
				Error(ERR_GOTO_OUTOF_FUNC);
			}
		}
	}
}

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

// Goto飛び先アドレス確定 770
void determinGotoAdrs(void)
{
	DBG_Func();
	
	int cnt=gotoBuffCtrl.cnt;
	DBG_printf1("飛び先登録数:%d\n",cnt);
	
	for (int i=0;i<cnt; i++) {
		GOTO_CHAIN *gotoChain=(GOTO_CHAIN *)getValueFromBuffer(&gotoBuffCtrl,i);

		// LabelNoはラベルとして定義された順なので、gotoとして出てくる順番ではない(要注意)
		slLabelNO labelNoL=gotoChain->no;	// ラベル番号
		uwCODE   *fromAdrs=gotoChain->jump;	// 飛び先書き込みアドレス
		
		LABEL_CHAIN *labelChain=(LABEL_CHAIN *)getValueFromBuffer(&labelBuffCtrl, (int)labelNoL);
		uwCODE *toAdrs=labelChain->lineAdrs;
		
		DBG_printf3("ラベル(%d):%p→%p\n",(int)labelNoL,fromAdrs,toAdrs);
		
		// goto=fromAdrs と 飛び先=toAdrs の間に func がないかどうか調べる
		gotoBlockCheck(fromAdrs,toAdrs);
		
		// 相対アドレスに変換
		uwCODE *ofst=calcAdrsOffset(toAdrs,fromAdrs);
		DBG_printf1("相対アドレス=%p\n",ofst);
		mmemcpy(fromAdrs, &ofst, SZ_VOIDP); // *((uwCODE *)*)fromAdrs=ofst;
	}
	DBG_printsn("gotoバッファーダンプ");
//	dumpBuffer(&gotoBuffCtrl, YES);
	DBG_Func2("(end)");
}

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

void S_Return(uwCODE code)
{
	DBG_Func();
	if (!operationStatus.flocal) {
		// ローカル中でない
		Error(ERR_NO_FUNC_TO_ENDFUNC_OR_RETURN);
	}
	if (*source=='(') {
		source++;
		if (firstCheckSouceInLine()==')') {
			// return()だった
			source++;
		} else {
			// リターン値がある
			storeInternalCode(code);		// 中間コード書き込み
			storeInternalCode(returnType);	// リターン値の型
			//
			interpretMath(_type2MathType(returnType),&internalCode.wp,NULL);	// MATH_*にして解釈させる
			//
			if (*source++!=')') {
				// )が閉じてない
				Error(ERR_SYNTAX_RETURN);
			}
			return;
		}
	}
	
	// リターン値指定はない
	if (returnType!=T_INT) {
		// リターン値はint型以外なのに指定がない
		Error(ERR_RETURN_NON_INT);
	}
	// int型の時は、実は指定が省略されているのがvoidである可能性もあるので許される
	storeInternalCode(CODE_endfunc);
	storeInternalCode(T_INT);
}

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

void S_Endfunc(uwCODE code)
{
	DBG_Func();
	DBG_printf1("operationStatus.flocal=%d\n",operationStatus.flocal);
	DBG_printf1("operationStatus.finFunc=%d\n",operationStatus.finFunc);
	if (!operationStatus.flocal) { // グローバル時
		// グローバルなのにendfuncが来た
		Error(ERR_NO_FUNC_TO_ENDFUNC_OR_RETURN);
	}
	if (!operationStatus.finFunc) {
		// fucnがないのにendfuncが来た
		Error(ERR_NO_FUNC_TO_ENDFUNC_OR_RETURN);
	}
	operationStatus.finFunc=NO;	// func終了
	
	NEST_WORK *now=nest_work;
	if (now->next!=NULL) {
		Error(ERR_NON_CLOSE_NEST);
	}

	storeInternalCode(code);		// 中間コード書き込み
	storeInternalCode(returnType);	// リターン値

	// 1ローカル変数確定
	determineLocalVariableList();
}

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

void S_Func(uwCODE code)
{	// 969
	DBG_Func();
	
	if (!fend) {
		// endがないのにfuncがあった
		Error(ERR_FUNC_WITHOUT_END);
	}
	
	if (operationStatus.flocal) { // 元々ローカル時
		// 内部関数あり	982
		if (operationStatus.finFunc) {
			// func中にfuncが来た
			Error(ERR_NO_ENDFUNC);
		}
	} else { // 元はglobal時	970
		DBG_printsn("グローバル→ローカル切り替え");
		operationStatus.flocal=YES; // ここから先ローカル
		NEST_WORK *now=nest_work;
		if (now->next!=NULL) {
			// ネスト構造が閉じていない
			Error(ERR_NON_CLOSE_NEST);
		}
		storeInternalCode(code);	// 中間コード書き込み
		//
		// グローバル変数確定；いったんfunc文が出たら以降、グローバルはあり得ないから
		determineGlobalVariableList();
	}

	// 型を得る	992
	getTypeWithSource(NULL,NULL);	// すでにわかっている（はず）
	// 994
	firstCheckSouceInLine();
	// ハッシュ値を計算しながら、文字数を数える	996
	swStrLEN	len;
	uwHash		hash;
	UByte		*name=source;
	calcHash(source,&len,&hash,&source);
	DBG_printName(name,len);
	if (len<=0) {
		nslog(@"funcはコンパイラ起動時に仮登録されているはずなので、ここで未登録になるのはおかしい");
		Error(ERR_SYSTEM);
	}
	
	// 関数を探す	1001
	swVarCNT	paramCnt;		// 引数リスト数(リターン値は含まない)
	uwCODE		*paramTable;	// 引数テーブル(リターン値も含む)
	swVarNO		fno;
	uwRETURNTYPE retType=functionCheck(name,hash,len,&paramCnt,&paramTable,&fno);
	if (retType==FuncNotFound) {
		// 内部関数はプログラム開始時にinternalFunction()で仮定義されているのでFuncNotFoundにはならない
		// ここに来るのは、未定義関数を呼び出そうとしている時
		Error(ERR_UNDEFINED_FUNC_OR_ARRAY);
	}
	// 関数があった
	if (fno>=0) {
		// 外部関数と同じ名前なので定義できない
		Error(ERR_DOUBLE_FUNCTION);
	}
	DBG_printf1("関数があった:番号=%d → ",fno);
	fno=_getFuncNo(fno); // 内部関数番号を復号する
	DBG_printf1("%d\n",fno);

	// 1012
	FUNCTION1 *func=&InternalFunctionBuffer[fno];
	func->exec.func=(RET_FUNC (*)(SWord numFAC,FAC fac[]))internalCode.bp;	// 実行アドレス

	// 1018
	INTERNAL_CODE_INFO *internalCodeInfo=(INTERNAL_CODE_INFO *)internalCode.wp;
	// 1020
	swVarCNT cnt=variableBuffCtrl.cnt;	// オリジナル(1021)は.cnt=個数-1なので+1しているが、ここでは不要
	internalCodeInfo->varChainListNo=cnt;	// 変数チェインリストから指定ブロックの変数情報を取り込む位置	1023
	DBG_printf1("variableBuffCtrl.cnt=%d\n",cnt);
	// 1024
	cnt=paramBuffCtrl.cnt;
	DBG_printf1("paramBuffCtrl.cnt=%d\n",cnt);
	internalCodeInfo->paramChainListNo=cnt;			// 引数を取り込む位置
	PARAM_CHAIN param1={paramCnt,0};
	addValueForBuffer(&paramBuffCtrl, &param1);		// この関数の引数個数の登録
	//
	internalCode.wp = internalCodeInfo->codes;		// 中間コードの格納はここから

	// ローカル変数領域の初期化	1042
	LocalInt.cnt	=0;
	LocalStr.cnt	=0;
	LocalChar.cnt	=0;
	LocalFloat.cnt	=0;
	LocalArray.cnt	=0;

	if (*source++!='(') {	// 1050
		Error(ERR_SYNTAX);
	}
	
	// 1053～
	DBG_printf1("func引数解釈:引数数=%d\n",paramCnt);
	#ifdef CORE_DEBUG
	int j=0;
	#endif
	
	uwCODE prm,*param=paramTable;
	// paramCnt=0のときは以下のループは回らないはず
	while (firstCheckSouceInLine(),	// 1054
			prm=*param++,			// 1055
			!(prm&PARAM_RETURN)) {	// 1057	リターン値定義が出てきたら終了
		// 引数解釈
		DBG_printf2("引数%d:type=$%04x\n",j++,prm);
		
		// 引数名のチェック	1064
		name=source;
		calcHash(source,&len,&hash,&source);	// 引数名
		DBG_printName(name,len);
		if (len<=0) {
			nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
			Error(ERR_SYNTAX_FUNC);
		}
		if (statementCheck(hash,len,name)!=CODE_NONE) {	// 1066
			// ステートメントに同じ名前の物がある
			Error(ERR_DEFINE_VARIABLE);
		}
		if (functionCheck(name,hash,len,NULL,NULL,NULL)!=FuncNotFound) {	// 1072
			// 関数と同じ名前が存在する
			DBG_printsn("関数と同じ名前が存在する 1072");
			Error(ERR_DOUBLE_VARIABLE);
		}
		
		// 他の変数名と重なってないかどうか	1081
		DBG_printsn("他の変数名と重なってないかどうか調べる");
		swVarNO		no;
		sbVarSTAT	stat;
		DIM1		*dimInfo;
		if (variableCheck(name,hash,len,&stat,&dimInfo,&no)!=MATH_NONE) {
			// 変数は既存である
			// 引数はローカル変数なので、globalで重複 のみのとき再定義出来る
			if (_isStatLocal(stat)) {
				// ローカル変数にて二重宣言
				DBG_printsn("ローカル変数にて二重宣言");
				Error(ERR_DOUBLE_VARIABLE);
			}
		} // 未宣言の時は必ず使える
		// 1097
		if (prm==PARAM_ARRAYext||(prm&(PARAM_ARRAY1|PARAM_ARRAY2))) {
			// 引数拡張配列または配列をパラメーターチェインリストに登録する
			DBG_printsn("引数拡張配列または配列をパラメーターチェインリストに登録する");
			param=defineArrayParam(prm,hash,len,name,param);
		} else {
			// 引数変数をパラメーターチェインリストに登録する
			DBG_printsn("引数変数をパラメーターチェインリストに登録する");
			defineVariableParam(prm,hash,len,name);
		}
		if (*source==';') { // 型指定がある
			nslog(@"型指定:");
			source++;

			// V2.3追加
			// ;の後ろにスペース/TABがあった場合は飛ばす
			UByte c;
			while (c=*source, c==' '||c=='\t') source++;

			#ifdef CORE_DEBUG // iOS
			name=source;
			#endif
			calcHash(source,&len,&hash,&source);	// 変数の型だが、無視
			if (len<=0) {
				// 型の実指定が抜けている
				nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
				Error(ERR_NO_TYPE);
			}
			DBG_printName(name,len);
		}
		// 1119
		UByte c=firstCheckSouceInLine();
		source++;	// 1120
		if (c==',') continue; // 次の引数へ	1121,1122
		//
		if (c!=')') {	// 1123
			// func(が)で閉じてない
			Error(ERR_SYNTAX);
		}
		// )で閉じた
		// ここでリターン値がなければならない
		prm=*param;
		if (prm&PARAM_RETURN) goto F1; // 1127
		// )で閉じた後にまだパラメーターがある
		Error(ERR_SYNTAX);
	}
	if (*source++!=')') {
		// )で閉じてない
		Error(ERR_SYNTAX);
	}
F1:;
	// パラメーターテーブルの一番最後はリターン値
	switch (prm) {
		case FLOAT_RET: // float
			returnType=T_FLOAT;
			break;
		case INT_RET: // int
			returnType=T_INT;
			break;
		case CHAR_RET: // char 
			returnType=T_CHAR;
			break;
		case STR_RET: // str
			returnType=T_STR;
			break;
		default:
			nslog(@"%s:%d",__FUNCTION__,__LINE__);
			Error(ERR_SYSTEM);
	}
	operationStatus.finFunc=YES; // func開始
}

//-----------------------------------------------
// ネスト構造を持つステートメント
//-----------------------------------------------

// nest_work登録(固定内容部のみ)
// nestType=種類 NESTTYPE_*
// リターン値：workのアドレス(これ以降は物によって内容が異なる)
static
void *defineNest(swNESTTYPE nestType)
{	// next登録 1424
	DBG_Func();
	DBG_printf1("ネスト登録:nestType=$%04x\n",nestType);
	#ifdef CORE_DEBUG2
	printf("nestWorkHontai=%p～%p\n",nestWorkHontai,&nestWorkHontai[nest_workSIZE]);
	DBG_dump("nextwork.dat",nestWorkHontai,nest_workSIZE);
	#endif
	//
	NEST_WORK *now =nest_work;	// 現在のブロック
	NEST_WORK *next=now->next;	// 次につなげる場所；これを格納するのは1つ前のネスト終了処理
	if (next!=NULL) {
		DBG_printf2("now=%p → %p\n",now,next);
		nest_work	=next;		// nest_workは最新のネストを持つ
		{ // エラー発生時のハングアップ回避のためのワーククリア
		// ネストを作る処理(while)などの中でエラーが発生した場合、ネストワーク内が不完全なままになる。
		// これによるメモリ内の残りカスによって落ちることがあるので、ワークをクリアして回避させる。
		// この場合も、後でエラーで安全に停止する。
		UByte *bp=(UByte *)next;
		int sz=16;
		if ((bp+sz)>=&nestWorkHontai[nest_workSIZE]) {
			sz=(int)calcAdrsOffset(&nestWorkHontai[nest_workSIZE],bp); // ワーク終了アドレス
		}
		memclr(bp,sz);
		}
		DBG_printf1("nest_work=%p(next)\n",nest_work);
		next->before=now;		// 今のを1つ前につなぐ
		now			=next;		// next
	} else {
		// 次の登録がないとき;ルートに登録(ルートだけ利用)
		DBG_printsn("next=NULL;ルートに登録");
		now->before	=NULL;		// 前もなし
	}
	now->nestType	=nestType;	// ネスト種類記録
	// 可変内容部のアドレスを返す；適当な型にキャストして使うこと
	return (now->work);
}

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

// nest削除	1438
void deleteNest(void)
{
	DBG_Func2("一番最後=最新のネストを削除する");

	NEST_WORK *now=nest_work;
	if (now->before!=NULL) { // 前がある時
		nest_work=now->before;	// 前ブロックに差し戻す
		DBG_printf1("nest_work=%p(=before)\n",nest_work);
	} else {
		// 前がない時は次もなしにする(ルートに戻す)
		now->next=NULL;
		// 戻すだけだからオーバーフローチェックはしない
	}
}

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

void S_Switch(uwCODE code)
{	// 1455
	DBG_Func();
	uwCODE *wp=internalCode.wp;	// 中間コード位置を保存
	storeInternalCode(code);	// 中間コード書き込み

	// 式の評価
	uwMATHTYPE msType=interpretMath(MATH_VOID,&internalCode.wp,NULL);

	UWord nestType=NESTTYPE_SWITCH;
	if (msType==MATH_STR) { // 文字列型である
		// Switch2:
		DBG_printsn("Switch2に変更");
		*wp=CODE_switch2; // 中間コード変更
		nestType=NESTTYPE_SWITCH_STR;
	}
	NEST_SWITCH *nest_switch=(NEST_SWITCH *)defineNest(nestType);
	
	nest_switch->table=internalCode.wp;	// case/default飛び先テーブルを書くアドレス
	DBG_printf1("case/default飛び先テーブルを書くアドレス=%p\n",nest_switch->table);
	internalCode.vp++;	// それを後で書き戻す分を飛ばしておく

	NEST_WORK *now=nest_work;
	now->next=(NEST_WORK *)nest_switch->next; // 次の書き込み位置
}

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

void S_Case(uwCODE code)
{
	DBG_Func();
	NEST_WORK *now=nest_work;
	if (now==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	if (now->next==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	NEST_CASE *nest_case	=(NEST_CASE *)now->next;
	nest_case->jump.adrs    =internalCode.wp; // case 中間コードアドレス(文字列型でも同じ位置)
	nest_case->jump.adrsFlag=ADRS_CASE;
	//
	switch (now->nestType) {
		default:
			// swicthではない
			Error(ERR_NEED_SWITCH_CASE_DEFAULT_ENDSWITCH);

		case NESTTYPE_SWITCH:
			// 数値case
			nest_case->caseValue=getIntConstant();	// case値
			DBG_printf2("case %d:ジャンプ先書き込みアドレス=%p\n",(int)nest_case->caseValue,nest_case->jump.adrs);
			now->next=(NEST_WORK *)nest_case->next;	// 次の書き込み位置
			checkNestWorkOver(now->next); // オーバーフローチェック
			break;
		
		case NESTTYPE_SWITCH_STR:
			// 文字列case
			if (*source++!='"') {
				// "で始まっていない＝文字列指定ではない
				Error(ERR_MISMATCH_FORMULA_TYPE);
			}
			NEST_CASE2 *nest_case2=(NEST_CASE2 *)now->next; // さらに読み替える
			swStrLEN len=0;
			UByte *bp=(UByte *)nest_case2->string;
			UByte c;
			while ((c=*source++)!='"') {
				if (c<' ') {
					// コントロールコードは入れられない
					Error(ERR_MISMATCH_FORMULA_TYPE);
				}
				*bp++=c;
				len++;
			}
			*bp++=EOS;
			if (((ULong)bp)&1) *bp++=EOS; // 偶数アドレス化
			// 格納するのはlenバイト+EOS(+境界整合)
			nest_case2->len=len; // lenは元のまま
			DBG_prints("case2 ");
			DBG_printName((UByte *)nest_case2->string,len);
			DBG_printf1(": → %p\n",nest_case->jump.adrs);
			//
			now->next=(NEST_WORK *)bp; // 次のネストの位置
			checkNestWorkOver(now->next); // オーバーフローチェック
			break;
	}
}

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

void S_Endswitch(uwCODE code)
{	// 1582
	DBG_Func();
	// endswitchはここで処理しきるため、中間コードとしては記録しない
	
	S_Break(CODE_break);	// Endswitch前にbreakがあるものとして処理させるため

	NEST_WORK *now=nest_work;
	if (now==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	if (now->next==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	swNESTTYPE nestType=now->nestType;
	switch (nestType) {
		default:
			// switchでない
			Error(ERR_NEED_SWITCH_CASE_DEFAULT_ENDSWITCH);
		//
		case NESTTYPE_SWITCH:
		case NESTTYPE_SWITCH_STR:
			break;
	}
	// switch/case/defaultで作ってきたネストワークを完成させる
	NEST_SWITCH *nest_switch=(NEST_SWITCH *)now->work;
	writeOfstAdrs(nest_switch->table,internalCode.wp);	// case/defaultテーブルの位置を書き戻す（現在の中間コード位置からのオフセット）
	//
	uwCODE *caseCntAdrs=internalCode.wp++;	// case の個数置き用アドレス保存（中間言語内）
	DBG_printf1("case個数を書くアドレス=%p\n",caseCntAdrs);
	
	// case/default/breakの飛び先アドレスとその格納先を取得する
	int	fafterDefault=NO;	// defaultが出てきたかどうか
	UWord caseCnt=0;		// caseの個数
	UWord breakCnt=0;		// breakの数 < MAX_BREAK
	#define	MAX_BREAK	256			// 1つのswitch内のbreakの数(たぶん足りるだろう);とりあえずASCIIコード全文字で判定してもいい数にしておく
	uwCODE	*breakAdrs[MAX_BREAK];	// オリジナルはスタック上に積んでいる
	//
	UByte *bp=(UByte *)nest_switch->next; // ここから先は構造が可変なのでいったんUByte *で受けておく
	while (bp<(UByte *)now->next) { // 読み出しアドレスがnextに到達するまで
		// すべてに共通して、先頭にLOOP_ADRSが存在する
		LOOP_ADRS *jump=(LOOP_ADRS *)bp; // 読み替え
		DBG_printf2("-----\nadrs=%p,flag=%d\n",jump->adrs,(int)jump->adrsFlag);
		switch (jump->adrsFlag) {
			case ADRS_CONTINUE:	// 1616
				DBG_printsn("continue");
				// continue : あるはずない（if 内から払い下げとか）
				Error(ERR_CONTINUE_IN_SWITCH);
			
			case ADRS_BREAK:	// 1622
				DBG_printsn("break");
				if (breakCnt>=MAX_BREAK) {
					// １つのswitch中のbreakが多すぎる
					Error(ERR_BREAK_TOO_MUCH);
				}
				DBG_printf2("breakAdrs[%d]=%p\n",breakCnt,jump->adrs);
				breakAdrs[breakCnt++]=jump->adrs;	// アドレスを一時保管(後で一括して書き込むため)
				NEST_BREAK *nest_break=(NEST_BREAK *)bp;
				bp=(UByte *)nest_break->next; // 次へ
				break;
			
			case ADRS_DEFAULT:	// 1648
				DBG_printsn("default");
				if (fafterDefault) {
					// すでにでdefaultは出てきている(多重default)
					Error(ERR_DEFAULT_AFTER_DEFAULT);
				}
				fafterDefault=YES; // defaultが出てきた
				NEST_DEFAULT *nest_default=(NEST_DEFAULT *)bp;
				uwCODE *defaultAdrs=nest_default->defaultAdrs;
				DBG_printf1("default<-%p\n",defaultAdrs);

				// オフセットアドレス書き込み
				storeInternalCodeP((void *)calcAdrsOffset(defaultAdrs,internalCode.wp));
				
				bp=(UByte *)nest_default->next;
				break;
			
			case ADRS_CASE:	// 1626
				DBG2_printsn("case");
				caseCnt++;
				if (fafterDefault) {
					// X-BASICではdefaultはcase群の後にしかおけないらしい
					Error(ERR_CASE_AFTER_DEFAULT);
				}
				if (nestType==NESTTYPE_SWITCH_STR) {
					// 文字列型switchのとき		1637
					// NEST_CASE2である
					NEST_CASE2 *nest_case2=(NEST_CASE2 *)bp;
					swStrLEN len=nest_case2->len; // EOSを含まないバイト数
					DBG_printf1("文字列case(%d)\n",len);
					storeInternalCode(len);
					UByte *name=nest_case2->string;
					len++; // EOS分
					if (len&1) len++; // 文字列は偶数バイト化されているので
					while (len-->0) {
						storeInternalCodeB(*name++);
					}
					bp=name; // nest_case2->next相当
				} else {
					// 数値型switchのとき	1632
					// NEST_CASEである
					NEST_CASE *nest_case=(NEST_CASE *)bp;
					DBG_printf1("数値case %d",(int)nest_case->caseValue);
					storeInternalCodeL(nest_case->caseValue);	// caseValue
					bp=(UByte *)nest_case->next;
				}
				DBG_printf1("<-%p\n",jump->adrs);
				// オフセットアドレス書き込み
				storeInternalCodeP((void *)calcAdrsOffset(jump->adrs,internalCode.wp));
				break;
		} // switch (jump->adrsFlag)
	} // while
	// 1657
	// case の個数確定
	if (caseCnt==0) { // 1660
		// caseが1つもなかった
		Error(ERR_NEED_CASE);
	}
	*caseCntAdrs=caseCnt;	// case個数を書き戻す	1661	オリジナルでは個数-1である
	DBG_printf1("case数=%d\n",caseCnt);
	if (!fafterDefault) {
		// 1664
		DBG_printsn("breakなし");
		storeInternalCodeP(SZ_VOIDP);	// defaultの指定が無かった時が、default相当の飛び先をendswitch の後にする(オフセットアドレス)
	}
	
	// breakの確定	1666
	// 各breakの飛び先として現在の中間コード位置を書く(後ろから)
	DBG_printsn("break確定");
	while (breakCnt-->0) {
		// breakCntには個数が入っているので、先に-1して要素番号になる
		// 各breakに飛び先を書く
		DBG_printf2("break[%d]=%p\n",breakCnt,breakAdrs[breakCnt]);
		writeOfstAdrs(breakAdrs[breakCnt],internalCode.wp); // 書き込むのはbreadAdrs[]へ
	}
	// 1675
	// 終わったので、switch系ネストを1段削除する
	deleteNest();
}

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

void S_Default(uwCODE code)
{
	DBG_Func();
	// defaultはここで処理しきるため、中間コードとしては記録しない
	
	NEST_WORK *now=nest_work;
	if (now==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	NEST_WORK *next=now->next;
	if (next==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	switch (now->nestType) {
		default:
			Error(ERR_NEED_SWITCH_CASE_DEFAULT_ENDSWITCH);
		//
		case NESTTYPE_SWITCH:
		case NESTTYPE_SWITCH_STR:
			{
			NEST_DEFAULT *nest_default =(NEST_DEFAULT *)next;
			nest_default->jump.adrs	   =NULL;	// defaultではアドレスは後で確定するから念のため
			nest_default->jump.adrsFlag=ADRS_DEFAULT;
			nest_default->defaultAdrs=internalCode.wp;	// default address
			DBG_printf1("default飛び先そのもの=%p\n",nest_default->defaultAdrs);
			now->next=(NEST_WORK *)nest_default->next;	// 次の利用位置を記録
			checkNestWorkOver(now->next); // オーバーフローチェック
			}
			break;
	}
}

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

// endwhile/until/next/endswitchの次に飛ぶ
void S_Break(uwCODE code)
{
	DBG_Func();

	storeInternalCode(code);	// 中間コード書き込み

	NEST_WORK *now=nest_work;
	if (now==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	NEST_WORK *next=now->next;
	if (next==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	NEST_BREAK *nest_break=(NEST_BREAK *)next;
	nest_break->jump.adrs	 =internalCode.wp;
	nest_break->jump.adrsFlag=ADRS_BREAK;
	internalCode.vp++; // 後でアドレスを書き込むので飛ばしておく
	DBG_printf1("break飛び先を書き込むアドレス=%p\n",nest_break->jump.adrs);
	//
	now->next =(NEST_WORK *)nest_break->next;	// 次の位置
}

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

// while/until/forに飛ぶ
void S_Continue(uwCODE code)
{
	DBG_Func();

	storeInternalCode(code);	// 中間コード書き込み

	NEST_WORK *now=nest_work;
	if (now==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	NEST_WORK *next=now->next;
	if (next==NULL) {
		Error(ERR_CANT_BREAK_CONTINUE_NO_NEST);
	}
	
	switch (now->nestType) {
		case NESTTYPE_SWITCH:
		case NESTTYPE_SWITCH_AFTER_DEFAULT:
		case NESTTYPE_SWITCH_STR:
		case NESTTYPE_SWITCH_STR_AFTER_DEFAULT:
			// switchにcontinueは使えない
			Error(ERR_CONTINUE_IN_SWITCH);
			break; // 念のため
	}
	
	NEST_CONTINUE *nest_continue=(NEST_CONTINUE *)next;
	nest_continue->jump.adrs	=internalCode.wp;
	nest_continue->jump.adrsFlag=ADRS_CONTINUE;
	internalCode.vp++; // 後でアドレスを書き込むので飛ばしておく
	DBG_printf1("continue飛び先を書き込むアドレス=%p\n",nest_continue->jump.adrs);
	//
	now->next =(NEST_WORK *)nest_continue->next;	// 次の位置
}

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

void S_While(uwCODE code)
{	// 1905
	DBG_Func();
	
	storeInternalCode(code);	// 中間コード書き込み

	NEST_WHILE_FOR_NEXT *nest_while=(NEST_WHILE_FOR_NEXT *)defineNest(NESTTYPE_WHILE);
	
	// 式 解釈
	UWord *codes=(UWord *)nest_while->sikis;
	SLong lenL;
	interpretMath(MATH_INT,&codes,&lenL);// codesからに結果を書き込む -> 長さ=lenL
	// 1926
	lenL=withWord(lenL);	// 式は.wであり、長さ/SZ_WORDが個数となる
	nest_while->cnt =lenL;	// 個数
	nest_while->no	=0;		// 変数番号は0にしておく
	// 1929
	DBG_printf1("式中間コード群書き込み:%d\n",(int)lenL);
	int i;
	for (i=0;i<lenL;i++) {
		storeInternalCode(nest_while->sikis[i]); // 中間コード領域に式をコピーする
	}
	// 後で飛び先そのもの、またはそれを後で書き込む位置を記録しておく
	NEST_LOOP *nest_loop=(NEST_LOOP *)&nest_while->sikis[i]; // 式群の直後のアドレス
	nest_loop->loops[LOOPS_BREAK].adrs=internalCode.wp;	// breakアドレスを入れる場所
	nest_loop->loops[LOOPS_BREAK].adrsFlag=ADRS_BREAK;
	internalCode.vp++;	// 式群の直後にはbreak adrsを入るので飛ばしておく
	nest_loop->loops[LOOPS_LOOP ].adrs=internalCode.wp;	// ループで戻ってくるアドレス
	nest_loop->loops[LOOPS_LOOP ].adrsFlag=ADRS_LOOP;
	//
	DBG2_printsn("while address(while側ではnext_loopに記録するだけ)");
	DBG_printf1("break書き込み先 =%p\n"	,nest_loop->loops[LOOPS_BREAK].adrs);
	DBG_printf1("ループ戻りアドレス=%p\n"	,nest_loop->loops[LOOPS_LOOP ].adrs);
	// 
	// 次の書き込み位置
	NEST_WORK *now=nest_work;
	now->next=(NEST_WORK *)&nest_loop->loops[LOOPS_CONTINUE]; // 次の格納位置
	checkNestWorkOver(now->next); // オーバーフローチェック
}

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

// repeat ～ until 式
// repeatはループで戻すアドレスの記録のみ
void S_Repeat(uwCODE code)
{	// 2088
	DBG_Func();

	// repeatはここで処理しきるため、中間コードとしては記録しない
	NEST_LOOP *nest_loop=(NEST_LOOP *)defineNest(NESTTYPE_REPEAT);
	DBG_printf1("nest_loop=%p\n",nest_loop);
	nest_loop->loops[LOOPS_LOOP].adrs =internalCode.wp; // ループで戻ってくるアドレス
	nest_loop->loops[LOOPS_LOOP].adrsFlag=ADRS_LOOP;
	DBG_printf1("ループ戻りアドレス=%p\n",nest_loop->loops[LOOPS_LOOP].adrs);
	//
	NEST_WORK *now=nest_work;
	now->next=(NEST_WORK *)&nest_loop->loops[LOOPS_BREAK]; // 次のネストワークはここからに作成する
	checkNestWorkOver(now->next); // オーバーフローチェック
}

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

// repeat ～ until 式
void S_Until(uwCODE code)
{	// 2106
	DBG_Func();
	
	NEST_WORK *now=nest_work;
	DBG_printf1("now=%p\n",now);
	NEST_WORK *next=now->next;
	if (next==NULL) {
		// repeatない
		DBG_printsn("next=NULLでrepeatなし");
		Error(ERR_UNTIL_WITH_NO_REPEAT);
	}
	if (now->nestType!=NESTTYPE_REPEAT) {
		// repeatない
		DBG_printf2("nestType!=FOR:$%04x-%04x\n",now->nestType,NESTTYPE_REPEAT);
		Error(ERR_UNTIL_WITH_NO_REPEAT);
	}
	DBG_printf1("now->next=%p\n",next);
	
	uwCODE *continueAddress=internalCode.wp;	// continue address
	storeInternalCode(code);	// 中間コード書き込み

	// 式１解釈:解釈した結果を 中間コード領域 からに書き込み、その長さを返す
	interpretMath(MATH_INT,&internalCode.wp,NULL);
	// enterNest2に渡すのはloopsのアドレス
	enterNest2((NEST_LOOP *)now->work,next,continueAddress);
}

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

void S_Endwhile(uwCODE code)
{
	DBG_Func();
	
	NEST_WORK *now=nest_work;
	DBG_printf1("now=%p\n",now);
	if (now==NULL) {
		// whileない
		DBG_printsn("now=NULLでwhileなし");
		Error(ERR_ENDWHILE_WITH_NO_WHILE);
	}
	NEST_WORK *next=now->next;
	if (next==NULL) {
		// whileない
		DBG_printsn("next=NULLでwhileなし");
		Error(ERR_ENDWHILE_WITH_NO_WHILE);
	}
	if (now->nestType!=NESTTYPE_WHILE) {
		DBG_printf2("nestType!=WHILE:$%04x-%04x\n",now->nestType,NESTTYPE_WHILE);
		Error(ERR_ENDWHILE_WITH_NO_WHILE);
	}
	DBG_printf1("now->next=%p\n",next);
	
	uwCODE *continueAddress=internalCode.wp;	// continue address
	storeInternalCode(code); // 中間コード書き込み
	
	enterNest((NEST_WHILE_FOR_NEXT *)now->work,next,continueAddress);
}

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

// for var = st to end
void S_For(uwCODE code)
{	// 1947
	DBG_Func();
	
	storeInternalCode(code);	// 中間コード書き込み
	
	NEST_WHILE_FOR_NEXT *nest_for=(NEST_WHILE_FOR_NEXT *)defineNest(NESTTYPE_FOR);	// 1958
	
	// ループ変数名を得る
	swStrLEN	len;
	uwHash		hash;
	UByte		*name=source;
	calcHash(source,&len,&hash,&source);	// 1961
	DBG_printName(name,len);
	if (len<=0) { // 変数名長=0の状態は、変数を書き忘れたときにあり得る(for =と書いたとき);オリジナルはこれが抜けている
		Error(ERR_SYNTAX_FOR);
	}
	
	// その変数をチェック
	swVarNO 	no;
	sbVarSTAT	stat;
	DIM1 		*dimInfo;
	uwMATHTYPE msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);	// 1970
	if (stat==VARIABLE_NONE) {
		if (operationStatus.fundefVarInt) {
			// 未宣言変数の場合、int型として確保する
			defineIntWithNoDefinitionVariable(&no,name,hash,len);
		} else {
			// 未宣言変数
			Error(ERR_UNDEFINED_VARIABLE);
		}
	} else {
		// グローバル変数
		if (stat&VARIABLE_SYSTEM) {
			// システム変数は使えない
			Error(ERR_UNDEFINED_VARIABLE);
		}
		if (msType!=MATH_INT) {
			// int型以外は使えない
			Error(ERR_MISMATCH_VARIABLE_TYPE);
		}
		if (_isStatLocal(stat)) {
			no=_setLocal(no);	// LOCAL 変数
		}
	}
	
	if (*source++!='=') {
		// = がない
		Error(ERR_SYNTAX_FOR);	// for
	}
	
	// 開始値式解釈
	DBG_printsn("開始値式解釈");
	// iOS
	//msType=
	interpretMath(MATH_INT,&internalCode.wp,NULL);	// 2006
	DBG_printsn("中間コードとして変数番号を書き込み");
	storeInternalCode(no);	// 中間コードとして変数番号を書き込み	2013
	
	// to を調べる
	DBG_printsn("toを調べる");
	if (firstCheckSouceInLine()==EOL) {	// 2016
		// 改行があった
		Error(ERR_SYNTAX_FOR);
	}
	if (*source++!='t') {	// 2022
		// toがない
		Error(ERR_SYNTAX_FOR);
	}
	if (*source++!='o') {	// 2924
		// toがない
		Error(ERR_SYNTAX_FOR);
	}
	
	nest_for->no=no;	// int変数番号	2031
	
	// 終了値式解釈	2033
	DBG_printsn("終了値式解釈");
	SLong lenL;
	uwCODE *wp=internalCode.wp;
	// iOS
	//msType=
	interpretMath(MATH_INT,&wp,&lenL);	// この中ではinternalCode.wpは動かさず、以下の書き込みで移動させる
	
	DBG2_printf1("nest_for->no=%p\n",&nest_for->no);	// 代入直後に表示するとinterpretMath()の表示で遠くなるのでここで
	
	DBG_printsn("終了値による処理分け");
	NEST_LOOP *nest_loop;
	uwCODE *sikis=(uwCODE *)nest_for->sikis; // 式を書き込むアドレス
	DBG_printf1("sikis=%p\n",sikis);
	
	*sikis++=no; // 変数番号
	//
	if (readInternalCodeN()==(_CONSTANT|T_INT)) {	// 2041
		// 終値がint定数の時は特別	2053	next2
		DBG_printsn("終値がint定数の時は特別");
		nest_for->cnt=0;	// 個数 = 0 が特別の印	2054
		internalCode.wp++;	// 〃分を飛ばす
		// 式2=.l定数コピー
		sikis=storeLong(sikis, readInternalCodeL());	// *(ULong *)sikis=readInternalCodeL();
	} else {
		// 2044
		SWord cnt=withWord(lenL);	// .w単位長さ=個数
		DBG_printf1("終値はint定数以外:cnt=%d\n",cnt);
		nest_for->cnt=cnt+1;		// 変数番号も入るから	2045
		DBG_printf1("&nest_for->cnt=%p\n",&nest_for->cnt);
		while (cnt-->0) {
			DBG2_printf2("sikis=%p<-%p\n",sikis,internalCode.wp);
			*sikis++=readInternalCode();	// 式２コピー
		}
	}
	nest_loop=(NEST_LOOP *)sikis;
	// 後で飛び先そのもの、またはそれを後で書き込む位置を記録しておく
	// 2060
	nest_loop->loops[LOOPS_BREAK].adrs=internalCode.wp;	// breakアドレスを入れる場所
	nest_loop->loops[LOOPS_BREAK].adrsFlag=ADRS_BREAK;
	internalCode.vp++;	// 式群の直後にはbreak adrsを入るので飛ばしておく
	nest_loop->loops[LOOPS_LOOP ].adrs=internalCode.wp;	// ループで戻ってくるアドレス
	nest_loop->loops[LOOPS_LOOP ].adrsFlag=ADRS_LOOP;
	//
	DBG_printf1("break書き込み先 =%p\n"	,nest_loop->loops[LOOPS_BREAK].adrs);
	DBG_printf1("ループ戻りアドレス=%p\n"	,nest_loop->loops[LOOPS_LOOP ].adrs);
	
	// 次の書き込み位置
	NEST_WORK *now=nest_work;
	now->next=(NEST_WORK *)&nest_loop->loops[LOOPS_CONTINUE];
	checkNestWorkOver(now->next); // オーバーフローチェック
}

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

void S_Next(uwCODE code)
{
	DBG_Func();
	
	NEST_WORK *now=nest_work;
	DBG_printf1("now=%p\n",now);
	if (now==NULL) {
		// (構文の)nextない
		DBG_printsn("now=NULLでforなし");
		Error(ERR_NO_FOR_WITH_NEXT);
	}
	NEST_WORK *next=now->next;
	if (next==NULL) {
		// (構文の)nextない
		DBG_printsn("next=NULLでforなし");
		Error(ERR_NO_FOR_WITH_NEXT);
	}
	if (now->nestType!=NESTTYPE_FOR) {
		DBG_printf2("nestType!=FOR:$%04x-%04x\n",now->nestType,NESTTYPE_FOR);
		Error(ERR_NO_FOR_WITH_NEXT);
	}
	DBG_printf1("now->next=%p\n",next);
	
	uwCODE *continueAddress=internalCode.wp;	// continue address : nextの位置
	storeInternalCode(code); 					// 中間コード書き込み
	//
	enterNest((NEST_WHILE_FOR_NEXT *)now->work,next,continueAddress);
}

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

// next/endwhile(ほぼ)共通処理
void enterNest(NEST_WHILE_FOR_NEXT *nest_while_for_next,NEST_WORK *next,uwCODE *continueAddress)
{	// Next飛込 2167
	DBG_Func();
	/*
	NEST_WHILE_FOR_NEXT
		.cnt=式の数		.w
		.sikis[0～cnt-1]	.w
		.loops[n]		LOOP_ADRS
	*/
	// 1つ前のfor/whileが作ったNEST_WORKを参照している状態
	SWord cnt=nest_while_for_next->cnt;	// 式の数	2168
	DBG_printf1("&nest_while_for_next->cnt=%p\n",&nest_while_for_next->cnt);
	//
	uwCODE *wp=nest_while_for_next->sikis;
	if (cnt==0) { // 特別処理 for側でcnt=0にしてある
		DBG_printsn("Next2に変更");
		// Next特別:	2174
		storeInternalCodeWithOffsetN(CODE_next2,-1);	// (元の位置の)中間コードをnext2に変更
		storeInternalCode(*wp++);	// 式=sikis[0]
		// 定数値のコピー;V3.00未満ではアドレスコピーになっていたが、それはバグ(たまたま定数=ULongをvoid *のサイズが同じだったので動いていた)
		ULong num=readLong(wp);
		wp+=withWord(SZ_LONG);
		storeInternalCodeL(num);
	} else { // 2170
		DBG_printf2("cnt=%d\nnest_while_for_next->sikis=%p\n",cnt,wp);
		while (cnt-->0) {
			storeInternalCode(*wp++);	// 中間コード領域に式をコピーする
		}
	}
	enterNest2((NEST_LOOP *)wp,next,continueAddress);
}

// さらにuntilとも共通処理
void enterNest2(NEST_LOOP *nest_loop,NEST_WORK *next,uwCODE *continueAddress)
{	// 2179	Next飛込2
	DBG_Func();
	//
	DBG_printf1("nest_loop=%p\n",nest_loop);
	DBG_printf1("continueAddress=%p\n",continueAddress);	// d3
	
	// ループアドレスの設定；すべてで共通で１つだけ存在する
	int i=LOOPS_LOOP;
	uwCODE *adrs=nest_loop->loops[i++].adrs;	// 飛び先そのもの
	DBG_printf1("ループ戻り先=%p\n",adrs);
	internalCode.wp=writeOfstAdrs(internalCode.wp,adrs);	// オフセットアドレス	2181
	
	// break/continueアドレスは、ループステートメントの持つ1組の他に、ループ中に複数存在する可能性がある
	uwCODE *breakAdrs=internalCode.wp;	// break時に飛んでくるアドレス	2182	d1
	DBG_printf1("break address=%p\n",breakAdrs);
	
	SLong sz =(ULong) next;					// このとき、nextはloopsの群の次のアドレスを持っている
	sz-=(ULong)&nest_loop->loops[i];	// これで残りのloops[]のバイト数が得られる
	DBG2_printf3("next=%p,&nest_loop->loops[%d]=%p\n",next,i,&nest_loop->loops[i]);
	sz/=SZ_LOOP_ADRS;
	DBG_printf1("アドレス数=%d\n",(int)sz);
	while (sz-->0) {
		adrs=nest_loop->loops[i].adrs;	// 2189
		DBG_printf2("adrs[%d]=%p\n",i,adrs);
		internalCode.wp=adrs; // オフセットを書き込む中間コード位置
		switch (nest_loop->loops[i].adrsFlag) {
			case ADRS_CONTINUE:
				// label3	2191
				DBG_printsn("continue");
				adrs=continueAddress;	// 書き込む飛び先アドレス	2194
				break;
			default: // 2196 ; breakのみのはず
				DBG_printf1("その他:%d\n",(int)nest_loop->loops[i].adrsFlag);
				adrs=breakAdrs;			// 書き込む飛び先アドレス	2198
				break;
		}
		writeOfstAdrs(internalCode.wp,adrs);
		i++;
	}
	// ループを抜ける	2203
	deleteNest();
	// 次の中間コードを書き込するのはbreakの位置
	internalCode.wp=breakAdrs;
}

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

// 以降をマルチステートメントとして処理させるための準備
static void forMultistatement(UWord ifFlag)
{
	DBG_Func();
	DBG_printName(source,10);
	// 正常に通すパターン
	// source={直後、またはthen直後の有効文字
	//					ok時	エラー時
	// then 文		(3)	*		*
	// then /*		(3)	*
	// then :/*		(1)	*		*
	// then:		(1)	*
	// then {		(2)	*				ifFlag=IF_BLOCK/IF_ELSE_BLOCK
	// then {:/*	(2)	*		*		同上	マルチステートメントの連続になるが、XBcompiler.m 200で対処
	if (ifFlag&IF_BLOCK) {
		// (2)
		DBG_printsn("ブロックがある");
		*--source=MULTI_STATEMENT3; // '{'を書き換える
		return;
	}
	if (*source==MULTI_STATEMENT) {
		// (1)すでにthen: , else:の場合は入れる必要なし
		// 事実上then:/* , else:/*のみ
		DBG_printsn("すでに':'がある");
		return;
	}
	// (3)その他
	// thenの後のスペースに':'を入れる
	DBG_printf2("その他:*source=%c($%02x)\n",*source,*source);
	*--source=MULTI_STATEMENT2;
}

void S_If(uwCODE code)
{	// 1736
	DBG_Func();
	storeInternalCode(code);	// 中間コード書き込み

	SLong lenL;
	UWord *wp=internalCode.wp;
	interpretMath(MATH_INT,&wp,&lenL);
	// wp			= 書き込んだ式解釈結果群の次のアドレス
	// internalCode	= 書き込んだ式解釈結果群の先頭アドレス になってる
	DBG_printf3("If式:%p～%p(len=%d)\n",internalCode.wp,wp,(int)lenL);
	
	// internalCode [0,1][2,3][4,5]
	if (readInternalCodeN()==T_INT) {	// int演算子
		code=*(internalCode.wp+1);	// 次の演算子
		DBG_printf1("int演算子:次code=$%04x\n",code);
		if (code>=EQU && code<=LARGEEQU) { // 関係演算子は中間コードに変換する
			DBG_printf1("関係演算子:次code=$%04x\n",*(internalCode.wp+2));
			if (_getType(*(internalCode.wp+2))==T_INT) { // int 型（定数であっても良い）
				DBG_printf1("演算子変更:$%04x->",code); // ここのcodeは中間コードではなく演算子のみのコード(CAL_CODE)
				code=(code-EQU)+CODE_ifeq;
				DBG_printf1("$%04x\n",code);
				storeInternalCodeWithOffsetN(code,-1);	// 中間コード書き込み	1567
				// 最初の演算子と次の演算子を除いた部分をコピーする
				DBG_printsn("最初の演算子と次の演算子を除いた部分をコピーする");
				lenL=lenL/2-2;
				while (lenL-->0) {	// 1760
				//	storeInternalCode(*(internalCode.wp+2));	// CORE_DEBUGなし時に警告が出るので展開
					*internalCode.wp=*(internalCode.wp+2);
					internalCode.wp++;
				}
				wp=internalCode.wp; // あとで再代入するため
			} // int以外
		} // 関係演算子以外
	} // int演算子以外
	internalCode.wp=wp;
	
	DBG_printsn("thenチェック");
	// 後ろにthenがあるか
	if (compareNameToSource((UByte *)nameTHEN,NO)!=CMP_EQUAL) {	// 1776
		// ない
		Error(ERR_SYNTAX_IF);
	}
	DBG_printsn("後ろにthenがある");
	
	UWord ifFlag=IF_1LINE;
	if (firstCheckSouceInLine()=='{') {	// 1782
		// ブロックif文
		ifFlag=IF_BLOCK;
		source++;
		DBG_printsn("{があるのでブロックif文");
	}
	#ifdef CORE_DEBUG
	else {
		// 1行if文
		DBG_printsn("1行if文");
	}
	#endif
	
	// 1787
	NEST_IF *nest_if=(NEST_IF *)defineNest(NESTTYPE_IF);
	nest_if->ifFlag	=ifFlag;			// flag
	nest_if->adrs	=internalCode.wp;	// 飛び先を書くアドレス
	internalCode.vp++;	// 後で飛び先.lを書き込むので飛ばしておく
	// 次の書き込み位置を保存
	DBG_printsn("ネスト設定");
	NEST_WORK *now=nest_work;
	now->next=(NEST_WORK *)nest_if->next; // 次のネストを書き込む位置
	DBG_printf2("now=%p,next=%p\n",now,now->next);
	checkNestWorkOver(now->next); // オーバーフローチェック

	// 以降をマルチステートメントとして処理させるための準備
	forMultistatement(ifFlag);
	//
	DBG_printsn("S_If(end)");
}

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

void S_Else(uwCODE code)
{
	DBG_Func();
	storeInternalCode(CODE_else);

	NEST_WORK *now=nest_work;
	if (now==NULL) {
		// ネストバッファ空っぽ
		Error(ERR_THEN_ELSE_WITH_NO_IF);
	}
	NEST_WORK *next=now->next;
	if (next==NULL) {
		// ネストバッファ空っぽ
		Error(ERR_THEN_ELSE_WITH_NO_IF);
	}
	if (now->nestType!=NESTTYPE_IF) { // 種類
		Error(ERR_THEN_ELSE_WITH_NO_IF);
	}

	NEST_IF *nest_if=(NEST_IF *)now->work; // 以後読み替えするため
	// a0=nest_if
	
	if (nest_if->ifFlag!=IF_1LINE) {
		// else 二重に使ってる／'{' に対応する '}' がない
		Error(ERR_THEN_ELSE_WITH_NO_IF);
	}
	
	SWord ifFlag=IF_ELSE;	// else
	if (firstCheckSouceInLine()=='{') {
		ifFlag=IF_ELSE_BLOCK;	// else_block_flag on
		source++;
	}
	nest_if->ifFlag=ifFlag;
	
	uwCODE *label2=internalCode.wp;	// label 2 を書くアドレスを保存
	uwCODE *label1=nest_if->adrs;	// label 1 を書くアドレス
	// iOS
	//label1=(uwCODE *)
#ifdef ARM64
	ULLong adrs=(ULLong)label2;
#else
	ULong  adrs=(ULong )label2;
#endif
	adrs+=SZ_VOIDP; // label2からにポインターを書き込み、その分label2を移動する ; ポインターのまま計算するとわかりにくいので数値化して計算
	writeOfstAdrs(label1,(uwCODE *)adrs);
	internalCode.vp++;		// label 1
	nest_if->adrs=label2;	// label 2 を書くアドレス
	
	// 以降をマルチステートメントとして処理させるための準備
	forMultistatement(ifFlag);
}

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

void If_end(void)
{
	DBG_Func();
	
	// 1つ前のifが作ったNEST_WORKを参照している状態

	NEST_WORK *now=nest_work;
	//
	if (now->nestType!=NESTTYPE_IF) {
		// ネストがifでない
		Error(ERR_THEN_ELSE_WITH_NO_IF);
	}
	
	NEST_IF *nest_if=(NEST_IF *)now->work; // 以後読み替えするため
	
	// 飛び先アドレスを相対で書き込む
	DBG_printsn("飛び先アドレスを相対で書き込む");
	writeOfstAdrs(nest_if->adrs,internalCode.wp);
	
	// nest_if->nextからにNEST_LOOPがつながっているなら、それを上につなげる
	// ループ中のifで発生する
	DBG_dumpNest();
	
	// これ以降memcpyでnowの内容が壊れるので先に必要な情報を読み出しておく
	NEST_WORK *next  =now->next;	// 次のブロックアドレス（このブロックの最終アドレス）
	NEST_WORK *before=now->before;	// 前のブロックのアドレス
	//
	psize_t sz=calcAdrsOffset(next,nest_if->next);
	DBG_printf3("%p<-%p～%zubytes\n",now,nest_if->next,sz);
	mmemcpy(now,nest_if->next,sz); // nowからにコピーするということは、1つ上の末尾にくっつけるということ

	// ネストリンクつなぎ直し
	DBG_printf1("ネストリンクつなぎ直し:before=%p\n",before);
	if (before==NULL) {
		now->next=NULL;		// 次ネスト構造無し；つなぎ直しなのでオーバーフローチェックなし
	} else {
		nest_work=before;	// 前のブロックのアドレス
		DBG_printf1("nest_work=%p(before)\n",nest_work);
		before->next=(NEST_WORK *)pointerAdd(now,sz);	// 今回のブロックの次のアドレスを入れる
		DBG_printf1("新しいnest=%p\n",before->next);
	}
	DBG_printsn("If_end(end)");
}

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

void S_Then(uwCODE code)
{
	DBG_Func();
	Error(ERR_THEN_ELSE_WITH_NO_IF);
}

//-----------------------------------------------
// print
//-----------------------------------------------

// 連続する#または%の数を数える
// comma : 途中に','があった場合その数を数える(#の数えは止めない)
//			=NULLのときは数えない(#を数えるのを止める)
static
int countSharps(UByte *(*format0),int *comma)
{
	UByte *format=*format0;
	int cnt=0;
	if (comma!=NULL) *comma=0;
	//
	UByte c;
	while ((c=*format),c=='#'||c=='%'||c==',') {
		if (c==',') {
			if (comma==NULL) {
				break; // 数えない
			} else {
				(*comma)++;
			}
		} else {
			cnt++; // 連続する#または%の数
		}
		format++;
	}
	//
	*format0=format;
	return (cnt);
}

// 書式文字かどうかを調べる
// フォーマット文字の'_'もここで処理する
// リターン値
//		>0 フォーマット文字として発見した文字
//		=0 普通文字だった → nc(UTF8/SJISなのでUByteとは限らない)
//		EOSならエラーが発生する
static
UByte checkUsingCharacter(UByte *(*format0),ULong *nc)
{
	DBG_Func();
	
	UByte *format=*format0;
	*nc=0;
	//
	ULong c=getSjisOrUtf8(&format,fsjisInRun);
	if (c==EOS) {
		// フォーマット文字群がない
		nslog(@"フォーマット文字群がない");
		Error(ERR_ILLEGAL_USING_FORMAT);
	}
	nslog(@"調べる1文字:%c($%x)",(char)c,(int)c);
	if (c<0x7f) { // isascii()は使うなと書いてあるので
		/*
			後ろに負号	-
			指数表示	^
			3桁毎に,	,
			は#の中で処理されるので、ここには入らない。
		*/
		UByte *formatChars=(UByte *)"#%.+*!&_@\\$$\x22"; // 一応ここでは日英両モード共通で認識させる
		UByte cf;
		do {
			cf=*formatChars++;
			if (cf==EOS) {
				nslog(@"不一致=書式文字ではない普通文字");
				*nc=c;
				c=0;
				break;
			}
		} while (c!=(ULong)cf);
		// 一致したフォーマット文字>0
		if (cf=='_') { // 素通し
			// 直後の1文字を素通しする
			// 基本的にはフォーマット文字向けだが、他の文字でも良い
			c=getSjisOrUtf8(&format,fsjisInRun);
			// c=素通し文字
			if (c=='"' || c<' ') {
				// ただし"とコントロールコードはだめ
				nslog(@"ただし\x22とコントロールコードはだめ");
				Error(ERR_ILLEGAL_USING_FORMAT);
			}
			*nc=c;
			c=0;
		}
	} else {
		// ASCII文字以外は絶対に一致しない
		// 不一致=書式文字ではない普通文字
		*nc=c;
		c=0;
	}
	nslog(@"素通し文字nc=$%x,フォーマット文字c=$%02x",(int)*nc,(int)c);
	//
	*format0=format;
	return (c);
}

// usingへの数値群を指定するときのセパレーターは';'でも','でもどちらでもよい
// X-BASIC/68では最初は';'限定である
static void checkUsingSeparator(void)
{
	UByte c;
	do { // 途中にスペースかタブがあった場合は読み飛ばす
		c=*source++;
	} while (c==' ' || c=='\t');
	if (c!=';' && c!=',') {
		nslog(@"checkUsingSeparator");
		Error(ERR_ILLEGAL_USING_FORMAT);
	}
}


void PrintUsing(void)
{ // 2581
	DBG_Func();
	
	// フォーマット文字列は"から始まる(文字列定数のみ)
	firstCheckSouceInLine();
	if (*source++!='"') {
		// using_format_err
		nslog(@"フォーマット文字列は\x22から始まる");
		Error(ERR_ILLEGAL_USING_FORMAT);
	}
	
	// いったん全体を軽くチェック
	// フォーマット文字には大きく分けて数値用と文字列用がある
	// 数値用は必ず#を伴い、その前後途中に修飾子が付く
	BOOL fnum=NO; // 文字列用の印
	UByte *format=source; // フォーマット文字列の位置
	UByte c;
	do {
		c=*source++;
		if (c==EOS || c==LF) { // 途中に改行やEOSがあったらエラー
			nslog(@"途中に改行やEOSがあったらエラー");
			Error(ERR_ILLEGAL_USING_FORMAT);
		}
		if (c=='#') fnum=YES; // #が入ってたら数値用
	} while (c!='"'); // 閉じ"まで
	// sourceは"～"の次のアドレス
	DBG_prints("フォーマット文字列:");
	DBG_printName(format,(int)(source-format)-1); // 閉じ側の"を除く
	nslog(@"直後=%p/文字='%c'",source,*source);
	nslog(@"フォーマット文字列:%@",fnum? @"数値用":@"文字列用");
	
	swStrLEN 	len=0,lenS=0; // 整数桁,小数桁
	UWord	fmtCode=USING_NONE;
	ULong	nc;
//	UByte	sep=';';		// 最初の引き数の区切り記号
	int		comma;
	uwCODE	*codeCount;		// 整数桁数を書き込んだ位置を記録する
	while (1) {
		// フォーマット文字チェック＆取得
		c=checkUsingCharacter(&format,&nc);
#ifdef CORE_DEBUG
		nslog(@"フォーマット文字:'%c'",c);
#endif
	  NextFormat:
		if (c=='"') {
			// 文字列終了
			nslog(@"フォーマット文字列終了");
			break;
		}
		#ifdef CORE_DEBUG2
		if (c==0) DBG_printf("普通文字:$%lx(c=0)\n",nc);
		else	  DBG_printf("処理する1文字:%c\n",c);
		#endif
		// iOS版では重複指定も許すし、記述順序も問わない。
		switch (c) {
			case '+': // us_plus
				// 前に符号を付ける
				if (fmtCode&USING_BPLUS) break; // 重複指定は排除
				fmtCode|=USING_BPLUS;	// 前にプラス
				DBG_printsn("フォーマット:前+");
				len++;
				continue;
//				goto us_num0;

			case '$':
				if (!operationStatus.fenglish) {
					// 英語モードでないときは普通の文字とする
					nc=c;
					goto NormalChar;
				}
				goto YenDollar;
			case '\\': // us_yen
				if (operationStatus.fenglish) {
					// 英語モードのときは普通の文字とする
					nc=c;
					goto NormalChar;
				}
			YenDollar:
				// 数字に\/$を付ける
				if (fmtCode&USING_YEN) break; // 重複指定は排除
				DBG_printsn("フォーマット:\\/$$");
				// 指定は\/$2個連続で初めて有効になる
				if (*format++!=c) {
					// 1つならエラー
					nslog(@"$が２個連続でなければエラー");
					Error(ERR_ILLEGAL_USING_FORMAT);
				}
				fmtCode|=USING_YEN;	// 前に￥/$
				len+=2;
				continue;
//				goto us_num0;

			case '*': // us_ast
				// "**"=空白を*で埋める
				// "%"と重複指定した場合、こちらが優先
				if (fmtCode&USING_ASTA) break; // 重複指定は排除
				DBG_printsn("フォーマット:**");
				switch (*format++) {
					case '*':fmtCode|=USING_ASTA; break;
					default:
						nslog(@"**が２個連続でなければエラー");
						Error(ERR_ILLEGAL_USING_FORMAT);
				}
				len+=2;
				if (*format==(operationStatus.fenglish? '$':'\\')) {
					// **\/**$の時
					if (fmtCode&USING_YEN) break; // 重複指定は排除
					format++;
					fmtCode|=USING_YEN;	// 前に￥＊
					len++;
				}
				continue;
//				goto us_num0;
			
			case '.': // us_period
				nslog(@"フォーマット:.");
				if (!fnum) {
					nslog(@"文字列用なので通常文字とする");
					nc=c;
					goto NormalChar; // 文字列型の時は普通文字として扱う
				}
				// 小数点位置の指定
				// 数値のフォーマット '##.#'
				char cc=*format;
				if (cc!='#' && cc!='%') {
					// 後ろに小数点以下の桁数指定がない場合は、普通文字として処理する
			case 0: // フォーマット文字ではない＝普通文字
			NormalChar:
					storeInternalCode(_CONSTANT|T_STR); // str 型	2625
					storeInternalCode(_CONSTANT|T_STR); // の定数	2626	!!何で2回も書いているのかは不明!!
					// 以降の文字列の書き込み
					DBG_printsn("以降の文字列の書き込み");
					do {	// 2627
						// storeInternalCodeB(nc); // 1文字書き込み	2628
						internalCode.bp=storeSjisOrUtf8(internalCode.bp,nc,fsjisInRun);
						// 次の文字はフォーマット文字？
						c=checkUsingCharacter(&format,&nc);	// 2629
						// 普通文字が続くなら連続で書き込む
					} while (c==0);
					storeInternalCodeB(EOS); // EOS
					if (internalCode.l&1) storeInternalCodeB(EOS); // 偶数境界化
					DBG_printf1("\n次のフォーマット文字=%c\n",c);
					len=0; // 普通文字が出てきたら整数桁数リセット
					goto NextFormat; // そのフォーマット文字の処理へ
				} // if (cc!='#' && cc!='%')
			case '%':
				fmtCode|=USING_ZERO;
			case '#': // us_num
				// 表示する数値の桁数を指定する
				nslog(@"表示する数値の桁数を指定する(開始):source=%p",source);
				format--;
		//	us_num0:
				storeInternalCode(UsingNum);	// 中間コード書き込み
				
				// ここでsourceはすでにusing ""の直後を示しており、その先にある表示すべき数値群の解釈を待っている
				// それらはセパレーターで区切られており、一連の#群につき1つずつ解釈を進める
				checkUsingSeparator(); // セパレーターチェック
				interpretMath(MATH_FLOAT,&internalCode.wp,NULL); // 表示する数値の解釈
				// 結局ここでの中間コードの書き込みは、
				// UsingNum,数値,整数桁,少数桁,フォーマット指定子の順になる
				
				// #を数える;整数部の桁数
				// 途中に,があったときは3桁ごと,で区切るも発動
				len+=countSharps(&format,&comma); // 整数部桁数には、**/\\/**\の桁数も含まれる
				nslog(@"整数部桁数=%d/comma=%d\n",len,comma);
				codeCount=internalCode.wp;	// 整数桁を記録した位置を保存(後で補正するかもしれないので)
				storeInternalCode(len);		// 整数桁
				if (comma>0) {
					fmtCode|=USING_COMMA;
					nslog(@"フォーマット指定子','あり:comma=%d",comma);
				}
				// 2739
				if (*format=='.') {
					// 2742
					format++;
					// #を数える;小数部の桁数
					lenS=countSharps(&format,NULL);
					DBG_printf1("小数部桁数=%d\n",lenS);
					storeInternalCode(lenS);	// 小数桁数
				} else { // 2747
					storeInternalCode(0);		// 小数桁数=0
				}
				// ##の後に続くフォーマット指定子を読む
				int fcheckEnd=NO;
				do {
					switch (*format) {
						default:
							DBG_printf1("フォーマット指定子以外→終了:'%c'\n",*format);
							fcheckEnd=YES;
							break;
						
						case '+': // us_plus2
							DBG_printsn("フォーマット:後ろ+");
							fmtCode|=USING_APLUS;	// 後ろ＋
							format++;
							break;
						case '-': // us_minus
							DBG_printsn("フォーマット:後ろ-");
							fmtCode|=USING_AMINUS;	// 後ろ－
							format++;
							break;
						case '^': // us_exp
							DBG_printsn("フォーマット:指数表現");
							// 指数表現は^を5つ連続で並べる
							// UTF8では2バイト目以降に^はこない
							// SHIFT-JISでは2バイト目に来る可能性はあるが、
							// checkUsingCharacter()は2バイト目のみ取り出さないので問題ない。
							if (memcmp((char *)format,"^^^^^",5)==0) {
								format+=5;
								fmtCode|=USING_SISUU;	// 指数表現
								if (fmtCode&USING_COMMA) {
									// 指数表現時は,は効かない
									fmtCode&=~(USING_COMMA);
									len+=comma; // コンマの出現もすべて桁数にする
									*codeCount=len; // 表示桁数を変更
									DBG_printf2("指数表現時は,は効かない:コンマ桁数=%d → 整数桁:%d\n",comma,len);
								}
							}
							break;
					}
				} while (!fcheckEnd);
				nslog(@"フォーマット指定:$%04x\n",fmtCode);
				storeInternalCode(fmtCode);
				break;

			// ↓文字列用

			case '!': // us_str1
				// 文字列の先頭1文字だけ表示する
				DBG_printsn("文字列の先頭1文字だけ表示する");
				lenS=1;
				goto us_str0;

			case '&': // us_str
				// 文字列を&から&までの文字数にする
				// &+空白+&の文字数
				DBG_printsn("文字列を&から&までの文字数にする");
				lenS=1; // 最初の&の文
				do {
					lenS++; // 最短で後ろの&、もしくは空白
				} while (*format++==' ');
				if (*(format-1)!='&') {
					nslog(@"&がなければエラー");
					Error(ERR_ILLEGAL_USING_FORMAT);
				}
			us_str0:
			//	DBG_printf2("lenS=%d/sep=%c\n",lenS,sep);
				DBG_printf1("lenS=%d\n",lenS);
				DBG2_printName(source,10);
				checkUsingSeparator();
				#if 0
				if (sep!=*source++) { // 指定セパレーターでないときはエラー
					nslog(@"指定セパレーターでない");
					Error(ERR_ILLEGAL_USING_FORMAT);
				}
				#endif
				storeInternalCode(UsingStr); // 中間コード書き込み
				//
				DBG_printsn("print using &からの呼び出し");
				interpretMath(MATH_STR,&internalCode.wp,NULL);
				DBG_printsn("print using &からの呼び出し終了");
				//
				//sep=',';	// 次の引き数の区切り記号
				storeInternalCode(lenS); // 文字列長
				break;

			case '@':
				// 文字列全出力
				checkUsingSeparator();
				#if 0
				if (sep!=*source++) {
					nslog(@"@のエラー");
					Error(ERR_ILLEGAL_USING_FORMAT);
				}
				#endif
				storeInternalCode(_CONSTANT|T_STR);
				//
				nslog(@"print using @からの呼び出し");
				interpretMath(MATH_STR,&internalCode.wp,NULL);
				nslog(@"print using @からの呼び出し終了");
				//
				//sep=',';	// 次の引き数の区切り記号
				break;
		} // switch
		nslog(@"using 1文字処理終了");
	} // while
	// フォーマット文字列終了 2783
	nslog(@"フォーマット文字列終了:直後='%c'/source=%p",*source,source);
	// 数値群の後に';'を付けたときは「改行しない」を意味する
	// ','をつけたら文法エラー(X-BASIC/68)
	switch (*source) {
		case ';':
			// 後ろが;なら改行しない	2786
			nslog(@"using:後ろが;なら改行しない");
			source++; // ;を飛ばす
			storeInternalCode(NoCrLfEnd);
			break;
		case ',': // V2.1
			nslog(@"using:後ろに,がある");
			Error(ERR_ILLEGAL_USING_FORMAT);
			break;
		default:
			// そうでなかったら改行
			storeInternalCode(CrLfEnd);
			break;
	}
	// 以下V2.1
	// usingで解釈余りの引数があったら、usingのエラーにする
	// これをしないと普通のSyntaxErrorになり、わかりにくいので
	switch (firstCheckSouceInLine()) {
		case EOL: // 改行系=OK
		case ':': // セパレーター
			break;
		case '/': // コメントかも
		{
			char c=*source;
			if (c=='/'||c=='*') break; // コメントなので無視
		}
		default:
			nslog(@"using:余り引数あり");
			Error(ERR_ILLEGAL_USING_FORMAT);
			break;
	}
}

void S_Print(uwCODE code)
{	// 2485
	DBG_Func();
	
	storeInternalCode(code);	// 中間コード書き込み	2486

	firstCheckSouceInLine();	// 2488
	if (compareNameToSource((UByte*)"using",NO)==CMP_EQUAL) {
		// print using
		PrintUsing();	// 2491
		return;
	}
	
	// usingがないprint
	nslog(@"usingがないprint");
	UByte c;
	int fend=NO;
	do {	// 2493
		switch (firstCheckSouceInLine()) {	// 2494
			case '/': // 2508
				nslog(@"/があった");
				c=*(source+1);
				if (c=='*'||c=='/') {
					// /*または// == 注釈	2509
					nslog(@"//があった->コメント");
			case '}': // 2501
	// MULTI_STATEMENT2はthen/else直後にしかこないから、ここで来たらだめ
	//		case MULTI_STATEMENT2:
			case MULTI_STATEMENT: // 2503 ':'
			case EOL: // 行終わり
					fend=YES;
					break;
				}
				// / の次が *,/ 以外
				goto pr_main;
			
			default:
				// 2519
				if (elseCheck()==YES) {
					// 2573 pr_crlf_end相当
					fend=YES;
					break;
				} // if (elseCheck())
				// 以下普通
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9': // 数字
			pr_main:; // 2525
				UWord *store=internalCode.wp;
				store++; // 後で型を入れる場所を飛ばしておく
				SLong len;
				uwMATHTYPE msType=interpretMath(MATH_VOID,&store,&len);
				storeInternalCode(_dainyuWithType(_mathType2Type(msType)));	// 中間コード書き込み(代入式);先に飛ばした場所
				internalCode.l+=len;
				continue;
			//
			case ',': // 連続表示	2511
				// pr_1	2544
				storeInternalCode(TabJump); // print用中間コード
			case ';': // 非改行	2516,2517
				// 2547
				source++;
				switch (firstCheckSouceInLine()) {	// 2549
					case '/':	// 2559
						c=*(source+1);
						if (c=='*'||c=='/') { // /*または//	2562
					case EOL: // 行終わり
				// MULTI_STATEMENT2はthen/else直後にしかこないから、ここで来たらだめ
				//	case MULTI_STATEMENT2:
					case MULTI_STATEMENT:	// 2555 ':'
					case '}':	// 2577
							// pr_not_crlf_end: 2570
							storeInternalCode(NoCrLfEnd);
							return;
						}
						// / の次が *か/ 以外
						break;
				}
				// else があるかどうかチェック	2564
				if (elseCheck()==YES) {
					// pr_not_crlf_end相当	2570
					storeInternalCode(NoCrLfEnd);
					return;
				}
				break;
		}
	} while (fend==NO);
	// pr_crlf_end	2573
	// 改行して終了
	storeInternalCode(CrLfEnd);
}

//-----------------------------------------------
// input
//-----------------------------------------------

// 入力催促メッセージを中間コードに落としながら飛ばす
static
UByte skipInputMessageInCompile(void)
{	// 2854
	source++;	// 2856 初めの"を飛ばす
	ULong c;
	while ((c=getSjisOrUtf8(&source,fsjisInRun))!='"') { // 2858
		switch (c) {
			case EOS:
			case LF:
			case CR:
				Error(ERR_SYNTAX_INPUT);
		}
		if (fsjisInRun) {
			// 表示用にUTF8に変換
			c=sjisToUtf8(c);	// SHIFT-JIS → UTF8
		}
		internalCode.bp=storeUtf8(internalCode.bp,c);
	}
	return (firstCheckSouceInLine());
}

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

void S_Input(uwCODE code)
{	// 2877
	DBG_Func();
	storeInternalCode(code);	// 中間コード書き込み	2878

	DBG_printf1("source=%p～\n",source);
	if (*source=='"') { // 入力催促メッセージがあるとき	2880
		switch (skipInputMessageInCompile()) {
			default:
				Error(ERR_SYNTAX_INPUT);
			case ',':
			case ';':
				break;
		}
		source++; // 後で--するから
	}
	source--;
	DBG_printf1("source=%p\n",source);
	storeInternalCodeB(EOS); // EOS
	if (internalCode.l&1) storeInternalCodeB(EOS); // 偶数バイト化	2892
	DBG_printf1("even=%p\n",source);
	
	// 変数名ゲット	2894
	do { // input_loop	2895
		source++;	// 2896
		firstCheckSouceInLine();	// 2898
		swStrLEN	len;
		uwHash	hash;
		UByte	*name=source;
		calcHash(source,&len,&hash,&source);	// 2899
		DBG_printName(name,len);
		if (len<=0) {
			Error(ERR_SYNTAX_INPUT);
		}
		swVarNO	no;
		sbVarSTAT	stat;
		DIM1	*dimInfo;
		uwMATHTYPE msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);	// 2902
		if (msType==MATH_NONE||(stat&VARIABLE_SYSTEM)) {
			// 未宣言またはシステム変数
			Error(ERR_UNDEFINED_VARIABLE);
		}
		if (stat&VARIABLE_DIM) {
			// 型違い(配列が来てる)
			Error(ERR_MISMATCH_VARIABLE_TYPE);
		}
		if (_isStatLocal(stat)) { // ローカル変数
			no=_setLocal(no);
		}
		storeInternalCode(msType);	// 2923
		storeInternalCode(no);		// 2923
	} while (*source==',');	// 2925
	// 終わりの印	2928
	// これで入力数を判断する
	storeInternalCode(MATH_VOID);
}

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

void S_Linput(uwCODE code)
{
	DBG_Func();
	storeInternalCode(code);	// 中間コード書き込み

	if (*source=='"') {
		skipInputMessageInCompile();
		if (*source++!=';') {
			Error(ERR_SYNTAX_INPUT);
		}
	}
	storeInternalCodeB(EOS); // EOS
	if (internalCode.l&1) storeInternalCodeB(EOS); // 偶数バイト化
	
	// 文字列変数名ゲット
	firstCheckSouceInLine();
	swStrLEN	len;
	uwHash	hash;
	UByte	*name=source;
	calcHash(source,&len,&hash,&source);
	DBG_printName(name,len);
	if (len<=0) {
		Error(ERR_SYNTAX_INPUT);
	}
	swVarNO	no;
	sbVarSTAT	stat;
	DIM1	*dimInfo;
	uwMATHTYPE msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);
	if (msType==MATH_NONE||(stat&VARIABLE_SYSTEM)) {
		// システム変数も含む
		Error(ERR_UNDEFINED_VARIABLE);
	}
	if (msType!=MATH_STR) {
		// 文字列以外
		Error(ERR_MISMATCH_VARIABLE_TYPE);
	}
	if (stat&VARIABLE_DIM) {
		// 型違い(配列が来てる)
		Error(ERR_MISMATCH_VARIABLE_TYPE);
	}
	if (_isStatLocal(stat)) { // ローカル変数
		no=_setLocal(no);
	}
	storeInternalCode(no);
}

//-----------------------------------------------
// 変数宣言系
//-----------------------------------------------

void S_Int(uwCODE code)
{
	DBG_Func();
	variableDefine((operationStatus.flocal? &LocalInt:&GlobalInt)		,T_INT	);
}

void S_Str(uwCODE code)
{
	DBG_Func();
	variableDefine((operationStatus.flocal? &LocalStr:&GlobalStr)		,T_STR	);
}

void S_Float(uwCODE code)
{
	DBG_Func();
	variableDefine((operationStatus.flocal? &LocalFloat:&GlobalFloat)	,T_FLOAT);
}

void S_Char(uwCODE code)
{
	DBG_Func();
	variableDefine((operationStatus.flocal? &LocalChar:&GlobalChar)		,T_CHAR	);
}

void S_Dim(uwCODE code)
{
	DBG_Func();
	// dimは前に型が付く ; 「例」dim int a(10)
 	// getTypeWithSource()で型を得てから定義処理へ
	variableDefine(NULL,getTypeWithSource(NULL,NULL));
	// 関数の引数にするときは後ろに;型が付く
	// これは他の型も同じ
	// funcの中が逆なのがそもそもわかりづらい
}

//-----------------------------------------------
// その他ステートメント
//-----------------------------------------------

void S_Error(uwCODE code)
{
	DBG_Func();
	storeInternalCode(code);	// 中間コード書き込み

	if (memcmp((char *)source,"on2" ,3)==0) { // v2.6
		source+=3;			// sizeof('on2')
		storeInternalCode(ERR_ON2);	// 引数書き込み
		return;
	}
	if (memcmp((char *)source,"on" ,2)==0) {
		source+=2;			// sizeof('on')
		storeInternalCode(ERR_ON);	// 引数書き込み
		return;
	}
	if (memcmp((char *)source,"off",3)==0) {
		source+=3;			// sizeof('off')
		storeInternalCode(ERR_OFF);	// 引数書き込み
		return;
	}
	Error(ERR_SYNTAX);
}

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

void S_End(uwCODE code)
{
	DBG_Func();
	fend=YES; // endがあった
	storeInternalCode(code);	// 中間コード書き込み
}

void S_Stop(uwCODE code)
{
	DBG_Func();
	storeInternalCode(code);	// 中間コード書き込み
}

void S_Exit(uwCODE code)
{
	DBG_Func();
#ifdef DOS
	if (*source++!='(') {
		Error(ERR_SYNTAX_EXIT);
	}
	if (firstCheckSouceInLine()==')') { // exit();
		source++;
		storeInternalCode(CODE_end);	// 中間コード書き込み
	} else { // exit(no);
		storeInternalCode(code);		// 中間コード書き込み
		// noを得る
		interpretMath(MATH_INT,&internalCode.wp,NULL);
		//
		if (*source++!=')') {
			Error(ERR_SYNTAX_EXIT);
		}
	}
#else	// iOS
	Error(ERR_NON_SUPPORT_STATEMENT);	// 未サポート
#endif
}

//--------------------------------------------------------------------------------------
// enum〜endenum	(V2.1,V3.1)
//--------------------------------------------------------------------------------------

void S_Enum(uwCODE code)
{
	DBG_Func();
	// enum自体〜endenumまではコードに出力されない
	if (operationStatus.fenum!=ENUM_NONE) {
		// enum中にenumが来た
		Error(ERR_NO_ENDENUM);
	}
	operationStatus.fenum=ENUM_INT;	// int enum開始
	operationStatus.intEnum=0;		// 値の初期値
}

void S_FEnum(uwCODE code)
{
	DBG_Func();
	// fenum自体〜endenumまではコードに出力されない
	if (operationStatus.fenum!=ENUM_NONE) {
		// enum中にenumが来た
		Error(ERR_NO_ENDENUM);
	}
	operationStatus.fenum=ENUM_FLOAT;	// float enum開始
	operationStatus.floatEnum=0.0;		// 値の初期値
}

#if 0
void S_SEnum(uwCODE code)
{
	DBG_Func();
	// senum自体〜endenumまではコードに出力されない
	if (operationStatus.fenum!=ENUM_NONE) {
		// enum中にenumが来た
		Error(ERR_NO_ENDENUM);
	}
	operationStatus.fenum=ENUM_STR;	// str enum開始
}
#endif

void S_Endenum(uwCODE code)
{
	DBG_Func();
	// endenum自体はコードに出力されない
	// enum/fenum/senum全て終わりはendenum(ネストできないのでこれでよい)
	
	nslog(@"operationStatus.fenum=%d",operationStatus.fenum);
	if (operationStatus.fenum==ENUM_NONE) {
		Error(ERR_NO_ENUM_TO_ENDENUM);
	}
	operationStatus.fenum=ENUM_NONE;	// enum終了
}

//--------------------------------------------------------------------------------------
// ステートメント表
//--------------------------------------------------------------------------------------

STATEMENT_TABLE statements[]={ // ステートメント;CODE_*と合わせること
	// hash/len部は初期化処理で入れ込む
	{0,0,"_dummy_"}, 	// 0=ダミー;NULLにしてはいけない
	{0,0,"print"},
	{0,0,"break"},
	{0,0,"case"},
	{0,0,"continue"},
	{0,0,"default"},
	{0,0,"endfunc"},
	{0,0,"endswitch"},
	{0,0,"error"},
	{0,0,"return"},
	{0,0,"switch"},		// 10
	{0,0,"end"},
	{0,0,"endwhile"},
	{0,0,"exit"},
	{0,0,"for"},
	{0,0,"gosub"},
	{0,0,"goto"},
	{0,0,"if"},
	{0,0,"input"},
	{0,0,"linput"},
	{0,0,"next"},		// 20
	{0,0,"repeat"},
	{0,0,"stop"},
	{0,0,"until"},
	{0,0,"while"},
	{0,0,"dim"},
	{0,0,"str"},
	{0,0,"func"},
	{0,0,nameELSE},
	{0,0,nameTHEN},
	{0,0,"label"},		// 30
	// ここから先はCODE_*と全く異なる;実行時には処理されない(存在しない＝コンパイルで終わる)ステートメント
	{0,0,"float"},
	{0,0,"int"},
	{0,0,"char"},
	{0,0,"enum"},				// v2.1
	{0,0,"endenum"},			// v2.1
	{0,0,"fenum"},				// v3.10
#if 0
	{0,0,"senum"},
#endif
	// end of table
	{0,0,NULL}
};

typedef struct {
	void (*exec)(uwCODE code);
} STATEMENT_JUMP_TABLE;
static 	STATEMENT_JUMP_TABLE statJumpTable[]={
	{NULL},				// ダミー
	// Cの標準構文名と重複させないようS_を付ける
	{S_Print},
	{S_Break},
	{S_Case},
	{S_Continue},
	{S_Default},
	{S_Endfunc},
	{S_Endswitch},
	{S_Error},
	{S_Return},
	{S_Switch},		// 10
	{S_End},
	{S_Endwhile},
	{S_Exit},
	{S_For},
	{S_Gosub},
	{S_Goto},
	{S_If},
	{S_Input},
	{S_Linput},
	{S_Next},		// 20
	{S_Repeat},
	{S_Stop},
	{S_Until},
	{S_While},
	{S_Dim},
	{S_Str},
	{S_Func},
	{S_Else},
	{S_Then},
	{NULL},			// 30 ラベルはここには処理なし(XBcompiler)
	// ここから先はCODE_*と全く異なる
	{S_Float},
	{S_Int},
	{S_Char},
	{S_Enum},
	{S_Endenum},
	{S_FEnum},
#if 0
	{S_SEnum},
#endif
};

void makeupStatementTable(void)
// 内蔵ステートメント表にハッシュ値＆文字列長情報を入れ完成させる
{
	DBG_Func();
	int i=1; // __dummy__分は作らない
	const char *st;
	while ((st=statements[i].token)!=NULL) {
		uwHash	hash;
		swStrLEN	len;
	 	calcHash((UByte *)st,&len,&hash,NULL);
	 	// ここではlen=0のチェックは不要(あったらプログラムの記述ミス)
		DBG_printf3("%s:len=%d/hash=$%04x\n",st,len,hash);
		statements[i].hash=hash;
		statements[i].len =len;
		i++;
	}
}

// ステートメント用のハッシュ値テーブル(ASC1文字:1対応)
static char statementHashTable[256];

// 内蔵ステートメントのハッシュ値表を作る
// オリジナルでは固定の表だったが、iOS版ではステートメントを削ったのでそのままでは使えなくなったため
void makeStatementHashTable(void)
{
	DBG2_Func();
	int c; // UByteにすると256で0になってしまうので念のため
	for (c=0x00;c<=0xff;c++) statementHashTable[c]=0x00; // 初期化
	c=0x01; // 0x00はダミーなので飛ばしておく
	while (statements[c].token!=NULL) {
		uwHash hash=statements[c].hash;
	 	// そのハッシュ値を持つステートメントの要素番号を記録しておく
	 	// 「検索時は、その番号より下にしか比較対象にすべきものはない」となる
	 	hash&=0xff;
	 	if (statementHashTable[hash]==0x00) statementHashTable[hash]=c;
	 	c++;
	}
	DBG2_dump("makeStatementHashTable",statementHashTable,sizeof(statementHashTable));
	DBG2_prints("makeStatementHashTable(end)");
}

// 対象がどれかステートメントと一致するかどうか
// hash = ハッシュ値
// len  = 文字数 - 1
// name = 元の対象の開始アドレス
// リターン値 : 一致 = そのステートメント番号(中間コード;CODE_*) / 不一致 = CODE_NONE
uwCODE statementCheck(uwHash hash,swStrLEN len,UByte *name)
{
	DBG_Func(); // 構文名と一致するかチェック
	DBG2_printf2("hash=$%04x/tbl=%d\n",hash,statementHashTable[hash&0xff]);
	UByte b=statementHashTable[hash&0xff]; // ハッシュ値の下位1バイトで見当を付ける
	while (b!=0) {
		if (statements[b].token==NULL) break; // 見つからなかった
		if (statements[b].len==len) {
			DBG_printf2("stat:%s(len=%d)\n",statements[b].token,len);
			if (memcmp((char *)statements[b].token,(char *)name,len)==0) {
				// 全一致
				DBG_printf2("stat(%d)=%s\n",b,statements[b].token);
				return ((UWord)b);
			}
		}
		// 同一ハッシュ/同一長のステートメントがあったときのため
		b++;
	} // ハッシュ表=0は、相当する文字列がないので不一致
	// 不一致
	DBG2_printsn("不一致");
	return (CODE_NONE);
}

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

// 各ステートメントごとに文法が違うのでいちいち異なる解釈をする
// code = statment番号
void interpretStatement(uwCODE code)
{	// 576	stat解釈
	DBG_Func();
	DBG_printCode(code);
	statJumpTable[code].exec(code);
}

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