//--------------------------------------------------------------------------------------
// X-BASIC'
// コンパイラ部分
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "XB.h"
#import "malloc2.h"

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

// 各行の先頭アドレスのテーブル=sourceAdrsEachLinesBuffCtrl()を作る
static
void makeEachLineAdrs(UByte *sourceTop)
{
	nslog(@"%s",__FUNCTION__);
	DBG_Func();
	//
//	DBG_printf1("最初ソースコード位置:source=%p → writeChainBufferL\n",sourceTop);
	nslog(@"最初ソースコード位置:source=%p → writeChainBufferL",sourceTop);
	addValueForBuffer(&sourceAdrsEachLinesBuffCtrl,&sourceTop); // ソースコード行毎先頭アドレス(最初はエリア先頭)
	//DBG_printName(sourceTop,10);

	// ソースコード行毎先頭アドレス : lineNoと対応する
	UByte c;
	while ((c=*sourceTop++)!=EOS) {
		switch (c) {
			case CR:
				if (*sourceTop==LF) {
					// CR+LF
					sourceTop++;
				}
			case LF:
//				DBG_printf1("行先頭ソースコード位置:source=%p → writeChainBufferL\n",sourceTop);
				nslog(@"行先頭ソースコード位置:source=%p → writeChainBufferL",sourceTop);
				addValueForBuffer(&sourceAdrsEachLinesBuffCtrl,&sourceTop);
				//DBG_printName(sourceTop,10);
				break;
		} // switch
	} // while
}

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

// アドレス→行番号変換
uwLineNO getLineNo(UByte *line)
{
	DBG_printf2("%s:line=%p\n",__FUNCTION__,line);
	DBG_printName(line,10);
	UByte *bp=sourceTop;
	uwLineNO lno=0;
	do {
		// 行数から行アドレスを得る
		SOURCEADRS *adrs=getValueFromBuffer(&sourceAdrsEachLinesBuffCtrl,lno); // その行の先頭アドレス
		UByte *bp2=*adrs;
		if (line>=bp && line<=bp2) {
//			DBG_printName(bp ,10);
//			DBG_printName(bp2,10);
			break;
		}
		lno++;
		bp=bp2;
	} while (bp<sourceEnd);
	// whileで終わってはいけない(というか、正しいアドレスなら来ない)
	return (lno); // 0〜
}

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

#ifdef DEBUG
void variableBuffPrint(void *data)
{
	UWord wp=*(UWord *)data;
	printf("var=$%04x(%d)\n",wp,wp);
}

void sourceAdrsEachLinesBuffPrint(void *data)
{
	SOURCEADRS adrs=*(SOURCEADRS *)data;
	printf("SrcAadrs=%p\n",adrs);
}

void internalCodeBytesBy1LineBuffPrint(void *data)
{
	CODEBYTES bytes=*(CODEBYTES *)data;
	printf("CodeBytes=%d\n",bytes);
}

void paramBuffPrint(void *data)
{
	PARAM_CHAIN *param=(PARAM_CHAIN *)data;
	printf("msType=$%04x,"	,param->msType);
	printf("no=%d\n"		,param->no);
}

void labelBuffPrint(void *data)
{
	LABEL_CHAIN *label=(LABEL_CHAIN *)data;
	printf("len=%d,"		,(int)label->len);
	printf("name=%s,"		,label->name);
	printf("lineAdrs=%p,"	,label->lineAdrs);
	printf("flabel=%d\n"	,(int)label->flabel);
}

void gotoBuffPrint(void *data)
{
	GOTO_CHAIN *goto1=(GOTO_CHAIN *)data;
	printf("no=%d,"		,(int)goto1->no);
	printf("jump=%p\n"	,goto1->jump);
}
#endif

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

// コンパイラ初期化処理
void initXBcompiler(UByte *sourceText)
{
	DBG_Func();
	
	errorNo =ERR_NONE;
	exitCode=0;
	//
	operationStatus.flocal 	=NO;
	operationStatus.finFunc	=NO;	// 最初はfunc中ではない
	operationStatus.fenum	=ENUM_NONE;	// 最初はenum中ではない
	//
	// ハッシュ計算用テーブルの初期化
	makeHashTable();
	// ステートメント表構築
	makeupStatementTable();
	makeStatementHashTable();
	// システム変数の設定
	makeSystemVariableTable();
	//
	// 外部関数設定
	externalFunctionRead();	// (エラーあり)
	
	// 外部関数の初期化処理
	externalFunctionsRoutine(noFinit);
	DBG_printsn("--------------------------------");
	//
	// 内部で使用する変数の初期化
	GlobalInt.cnt	=0;
	GlobalStr.cnt	=0;
	GlobalChar.cnt 	=0;
	GlobalFloat.cnt	=0;
	GlobalArray.cnt	=0;
	//
	// initBuffer(構造体,増分,１要素サイズ)
	initBuffer(&variableBuffCtrl				,16*K	,sizeof(UWord)		,variableBuffPrint);					// 変数領域は可変要素になるので、UWord単位で確保しておき、分割利用する(元のチェインバッファーと同じになる)
	initBuffer(&sourceAdrsEachLinesBuffCtrl		,1*K	,sizeof(SOURCEADRS)	,sourceAdrsEachLinesBuffPrint);			// ソース行ごとの先頭アドレス
	initBuffer(&internalCodeBytesBy1LineBuffCtrl,1*K	,sizeof(CODEBYTES)	,internalCodeBytesBy1LineBuffPrint);	// 行ごとの中間コードバイト数
	initBuffer(&paramBuffCtrl					,512	,sizeof(PARAM_CHAIN),paramBuffPrint);
	initBuffer(&labelBuffCtrl					,64		,sizeof(LABEL_CHAIN),labelBuffPrint);
	initBuffer(&gotoBuffCtrl					,32		,sizeof(GOTO_CHAIN)	,gotoBuffPrint);
	//
	initEnum();
	
	// 275
	// ネスティングワークの割り付け&初期化
	nest_work=(NEST_WORK *)nestWorkHontai;
	nest_work->next  =NULL;
	nest_work->before=NULL;
	nest_work->nestType=0; // 念のため
	DBG_printf1("nest_work=%p\n",nest_work);
	//
	defineNameInit();	// 名前バッファー初期化

	DBG_printsn("-----------------------------------\nプログラム全体から'func'を探し、内部関数として名前とパラメーターリストを登録する");
	// 以下のエラー処理のため、各行の先頭アドレスのテーブル=sourceAdrsEachLinesBuffCtrl()を作る
	makeEachLineAdrs(sourceTop);

	// プログラム全体から'func'の文字列を探し、内部関数として登録する
	lineNo=LINENO_SPECIAL;	// エラー発生時のソース行をlineNoによらず得る印
	source=sourceText;		// グローバルアクセスのため
	internalFunction();		// (エラーあり)
	
	// グローバル関数ブロックの冒頭処理
	DBG_printsn("グローバル関数ブロックの冒頭処理");
	INTERNAL_CODE_INFO *internalCodeInfo=(INTERNAL_CODE_INFO *)internalCodeTop;
	internalCodeInfo->varChainListNo  =0;	// 変数チェインリストから指定ブロックの変数情報を取り込む位置
	// 341
	internalCodeInfo->paramChainListNo=0;	// パラメーターチェインリストから引数情報を取り込む位置;[0]
	PARAM_CHAIN param1={0,0}; 				// グローバルは引数の個数=0
	addValueForBuffer(&paramBuffCtrl, &param1);
}

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

// コンパイラーメイン
XB_ERRORNO mainXBcompiler(UByte *sourceText)
{
	DBG_Func();
	
	lineNo=0;
	
	// 中間コード領域の先頭にINTERNAL_CODE_INFOが入ってる
	INTERNAL_CODE_INFO *internalCodeInfo=(INTERNAL_CODE_INFO *)internalCodeTop; // 最初は一番先頭から
	internalCode.wp     =internalCodeInfo->codes; // 実中間コードの格納はここから
	internalCodePrevLine=internalCode.wp; // 1行前の中間コード格納位置
	//
	source=sourceText; // グローバルアクセスのため
	DBG_printf2("source=%p～%p\n",sourceTop,sourceEnd);
	//
	swStrLEN	len;
	SLong		lenL;
	uwHash		hash;
	UByte		*name;
	UByte		c;
	SWord		ifFlag;
	NEST_WORK *now;
	NEST_IF	  *nest_if;
	
	while (1) {	// 350	解釈ループ0
		DBG_prints("\n---------------------解釈ループ開始(XBcompiler)\n");
		switch (setjmp(jmpEnv)) {
			case JMP_IERROR: // 来たらおかしい
			case JMP_ERROR:
				if (lastErrNo==ERR_NO_WORKAREA) {
					// メモリ不足の時だけは特殊処理
					return (ERR_NO_WORKAREA);
				}
				nslog(@"mainXBcompiler:ループ中にエラー発生(1行飛ばしで続行)");
				if (errorLimit>0) { // エラー発生上限指定有り
					if (errorCnt>=errorLimit) {
						// エラー発生数がエラー発生上限を超えるとき
						return(ERR_NONE); // コンパイル強制終了
					}
				}
				UByte c=skipToEndOfLine(); // 次の行へ
				nslog(@"source=%p/end=%p/c=$%02x",source,sourceEnd,c);
				if (c==EOS||source>=sourceEnd) {
					nslog(@"次の行はない=ここで終わり");
					return(ERR_NONE); // コンパイル強制終了
				}
				nslog(@"改行位置source=%p",source);
				break;
			case JMP_NONE: // 正常通過時
				break;
		}
		// 空白(TAB,LF,CR,SPC)を飛ばして、先頭の文字を見る
		// '/'か（注釈の可能性大）、その他か（プログラムの本文か）
		c=firstCheckSource();
//		nslog(@"$%02x",c);
		#ifdef CORE_DEBUG2
		if (c<=' ') DBG_printf("最初文字=$%02x\n",c);
		else		DBG_printf("最初文字=%c\n",c);
		#endif
		if (c==EOS) break;
		//
		switch (c) {
			case '}': 	// if_block 426
				DBG_printsn("}=ブロックif終了");
			LBLIf:;
				source++;
				//
				now=nest_work;
				if (now->next==NULL) {
					DBG_printsn("ネストがないエラー");
					Error(ERR_MISMATCH_FORMULA_TYPE);
				}
				if (now->nestType!=NESTTYPE_IF) {
					DBG_printsn("ifネストがないエラー");
					Error(ERR_MISMATCH_FORMULA_TYPE);
				}
				DBG_printsn("ifネストがあった");
				// 435
				nest_if=(NEST_IF *)now->work; // 以後読み替えするため
				ifFlag=nest_if->ifFlag;
				if (ifFlag&IF_BLOCK) { // 436
					// ifブロックである	442	ifb1
					DBG_printsn("ifブロックである");
					if (!(ifFlag&IF_ELSE)) {	// else
						// 446
						DBG_printsn("else内ではない");
						if (elseCheck()==YES) {
							// elseがあった 448
							DBG_printsn("elseがあった");
							source+=lenELSETHEN; // "else"を飛ばす
							nest_if->ifFlag=IF_1LINE;
							S_Else(CODE_else);
							source++;	// コンパイラがマルチステートメント記号を入れているので飛ばす(MULTI_STATEMENT2)
							continue;
						}
						// elseはない
					}
					#ifdef CORE_DEBUG
					else { // else内である
						DBG_printsn("else内である");
					}
					#endif
					// 457 ib3
					DBG_printsn("ifブロックである");
					If_end();	// if 文で、ブロック終わりの時
					DBG_printsn("ifブロック終了");
				} else {
					// if文で改行終わりの時	439
					DBG_printsn("if文で改行終わり");
					If_end();
					DBG_printsn("もう1つ上にあるはずなので再処理へ");
					goto LBLIf; // もう1つ上にあるはず
				}
				goto LoopInterpret; // 459
			
			case '/': // 注釈 384
				DBG_printsn("/=注釈の可能性大");
				c=*(source+1);
				if (c!='*' && c!='/') break;
				// /*,// = 行末まで注釈
				DBG_printsn("/=注釈であった");
				//DBG_printName(source,20);
				skipToEndOfLine();	// 注釈
				//DBG_printName(source,20);
				continue;
		}

		// 文解釈: 469
		// 最初の対象を見つけたので、これからハッシュ値を計算しながら、文字数を数える
		DBG_printsn("\n--------------------文解釈(mainXBcompiler)");
		DBG_printName(source,10);
		
		name=source;
		c=calcHash(source,&len,&hash,&source);
		DBG_printName(name,len);
#if 1	// テストでthen { :/*でエラーを発生させるときは0にする
		if (len==0) {
			switch (c) {
				case MULTI_STATEMENT:
				case MULTI_STATEMENT2:
				case MULTI_STATEMENT3:
					DBG_printsn("連続マルチステートメント");
					goto LoopInterpret;
			}
		}
#endif
		if (len<=0) {
			// bunpo_err
			Error(ERR_SYNTAX);
		}
		
		// 対象がいずれかのステートメントと一致するかどうか	486
		uwCODE code=statementCheck(hash,len,name);
		if (code!=CODE_NONE) {
			// ステートメント
			DBG_prints("ステートメント:");
			DBG_printCode(code);
			switch (code) {
				case CODE_label:
					DBG_printsn("\"ラベル登録");
					if (operationStatus.fenum!=ENUM_NONE) {
						nslog(@"enum中にステートメントが来た");
						Error(ERR_DEFINE_ENUM_SAME_AS_STATEMENT);
					}
					//	label_quote		401
					if (*source++!='"') {
						// ラベルが"でくくられてない(始め)
						DBG_printsn("ラベルが\"でくくられてない(始め)");
						Error(ERR_SYNTAX_LABEL);
					}
					labelHash(&len,&hash,&name);
					DBG_printName(name,len);
					setLabelWithLine(name,len);
					if (*source++!='"') {
						// ラベルが"でくくられてない(終わり)
						DBG_printsn("ラベルが\"でくくられてない(終わり)");
						Error(ERR_SYNTAX_LABEL);
					}
					break;
				case CODE_endenum:
					if (operationStatus.fenum==ENUM_NONE) {
						// enum中でないのにendenumが来た
						Error(ERR_NO_ENUM_TO_ENDENUM);
					}
					nslog(@"enum中のendenum(正常終了)");
					interpretStatement(code);
					break;
					
				default:
					// ステートメント
					if (operationStatus.fenum!=ENUM_NONE) {
						nslog(@"enum中にステートメントが来た");
						Error(ERR_DEFINE_ENUM_SAME_AS_STATEMENT);
					}
					DBG_printsn("ステートメント解釈開始");
					interpretStatement(code);
					DBG_printsn("ステートメント解釈終了");
					break;
			}
			goto LoopInterpret;
		}
		// ステートメントでない: 516
		DBG_printsn("ステートメントでない");
		
		// 関数かどうかチェックする
		if (c=='(') { // calcHash()のリターン値	520
			if (operationStatus.fenum!=ENUM_NONE) {
				nslog(@"enum中に関数が来た");
				Error(ERR_DEFINE_ENUM_SAME_AS_FUNCTION);
			}
			swVarCNT paramCnt;
			UWord *paramTable;
			swFuncNO fno;
			// 526
			if (functionCheck(name,hash,len,&paramCnt,&paramTable,&fno)!=FuncNotFound) { // 見つかった
				// 関数の処理
				storeInternalCode(CODE_FUNC);	// 中間コード書き込み
				// 関数の解釈
				internalCode.l+=interpretFunctions(internalCode.wp,paramTable,paramCnt,fno);
					// ↑書き込んだ長さだけ動かす；一番最後の関数番号は消される
				goto LoopInterpret;	// 556
			}
		}
		
		// 変数かどうかチェック:	565
		DBG_printsn("関数でもない\n変数かどうかチェック");
		swVarNO		no;
		sbVarSTAT	stat;
		DIM1		*dimInfo;
		swJigen		jigen;
		uwCODE		*wp;
		uwMATHTYPE	msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);	// 569
		if (msType==MATH_NONE) {	// 581
			// 未宣言変数
			if (*source=='=') { // 代入式である
				switch (operationStatus.fenum) {
					case ENUM_FLOAT:
						nslog(@"float enum中の値の取得");
						source++; // '='を飛ばす
						operationStatus.floatEnum=getFloatConstant(); // float定数のみ
						goto ENUM2;
					case ENUM_INT:
						nslog(@"int enum中の値の取得");
						source++; // '='を飛ばす
						operationStatus.intEnum=getIntConstant(); // int定数のみ
					ENUM2:;
						if (storeEnum(hash,len,name,operationStatus.fenum)) {
							// 重複定義
							Error(ERR_ENUM_DOUBLE_DEFINE);
						}
						// 値の後ろへ
						goto LoopInterpret;
				}
				if (operationStatus.fundefVarInt) {
					// 代入の場合、未宣言変数をintで自動的に宣言する
					// 未宣言変数への代入があれば、警告を出して整数型に勝手に宣言する
					msType=defineIntWithNoDefinitionVariable(&no,name,hash,len);
					stat=VARIABLE_GLOBAL_VAR;	// StoreToVariableにつなぐため必要
					goto StoreToVariable;
				} else {
					// 未宣言変数
					Error(ERR_UNDEFINED_VARIABLE);
				}
			}
			// 代入がない時
			if (operationStatus.fenum!=ENUM_NONE) {
				// enum中は自動代入
				nslog(@"enum中で連続値の設定");
				goto ENUM2;
			}
			// 未宣言変数の参照なのでエラーにする
			if (*source!='(') {
				// 未宣言変数
				Error(ERR_UNDEFINED_VARIABLE);
			}
			// 未宣言配列
			Error(ERR_UNDEFINED_FUNC_OR_ARRAY);
		}
		// 宣言済み変数	582
		DBG_printf2("宣言済み変数：変数番号=%d/stat=$%04x(bit0=dim)\n",no,stat);
		if (operationStatus.fenum!=ENUM_NONE) {
			nslog(@"enum中に変数宣言が来た");
			Error(ERR_ENUM_FORMAT);
		}
		
		if (stat&VARIABLE_SYSTEM) { // システム変数だった
			// sysに代入:	629
			// iOS:date$/time$への代入は全て禁止
			Error(ERR_DISABLE_ASSIGN_SYSTEMVAR);
		}
		// 585
		if (_isStatLocal(stat)) {
			// LOCAL 変数
			// 以下、ローカル変数かどうかは変数番号の方に入れ込む
			stat=_getStatOnly(stat);
			no=_setLocal(no); // 588
		}
		// 592
		if (stat==VARIABLE_GLOBAL_VAR) {
			// 配列以外に代入: 659
			DBG_printsn("配列以外に代入(の前処理)");
			if (*source=='[') {
				// 文字列の途中への代入: 716
				// str[i]への代入
				
				storeInternalCode(CODE_str);	// 719
				source++;	// 722
				
				wp=internalCode.wp;	// 725
				DBG_printsn("文字位置指定");
				interpretMath(MATH_INT,&wp,NULL);	// 文字位置は整数で指定 728
				
				if (*source++!=']') {	// 730
					Error(ERR_SYNTAX);
				}
				if (firstCheckSouceInLine()!='=') { // 732
					Error(ERR_SYNTAX);
				}
				source++;
				
				DBG_printsn("文字指定");
				interpretMath(MATH_CHAR,&wp,NULL);	// 740
				internalCode.wp=wp;	// 742
				
				storeInternalCode(no);	// 中間コード書き込み 746
				goto LoopInterpret;
			}
			// [がなかった
			//goto StoreToVariable;
		} else {
			// 配列に代入	597
			DBG_printsn("配列に代入(の前処理)");
			//
			if (*source!='(') {
				// dim_init:	757
				DBG_printsn("初期化;内容不明");
				if (firstCheckSouceInLine()!='=') {
					Error(ERR_SYNTAX);
				}
				// 配列=
				// 要素総サイズを計算
				jigen=dimInfo->jigen;
				ULong totalYouso=1;
				int i;
				for (i=0;i<jigen;i++) {
					totalYouso*=dimInfo->youso[i];
				}
				// 初期化	773
				dimInitWithData(no,_mathType2Type(msType),totalYouso);	// 780
				//
				goto LoopInterpret;
			} else {
				// 600
				DBG_printsn("要素番号指定式の作成");
				len=0;					// 要素数書き込みサイズ
				jigen=dimInfo->jigen;	// 次元
				wp=(uwCODE *)tmp;
				// 604
				DBG_printf1("要素番号指定:次元=%d\n",jigen);
				// ｢例」dim(1,2,3)
				while (jigen-->0) {
					source++;
					interpretMath(MATH_INT,&wp,&lenL);	// 要素番号は整数
					len+=lenL;
					if (*source==',') { // 継続指定あり
						if (jigen==0) {
							// 要素数指定が多い
							Error(ERR_ARRAY_COUNT_TOO_MUCH);
						}
						// 解釈継続
					} else { // !=',' : 以降の指定はない
						if (jigen>0) {
							//	要素数指定が少ない
							Error(ERR_ARRAY_COUNT_NOT_ENOUGHT);
						}
						break;
					}
				} // while
				if (*source++!=')') { // )で閉じてなかったらエラー
					Error(ERR_SYNTAX);
				}
				#ifdef CORE_DEBUG
				{
				int i;
				DBG_printf("要素番号指定群\n");
				wp=(uwCODE *)tmp;
				for (i=0;i<withWord(len);i++) {
					DBG_printf("要素番号(%d)=%d\n",i,*wp++);
				}
				DBG_printf("\n");
				}
				#endif
				
				// 以下普通の変数へ代入の処理と同じ
			}
		}
		//
	StoreToVariable:	// 663
		DBG_printsn("変数へ代入");
		if (firstCheckSouceInLine()!='=') {
			Error(ERR_SYNTAX);
		}
		source++;
		
		// 672
		wp=internalCode.wp;
		wp++; // 後で中間コードを書き込むので飛ばしておく
		
		DBG_printsn("変数代入でinterpretMath");
		msType=interpretMath(msType,&wp,&lenL);	// 679
		DBG_printf1("変数代入で:結果長さ=%dバイト\n",(int)lenL);
		
		code=_dainyuWithType(_mathType2Type(msType));	// 代入式の印、下位バイトは変数の型
		if (stat==VARIABLE_GLOBAL_VAR) {
			// 普通変数代入用中間コード	706
			DBG_printf2("普通変数代入用中間コード:code=$%04x,変数番号=%d\n",code,no);
			storeInternalCode(code);	// 中間コード書き込み
			internalCode.wp+=withWord(lenL); // interpretMath()で書き込んでいるので飛ばす
			storeInternalCode(no);		// 変数番号
		} else {
			// 配列代入用中間コード	689
			code|=CODE_ATRB_ARRAY;		// 配列の印
			DBG_printf2("配列代入用中間コード:code=$%04x,配列番号=%d\n",code,no);
			storeInternalCode(code);	// 中間コード書き込み
			internalCode.wp+=withWord(lenL); // interpretMath()で書き込んでいるので飛ばす
			storeInternalCode(no);		// 配列番号
			//
			jigen=dimInfo->jigen;
			DBG_printf1("次元数=%d\n",jigen);
			if (jigen==0) {
				nslog(@"次元数に0が入っていたらおかしい");
				Error(ERR_SYSTEM);
			}
			int i;
			wp=(uwCODE *)tmp;	// 要素数の式;上の要素番号指定式の作成で作った物
			for (i=0;i<withWord(len);i++) {
				DBG_printf1("要素数式=$%04x\n",*wp);
				storeInternalCode(*wp++);
			}
			DBG_printsn("");
		}
		//
	LoopInterpret:	// 解釈ループ	788
		nslog(@"LoopInterpret");
		//
		UByte c=firstCheckSouceInLine();
		switch (c) {
			case MULTI_STATEMENT3: // マルチステートメント(内部処理用2)
			case MULTI_STATEMENT2: // マルチステートメント(内部処理用1)
				DBG_prints("内部処理用");
			case MULTI_STATEMENT:  // マルチステートメント	806
				DBG_printsn("マルチステートメント");
				source++;
			case '}': // ifブロック終了	793
				break;
			//
			case '/':	// 796
				DBG_printsn("/がある");
				// 798
				c=*(source+1);
				if (c=='*'||c=='/') break; // 注釈
				// 注釈ではなかった
			default: // 801
				DBG_printf2("その他文字=%c[$%02x]\n",c,c);
				// elseがある？
				if (elseCheck()==NO) {
					// ない
					// bunpo_err
					Error(ERR_SYNTAX);
				}
				break;
			
			case EOL: // 改行またはプログラム終了
				DBG_printsn("--改行--");
				// 次のwhileで判別
				break;
		}
	} // while
	// コンパイル終了
	return (ERR_NONE);
}

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

// コンパイラ終了処理
void endXBcompiler(void)
{
	DBG_Func();

	// この中でエラーが発生した場合、対応するソースが存在しない(ソース外)
	
	if (operationStatus.fenum!=ENUM_NONE) {
		// enum中のまま終わった
		Error(ERR_NO_ENDENUM2);
	}
	if (operationStatus.flocal) {
		// ローカル状態
		if (operationStatus.finFunc) {
			// func中のまま終わった
			Error(ERR_NO_ENDFUNC2);
		}
	} else {
		// グローバル状態
		NEST_WORK *now=nest_work;
		if (now->next!=NULL) {
			// nest_structure終わってない:
			Error(ERR_NON_CLOSE_NEST2);
		}
		storeInternalCode(CODE_end);
		//
		determineGlobalVariableList();	// これでvariableBuffCtrlの管理するチェーンバッファーの内容が確定する
	}
	#ifdef CORE_DEBUG2
	printf("nestWorkHontai=%p～%p\n",nestWorkHontai,&nestWorkHontai[nest_workSIZE]);
	DBG_dump("nextwork.dat",nestWorkHontai,nest_workSIZE);
	#endif
	
	// goto飛び先確定
	determinGotoAdrs();

	// 中間コードにコンパイルするのが終わった

	// v2.1
	closeEnum();
}

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

// ラベルを行数で登録する	409
void setLabelWithLine(UByte *name,swStrLEN len)
{
	DBG_Func();
	if (len<=0) {
		Error(ERR_SYNTAX_LABEL);
	}

	// そのラベル番号のラベル格納位置を得る
	int falready;
	swLabelNO labelNo=labelCheckAndDefine(name,len,FLABEL_LABEL,&falready);
	if (falready) { // すでに定義済みだったとき
		// ラベル二重定義:
		Error(ERR_DOUBLE_LABEL);
	}
	LABEL_CHAIN *labelChain=(LABEL_CHAIN *)getValueFromBuffer(&labelBuffCtrl, labelNo);
	labelChain->lineAdrs=(uwCODE *)internalCode.bp;	// 中間コードaddress
}

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

// 1外部関数ファイルに含まれる関数数を数える
// リターン値:関数数そのもの(-1ではない)
int getFunctionsCount(const INFORMATION_TABLE *info)
{
	int i=0;
	while (info->tokens[i]!=NULL) i++;
	return (i);
}

// infoにて定義される１外部関数を単一のテーブル(funcTable)に登録する
// リターン値:関数数そのもの(-1ではない)
int calcFuncHash(const INFORMATION_TABLE *info,FUNCTION1 *funcTable)
{
	DBG_Func();
	int i=0;
	while (info->tokens[i]!=NULL) {
		// hash値計算&登録
		calcHash((UByte *)info->tokens[i],&funcTable->len,&funcTable->hash,NULL);
		// ここはlen=0のチェックは要らない(あったらプログラムの記述ミス)
		funcTable->token=	   (UByte *)info->tokens[i];	// 関数名
		funcTable->param=(uwPARAMTYPE *)info->params[i];	// パラメーターテーブル
		funcTable->exec.func =info->execs[i].func;			// 実行アドレス
		// 同意名関数もあるかもしれないが、そのまま登録する
		// 上から一致を見ていくから、先に登録したものが優先となる
		i++;
		DBG2_printf4("%3d:%s(len=%d,hash=$%04x)\n",i,funcTable->token,funcTable->len,funcTable->hash);
		funcTable++;
	}
	return (i); // 関数の個数
}

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

// qsort()用の比較関数
// 引数の宣言仕方はstdlib.hの仕様
int compareFuncWithHashL(const void *vf1,const void *vf2)
{
	FUNCTION1 *f1=(FUNCTION1 *)vf1; // void *で受けて型キャストする必要がある
	FUNCTION1 *f2=(FUNCTION1 *)vf2;
	UByte h1=f1->hash&0xff; // hashの下位1バイト
	UByte h2=f2->hash&0xff;
	if (h1 < h2) return(-1);
	if (h1 > h2) return( 1);
	// 同じ
	return(0);
}

// functionsList[]から外部関数を登録する
// functionsList[]はあらかじめ設定しておくこと
void externalFunctionRead(void)
{
	DBG_Func();
	// 初期化
	ExternalFuncsionFiles=0; // 総ファイル数
	AllExternalFuncsionCount=0;
	int cnt;
	const INFORMATION_TABLE *infoTable;
	while ((infoTable=functionsList[ExternalFuncsionFiles])!=NULL) {
		// この外部関数ファイルに含まれる関数数を数える
		cnt=getFunctionsCount(infoTable);
		// AllExternalFuncsionCount
		AllExternalFuncsionCount+=cnt;
		ExternalFuncsionFiles++;
#ifdef FUNC_DEBUG
		nslog(@"%d.%s:%d関数",ExternalFuncsionFiles,infoTable->funcName,cnt);
#endif
	}
	if (AllExternalFuncsionCount==0) {
		// 外部関数は１つもない
		// 現在はあり得ない
		return;
	}
	nslog(@"全関数数=%d",AllExternalFuncsionCount);
	
	// 全外部関数情報を格納するワークを確保
	nslog(@"全外部関数情報を格納するワーク");
	if ((FunctionBuffer=(FUNCTION1 *)malloc2(SZ_FUNCTION1*(AllExternalFuncsionCount+1)))==NULL) { // +1 for end of table
		// メモリー不足
		Error(ERR_NO_WORKAREA);
	}
	
	int i;
	int allCnt=0;
	for (i=0;i<ExternalFuncsionFiles;i++) {
		const INFORMATION_TABLE *info=functionsList[i];
		cnt=getFunctionsCount(info); // その外部関数に含まれる関数の数
		// インフォメーションテーブルからFUNCTION1を構築する
		nslog(@"&FunctionBuffer[%d:%d]=%p",allCnt,cnt,&FunctionBuffer[allCnt]);
		calcFuncHash(info,&FunctionBuffer[allCnt]);	// FunctionBuffer[allCnt+0～cnt-1]に格納
		allCnt+=cnt; // 外部関数総数
	}
	
	#ifdef CORE_DEBUG
	nslog(@"ソート前全関数テーブル(allCnt=%d)",allCnt);
	for (i=1;i<allCnt;i++) {
		nslog(@"%d.%s(hash=$%04x)",i,FunctionBuffer[i].token,FunctionBuffer[i].hash);
	}
	#endif
	
	// 全関数テーブルを、hashの下位1バイトによって小→大順にソートする
	nslog(@"外部関数ソート(ハッシュ値下位8ビット)");
	qsort(FunctionBuffer,allCnt,SZ_FUNCTION1,compareFuncWithHashL);
	
	// End of table
	FunctionBuffer[allCnt].token=NULL;
	
#ifdef CORE_DEBUG
	nslog(@"ソート後全関数テーブル(allCnt=%d)",allCnt);
	for (i=1;i<allCnt;i++) {
		nslog(@"%d.%s(hash=$%04x)",i,FunctionBuffer[i].token,FunctionBuffer[i].hash);
	}
#endif
	
	// その結果をExternalFuncsionTableに登録する
	// ExternalFuncsionTable[hash値下位1バイト別]
	// いったん全体を初期化
	for (i=0x00;i<=0xff;i++) {
		ExternalFuncsionTable[i].offset=0;
		ExternalFuncsionTable[i].cnt   =0;
	}
	
	UByte h0=FunctionBuffer[0].hash&0xff; // 先頭のハッシュ値
	ExternalFuncsionTable[h0].offset=0;
	ExternalFuncsionTable[h0].cnt++;
	for (i=1;i<allCnt;i++) {
		DBG_printf3("%d.%s(hash=$%04x)\n",i,FunctionBuffer[i].token,FunctionBuffer[i].hash);
		UByte h=FunctionBuffer[i].hash&0xff;
		if (h==h0) { // 同一ハッシュ値関数が続く
			ExternalFuncsionTable[h0].cnt++;
		} else { // 変化した
			h0=h;
			ExternalFuncsionTable[h0].offset=0;
			ExternalFuncsionTable[h0].cnt++;
		}
	}
}

//--------------------------------------------------------------------------------------
// 外部関数のさまざまなルーチンを呼ぶ

// no = 処理するルーチンの番号(noF*;variable.h)
void externalFunctionsRoutine(int no)
{ // Fルーチン	2487
	DBG_Func();
	// 外部関数がある時しか実行されない
	errorNo=ERR_NONE; // エラーをクリアしておく
	int i;
	for (i=0;i<ExternalFuncsionFiles;i++) {
		DBG_printf2("ExternalFuncsionFiles=%d/%d\n",i,ExternalFuncsionFiles);
		const INFORMATION_TABLE *info=functionsList[i];
		switch (no) {
			case noFinit:
				nslog(@"Finit処理");
				info->Finit();
				break;
			case noFrun:
				nslog(@"Frun処理");
				// enum登録時にはここは通らないので注意
				info->Frun();
				break;
			// ↑errorNoを設定していいのは上記のみ。↓以下は設定してはいけない(エラー処理でハングアップする)。
			case noFend:
				// break後にも通る
				nslog(@"Fend処理");
				info->Fend();
				break;
			case noFexit:
				// 終了時には必ず通る
				nslog(@"Fexit処理");
				info->Fexit();
				break;
			case noFbreak:
				nslog(@"Fbreak処理");
				info->Fbreak();
				break;
			case noFctrlD:
				nslog(@"FctrlD処理");
				info->FctrlD();
				break;
		}
		if (errorNo!=ERR_NONE) {
			// 外部関数処理でエラーが発生している
			Error(errorNo);
		}
		DBG_printf1("%d番処理終了\n",i);
	}
}

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

// 1内部関数をFUNCTION1に登録する
// func 型 name(引数名;型指定,～)を解釈し(外部関数のパラメーターテーブルと同様に)登録する
//		関数の型指定はT_INTの場合省略されることもある
//		引数の;型指定はT_INTの場合省略されることもある
//		引数には配列が指定されることもある
static
void internalFunctionDefine(FUNCTION1 *funcs1,UWord *(*pparam))
{	// 内部関数登録 2178
	DBG_Func();
	
	UWord *param=*pparam;	// !=NULL
	#ifdef CORE_DEBUG
	UWord *param0=param;
	#endif
	
	source++;
	
	// 関数の型を得る（省略なら int )
	int fomit;
	uwTYPE returnType=getTypeWithSource(NULL,NULL);
	DBG_printf1("戻り値:$%04x\n",returnType);
	
	firstCheckSouceInLine();
	// ハッシュ値を計算しながら、文字数を数える
	swStrLEN	len;
	uwHash	hash;
	UByte	*name=source;
	calcHash(source,&len,&hash,&source);
	if (len<=0) { // 文字数=0
		nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
		Error(ERR_SYNTAX_FUNC);
	}
	
	if (statementCheck(hash,len,name)!=CODE_NONE) {
		// ステートメントに同じ名前の物がある
		Error(ERR_DOUBLE_FUNCTION);
	}
	// 2171
	if (functionCheck(name,hash,len,NULL,NULL,NULL)!=FuncNotFound) { // ここは存在チェックだけ
		// 同名の関数が存在する
		Error(ERR_DOUBLE_FUNCTION);
	}
	// 2179
	DBG_printsn("内部関数として登録");
	funcs1->hash	 =hash;
	funcs1->len		 =len;
	funcs1->token	 =defineName(name,len);	// 名前を登録してそのアドレスを記録(EOSを含む）
	funcs1->param	 =param;	// パラメータリストを指すポインタ；以下の処理でここからにパラメーターリストを作成する
	funcs1->exec.func=NULL;		// 実行アドレス（念のためクリアしとく）

	// func(a;int,b)	2190
	if (*source++!='(') {
		// 関数定義エラー
		nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
		Error(ERR_SYNTAX_FUNC);
	}
	DBG_printName(name,len);
	DBG_printf1("番号:%d\n",InternalFunctionCount);
	
	// func(	2192
	if (firstCheckSouceInLine()!=')') { // 2193
		// 引数指定がある時
		nslog(@"引数解釈:param=%p\n",param);
		UByte c;
		do { // 2196
			// func(
			firstCheckSouceInLine();
			#ifdef CORE_DEBUG	// iOS
			name=source;
			#endif
			//c=
			calcHash(source,&len,&hash,&source); // 引数名
			if (len<=0) {
				nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
				Error(ERR_SYNTAX_FUNC);
			}
			// V2.3追加
			// ;の前にスペース/TABがあった場合は飛ばす
			while (c=*source, c==' '||c=='\t') source++;
			//
			DBG_prints("引数");
			DBG_printName(name,len);
			if (c=='(') {	// 2200
				// 配列引数	2202
				nslog(@"配列引数");
				// func(dimname(
				// sourceは'('の位置
				arrayParam(&param);
			} else { // 2205
				// func(name
				nslog(@"普通引数");
				int i=TypeOfParameters_int; // 型指定が省略された時はintになるようにする
				if (c==';') {
					// 型指定がある 2211
					// func(name;
					source++;
					getTypeWithSource(&fomit,&i);
					if (fomit) {
						// でもその実体がない時
						nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
						Error(ERR_SYNTAX_FUNC);
					}
					DBG_prints(";"); // 明示的に指定ありの印
				}
				// @@: 2216
				DBG_printf2("引数型:$%04x(%p)\n",TypeOfParameters[i],param);
				*param++=TypeOfParameters[i];
			}
			// 内部関数登録cont: 2219
			c=firstCheckSouceInLine();
			source++;
		} while (c==','); // まだ引数があるなら続ける
		// 2225
		if (c!=')') {
			// func name(～)の閉じ括弧がない
			nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
			Error(ERR_SYNTAX_FUNC);
		}
	} // func()=引数なしのときはすぐここに来る
	// 内部関数登録loop_end: 2227
	DBG_printf3("リターン値:%d → $%04x → %p\n",returnType,ReturnTypes[returnType],param);
	*param++=ReturnTypes[_getSerialType(returnType)];
	#ifdef CORE_DEBUG
	DBG_printf("生成したパラメーターテーブル:%p～%p\n",param0,param);
	for (;param0<param;param0++) {
		DBG_printf("$%04x,",*param0);
	}
	DBG_printf("\n");
	#endif
	
	// 戻す
	*pparam=param;
}

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

// プログラム全体から "func " を探し出し、内部関数宣言なら登録する(名前とパラメーターリスト)
// グローバル変数sourceを動かすので、必要なら後で戻すこと
// この中では直接エラー発生行が特定できない('func'を直接探すため)。
// したがって、必要ならバイト位置から行を特定する処理をエラー処理側にかませること
void internalFunction(void)
{	// 内部関数	2059
	DBG_Func();

	FUNCTION1	*lFuncs=InternalFunctionBuffer;	// ポインターアクセス用
	uwPARAMTYPE	*param =InternalFunctionParam;	

	// func を探すための BM法テーブル用意(全ASCコード分)
	// 入れているのは、不一致時に飛ばす文字数
	#define	SZ_FUNC	(sizeof("func ")-1)	// -1 for EOS
	int size=SZ_FUNC-1; // 最後の" "を除いた長さ
	UByte *bp=tmp;
	int i;
	for (i=0x00;i<=0xff;i++) {
		*bp++=(UByte)size;
		if (i==' ') size++; // ' 'の次からは全体の長さ
	}
	tmp['f']=3;
	tmp['u']=2;
	tmp['n']=1;
	tmp['c']=0;
	DBG2_dump("BMtable",tmp,256);
	
	InternalFunctionCount=0; // 登録済み内部関数の個数
	
	source+=(SZ_FUNC-1); // "func"分を飛ばす
	do { // search_func_loop: 2088
		while ((size=tmp[*source])==0) { // 'c'を見つけた
			size=SZ_FUNC;
			bp=source; // 'c'の位置
			if (*--bp!='n') break;
			if (*--bp!='u') break;
			if (*--bp!='f') break;
			DBG2_printName(bp,SZ_FUNC);
			setExternalSourceLine(bp); // エラー表示用
			// １つ前の文字は空白を飛ばすと、前行の改行でなければならない
			// ＝行頭からの宣言に限る
			UByte c;
			do { // 空白の時は飛ばす
				c=*--bp;
			} while (c==' ' || c==TAB);
			switch (c) {
				// "\nfunc"を探す
				case LF: // LFのみまたはCR+LFのとき
				case CR: // CRのみのとき
					// 改行があった = func文として有効になりえる
					c=*(source+1);
					if (c==LF) {
						// CR+LFの時はさらにもう1バイト後ろを見る
						c=*(source+1);
					}
					if (c==' '||c==TAB) { // 後ろに空白がある="func "である(確定)
						nslog(@"\n------------------------------\nfunc発見");
						if (InternalFunctionCount>=MAX_INTERNAL_FUNC) {
							// 内部関数が多すぎる
							Error(ERR_TOO_MUCH_FUNC);
						}
						// 登録
						internalFunctionDefine(lFuncs,&param);
						lFuncs++;
						lFuncs->token=NULL; // end of table
						InternalFunctionCount++;
					}
					break;
			}
			// 他の文字があった:funcが行頭から出ない=このfuncは無効
			break; // これはループではなくbreakで飛ぶための構文
		}
		source+=size;
	} while (source<sourceEnd);
}

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

// 関数の配列引数の解釈
void arrayParam(UWord *(*pparam))
{	// 配列引き数	2281
	DBG_Func();

	UWord *param=*pparam;
	DBG_printf1("最初param=%p\n",param);

	swJigen jigen=0;	// 次元
	UWord yousoFlag=0;	// 配列の要素数指定フラグ
	
	// 以下のように格納していく
	// param [PARAM_ARRAYext][型＋次元][要素数指定フラグ]↑
	// 													param2
	UWord *param2=&param[3];	// a3=param, a2=param2
	//
	while (1) { // 2289
		source++;	// '(',',' // 2290
		switch (firstCheckSouceInLine()) { // 2291
			case ')': // func(	2292
				// 2317
				jigen++;		// 次元数+1
				*param2++=0;	// 要素数(一応)
				nslog(@"次元=%d,要素数=%d\n",jigen,0);
				break;	 // → 3:
			
			case ',': // dim a(n,m 次の次元へ	2294
				// 2296
				jigen++;		// 次元数+1
				*param2++=0;	// 要素数(一応)
				nslog(@"次元=%d,要素数=%d\n",jigen,0);
				continue; // → while(1)
			
			default:
				// 1: 2299
				{
				uwYouso cnt=getIntConstant();	// 配列の要素数	2300
				if (cnt>=MAX_DIM) { // 2301
					// 要素数が多すぎる(1次元分)
					Error(ERR_ARRAY_COUNT_TOO_LARGE);
				}
				// yousoFlagに使っている次元をビットで入れ込む
				// 最上位ビットから下へ
				// bit15=1次元目,bit14=2次元目,...
				yousoFlag|=(bit(15)>>jigen);	// ここでのjigenは++前なので次元-1の状態(1次元=0,...)
				//
				jigen++;		// 次元数+1
				cnt++;			// a(10)の時は0～10=11個使えるから
				*param2++=cnt;	// 要素数
				nslog(@"次元=%d,要素数=%d,要素フラグ=$%04x\n",jigen,cnt,yousoFlag);
				
				// 2310
				UByte c=firstCheckSouceInLine();
				if (c==')') break;		// 2311
				if (c==',') continue;	// → while(1) 2313
				}
				// 他の文字は認められない 2315
				Error(ERR_SYNTAX);
		}
		break; // ループしない → 3:
	}
	// 3:	2320
	int fomit,i;
	source++;
	if (yousoFlag!=0 // 配列の要素数指定フラグが一個でもあれば
	 || jigen>=3) {	 // 三次元以上なら
		// 拡張配列引き数 2351
		nslog(@"拡張配列");
		if (jigen>=MAX_DIM_JIGEN) {
			// 次元数が多すぎる
			Error(ERR_TOO_MUCH_ARRAY_DIMENSION);
		}
		
		*param++=PARAM_ARRAYext;	// 拡張配列引き数	2356
		// 2360
		i=0;	// 型省略時はint	TypeOfParameters[]内のintの要素番号
		if (firstCheckSouceInLine()==';') { // 型指定有り	2358
			source++; // 2363
			getTypeWithSource(&fomit,&i);	// 2365
			if (fomit) {
				// 型が記述されてない
				nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
				Error(ERR_NO_TYPE);
			}
			nslog(@"MathTypeOfParameters[%d]=$%04x\n",i,MathTypeOfParameters[i]);
		}
		*param++=(MathTypeOfParameters[i]|jigen);	// 型＋次元
		*param++=yousoFlag;	// 要素数指定フラグ
		nslog(@"$%04x,型=$%04x,要素数指定フラグ=$%04x\n",PARAM_ARRAYext,(jigen|MathTypeOfParameters[i]),yousoFlag);
		//
		param=param2;
	} else { // 1,2次元
		// 2327
		nslog(@"2次元以下");
		uwPARAMTYPE prm;
		if (jigen==2) {
			prm=PARAM_ARRAY2;	// 普通の2次元
		} else {
			prm=PARAM_ARRAY1;	// 普通の1次元
		}
		// 2333
		i=0;	// 型省略時はint	TypeOfParameters[]内のintの要素番号
		if (firstCheckSouceInLine()==';') { // 型指定有り 2334,2335
			source++; // 2338
			getTypeWithSource(&fomit,&i); // 2339
			if (fomit) {
				// 型が記述されてない
				nslog(@"file=%@/line=%d",@(__FILE__),__LINE__);
				Error(ERR_NO_TYPE);
			}
			nslog(@"TypeOfParameters[%d]=$%04x\n",i,TypeOfParameters[i]);
		}
		// 2次元以下配列型指定	2344
		*param++=(prm|TypeOfParameters[i]);
		nslog(@"次元=%d,型=$%04x\n",jigen,(prm|TypeOfParameters[i]));
	}
	// 戻す
	nslog(@"最後param=%p\n",param);
	*pparam=param; // a3
}

