#include "stdafx.h"
#include "Rnsf7.h"
#include "commfunc.h"
#include "pre_interprete.h"
#include "splash.h"

using namespace std;
using namespace boost;

// 生ソースのロード
// 引数　：ソースファイル名
// 戻り値：エラーコード
int LOAD_RSC::source_load(const char *rsc)
{
	if ( rsc == NULL ) {
		return pre_errcode = LR_BADPARAM;
	}

	// ファイル名からダブルコーテーションははずす
	if ( rsc[0] == '"' ) {
		rscfname = rsc+1;
		rscfname = rscfname.substr(0, rscfname.size()-1);
	}
	else {
		rscfname = rsc;
	}

	try {
		if ( !tFileExist(rsc) ) {
			return pre_errcode = LR_NOFILE;
		}

		char cEncodeFlag = ENCODE_SJIS;

		FILE *fp;
		long fsize;
		UINT64 qwSize = getFileSizeQ(rsc);

		if ( qwSize == -1 ) {
			// エラー(-1==0xffffffffffffffff)の場合は取り扱わない
			return pre_errcode = LR_CANNOTOPEN;
		}
		else if ( qwSize >= 2u*1024u*1024u*1024u-16u ) {
			// ファイルサイズが2GB以上の場合は取り扱わない
			return pre_errcode = LR_TOOLARGE;
		}

		if ( 0 != fopen_s(&fp, rscfname.c_str(), "rb") ) {
			return pre_errcode = LR_CANNOTOPEN;
		}

		// ファイルがwidecharか、multibyteかを調べる
		// (ネイティブで扱えるwidecharはUnicode[LE]のみ)
		// [BOMの識別]
		//   ff fe    … Unicode (Little Endian)
		//   fe ff    … Unicode (Big Endian)
		//   ef bb bf … UTF-8
		// 上記のいずれでもなければ、Shift-JISと見なして処理を行う
		{ int b1 = 0, b2 = 0, b3 = 0;
			b1 = fgetc(fp);
			b2 = fgetc(fp);
			if (b1 == 0xff) {
				if (b2 == 0xfe) {
					cEncodeFlag = ENCODE_UNICODE_LE;
				}
			}
			else if (b1 == 0xfe) {
				if (b2 == 0xff) {
					cEncodeFlag = ENCODE_UNICODE_BE;
				}
			}
			else if (b1 == 0xef) {
				if (b2 == 0xbb) {
					b3 = fgetc(fp);
					if (b3 == 0xbf) {
						cEncodeFlag = ENCODE_UTF8;
					}
				}
			}
			// これら以外でENCODE_SJIS(初期値)
		}

		// ファイルポインタを先頭に戻す
		fseek(fp, 0, SEEK_SET);

		// ファイルのサイズを計測
		fsize = (long)qwSize;

		if ( fsize == 0 ) {
			fclose(fp);
            return pre_errcode = LR_BADFILE;
		}

		// vectorのメモリを確保
		// rscファイルを読み込み
		if (cEncodeFlag == ENCODE_UNICODE_LE || cEncodeFlag == ENCODE_UNICODE_BE) { // widecharのファイルだったら
			int mb_fsize;	// マルチバイト版ファイルサイズ

			fsize -= 2;								// -2はBOMの分
			vector<unsigned char> wsrc(fsize+2);	// +2は終端のNULL文字の分

			fseek(fp, 2, SEEK_SET);					// BOMを飛ばす
			if ( 1 > fread(&wsrc[0], fsize, 1, fp) ) {
				fclose(fp);
				return pre_errcode = LR_BADFILE;
			}
			wsrc[fsize-2] = wsrc[fsize-1] = 0;
			if (cEncodeFlag == ENCODE_UNICODE_BE) {
				unsigned char ucTemp;
				// BE→LE へ上下バイト入れ替え
				for(long i=0 ; i<fsize-2 ; i+=2) {
					ucTemp = wsrc[i];
					wsrc[i] = wsrc[i+1];
					wsrc[i+1] = ucTemp;
				}
			}

			mb_fsize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR)&wsrc[0], -1, NULL, 0, NULL, NULL);
			nsrc.resize(mb_fsize+1);
			fsize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR)&wsrc[0], -1, &nsrc[0], mb_fsize, NULL, NULL);
			--fsize;
		}
		else if (cEncodeFlag == ENCODE_UTF8) { // UTF-8のファイルだったら
			// UTF8 → Unicode[LE] → Shift-JIS の順にエンコードを行う
			int mb_fsize;			// マルチバイト(SJIS)版ファイルサイズ
			int wc_fsize;			// ワイドキャラクタ(Unicode)版ファイルサイズ
			string  src_utf8;

			fsize -= 3;								// -3はBOMの分

			// UTF-8としてファイルを読み込む
			fseek(fp, 3, SEEK_SET);					// BOMを飛ばす
			nsrc.resize(fsize+1);					// +1は終端のNULL文字の分
			if ( 1 > fread(&nsrc[0], fsize, 1, fp) ) {
				fclose(fp);
				return pre_errcode = LR_BADFILE;
			}
			nsrc[fsize] = 0;

			// UTF-8→Unicode[LE]変換
			wc_fsize = MultiByteToWideChar(CP_UTF8, 0, &nsrc[0], -1, NULL, 0);
			vector<wchar_t> wsrc(wc_fsize+1);
			MultiByteToWideChar(CP_UTF8, 0, &nsrc[0], -1, &wsrc[0], wc_fsize);

			// Unicode[LE]→SJIS変換
			mb_fsize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR)&wsrc[0], -1, NULL, 0, NULL, NULL);
			nsrc.resize(mb_fsize+1);
			fsize = WideCharToMultiByte(GetACP(), 0, (LPCWSTR)&wsrc[0], -1, &nsrc[0], mb_fsize, NULL, NULL);
			--fsize;
		}
		else { // その他はすべてSJIS
			nsrc.resize(fsize+1);
			if ( 1 > fread(&nsrc[0], fsize, 1, fp) ) {
				fclose(fp);
				return pre_errcode = LR_BADFILE;
			}
			nsrc[fsize] = 0;
		}
		fclose(fp);

		if ( fsize <= 0 ) {
			return pre_errcode = LR_BADFILE;
		}
	}
	catch(bad_alloc) {
		return pre_errcode = LR_OUT_OF_MEMORY;
	}
	catch(out_of_range) {
		return pre_errcode = LR_OUT_OF_RANGE;
	}
	catch(std::exception e) {
		str_er = e.what();
		return pre_errcode = LR_ERROR_STR;
	}
	catch(...) {
		return pre_errcode = LR_ERROR;
	}

	return pre_errcode = LR_OK;
}

// 定義部の解析
// 引数　：
//   pszItemName … アイテム名を示す数値 LR_SI_ で始まる。
//   pszDefault	 … アイテムのデフォルト値。
//   iIncNo      … Includeを読む場合、いくつめのIncludeを読むか。(zero based index)
//   iErrorCode  … エラーコード（参照）。
// 戻り値：エラーコード
const char * LOAD_RSC::searchItem(int iLoadItem, const char *pszDefault, int iIncNo, int &iErrorCode)
{
	iErrorCode = pre_errcode = LR_OK;

	try {
		if (iLoadItem == LR_SI_LOAD) {
			if (done_LR_SI_LOAD == true) {
				// すでにLR_SI_LOADで呼ばれている
				iErrorCode = pre_errcode = LR_OK;
				return pszDefault;
			}

			// ワーク用のエリアを確保
			vector<char> tsrc(nsrc);

			// %%を探す（%%は定義部の終端）
			char *pszline, *pc = NULL;
			pszline = strtok_s(&tsrc[0], "\r\n", &pc);

			if (!pszline) {
				iErrorCode = pre_errcode = LR_NOPP;
				return pszDefault;
			}

			do {
				if ( 0 == strncmp(pszline, "%%", 2) ) { // %%に到達
					done_LR_SI_LOAD = true;
					iErrorCode = pre_errcode = LR_OK;
					return pszDefault;
				}

				// 文字列の解析
				int i = 0;

				// (1)まず、タブorスペースでないところまで進む
				for(; pszline[i] == ' ' || pszline[i] == '\t'; ++i)
					;

				// (2)文字列終端だったらおしまい
				if ( pszline[i] == '\0' )
					continue;

				// (3)文字列終端でなければ、そこが左辺値の最初の文字であると見なす
				char *pszItemNameLeft = &pszline[i];

				// (4)タブorスペースorイコールになるところまで進む
				for(; pszline[i] != ' ' && pszline[i] != '\t' && pszline[i] != '=' && pszline[i] != '\0' ; ++i)
					;

				// (5)文字列終端だったらおしまい
				if ( pszline[i] == '\0' )
					continue;

				// (6)文字列終端でなければ、そこを終端とする。
				//    pszItemNameLeftが、アイテム名の先頭アドレスとなる
				pszline[i] = '\0';

				// (7)タブorスペースorイコールでないところまで進む
				//    そこがアイテム値の先頭アドレスとなる
				++i;
				for(; pszline[i] == ' ' || pszline[i] == '\t' || pszline[i] == '=' || pszline[i] == '\0' ; ++i)
					;

				if ( _stricmp(pszItemNameLeft, "ITEM") == 0 ) {
					strItem = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "INFORMATION") == 0 ) {
					strInformation = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "ICON") == 0 ) {
					strIcon = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "HELP") == 0 ) {
					strHelp = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "CONTEXTID") == 0 ) {
					strConTextId = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "AUTHOR") == 0 ) {
					strAuthor = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "URL") == 0 ) {
					strUrl = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "CATEGORY") == 0 ) {
					strCategory = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "TRY") == 0 ) {
					strTry = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "MUSTDEFVAR") == 0 ) {
					strMustDefVar = &pszline[i];
				}
				else if ( _stricmp(pszItemNameLeft, "INCLUDE") == 0 ) {
					if ( pszline[i] == '"' ) {
						string strline(&pszline[i+1]);
						if ( strline.size() >= 1 ) {
							vstrInclude.push_back(strline.substr(0, strline.size()-1));
						}
						else { // " を取ったら、ファイル名が無くなってしまった（不正）なとき
							strline = &pszline[i];
							vstrInclude.push_back(strline);
						}
					}
					else {
						string strline(&pszline[i]);
						if ( strline.size() >= 1 ) {
							vstrInclude.push_back(strline);
						}
					}
				}
				continue;
			} while(NULL != (pszline = strtok_s(NULL, "\r\n", &pc)));
			iErrorCode = pre_errcode = LR_NOPP;
			return pszDefault;
		}
		else {
			// まだLR_SI_LOADの呼出しが済んでいなければ、済ませてしまう。
			if (done_LR_SI_LOAD == false) {
				int ec;

				searchItem(LR_SI_LOAD, NULL, 0, ec);
				if (ec != LR_OK) {
					iErrorCode = pre_errcode = ec;
					return pszDefault;
				}
			}

			switch(iLoadItem) {
				case LR_SI_ITEM:
					iErrorCode = pre_errcode = LR_OK;
					return strItem.empty() ? pszDefault : strItem.c_str();

				case LR_SI_INFORMATION:
					iErrorCode = pre_errcode = LR_OK;
					return strInformation.empty() ? pszDefault : strInformation.c_str();

				case LR_SI_ICON:
					iErrorCode = pre_errcode = LR_OK;
					return strIcon.empty() ? pszDefault : strIcon.c_str();

				case LR_SI_HELP:
					iErrorCode = pre_errcode = LR_OK;
					return  strHelp.empty() ? pszDefault : strHelp.c_str();

				case LR_SI_CONTEXTID:
					iErrorCode = pre_errcode = LR_OK;
					return strConTextId.empty() ? pszDefault : strConTextId.c_str();

				case LR_SI_AUTHOR:
					iErrorCode = pre_errcode = LR_OK;
					return strAuthor.empty() ? pszDefault : strAuthor.c_str();

				case LR_SI_URL:
					iErrorCode = pre_errcode = LR_OK;
					return strUrl.empty() ? pszDefault : strUrl.c_str();

				case LR_SI_CATEGORY:
					iErrorCode = pre_errcode = LR_OK;
					return strCategory.empty() ? pszDefault : strCategory.c_str();

				case LR_SI_TRY:
					iErrorCode = pre_errcode = LR_OK;
					return strTry.empty() ? pszDefault : strTry.c_str();

				case LR_SI_MUSTDEFVAR:
					iErrorCode = pre_errcode = LR_OK;
					return strMustDefVar.empty() ? pszDefault : strMustDefVar.c_str();

				case LR_SI_INCLUDE:
					iErrorCode = pre_errcode = LR_OK;
					try {
						return vstrInclude.at(iIncNo).empty() ? pszDefault : vstrInclude.at(iIncNo).c_str();
					} // ここで OUT_OF_RANGEが返されるときは、もうこれ以上includeが見つからないとき。なので、エラーとはせず正常終了とみなす。
					catch(out_of_range) {
						return pszDefault;
					}

				default: // 不正な引数指定
					iErrorCode = pre_errcode = LR_BADPARAM;
					return pszDefault;
			}
		}
	}
	catch(bad_alloc) {
		iErrorCode = pre_errcode = LR_OUT_OF_MEMORY;
	}
	catch(out_of_range) {
		iErrorCode = pre_errcode = LR_OUT_OF_RANGE;
	}
	catch(std::exception e) {
		iErrorCode = pre_errcode = LR_ERROR_STR;
		str_er = e.what();
	}
	catch(...) {
		iErrorCode = pre_errcode = LR_ERROR;
	}
	return pszDefault;
}

// 行頭のスペースや行末のコメントなどを取り除く
char *LOAD_RSC::regka(char *line)
{
	char *p = line;
	char wq = 0; // 文字列中であるかどうかを示すフラグ（ " または ' ）
	char at = 0; // wq != 0 であるとき、at = '@' であれば、\をエスケープしない文字列

	if ( p && p[0] ) {
		// 行頭のスペースあるいはタブを取り除く
        for(; *p == ' ' || *p == '\t' ; ++p)
			;

		// 行末のスペース・タブ・コメントを取り除く
		char *q = p;

		for(; *q ; ++q) { // 文字列中ではない //, #, ; を探す
			if ( ISKANJI1M(*q) || (!at && *q == '\\') ) { // (SJIS漢字の1バイト目か、エスケープ文字なら)
				++q; // 次の文字は監視対象外
				if ( *q == '\0' )
					break;
			}
			else if ( *q == '"' || *q == '\'' ) { // 文字列の始まりだったら
				if ( wq == *q ) {
					// 文字列終了
					wq = 0;
					at = 0;
				}
				else if ( wq == 0 ) { // 文字列開始
					wq = *q;
					if ( q != p && *(q-1) == '@' ) { // @文字列は、エスケープシーケンスを無視するので
                        at = '@';
					}
				}
			}
			else {
				if ( wq == 0 ) {
					if ( *q == '#' || *q == ';' || (*q == '/' && *(q+1) == '/') ) { // コメントだったら
						*q = '\0';
                        break;
					}
				}
			}
		}

		// 行末から遡って、無駄なスペースやタブがあれば取り除く
		if ( p != q ) {
			for(--q; p != q && (*q == '\t' || *q == ' ') ; --q) {
				*q = '\0';
			}
		}
	}

	if ( wq != 0 ) {
		pre_errcode = LR_TEXT_NOT_CLOSED;
	}
	else {
		pre_errcode = LR_OK;
	}

	return p;
}

bool strncmpi(const char *str1, const char *str2)
{
	size_t n = strlen(str2);

	for(size_t i=0 ; i<n ; ++i) {
		if ( toupper(str1[i]) != str2[i] ) {
			return false;
		}
	}

	return true;
}

char *get1line(char *buf)
{
	static char *pbuf;
	char *left = NULL;

	if ( buf ) { // 初回呼び出し。2回目以降の呼び出しはbufにNULLを入れて呼び出す
		pbuf = buf;
	}
	if ( pbuf && *pbuf ) {
		// left:これから返す文字列の左端
		left = pbuf;

		// pbuf:これから返す文字列の右端。終端記号になるまで、インクリメント
		for(; !(*pbuf == '\r' || *pbuf == '\n' || *pbuf == '\0') ; ++pbuf)
			;

		// 終端が\rだった場合は、その次が\nであるかどうかも調べる
		if ( *pbuf == '\r' ) {
			*pbuf = '\0';
			++pbuf;
			if ( *pbuf == '\n' ) {
				*pbuf = '\0';
				++pbuf;
			}
		}
		// 終端が\nだった場合は、単にそこが終端であるとして扱う
		else if ( *pbuf == '\n' ) {
			*pbuf = '\0';
			++pbuf;
		}
		// 終端が\0だった場合は、そのまま終端であるとして扱う。次回以降の呼び出しではNULLを返す
	}

	// これ以上行がない場合か、エラーの場合はNULLを返す
	return left;
}

regex re_else("ELSE(\\s|\t)*$",  regex_constants::icase);
regex re_elif("ELSE(\\s|\t)+IF.*", regex_constants::icase);
regex re_break("BREAK[0-9]*", regex_constants::icase);
regex re_continue("CONTINUE[0-9]*", regex_constants::icase);

int LOAD_RSC::skip_until_blockclose(list<RSCLINES>::iterator &vrli)
{
	list<RSCLINES>::iterator vrlend = vrl.end();
	string::size_type lsize;

	while(vrli != vrlend) {
		lsize = vrli->line.size();

		// 閉じカッコが見つかったら
		if ( vrli->line[0] == '}' ) {
			// 注↑：終端がnull文字であることを暗黙に使っているため、at() は使わず operater[]() を使っている
			//       この先、そういう箇所が度々登場する。
			return LR_OK;
		}
		// 閉じカッコより前に、ネストの { が見つかったら
		else if ( lsize >= 1 && vrli->line.at(lsize-1) == '{' ) {
			int ec = analyze_blocks(vrli);
			if ( ec != LR_OK ) return ec;
		}
		else {
			// BREAK
			if ( regex_match(vrli->line, re_break) ) {
				unsigned int n = vrli->line.size() == 5 ? 1 : atoi(vrli->line.substr(5).c_str());
				unsigned int llsize = (unsigned int)(looplabel.size());
				
				if ( llsize >= n  )
					vrli->line = "GOTO " + looplabel.at(llsize-n) + "END";
				else
					return LR_WRONG_BREAK;
			}
			// CONTINUE
			else if ( regex_match(vrli->line, re_continue) ) {
				unsigned int n = vrli->line.size() == 8 ? 1 : atoi(vrli->line.substr(8).c_str());
				unsigned int llsize = (unsigned int)(looplabel.size());

				if ( llsize >= n )
					vrli->line = "GOTO " + looplabel.at(llsize-n) + "START";
				else
					return LR_WRONG_CONTINUE;
			}
			++vrli;
		}
	}
	return LR_NO_BLOCK_CLOSE;
}

// ブロックの解析（再帰呼び出し関数）
int LOAD_RSC::analyze_blocks(list<RSCLINES>::iterator &vrli)
{
	list<RSCLINES>::iterator vrlend = vrl.end();

	for(; vrli != vrlend ; ++vrli) {
		// 行が空でなくて、
		if ( !vrli->line.empty() ) {
			string::size_type lsize = vrli->line.size();

			// 行末が { であったならば
			if ( lsize >= 1 && vrli->line.at(lsize-1) == '{' ) {
				vrli->line.erase(lsize-1); // { を取り除く

				// その行が何のフロー制御によるモノかを調べる。
				// ただし、ラベル（先頭がコロン）で始まる場合を考慮する
				int i = 0;
				while ( vrli->line[i] == ':' ) {
					++i;
					while( vrli->line[i] != ' ' && vrli->line[i] != '\t' && vrli->line[i] != '\0' ) {
						if ( vrli->line[i] == '\0' )
							return LR_WRONG_BLOCK_OPEN;
						++i;
					}
					while( vrli->line[i] == ' ' || vrli->line[i] == '\t' )
						++i;
				}

				int cn_i = ++n_i;
				char itbuf[16];

				string strLabel(":_");
				if ( 0 == _ultoa_s(cn_i, itbuf, _countof(itbuf), 10) ) {
					strLabel += itbuf;	// ブロック前後を表すラベルのベース文字列
				}

				if ( strncmpi(vrli->line.substr(i).c_str(), "IF") ) {
					vrli->line = "ELSE " + vrli->line + " " + strLabel + "NEXT0";
					vrli->fname;
					int iNext = 0;

					while(1) {
						int ec = skip_until_blockclose(vrli);
						if ( ec != LR_OK ) {
							return ec;
						}

						string::size_type lsizev = vrli->line.size();

						if ( lsizev >= 1 && vrli->line.at(lsizev-1) == '{' ) { // 行末が { だったら - else/else if
							vrli->line.erase(lsizev-1); // { を取り除く

							RSCLINES rl;
							rl.fname    = vrli->fname;
							rl.line_num = vrli->line_num;
							rl.line     = "GOTO " + strLabel + "END";

							vrl.insert(vrli, rl);
							vrli->line.erase(0, 1); // } を取り除く

							// elseなのかelse if なのかを判定
							char itbuf[16];
							if ( regex_match(vrli->line, re_else) ) { // else
								if ( 0 == _ultoa_s(iNext, itbuf, _countof(itbuf), 10) ) {
									vrli->line = strLabel + "NEXT" + itbuf;
								}
								++iNext; // 条件分岐終了時のためにインクリメントしておく
							}
							else if ( regex_match(vrli->line, re_elif) ) { // else if
								if ( 0 == _ultoa_s(iNext, itbuf, _countof(itbuf), 10) ) {
									vrli->line = strLabel + "NEXT" + itbuf + " " + vrli->line;
								}
								++iNext;
								if ( 0 == _ultoa_s(iNext, itbuf, _countof(itbuf), 10) ) {
									vrli->line += " " + strLabel + "NEXT" + itbuf;
								}
							}
							else {
								return LR_WRONG_BLOCK_OPEN;
							}
						}
						else { // 行末が { でなかったら（条件分岐終了）
							char itbuf[16];

							if ( 0 == _ultoa_s(iNext, itbuf, _countof(itbuf), 10) ) {
								vrli->line = strLabel + "END " + strLabel + "NEXT" + itbuf;
							}
							return LR_OK;
						}
					}
				}
				else if ( strncmpi(vrli->line.substr(i).c_str(), "WHILE") ) {
					vrli->line = strLabel + "START " + vrli->line + " " + strLabel + "END";
					
					looplabel.push_back(strLabel);
					int ec = skip_until_blockclose(vrli);
					if ( ec != LR_OK ) {
						return ec;
					}
					looplabel.pop_back();
					vrli->line = "GOTO " + strLabel + "START";
					RSCLINES rl;
					rl.fname    = vrli->fname;
					rl.line_num = vrli->line_num;
					rl.line     = strLabel + "END";

					++vrli;
					vrl.insert(vrli, rl);
					return LR_OK;
				}
				else if ( strncmpi(vrli->line.substr(i).c_str(), "LOOP") ) {
					vrli->line = strLabel + "START " + "WHILE(1) " + strLabel + "END";

					looplabel.push_back(strLabel);
					int ec = skip_until_blockclose(vrli);
					if ( ec != LR_OK ) {
						return ec;
					}
					looplabel.pop_back();
					vrli->line = "GOTO " + strLabel + "START";
					RSCLINES rl;
					rl.fname    = vrli->fname;
					rl.line_num = vrli->line_num;
					rl.line     = strLabel + "END";

					++vrli;
					vrl.insert(vrli, rl);
					return LR_OK;
				}
				else if ( strncmpi(vrli->line.substr(i).c_str(), "FOR") ) {
					vrli->line += " " + strLabel + "END";

					RSCLINES rl;
					rl.fname    = vrli->fname;
					rl.line_num = vrli->line_num;
					rl.line     = strLabel + "START F0R " + vrli->line.substr(i);

					vrl.insert(++vrli, rl);

					looplabel.push_back(strLabel);
					int ec = skip_until_blockclose(vrli);
					if ( ec != LR_OK ) {
						return ec;
					}
					looplabel.pop_back();
					vrli->line = "GOTO " + strLabel + "START";

					rl.fname    = vrli->fname;
					rl.line_num = vrli->line_num;
					rl.line     = strLabel + "END";

					++vrli;
					vrl.insert(vrli, rl);
					return LR_OK;
				}
				else if ( strncmpi(vrli->line.substr(i).c_str(), "REPEAT") ) {
					vrli->line = strLabel + "START ";
					
					looplabel.push_back(strLabel);
					int ec = skip_until_blockclose(vrli);
					if ( ec != LR_OK ) {
						return ec;
					}
					looplabel.pop_back();
					vrli->line.erase(0,1);

					unsigned lsizev = (unsigned)(vrli->line.size());

					for(unsigned j=0;j<lsizev;++j) {
						if ( strncmpi(vrli->line.substr(j,5).c_str(), "UNTIL") ) {
							vrli->line.replace(j, 5, "WHILE");
							vrli->line += " " + strLabel + "START";

							RSCLINES rl;
							rl.fname    = vrli->fname;
							rl.line_num = vrli->line_num;
							rl.line     = strLabel + "END";

							++vrli;
							vrl.insert(vrli, rl);
							return LR_OK;
						}
					}
					return LR_WRONG_BLOCK_CLOSE;
				}
				else {
					return LR_WRONG_BLOCK_OPEN;
				}
			}
		}
	}

	return LR_OK;
}

// プリインタラプト
// 戻り値：エラーコード
int LOAD_RSC::pre_interprete(void)
{
	bool bPreWriteFlag; // デバッグモードかどうかの判定(詳細はprewrite()参照)
	if ( 1 == rnsf7RegRead("DEBUG_LOWLEVEL_INTERPRETE", 0) ) {
		bPreWriteFlag = true;
	}
	else {
		bPreWriteFlag = false;
	}

	try {
		// 領域をクリア
		vrl.clear();
		
		// 定義部の解析
		int ec;
		bool pp_exist = 0;

		searchItem(LR_SI_LOAD, NULL, 0, ec);

		// 解析中の行数
		int  nline = 0;

		// %%を探す（%%は定義部の終端であり、ここまでは行数のカウントしか行わない）
		char *pszline;
		vector<char> tsrc(nsrc);

		pszline = get1line(&tsrc[0]);
		if (!pszline) {
			return pre_errcode = LR_NOPP;
		}

		do {
			if ( 0 == strncmp(pszline, "%%", 2) ) {
				pp_exist = 1;
				break;
			}
		}while(++nline,NULL != (pszline = get1line(NULL)));

		if ( !pp_exist ) { // %% が見つからない
			return pre_errcode = LR_NOPP;
		}

		++nline;
		pszline = get1line(NULL);

		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力

		// 定義部終了／定義部以降の読み込み
		RSCLINES rscline;
		if ( pszline ) {
			do {
				rscline.fname    = rscfname;
				rscline.line_num = nline + 1;
				rscline.line     = regka(pszline); // 文頭よりサーチし、行頭と行末の余計なスペースやコメントを取り除く
				vrl.push_back(rscline);

				if ( pre_errcode == LR_TEXT_NOT_CLOSED ) {
					pre_errline = vrl.end();
					--pre_errline;
					return pre_errcode = LR_TEXT_NOT_CLOSED;
				}
			}while(++nline,NULL != (pszline = get1line(NULL)));
		}

		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力

		// 各Includeの読み込み
		{
			vector<char> n0src(nsrc);
			string       n0rscfname(rscfname);
			try {
				int iIncNo = 0;

				while(1) {
					nline = 0;
					source_load(vstrInclude.at(iIncNo).c_str());
					if ( NULL != (pszline = get1line(&nsrc[0])) ) {
						do {
							rscline.fname    = vstrInclude.at(iIncNo);
							rscline.line_num = nline + 1;
							rscline.line     = regka(pszline); // 文頭よりサーチし、行頭と行末の余計なスペースやコメントを取り除く
							vrl.push_back(rscline);

							if ( pre_errcode == LR_TEXT_NOT_CLOSED ) {
								pre_errline = vrl.end();
								--pre_errline;
								return pre_errcode = LR_TEXT_NOT_CLOSED;
							}
						}while(++nline,NULL != (pszline = get1line(NULL)));
					}

					++iIncNo;
				}
			}
			catch(out_of_range) {
				; // vstrInclude.at(iIncNo) が out_of_range を送出したときを終了とする
			}
			nsrc = n0src;
			rscfname = n0rscfname;
		}

		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力

		// ソース+includeの読み込み完了
		// -------------------------------
		// 行を跨る文の結合、あるいはその逆の分割

		list<RSCLINES>::iterator vrli = vrl.begin();
		list<RSCLINES>::iterator vrlend = vrl.end();

		for( ; vrli != vrlend ; ++vrli) {
			size_t i;

			// 行を跨る文の結合
			// 前行の続きかどうかを調べる
			// 行の始まりが２項演算子あるいは３項演算子の'?'で始まっていたら、前行の続きとみなす
			// '{' から始まっていた場合も前行にくっつくものとみなす
			while(1) {
				if ( vrli != vrl.begin() &&
					(vrli->line[0] == '=' ||
					vrli->line[0] == '>' ||
					vrli->line[0] == '<' ||
					vrli->line[0] == '|' ||
					vrli->line[0] == '&' ||
					vrli->line[0] == '*' ||
					vrli->line[0] == '/' ||
					vrli->line[0] == '%' ||
					vrli->line[0] == '^' ||
					vrli->line[0] == '?' ||
					vrli->line[0] == ',' ||
					vrli->line[0] == ')' ||
					vrli->line[0] == '[' ||
					vrli->line[0] == ']' ||
					vrli->line[0] == '{' ||
					(vrli->line[0] == '-' && vrli->line[1] != '-') ||
					(vrli->line[0] == '+' && vrli->line[1] != '+'))) {

					list<RSCLINES>::iterator vrlib = vrli;
                    --vrlib; // vrlib は vrli の前の要素を表す

					vrli->line = (vrlib->line + vrli->line);
					vrl.erase(vrlib);
					--vrli;
					continue;
				}
				break;
			}

			list<RSCLINES>::iterator vrlia = vrli;
			++vrlia; // vrlia は vrli の次の要素を表す

			// 行が'}'だけで構成されており、その次の行が 'until', 'else' で
			// あったならば、結合する
			// ただし、until, else に至るまでに空行があった場合は、削除していく
			if ( vrlia != vrlend && vrli->line == "}" ) {
				for(; vrlia != vrlend; ++vrlia) {
					if ( vrlia->line.empty() ) {
						vrl.erase(vrlia);
						vrlia = vrli;
					}
					else if ( strncmpi(vrlia->line.c_str(), "UNTIL ") ||
						      strncmpi(vrlia->line.c_str(), "UNTIL\t") ||
						      strncmpi(vrlia->line.c_str(), "UNTIL(") ||
							  strncmpi(vrlia->line.c_str(), "ELSE ") ||
							  strncmpi(vrlia->line.c_str(), "ELSE\t") ||
							  strncmpi(vrlia->line.c_str(), "ELSE{") ) {
						vrli->line += vrlia->line;
						vrli->line_num = vrlia->line_num;
						vrl.erase(vrlia);
						break;
					}
					else {
						break;
					}
				}
			}

			vrlia = vrli;
			++vrlia; // vrlia は vrli の次の要素を表す

			// 行の終わりが２項演算子あるいは３項演算子で終わっていたら、次行へ続くとみなす
			i = vrli->line.size();
			if ( i > 0 ) {
				--i;
				if ( vrlia != vrlend &&
					(vrli->line[i] == '=' ||
					vrli->line[i] == '>' ||
					vrli->line[i] == '<' ||
					vrli->line[i] == '|' ||
					vrli->line[i] == '&' ||
					vrli->line[i] == '*' ||
					vrli->line[i] == '/' ||
					vrli->line[i] == '%' ||
					vrli->line[i] == '^' ||
					vrli->line[i] == '?' ||
					vrli->line[i] == ':' ||
					vrli->line[i] == ',' ||
					vrli->line[i] == '(' ||
					vrli->line[i] == '[' ||
					(vrli->line[i] == '-' && (i != 0 && vrli->line[i-1] != '-')) ||
					(vrli->line[i] == '+' && (i != 0 && vrli->line[i-1] != '+')))) {

					vrlia->line = (vrli->line + vrlia->line);
					vrli->line = "";
				}
			}
		}

		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力

		// ----------------------------------------
		// 中カッコの解析と、単行命令への置き換え
		// ｛｝は入れ子なので、再帰呼び出しでうまいこと処理できる
		vrli = vrl.begin();
		vrlend = vrl.end();
		n_i = 0;
		looplabel.clear();
		while(vrli != vrlend) {
			ec = analyze_blocks(vrli);
			if ( ec != LR_OK ) {
				if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力
				pre_errline = vrli;
				return pre_errcode = ec;
			}
		}

		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力

		// ----------------------------------------
		// 未対応の },break,continue を捜索／重複ラベルチェック
		vrli = vrl.begin();
		vrlend = vrl.end();
		vector<string> strLabels;
		vector<string>::iterator isl;
		string newLabelName;

		for(nline = 1; vrli != vrlend ; ++vrli, ++nline) {
			if ( vrli->line[0] == '}' ) {
				pre_errline = vrli;
				return pre_errcode = LR_BLOCK_NOT_CLOSED;
			}
			// BREAK
			else if ( regex_match(vrli->line, re_break) ) {
				pre_errline = vrli;
				return pre_errcode = LR_WRONG_BREAK;
			}
			// CONTINUE
			else if ( regex_match(vrli->line, re_continue) ) {
				pre_errline = vrli;
				return pre_errcode = LR_WRONG_CONTINUE;
			}
			else {
				int i = 0, j;

				while ( vrli->line[i] == ':' ) {
					j = i + 1;
					while ( vrli->line[j] != ' ' && vrli->line[j] != '\t' && vrli->line[j] != '\0' )
						++j;

					newLabelName = vrli->line.substr(i,j-i);
					if ( !strLabels.empty() ) {
						for(isl = strLabels.begin(); isl != strLabels.end() ; ++isl) {
							if ( _stricmp(isl->c_str(), newLabelName.c_str()) == 0 ) {
								pre_errline = vrli;
								return pre_errcode = LR_OLLABEL;
							}
						}
					}
					strLabels.push_back(newLabelName);

					while ( vrli->line[j] == ' ' || vrli->line[j] == '\t' )
						++j;
					i = j;
				}
			}
		}

		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力

		// ----------------------------------------
		// すべての行の行末に\nを加える
		vrli = vrl.begin();
		vrlend = vrl.end();
		for(; vrli != vrlend ; ++vrli) {
			vrli->line.push_back('\n');
		}

		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力

		return pre_errcode = LR_OK;
	}
	catch(bad_alloc) {
		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力
		return pre_errcode = LR_OUT_OF_MEMORY;
	}
	catch(out_of_range) {
		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力
		return pre_errcode = LR_OUT_OF_RANGE;
	}
	catch(std::exception e) {
		str_er = e.what();
		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力
		return pre_errcode = LR_ERROR_STR;
	}
	catch(...) {
		if ( bPreWriteFlag ) prewrite(); // デバッグモードの場合、途中経過をファイル出力
		return pre_errcode = LR_ERROR;
	}
}

void LOAD_RSC::prewrite(void)
{
	// ----------------------------------------
	// プリインタプリタの出力結果を見る場合
	// Rnsf7のレジストリキーに値「DEBUG_LOWLEVEL_INTERPRETE」を作り、
	// (DWORD)1 を入れる。
	// ----------------------------------------
	// debug用 - 高級[if-elseやwhileを使ったもの]→低級[ifとgotoのみ]　変換後のスクリプトを書き出す
	string listname;
	FILE *op;
	string::size_type lsize;
	
	listname = rscfname + "_debug.txt";
	if ( 0 == fopen_s(&op, listname.c_str(), "wt") ) {
		list<RSCLINES>::iterator vrlend = vrl.end();

		for(list<RSCLINES>::iterator vrli = vrl.begin(); vrli != vrlend ; ++vrli) {
			fprintf(op, "%s[%d]:%s", vrli->fname.c_str(), vrli->line_num, vrli->line.c_str());
			lsize = vrli->line.size();
			if ( lsize == 0 || vrli->line.at(lsize-1) != '\n' ) {
                fputc('\n', op);
			}
		}
		fclose( op );
	}
}

list<RSCLINES>::const_iterator LOAD_RSC::GoTo(const char *szLabel) const
{
	list<RSCLINES>::const_iterator vrli = vrl.begin();
	list<RSCLINES>::const_iterator vrlend = vrl.end();

	for(; vrli != vrlend ; ++vrli) {
		int i = 0, j;
		while ( vrli->line[i] == ':' ) {
			j = i + 1;
			while ( vrli->line[j] != ' ' && vrli->line[j] != '\t' && vrli->line[j] != '\n' && vrli->line[j] != '\0' )
				++j;

			string strLabelName = vrli->line.substr(i,j-i);
			if ( _stricmp(strLabelName.c_str(), szLabel) == 0 ) {
				return vrli;
			}
			while ( vrli->line[j] == ' ' || vrli->line[j] == '\t' )
				++j;
			i = j;
		}
	}

	return vrli;
}

void LOAD_RSC::errmes(HWND hWnd) const
{
	// スプラッシュウィンドウが表示されている場合に備え、まずは消してから
	destroy_splash_window();

	switch( pre_errcode ) {
		case LR_OK:
			MessageBox(hWnd, "エラーなし。", "R-Script Pre-Interprete", MB_OK | MB_ICONINFORMATION);
			break;

		case LR_BADPARAM:
			MessageBox(hWnd, "不正なパラメータ。", "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			break;

		case LR_NOFILE:
			{
				string mes("ファイルが見つかりません。\r\n");
				mes += rscfname;
				mes += "\r\n\r\nファイル名を直に指定している場合は、ファイル名をフルパスで指定してみてください。\r\n"
					   "機能項目一覧、お気に入り、最近使った機能項目、リンク等から呼び出そうとしている場合は、呼び出そうとするスクリプトファイルが存在しないか、削除されている可能性があります。";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_TOOLARGE:
			{
				string mes("スクリプトファイルのサイズが大きすぎます。取扱可能なファイルのサイズは2GB未満です。\r\n");
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_CANNOTOPEN:
			{
				string mes("ファイルを開けません。\r\n");
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_BADFILE:
			{
				string mes("不正な形式のファイルです。\r\n");
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_NOPP:
			{
				string mes("定義部の終端(%%)が見つかりません。\r\n");
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_OUT_OF_MEMORY:
			{
				string mes("ファイルを解析するためのメモリが足りません。\r\n");
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_OUT_OF_RANGE:
			{
				string mes("OUT_OF_RANGEエラーです。\r\nR-Scriptの内部エラーである可能性があります。問題の発生したスクリプトを添えて、開発元へ問い合わせて下さい。\r\n");
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_NOITEM:
			{
				string mes("定義部の項目が見つかりません。\r\n");
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_TEXT_NOT_CLOSED:
			{
				char itbuf[16];
				string mes("文字列が閉じていません。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_BLOCK_NOT_CLOSED:
			{
				char itbuf[16];
				string mes("ブロックが閉じていません。{ と未対応の } が見つかりました。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_WRONG_BLOCK_OPEN:
			{
				char itbuf[16];
				string mes("不正な { 。\r\nif/while/loop/repeat/for 以外の場所で { が使われました。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_WRONG_BLOCK_CLOSE:
			{
				char itbuf[16];
				string mes("不正な } 。\r\n不正な位置に } があるか、{ とペアになっていない } がありました。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_NO_BLOCK_OPEN:
			{
				char itbuf[16];
				string mes("この行には { が必要です。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_NO_BLOCK_CLOSE:
			{
				string mes("} が見つかりません。\r\n { が余っています。\r\n");

				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_OLLABEL:
			{
				char itbuf[16];
				string mes("ラベルが重複しています。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_WRONG_BREAK:
			{
				char itbuf[16];
				string mes("不正なbreakです。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_WRONG_CONTINUE:
			{
				char itbuf[16];
				string mes("不正なcontinueです。\r\n");

				mes += pre_errline->fname;
				mes += "\r\n";
				if ( 0 == _ultoa_s(pre_errline->line_num, itbuf, _countof(itbuf), 10) ) {
					mes += itbuf;
				}
				mes += "行目";
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_ERROR:
			{
				string mes("エラーです。\r\n原因は不明です。R-Scriptの内部エラーである可能性があります。問題の発生したスクリプトを添えて、開発元へ問い合わせて下さい。\r\n");

				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_ERROR_STR:
			{
				string mes("エラーです。\r\nR-Scriptの内部エラーである可能性があります。問題の発生したスクリプトを添えて、開発元へ問い合わせて下さい。\r\n");
				mes += "原因：";
				mes += str_er;
				mes += "\r\n";
				mes += rscfname;
				MessageBox(hWnd, mes.c_str(), "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;

		case LR_USER_ERROR:
			MessageBox(hWnd, "エラーです。(pre_errcode = LR_USER_ERROR)", "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			break;

		default:
			{
				char buf[50];
				wsprintf(buf, "エラーです。(pre_errcode = %d)", pre_errcode);
				MessageBox(hWnd, buf, "R-Script Pre-Interprete", MB_OK | MB_ICONSTOP);
			}
			break;
	}
}
