//--------------------------------------------------------------------------------------
//
// X-BASIC'
//	コンパイラ：ステートメント解析用サブルーチン
//
//--------------------------------------------------------------------------------------

#include "fdef.h"
#include "XB.h"
#include <ctype.h>
#include <errno.h>
#import "malloc2.h"
#include "atod3.h"

//--------------------------------------------------------------------------------------
// ソース行読み
//--------------------------------------------------------------------------------------

// source から調べる
// まず、空白(TAB,LF,CR,SPC)を飛ばして、先頭の文字を見る。
// リターン値
//		EOS		プログラム終了
//		その他	そのキャラクタ（当然、空白・改行は入らない）
UByte firstCheckSource(void)
{	// first_check_a5	38
	nslog(@"firstCheckSource");
	UByte c;
	while (c=*source,c!=EOS && c!=EOT) {
		switch (c) {
			default:
				// その他文字
				nslog(@"その他文字:%c",c);
				return ((int)c);
			
			case SPC:
			case TAB:
				// 154
				source++;
				break;
			
			case CR:
				if (*(source+1)==LF) source++; // CR,LFならLFも飛ばす
			case LF: // 念のため
				// 改行処理	63
				lineNo++;
				if (lineNo>=LINENO_SPECIAL) {
					// 行数が多すぎる
					Error(ERR_TOO_MUTCH_LINES);
				}
				DBG_printf1("\n-------------\n>>行=%d\n-------------\n",lineNo+1);
				// internalCode=中間コード格納位置（この行分の最後の位置＋１）
				// 1行当たりの中間コードバイトを保存する;1行がUWordを超えることはない
				CODEBYTES codeBytes=(CODEBYTES)calcAdrsOffset(internalCode.bp,internalCodePrevLine);
				addValueForBuffer(&internalCodeBytesBy1LineBuffCtrl, &codeBytes);
				internalCodePrevLine=internalCode.wp;
				
				// 中間コード領域オーバーフローチェック
				// もうちょっとで超えそうになったら追加する
				if (calcAdrsOffset(internalCode.bp,internalCodeTop)>=internalCodeSize-LIMIT_INTERNAL_CODE) {
					// internalCodeTopが変化するかもしれないので、まずinternalCodeの位置を相対で求めておく
					psize_t offset=calcAdrsOffset(internalCode.bp,internalCodeTop);
					//
					internalCodeSize+=SZ_INTERNAL_CODE;
					internalCodeTop=realloc(internalCodeTop,internalCodeSize);
					if (internalCodeTop==NULL) {
						// もうこれ以上拡大できない
						Error(ERR_INTERNALCODE_AREA_OVERFLOW);
					}
					// internalCodeを新しいワーク内のアドレスに変換する
					internalCode.bp=pointerAdd(internalCodeTop,offset);
				}
				
				// 1行if中の終了処理	84
				#ifdef CORE_DEBUG
				int i=0;
				#endif
				NEST_WORK *now=nest_work;
				while (now->next!=NULL) { // nextがあると言うことは、上で誰かがネストを構築している証拠
					DBG_printf1("1行ifの判定(%d段目)\n",i);
					DBG_printf3("now=%p,nestType=%d%s\n",now,now->nestType,now->nestType==NESTTYPE_IF? "(=if)":"");
					if (now->nestType!=NESTTYPE_IF) {
						// ifでない
						DBG_printsn("ifでないので不要");
						break;
					}
					NEST_IF *nest_if=(NEST_IF *)now->work;
					DBG_printf2("ifFlag=$%02x:IF_BLOCK=$%02x\n",nest_if->ifFlag,IF_BLOCK);
					if (nest_if->ifFlag&IF_BLOCK) {
						// ブロックifである
						DBG_printsn("ブロックifなので不要");
						break;
					}
					// 1行if文である
					DBG_printsn("1行if文である");
					If_end();	// ネストが再構築される
					// もう一個上にあるかもしれないので調べる
					DBG_printsn("もう一個上にあるかもしれないので調べる");
					// if ～ then if ～の時
					now=nest_work;
					#ifdef CORE_DEBUG
					i++;
					#endif
				}
				DBG_printsn("1行ifの判定終了");
				if (*source++==EOS) return(EOS);
				break;
		} // switch (c)
		DBG2_printsn("=====");
	} // while
	// プログラム終端まで来た
	return (EOS);
}

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

// 指定文字が出てくるまでソースを飛ばす
UByte skipToChar(UByte cc)
{
	UByte c;
	do {
		c=*source++;
		if (c==EOS || c==EOT) {
			c=EOS;
			break;
		}
	} while (cc!=c);
	return (c);
}

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

///BOOL fdisp=NO;

// 行末(改行コードの位置)まで飛ばす
UByte skipToEndOfLine(void)
{
	DBG2_Func();
	UByte c;
	do {
		c=*source++;
///		if (fdisp) fputc(c,stdout);
	} while (c!=LF && c!=EOS);
	// source=LFまたはEOSのアドレス
	// LFまで飛ばしてしまうと行数計算を間違えるのでダメ
	source--;
///	if (fdisp) fputc('\n',stdout);
	return c;
}

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

// /*、// 注釈行かどうか
UByte firstCheckSouceComment(void)
{
	nslog(@"firstCheckSouceComment");
	UByte c;
	while ((c=firstCheckSource())=='/') {
		nslog(@"コメントかも");
		c=*(source+1);
		if (c!='*' && c!='/') {
			// /*,//ではなかった
			nslog(@"コメントではなかった");
			break;
		}
		// 行末までコメントなので飛ばす
		nslog(@"行末までコメントなので飛ばす");
///		fdisp=YES;
		skipToEndOfLine();
///		fdisp=NO;
		// 次の行もチェックする
		nslog(@"次の行もチェックする");
	}
	return (c);
}

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

// 全ASCIIコード別 プログラムコードに使える文字かどうかテーブル
static char	is_hash[256];	// 符号付き

enum {
	HASH_CRLF	=-2,	// -2=EOS/EOT/LF/CR
	HASH_SPACE	=-1,	// -1=TAB/SPC
	HASH_USE,			//  0=使える文字	isalnum()/$_
	HASH_NOUSE,			//  1=使えない
};

// 行はじめのチェック
// リターン値
//	=EOL:EOS/EOT/CR/LFがある（改行またはプログラム終了）
//	  >0:最初の文字
SWord firstCheckSouceInLine(void)
{	// first_check_a5_in_line 186
	DBG2_Func();
//	nslog(@"firstCheckSouceInLine:source=%p,$%02x",source,*source);
	char hs1;
	while ((hs1=is_hash[*source])==HASH_SPACE) {
		// 空白は読み飛ばす
		source++;
	}
//	nslog(@"hs1=%d",hs1);
	// 行番号で返ることはない(オリジナルは=0)
	if (hs1==HASH_CRLF) {
		// 改行系
//		nslog(@"改行系");
		return (EOL); // オリジナルは-1
	}
	// その他文字>0
//	nslog(@"その他文字");
	return((SWord)*source);
}

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

// else があるかどうかチェック
// 1 = ある , 0 = ない
int elseCheck(void)
{
	firstCheckSouceInLine();
	return (memcmp((char *)source,nameELSE,lenELSETHEN)==0);
}

//--------------------------------------------------------------------------------------
// hash
//--------------------------------------------------------------------------------------

// 全ASCIIコード別 プログラムコードに使える文字かどうかテーブル作成
void makeHashTable(void)
{
	DBG2_Func();
	int c; // UByteでは256で0になってしまうので念のため
	for (c=0x00;c<=0xff;c++) {
		if (isalnum(c) || c=='$' || c=='_') {
			is_hash[c]=HASH_USE;
		} else {
			is_hash[c]=HASH_NOUSE;
		}
	}
	is_hash[TAB]=is_hash[SPC]=HASH_SPACE;
	is_hash[EOS]=is_hash[EOT]=
	is_hash[CR ]=is_hash[LF ]=HASH_CRLF;
	//
	DBG2_dump("makeHashTable",is_hash,sizeof(is_hash));
}

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

// pからハッシュ値を計算しながら、文字数を数える
// 基本的にスペース以外の文字から始まる位置を与えること
// リターン値:一致しなかった文字
// p
// ↓	       ↓=c / *after
// name[空白*][その他文字]
// ~~~~=>len,hash
UByte calcHash(UByte *p,swStrLEN *len,uwHash *hash0,UByte *(*after))
{
	DBG2_Func();
	uwHash	hash=0;
	int		fend=NO;
	UByte	c;
	*len=0;
	do {
		c=*p++;
		switch (is_hash[c]) {
			case HASH_USE:
				// ハッシュ値計算
				DBG2_printf1("[%c]",c);
				hash=_calcHashMain(hash,c);
				(*len)++;
				break;
			case HASH_SPACE:
				// 後ろに空白が続く場合、それは読み飛ばしておく
				while (is_hash[*p++]==HASH_SPACE);
				// 空白以外が出てきたところで終了
			case HASH_CRLF:	 // テーブル文字列はEOSで終わる
			case HASH_NOUSE: // 名前に使えない文字なので終了
				fend=YES;
				break;
		}
	} while (!fend);
	DBG2_printf1("hash=$%04x\n",hash);
	if (after!=NULL) *after=--p; // 使えない文字の先頭を返す
	*hash0=hash;
	return (c);
}

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

void labelHash(swStrLEN *len,uwHash *hash0,UByte *(*original))
{	// hash_label特別	351
	DBG_Func();
	if (original!=NULL) *original=source; // 元の位置を返す
	//
	*len=0;
	uwHash hash=0;
	UByte c;
	DBG_prints("ラベル名:");
	while ((c=*source)!='"') {
		if (c<' ') {
			// ラベルに使えない文字
			Error(ERR_SYNTAX_LABEL);
		}
		DBG_printf1("%c",c);
		// ハッシュ値計算
		hash=_calcHashMain(hash,c);
		(*len)++;
		source++;
	}
	// sourceは使えない文字の先頭を返す
	DBG_printf3("\n次の文字=%c,長さ=%d,hash=$%04x\n",*source,*len,hash);
	*hash0=hash;
}

//--------------------------------------------------------------------------------------
// 名前登録
//--------------------------------------------------------------------------------------

// nameからlen(長さそのもの)を登録し、そのアドレスを返す
UByte *defineName(UByte *name,swStrLEN len)
{	// 名前登録	389
	DBG_Func();

	#ifdef CORE_DEBUG
	DBG_printf("nameLeftSize=%d,len=%d\n",nameLeftSize,len);
	#endif
	
	if (nameLeftSize<len) {
		// もう入らない
		if (nameBufferCnt>=MAX_NAMEBUFFER_LIST) {
			// 名前が多すぎて入らない
			Error(ERR_TOO_MUCH_NAMES);
		}
		// 先に追加のバッファーを確保
		// 入らない長さの領域は無駄になるが、無視する
		// バッファー全体は不連続でもかまわない
		nslog(@"nameBufferバッファー");
		nameLeftSize=ADD_NAME_BUFFER;
		nameBuffer=malloc2(nameLeftSize);
		if (nameBuffer==NULL) {
			Error(ERR_NO_WORKAREA);
		}
		DBG_printf2("nameBufferList[%d]=%p\n",nameBufferCnt,nameBuffer);
		nameBufferList[nameBufferCnt++]=nameBuffer; // 先頭アドレスを保管
	}
	nameLeftSize-=len;	// 残りバッファーサイズ
	memcpy(nameBuffer,name,len);
	DBG_printf1("名前登録:%p=",nameBuffer); DBG_printName(nameBuffer,len);
	//
	UByte *buff=nameBuffer;	// 格納アドレスを保存
	nameBuffer+=len;		// 次の書き込みアドレス
	*nameBuffer++=0x00;		// EOS
	//
	return (buff); // 格納アドレスを返す
}

void defineNameInit(void)
{
	DBG_Func();
	nameBufferCnt=0;
	nameLeftSize =0;
	// これで一番最初にバッファーが確保される
}

// 名前登録バッファーを全解放する
void defineNameFree(void)
{
	DBG_Func();
	DBG_printf1("nameBufferCnt=%d\n",nameBufferCnt);
	#ifdef CORE_DEBUG2
	int i;
	for (i=0;i<nameBufferCnt;i++) {
		DBG_printf2("nameBufferList[%d]=%p\n",i,nameBufferList[i]);
		DBG2_dump2("namebuff",nameBufferList[i],ADD_NAME_BUFFER,i>0? "a":"w");
	}
	DBG_printf("実解放\n"); _f();
	#endif
	
	while (nameBufferCnt-->0) {
		DBG_printf2("nameBufferList[%d]=%p\n",nameBufferCnt,nameBufferList[nameBufferCnt]);
		free2(nameBufferList[nameBufferCnt]); // 後ろから解放していく
	}
}

//--------------------------------------------------------------------------------------
// ラベル
//--------------------------------------------------------------------------------------

// ラベルは存在するかどうか調べる
// リターン値：-1=存在しない , >=0:ラベル番号
swLabelNO labelCheck(UByte *name,swStrLEN len)
{
	DBG_Func();
	
	int cnt=labelBuffCtrl.cnt;	// 登録済みラベル数
	DBG_printf1("登録済みラベル数:%d\n",cnt);
	
	swLabelNO labelNo=0;
	for (int i=0;i<cnt; i++) {
		LABEL_CHAIN *labelChain=(LABEL_CHAIN *)getValueFromBuffer(&labelBuffCtrl, i);
		if ((ULong)len==labelChain->len) { // ラベル文字数が一致
			// 名前比較
			if (memcmp((char *)name,(char *)labelChain->name,len)==0) {
				// ラベル名一致
				return(labelNo);
			}
		} // 文字数が合わない時は当然ラベルは一致しない
		labelNo++;	// ラベル番号
	} // ラベルが1つも登録されてない時は即不一致
	// 不一致
	return (-1);
}

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

// ラベルをチェックし、未登録なら登録する
// flabel : どこからの定義か(FLABEL_*)
// リターン値：-1=存在しない , >=0:ラベル番号
swLabelNO labelCheckAndDefine(UByte *name,swStrLEN len,int flabel,int *falready)
{
	DBG_Func();
	int f=YES; // ラベルがすでに存在した（にしておく）
	swLabelNO labelNo=labelCheck(name,len);
	if (labelNo<0) { // ラベルが未登録の時
		DBG_printsn("未登録ラベル→登録");
		f=NO; // ラベルは新規登録
		
		labelNo=labelBuffCtrl.cnt; // 次のラベル番号
		DBG_printf2("labelNo=%d,flabel=%d\n",labelNo,flabel);

		// バッファーに登録
		UByte *nameAdrs=defineName(name,len);
		LABEL_CHAIN label1={len,nameAdrs,LABEL_NO_LINE,flabel};	// 行数はここでは未登録にしておき、後でdeterminGotoAdrs()で確定する
		addValueForBuffer(&labelBuffCtrl,&label1);
	} else {
		DBG_printf1("ラベルは定義済みだった:labelNo=%d\n",labelNo);
		// ラベルは定義済みだったとき
		if (flabel==FLABEL_GOTO) {
			DBG_printsn("今回がgotoの場合は確定ラベル参照なので問題ない");
			f=NO; // ラベルは常に新規登録相当とみなさせる
		} else {
			// 今回はlabel文 または *label定義である
			DBG_printsn("今回はlabel文 または *label定義である");
			DBG_printsn("前回のラベル定義がgotoからなら前方参照解決になるので問題ない");
			
			LABEL_CHAIN *labelChain=(LABEL_CHAIN *)getValueFromBuffer(&labelBuffCtrl, labelNo);
			SLong flabel=labelChain->flabel;
			DBG_printf1("前回定義の状態:flabel=%d(1=goto)\n",(int)flabel);
			if (flabel==FLABEL_GOTO) {
				f=NO; // ラベルは常に新規登録相当とみなさせる
			} // else label文 または *labelからの定義の時は、呼び出し側で二重定義にしてもらう
		}
	}
	if (falready!=NULL) *falready=f; // 登録状態を返す
	return (labelNo);
}

//--------------------------------------------------------------------------------------
// 変数系
//--------------------------------------------------------------------------------------

// 配列引き数登録 1158
UWord *defineArrayParam(uwCODE prm,uwHash hash,UWord len,UByte *name,uwCODE *param)
{
	DBG_Func();
	DBG_printName(name,len);
	
	DIM1 *dim1;
	nslog(@"%s:defineVariableSub",__FUNCTION__);
	swVarNO hno=defineVariableSub(&LocalArray,SZ_VARIABLE_DIM1,hash,len,name,&dim1);	// 配列登録	1162
	DBG_printf1("登録配列番号:%d\n",hno);
	swJigen jigen;
	uwMATHTYPE msType=MATH_INT; // 警告回避のため
	if (prm==PARAM_ARRAYext) {	// 1165
		// 拡張配列	1168
		DBG_prints("拡張配列:");
		UWord prm=*param++; 		// 型＋次元
		jigen=_getJigen(prm);		// 次元
		msType=getMathType(prm);	// 型(MATH_*)
		param+=(1+jigen); 			// 要素数フラグと次元数分の要素情報を飛ばす
	} else {
		// 通常配列
		DBG_prints("通常配列:");
		jigen=1; // 1次元配列
		if (prm&PARAM_ARRAY2) jigen++; // 2次元
		do {
			if (prm&PARAM_FLOAT) {
				msType=MATH_FLOAT;
				break;
			}
			if (prm&PARAM_INT) {
				msType=MATH_INT;
				break;
			}
			if (prm&PARAM_CHAR) {
				msType=MATH_CHAR;
				break;
			}
			if (prm&PARAM_STR) {
				msType=MATH_STR;
				break;
			}
			nslog(@"なぜか他の型が指定されている:%s",__FUNCTION__);
			Error(ERR_SYSTEM);
		} while (0);
	}
	// 1207
	dim1->msType=msType;	// 型
	dim1->jigen =jigen;		// 次元
	DBG_printf2("次元=%d,型=$%04x\n",jigen,msType);
	//
	// name(1,2,3)				 ↓ここ
//	DBG_printName(source,10); // (n);type
	DBG_printsn("要素数テーブル");
	// 関数の引数に配列を置くときは、渡し側(呼び出し側)の配列情報が渡されるため、受け側(関数側)では配列実体=DIM1_EXECを生成する必要がない
	int i=0;
	dim1->youso[i++]=0;		// 1次元目分
	for (;i<jigen;i++) {	// 次元数-1だけ,があるはず;2次元以上の時だけ回る
		// 要素数区切りの,が出てくるまでテキストを飛ばす
		if (skipToChar(',')==EOS) {
			// 要素数指定が足りない（にする）
			Error(ERR_ARRAY_COUNT_NOT_ENOUGHT);
		}
		dim1->youso[i]=0;		// 変数領域大きさ計算用に配列の要素数大きさクリア
	}
//	while (*source++!=')'); // ')'まで飛ばす 1220 ; オリジナルはここにバグがある
	if (skipToChar(')')==EOS) {
		// ')'がない
		Error(ERR_SYNTAX);
	}
	//
	PARAM_CHAIN param1={jigen,getVarNo(hno)};	// 次元,配列番号
	addValueForBuffer(&paramBuffCtrl,&param1);
	
	return (param);
}

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

// 登録するローカル変数管理構造体を設定する
uwTYPE setLocalVarCtrlFromBit(uwPARAMTYPE prmType,VAR_CTRL *(*varCtrl))
{
UWord ret=0; // どれにも当てはまらないの印
VAR_CTRL *dummyWork;
	if (varCtrl==NULL) varCtrl=&dummyWork;
	
	if (prmType&PARAM_FLOAT) {
		// float引き数
		//nslog(@"float引数");
		*varCtrl=&LocalFloat;
		return (_PARAM|T_FLOAT);
	}
	if (prmType&PARAM_INT) {
		// int引き数
		//nslog(@"int引数");
		*varCtrl=&LocalInt;
		return (_PARAM|T_INT);
	}
	if (prmType&PARAM_CHAR) {
		// char引き数
		//nslog(@"char引数");
		*varCtrl=&LocalChar;
		return (_PARAM|T_CHAR);
	}
	if (prmType&PARAM_STR) {
		// str引き数
		*varCtrl=&LocalStr;
		//nslog(@"str引数");
		return (_PARAM|T_STR);
	}
	return(ret);
}

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

// 変数引数登録 1236
void defineVariableParam(uwPARAMTYPE prmType,uwHash hash,UWord len,UByte *name)
{
	DBG2_Func();

	// 登録する変数管理構造体を設定する
	VAR_CTRL *varCtrl;
	uwTYPE type=setLocalVarCtrlFromBit(prmType,&varCtrl);
	if (type==0) {
		// どれにも一致しない型
		nslog(@"(%s)",__FUNCTION__);
		Error(ERR_SYSTEM);
	}
	swVarNO no=defineVariableSub(varCtrl,SZ_VARIABLE1,hash,len,name,NULL);
	DBG_printf1("登録変数番号:%d\n",no);

	PARAM_CHAIN param1={type,getVarNo(no)};	// 変数型,変数番号;元がローカル変数番号なので復号しておく
	addValueForBuffer(&paramBuffCtrl,&param1);
}

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

// variableBuffCtrlに変数リスト(VARLIST_CHAIN)を確定構築する	1288
void determineVariableList(VAR_CTRL varCtrl[])
{
	DBG_Func();

	VARLIST_CHAIN	varlistChain;
	SLong sizeL=0;	// 変数領域のサイズ.l(sizeVarArea)＝実行時に此の分確保する。後で確定するので、ここでは仮値の書いておく。
	varlistChain.sizeVarArea=sizeL;
	
	// 型別変数個数を登録(int→str→char→float→配列の順)
	DBG_printsn("型別変数個数を登録");
	// ここでグローバル/ローカルそれぞれで使われる型別の変数の個数が確定される
	swVarCNT cnt;
	VAR_TYPES i;
	for (i=VAR_INT;i<=VAR_DIM;i++) {
		cnt=varCtrl[i].cnt;
		varlistChain.cnt[i]=cnt;
		DBG_printf2("型%d=%d個\n",i,cnt);
		SLong sz1L=cnt*Var1Size[i]; 	// 配列分は後で計算(だからVar1Size[VAR_DIM]=0);Var1Size[]=型別1要素サイズ
		if (i==VAR_CHAR) {
			sz1L=quadBoundary(sz1L);	// 4バイト(.l)境界化
		}
		sizeL+=sz1L;
	}
	// cnt=配列数
	ULong *pSizeVarAre=(ULong *)addValueForBufferWithSize(&variableBuffCtrl, &varlistChain, sizeof(varlistChain));
 		// 後で確定するのでsizeVarAreaの位置を保存しておく
		// 一応typeof(sizeVarArea)*=ULong *ではあるが、バッファー内の記録アドレスが境界整合できているかわからないので、書き込み時は直接*(ULong *)=とはしない
	
	// 配列 DIMLIST_CHAIN まとめ	1327
	VARIABLE1 *var1=varCtrl[VAR_DIM].var1Top;
	swVarCNT cnt0=cnt;
	while (cnt0-->0) {
		DBG_prints("配列登録:");
		DIM1 *dim1=(DIM1 *)var1->dims;
		uwMATHTYPE	msType=dim1->msType;	// 型(MATH_*)
		swJigen 	jigen =dim1->jigen;		// 次元
		uwTYPE		type  =_mathType2Type(msType);
		uwCODE		w=_setJigenAndType(jigen,type);	// 次元＋型(T_*)
		addValueForBuffer(&variableBuffCtrl, &w);
		
		ULong sz1L=Var1Size[_getSerialType(type)];	// 変数型別に1要素のサイズを得る
		UWord youso=0; // =0は警告回避のため
		i=0;
		DBG_prints("要素数=");
		swJigen jigen0=jigen;
		while (jigen0-->0) {
			youso=dim1->youso[i++]; // 要素数
			DBG_printf1("%d",youso);
			addValueForBuffer(&variableBuffCtrl,&youso);
			sz1L*=youso;
		}
		
		// 配列には情報領域がある
		sz1L+=SZ_VOIDP; // DIM1_EXEC *dim1_exec_adrs[]の1つ分(これは拡張配列分も確保)
		if (youso>0) { // 拡張配列でないときは情報領域分も確保
			sz1L+=dimInfoAreaSize(jigen); // オリジナルでは↑とこの分が抜けている
		} // 拡張配列ではdimで確保する
		DBG_printf1("\n配列用サイズ=%u\n",(uint)sz1L);
		// 総サイズ合計
		sizeL+=sz1L;
		//
		var1=(VARIABLE1 *)pointerAdd(var1,SZ_VARIABLE_DIM1); // 次の配列分の位置;DIM1付きなので++では計算出来ないため
	}
	//
	// この関数ブロックで使用する変数領域の大きさを記録(飛ばした場所への書き戻し)	1386
	memcpy(pSizeVarAre,&sizeL, sizeof(sizeL));	// varListInfo.sizeVarArea=sizeL;
												// 一応typeof(sizeVarArea)*=ULong *ではあるが、バッファー内の記録アドレスが境界整合できているかわからないので、書き込み時は直接*(ULong *)=とはしない

	DBG_printf2("variableBuffCtrl.cnt(格納個数)=%d/sizeVarArea=%d\n",variableBuffCtrl.cnt,(int)sizeL);
	DBG_Func2("(end)");
}

// count個の,でつながれるintの引数を取り込む
void getIntParamCnt(UWord count)
{
	DBG_Func();
	while (count-->0) {
		interpretMath(MATH_INT,&internalCode.wp,NULL);
		if (count>0) { // まだ続きが必要な時
			if (*source++!=',') {
				// 複数個の時のセパレーターがない
				Error(ERR_NOT_ENOUGHT_PARAM_IN_STATEMENT);
			}
		}
	}
}

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

// source～に記述されている型を返す(INT,STR,CHAR,FLOAT)
// 省略時はintと見なす
// fomit = 省略されていたかどうか(YES=省略されてた)
// no    = 型の番号
uwTYPE getTypeWithSource(int *fomit,int *no)
{	// 型get 3042
	DBG_Func();
	
	UByte c=firstCheckSouceInLine();
	if (c==EOL||isdigit(c)) {
		// 改行または数字があった
		nslog(@"改行または数字があった");
		Error(ERR_ILLEGAL_DEFINE_ARRAY);
	}
	int i=0;
	while (name_type[i].name!=NULL) {
		if (compareNameToSource((UByte*)name_type[i].name,NO)==CMP_EQUAL) {
			DBG_printf1("型=%s\n",name_type[i].name);
			if (fomit!=NULL) *fomit=NO;
			if (no   !=NULL) *no   =i;
			return(name_type[i].type);
		}
		i++;
	}
	DBG_printsn("型省略=T_INT");
	// 型指定が省略されている(指定がない)
	if (fomit!=NULL) *fomit=YES;
	if (no   !=NULL) *no   =-1;
	// 省略時はT_INTとみなす
	return(T_INT);
}

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

// 変数または配列の登録(コンパイル時)
// varCtrl	変数実体管理構造体
// size1 	1変数管理ワークサイズ（普通変数の時はVARIABLE1のみ、配列の時はVARIABLE1+DIM1になるので）
// hash		ハッシュ値
// len		長さ
// name		名前へのポインタ
// リターン値:変数番号
//		dim1	VALIABLE1->dimsが入る；ここから先に配列情報を書き込む
swVarNO defineVariableSub(VAR_CTRL *varCtrl,int size1,uwHash hash,UWord len,UByte *name,DIM1 *(*dim1))
{	// 変数登録sub	3090
	DBG_Func();

	VARIABLE1 *var1=varCtrl->var1Top; // VARIABLE1で代表しているが、実際には変数と配列でdimsの内容の有り無しが変わる
	swVarCNT cnt	=varCtrl->cnt;
	if (cnt>=CNT_VAR_IN_1_BLOCK) {
		nslog(@"変数または配列が多すぎる");
		Error(ERR_TOO_MUCH_VARIABLES);
	}
	swVarCNT cnt0=cnt;
	if (cnt==0) {
		// 最初の登録時：ワークを確保する
		nslog(@"最初の登録時：ワークを確保する");
		var1=(VARIABLE1 *)malloc2(size1*CNT_VAR_IN_1_BLOCK);
		if (var1==NULL) {
			Error(ERR_NO_WORKAREA);
		}
		varCtrl->var1Top=var1;
	} else {
		DBG_prints("ブロック内移動");
		// cnt0は登録数＝次の登録位置になる
		// 変数と配列でdimsの内容の有り無しが変わるので
		//	var1+=cnt0;	// ブロック内での移動
		// ではだめ
		var1=(VARIABLE1 *)pointerAdd(var1,size1*cnt0);
	}
	// 登録:コンパイル時は以下の情報を格納する
	var1->hash =hash;
	var1->len  =len;
	var1->token=defineName(name,len);
	
	// 変数番号(0～)=登録数(1～)-1
	nslog(@"%d.登録変数(len=%d,hash=$%04x,var1=%p,size1=%d,token=%s) ",varCtrl->cnt,len,hash,var1,size1,var1->token);
	#ifdef CORE_DEBUG
	DBG_printf("%d.登録変数(len=%d,hash=$%04x,var1=%p,size1=%d) ",varCtrl->cnt,len,hash,var1,size1);
	DBG_printName(var1->token,len);
	#endif
	varCtrl->cnt=cnt+1;	// 登録数を一つ増やす
	if (operationStatus.flocal) {
		cnt=_setLocal(cnt);	// ローカルの時
	}
	if (dim1!=NULL) *dim1=(DIM1 *)var1->dims;
	return (cnt);
}

// 変数登録ワークを解放する
static
void freeVariableDefine(VAR_CTRL *varCtrl)
{	// 変数登録free
	nslog(@"freeVariableDefine");

	DBG_printf1("varCtrl=%p\n",varCtrl);
	VARIABLE1 *var1=varCtrl->var1Top;
	DBG_printf1("varCtrl.var1Top=%p\n",var1);
	SWord cnt=varCtrl->cnt;
	DBG_printf1("varCtrl.cnt=%d\n",varCtrl->cnt);
	// 本当は後ろから解放したいが、面倒なため前から解放
	while (cnt>CNT_VAR_IN_1_BLOCK) {
		// 先に次のリンクを得ておく(free以降、内容が改変される可能性があるため)
		VARIABLE1 *varNext=var1+CNT_VAR_IN_1_BLOCK;
		varNext=*(VARIABLE1 **)varNext;
		nslog(@"このブロックを解放");
		free2(var1);
		var1=varNext;
		cnt-=CNT_VAR_IN_1_BLOCK;
	}
	if (cnt>0) {
		// 最後の(全ては埋まっていない)ブロックを解放
		nslog(@"最後の(全ては埋まっていない)ブロックを解放");
		free2(var1);
	}
	// 念のため
	varCtrl->var1Top=NULL;
	varCtrl->cnt=0;
	DBG_printsn("freeVariableDefine(end)\n");
}

void freeVariableDefineAll(int flocal)
{
	nslog(@"freeVariableDefineAll:flocal=%d\n",flocal);
	int i;
	for (i=VAR_INT;i<=VAR_DIM;i++) {
		freeVariableDefine(flocal? &localVarCtrl[i]:&globalVarCtrl[i]);
	}
}

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

// 文字列の大きさ指定部分を飛ばす
// ぺけ-BASICでは長さ指定を無視するから
// ただし、指定そのものの記述が正しいかどうかはチェックする
ULong skipStrSize(uwTYPE type)
{
	if (type==T_STR) { // str型のみ
		if (*source=='[') {
			// サイズの指定がある
			source++;
			ULong len=getIntConstant();
			firstCheckSouceInLine();
			if (*source++!=']') {
				Error(ERR_DEFINE_VARIABLE);	// 宣言がおかしい
			}
			return (len); // 一応返す
		}
		// 指定なし=最大長にしておく(X-BASICでは32)
		return (operationStatus.sz_str);
	}
	// STRじゃない
	return (0);
}

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

// 型宣言のない変数をintとして登録する
uwMATHTYPE defineIntWithNoDefinitionVariable(swVarNO *no,UByte *name,uwHash hash,UWord len)
{	// 未宣言をint_sub	3207
	DBG_Func();
	
//	Error(ERR_AUTO_DEFINE_INT); // 警告を出す

	nslog(@"型宣言のない変数をintとして登録");
	*no=defineVariableSub(operationStatus.flocal? &LocalInt:&GlobalInt,SZ_VARIABLE1,hash,len,name,NULL);
	return (MATH_INT);
}

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

// 変数登録
// 配列の時はvarCtrl==NULLで呼び出す
void variableDefine(VAR_CTRL *varCtrl,uwTYPE type)
{	// 変数登録	3293
	DBG_Func();
	DBG_printf1("type=$%04x\n",type);
	do {
		UByte c=firstCheckSouceInLine();
		if (c==EOL || isdigit(c)) {
			// 行末または数字があった(数字から始まる変数名は許されない)
			Error(ERR_DEFINE_VARIABLE);
		}
		
		// ハッシュ値を計算しながら、文字数を数える	3303
		swStrLEN	len;
		uwHash		hash;
		UByte		*name=source;
		calcHash(source,&len,&hash,&source); // 変数名
		nslog(@"変数名(len=%d/hash=$%04x):",len,hash); DBGprintName(name,len);
		if (len<=0) {
			Error(ERR_DEFINE_VARIABLE);	// 宣言がおかしい
		}
		
		// 対象がステートメント・関数と一致しないかどうか
		if (statementCheck(hash,len,name)!=CODE_NONE) {	// 3311
			// ステートメントに同じ名前の物がある
			Error(ERR_DEFINE_VARIABLE_SAME_AS_STATEMENT);
		}
		if (functionCheck(name,hash,len,NULL,NULL,NULL)!=FuncNotFound) {	// 3319
			// 関数と同じ名前が存在する
			Error(ERR_DEFINE_VARIABLE_SAME_AS_FUNCTION);
		}
		
		// enumと一致しないか(V3.00)
		{
		SLong num;
		double fnum;
		int fenum;
			if (getEnum(name,hash,len,&num,&fnum,&fenum)) {
				// 定数内にあった
				Error(ERR_DEFINE_VARIABLE_SAME_AS_ENUM);
			}
		}
		
		DBG_printsn("既存変数名と重なってないかどうか");
		// 既存変数名と重なってないかどうか
		swVarNO 	no;
		sbVarSTAT 	stat;
		DIM1 		*dimInfo;
		uwMATHTYPE msType=variableCheck(name,hash,len,&stat,&dimInfo,&no);	// 3328
		if (msType!=MATH_NONE) {
			if (operationStatus.flocal) {
				// ローカル変数モードである
				nslog(@"ローカル変数モードである");
				if (_isStatLocal(stat)) {
					// ローカル変数にあったら重複
					DBG_printsn("ローカル変数にあったら重複");
					Error(ERR_DOUBLE_VARIABLE);
				}
			} else {
				if (!_isStatLocal(stat)) {
					// グローバル変数にあったら重複
					DBG_printsn("グローバル変数にあったら重複");
					Error(ERR_DOUBLE_VARIABLE);
				}
			}
		}
		if (*source!='(') {
			// 変数の登録
			nslog(@"変数の登録");
			// normal_var_def:	3455
			if (varCtrl==NULL) {
				nslog(@"変数の登録");
				Error(ERR_ILLEGAL_DEFINE_ARRAY);
			}
			nslog(@"変数登録");
			no=defineVariableSub(varCtrl,SZ_VARIABLE1,hash,len,name,NULL);
			skipStrSize(type);	// 文字列型だったら、サイズ指定を読み飛ばす

			// 初期値がある？
			if (firstCheckSouceInLine()=='=') {
				DBG_printsn("初期値設定");
				source++; // =を飛ばす
				storeInternalCode(_dainyuWithType(type)); // 中間コード書き込み:普通の代入
				// 初期値代入式の解釈
				interpretMath(_type2MathType(type),&internalCode.wp,NULL);
				storeInternalCode(no); // 中間コード書き込み:変数番号
			}
		} else {
			// 配列の登録	3341
			nslog(@"配列の登録");
			if (varCtrl!=NULL) { // 登録ハンドル
				// dimなしで配列宣言した(オリジナルでは警告扱い)	3344
				if (!operationStatus.fundefVarInt) {
					Error(ERR_ARRAY_DEFINE_WITH_NO_DIM);
				}
			}
			
			nslog(@"配列登録");
			DIM1 *dim1;
			swVarNO hno=defineVariableSub(operationStatus.flocal? &LocalArray:&GlobalArray,SZ_VARIABLE_DIM1,hash,len,name,&dim1);
			dim1->msType=_type2MathType(type);	// 型 3357
			nslog(@"配列番号=%d,型=$%04x\n",hno,dim1->msType);
			uwCODE *sikis;
			swJigen jigen=0;
			ULong totalYouso=1;	// 配列の総要素数

			SLong lenL;
			operationStatus.fdimSizeVar=NO;	// とりあえず要素数指定は定数にしておく	3367
			sikis=(uwCODE *)tmp; // 式の解析結果はいったんtmpに入れる
			do {	// 3368 soeji_loop
				source++;	// 3369
				uwCODE *sikis0=sikis; // 今回の先頭
				DBG_printsn("配列要素数指定式");
				interpretMath(MATH_INT,&sikis,&lenL);	// interpretMathの最適化を利用	3374
				
				// 解析した式の先頭から読む
				#ifdef CORE_DEBUG
				DBG_printf("配列要素数指定式:lenL=%d\nsikis0=",(int)lenL);
				int i;
				for (i=0;i<withWord(lenL);i++) {
					DBG_printf1("$%04x,",*(sikis0+i));
				}
				DBG_printf("\n");
				#endif
				
				UWord youso1;
				DBG_printf1("式=$%04x\n",*sikis0);
				if (*sikis0++==(_CONSTANT|T_INT)) {	// 3377
					// 式はint定数だった 3377
					DBG_printsn("要素数指定は定数だった");
					youso1=(UWord)readLong(sikis0);	// youso1=(UWord)(*(ULong *)sikis0);	// 要素数:記録は.lでされているが、式としては.wまで	3383
					youso1++; // basicではdimの要素指定数まで要素が使える＝dim a(10)ならa(0)～a(10)まで。故に+1する
				} else {
					// 式は変数だった 3379
					DBG_printsn("要素数指定は変数だった");
					operationStatus.fdimSizeVar=YES;	// 要素数の指定に変数があった
					youso1=0;	// 変数なので大きさはここではわからない(=0が拡張配列の印になる)
				}
				if (youso1>MAX_DIM) { // 3386
					// 配列1次元の最大要素数を超えた
					nslog(@"配列の1次元の最大要素数を超えた");
					Error(ERR_ILLEGAL_DEFINE_ARRAY);
				}
				
				if (jigen>=MAX_DIM_JIGEN) {
					// 次元数が最大を超える
					Error(ERR_TOO_MUCH_ARRAY_DIMENSION);
				}
				dim1->youso[jigen++]=youso1; // 要素数	3391
				DBG_printf2("%d次元目要素数=%d\n",jigen,youso1);
// v3.2で上に移動
//				if (jigen>MAX_DIM_JIGEN) {
//					// 次元数が最大を超えた
//					Error(ERR_TOO_MUCH_ARRAY_DIMENSION);
//				}
				
				// 総要素数計算
				totalYouso*=youso1;
			} while (firstCheckSouceInLine()==','); // 3397
			
			// 配列の要素数＆次元の解釈終わり 3400
			dim1->jigen=jigen;	// 3405
			DBG_printf1("次元数=%d\n",jigen);
			
			// totalYouso = 配列データ部のサイズ（要素の個数全体）
#if 0	// V2.6で削除
			if (totalYouso>MAX_DIM) {
				// 総要素数が多すぎる
				Error(ERR_TOO_MUCH_ARRAY_COUNT);
			}
#endif
			if (operationStatus.fdimSizeVar) {	// 要素数指定に変数がある
				// 3411
				DBG_printsn("要素数指定に変数がある");
				// 中間コード書き込み
				storeInternalCode(CODE_dim);			// 配列確保 Dim(拡張配列)
				storeInternalCode(_notConstType(type));	// 可変長配列の定義|型
				storeInternalCode(hno);					// 配列番号
				if (!_isLocal(hno)) {
					// global可変長配列は使えへんねん
					Error(ERR_CANT_USE_GLOBAL_EXTARRAY);
				} // ローカル変数
				storeInternalCode(jigen);	// 次元；拡張配列も次元までは指定が必要=確定	3417
				// 3418
				DBG_printsn("要素数の式書き込み");
				// 式の解析は上のループで行われている
				int i;
				for (i=0;i<jigen;i++) { // 要素数は実行時まで確定できないので0にしておく	3420
					dim1->youso[i]=0;	// 3419
				}
				// 3421
				lenL=(ULong)withWord(calcAdrsOffset(sikis,tmp));
				sikis=(uwCODE *)tmp;
				while (lenL-->0) {
					storeInternalCode(*sikis++);	// tmpに入れといた配列の要素数式を入れる
				}
			} // else 配列の要素数は定数ばかりだった
			//
			firstCheckSouceInLine();
			// 配列の添え字
			if (*source++!=')') {
				// )で閉じられていない
				nslog(@")で閉じられていない");
				Error(ERR_ILLEGAL_DEFINE_ARRAY);
			}
			//
			skipStrSize(type);	// 文字列サイズ指定があったら読み飛ばす
			if (firstCheckSouceInLine()=='=') {
				// 初期値データあるので代入する
				dimInitWithData(hno,type,totalYouso);
			}
		} // if (配列の登録)
		// 続きがあるなら継続する
	} while (*source++==',');
	source--; // ++を取り消す
}

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

// 配列に初期化データを代入する(普通配列用)
// type	型
// hno	配列番号
void dimInitWithData(swVarNO hno,uwTYPE type,ULong totalYouso)
{ // dim_init_data	3501
	DBG_Func();
	nslog(@"配列番号=%d,型=$%04x,総要素数=%d",hno,type,(int)totalYouso);
	source++;	// 3502

	storeInternalCode(CODE_dim);	// 配列初期化 dim (dimの初期値代入処理に任せる)
	storeInternalCode(type);		// 型
	storeInternalCode(hno);			// 配列番号
	
	uwCODE *internalCode0=internalCode.wp;	// 中間コードの初期化データの個数を書き込むアドレスを保存	3509
	internalCode.wp++;				// その位置を飛ばしておく	3510

	if (firstCheckSouceInLine()!='{') {	// 3512,13
		// 初期化データ群が{で始まってない
		nslog(@"初期化データ群が{で始まってない");
		Error(ERR_ILLEGAL_DEFINE_ARRAY);
	}
	// 配列={  まで確定
	
	nslog(@"配列初期化データ群読み取り");
	// ここから先に要素データが並ぶ
	// 行を超えて存在することもある
	
	swVarCNT cnt=0;	// 3516
	do {	// 3519 did_loop
		nslog(@"source=%c",*source);
		source++; // 最初の { を飛ばすところから
		firstCheckSouceComment();
//		nslog(@"source=%c(firstCheckSouceComment後)",*source);
		
		// 要素の型が混在することはない
		// 1要素が奇数バイト(charとstrであり得る)の場合も、終わるまではアドレス補正しない
		
		switch (type) {
			case T_STR: // 3527
				nslog(@"(%d)=文字列",cnt);
				if (*source++!='"') {
					// 文字列が"で始まってない
					nslog(@"文字列が\"で始まってない");
					Error(ERR_ILLEGAL_DEFINE_ARRAY);
				}
				UByte c;
				while ((c=*source++)!='"') {
					storeInternalCodeB(c);
				}
				if (c==EOS) {
					// 文字列が"で閉じられてない
					nslog(@"文字列が\"で閉じられてない");
					Error(ERR_ILLEGAL_DEFINE_ARRAY);
				}
				storeInternalCodeB(EOS);
				break;

			case T_INT: // 3564
				nslog(@"(%d)=INT",cnt);
				ULong num=getIntConstant();
				storeInternalCodeL(num);
				break;
			case T_CHAR: // 3547
				nslog(@"(%d)=CHAR",cnt);
				storeInternalCodeB((UByte)getIntConstant());
				break;
			
			case T_FLOAT: // 3551
				nslog(@"(%d)=FLOAT",cnt);
				BOOL ferr;
				DOUBLE_LONG dl;
				dl.d=atod3(source,&source,&ferr);	// +/-/10進/16進数(0x～)/浮動小数点はこれで処理できる;後の#もこの中で処理
				// 全く謎なことに、atod3()がerrno=0で返しても、ここでerrno=3(ESRCH)になってしまう
				// そのため、errnoを使ってのエラー判定ができない
				nslog(@"errno=%d/ferr=%d",errno,ferr); // errnoに何が入っていても無視する
				if (ferr) {
					// 数値として異常
					nslog(@"数値として異常");
					Error(ERR_ILLEGAL_NUM);
				}
				readDOUBLE_LONG(internalCode.dp++, &dl); // *internalCode.dp++=dl;
				break;
		}
		if (++cnt>totalYouso) { // 3570
			// 総要素数より初期化データの方が多い
			nslog(@"総要素数より初期化データの方が多い");
			Error(ERR_ILLEGAL_DEFINE_ARRAY);
		}
		nslog(@"次の要素を探す:source=%c",*source);
	} while (firstCheckSouceComment()==','); // 3572-74

	DBG_printsn("配列初期化データ群読み取り終了");
	if (*source++!='}') { // 3576
		// 初期化データ群が}で閉じてない
		nslog(@"初期化データ群が}で閉じてない");
		Error(ERR_ILLEGAL_DEFINE_ARRAY);
	}
	if (cnt==0) {	// 3579
		// 初期化データが1つもない
		nslog(@"初期化データが1つもない");
		Error(ERR_ILLEGAL_DEFINE_ARRAY);
	}
	
	*internalCode0=cnt;	// 初期化データの個数を記録
	
	// 偶数境界化
	if (internalCode.l&1) storeInternalCodeB(EOS);
	
	DBG_Func2("(end)");
}

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

// ネストワークのオーバーフローチェック
int checkNestWorkOver(NEST_WORK *next)
{
	if ((UByte *)next>=&nestWorkHontai[nest_workSIZE]) {
		DBG_printsn("ネストワークを超えている");
		Error(ERR_NESTWORK_OVERFLOW); // ここでエラーを出してしまう
		// ここには来ない
		return (YES);
	}
	// 超えてない
	return (NO);
}

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