/*****************************************************************************
 * Bison/Flexプログラム部分をテストするための、Windowsアプリケーションの雛型 *
 * □ビルド・実行方法:                                                       *
 * ┃"C:\Program Files (x86)\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT"  *
 * ┃make -f winapp.mk run                                                   *
 *****************************************************************************/
#include "winapp.h"
//-----------------------------------------------------------------------------
//{{定型コード:winapp.c(先頭部)================================================
/*---------------------------------------------------------------------------*/
//エラーログ用
static char err_path[_MAX_PATH];	//'-e'オプションが指定されたら、エラーログファイル名を格納する。
static FILE* fp_err;			//最初のエラーログを記録する時に、エラーログファイルを作成する。
//{{2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
typedef struct _ST_Location {
	const char*	path;					//push_location()が呼び出された直前のファイル名
	int		line;					//push_location()が呼び出された直前の行番号
} ST_Location;
static ST_Location TBL_Location[16/*調整可*/];			//ロケーションスタック
static nLocation;						//ロケーションスタックの格納数
static const char* filename = "-";				//現在のファイル名(popen時はコマンド名)。現在の行番号はyylinenoを参照して下さい。
static void init_location(const char* path) {
	nLocation = 0;						//ロケーションスタックを空にする。
	filename = strdup(path);				//現在のファイル名をコピーして保持する。
	yylineno = 1;						//現在の行番号を初期化する。	yylex_init()でも初期化しているのでこの行は無くても構わないのだが、判り易さのためにここでも初期化する事にした。
}
void push_location(const char* path) {
	if(nLocation >= ARRAY_SIZE(TBL_Location)) { DIE(); }	//ロケーションスタックがフルでない事を確認する。
	TBL_Location[nLocation].path = filename;		//現在のファイル名をロケーションスタックに退避する。
	TBL_Location[nLocation].line = yylineno;		//現在の行番号をロケーションスタックに退避する。
	nLocation++;						//ロケーションスタックの格納数を増やす。
	filename = strdup(path);				//現在のファイル名をコピーして保持する。
	yylineno = 1;						//現在の行番号を初期化する。
}
void pop_location() {
	if(!nLocation) { DIE(); }				//ロケーションスタックが空でない事を確認する。
	nLocation--;						//ロケーションスタックの格納数を減らす。
	filename = TBL_Location[nLocation].path;		//現在のファイル名をロケーションスタックから復元する。
	yylineno = TBL_Location[nLocation].line;		//現在の行番号をロケーションスタックから復元する。
}
//}}2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
void yyerror(const char* fmt, ...) {	//←{{2015/03/06:'-e'オプション対応のためにwinapp.cから移動しました。}}
	//'-e'オプションが指定されていて、最初のエラーログを記録する時ならば…
	if(*err_path && !fp_err) {
		//エラーログファイルを作成する。
		fp_err = fopen(err_path, "w");
		if(!fp_err) { error(EXIT_FAILURE, errno, "%s が作成できません。", err_path); }	//{{2016/09/21変更:die(～)で終了していた箇所を、error(EXIT_FAILURE,～)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
		//エラーログファイルの出力ストリームは、バッファリング無しとする。
		// - die()で終了した時(abort()時)に、バッファ分がフラッシュされないようなので、こうしておく必要が有る。
		//   別の案として、この下の処理で毎回fflush()する方法も有るが、バッファリング無しとする方が簡単だろう。
		setbuf(fp_err, NULL);
	}
	//エラーメッセージ(,及び,エラーログ)を出力する。
//{{2016/09/24変更:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
//	             fprintf(stderr, "### error at line %d : ", yylineno);	//エラーメッセージ
//	if(fp_err) { fprintf(fp_err, "### error at line %d : ", yylineno); }	//エラーログ
//↓2016/09/24変更:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
	             fprintf(stderr, "%s(%d) : ", filename, yylineno);		//エラーメッセージ
	if(fp_err) { fprintf(fp_err, "%s(%d) : ", filename, yylineno); }	//エラーログ
//}}2016/09/24変更:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
	{
		va_list ap;
		va_start(ap, fmt);
		             vfprintf(stderr, fmt, ap);		//エラーメッセージ
		if(fp_err) { vfprintf(fp_err, fmt, ap); }	//エラーログ
		va_end(ap);
	}
	             fputc('\n', stderr);	//エラーメッセージ
	if(fp_err) { fputc('\n', fp_err); }	//エラーログ
}
/*---------------------------------------------------------------------------*/
//}}定型コード:winapp.c(先頭部)================================================
//-----------------------------------------------------------------------------
//警告定義
enum {
	WARN_CAST,			//暗黙の型変換で誤差が生じたら、警告を表示し最終的にエラー終了します。このオプションを指定しなければ、警告表示もエラー終了もしません。
};
static const char* const warn_tokens[]={
	"cast",				//暗黙の型変換で誤差が生じたら、警告を表示し最終的にエラー終了します。このオプションを指定しなければ、警告表示もエラー終了もしません。
NULL};//終端
int warn;				//各警告(WARN_*)について(warn&(1<<WARN_*))がセットされていたらその警告がOnである事を示します。
/*---------------------------------------------------------------------------*/
//言語選択
static char* opt_x = "c";		//"c"=C言語形式,"cs"=C#形式
/*---------------------------------------------------------------------------*/
//ローカル変数定義
static GTree* tree_pSnrTbl;		//シナリオテーブルラベル⇒(ST_SnrTbl*)
static GTree* tree_pSnrSeq;		//シナリオシーケンスラベル⇒(ST_SnrSeq*)
static GTree* tree_pSnrSeq_Used;	//シナリオシーケンスラベル⇒(ST_SnrSeq*)	2パス目でのマーク用。
static GTree* tree_pArg;		//(ST_Arg*)を単一化して登録する。
static GTree* tree_pArgList;		//(GSList*)を単一化して登録する。(GSList*)の要素は(ST_Arg*)です。
static GTree* tree_pArgs;		//(ST_Args*)を単一化して登録する。
static GTree* tree_pArgs_Used;		//(ST_Args*)を単一化して登録する。		2パス目でのマーク用。
static GTree* tree_pArgs_Blob;		//(ST_Args*)⇒BLOBデータ			2パス目でのBLOB構築用。
static GTree* tree_pArgs_Code;		//(ST_Args*)⇒(ST_Code*)			2パス目でのコード生成用。
static GTree* tree_pFunc;		//(ST_Func*)を単一化して登録する。
static GTree* tree_pCond;		//(ST_Cond*)を単一化して登録する。
static GTree* tree_pCondSubs;		//(ST_CondSubs*)を単一化して登録する。
static GTree* tree_pCondSubsList;	//(GSList*)を単一化して登録する。(GSList*)の要素は(ST_CondSubs*)です。
static GTree* tree_pValueSubs;		//(ST_ValueSubs*)を単一化して登録する。
static GTree* tree_pValueSubsList;	//(GSList*)を単一化して登録する。(GSList*)の要素は(ST_ValueSubs*)です。
static GTree* tree_pSnrTblBody;		//(ST_SnrTblBody*)を単一化して登録する。
static GTree* tree_pSnrTblBody_Code;	//(ST_SnrTblBody*)⇒(ST_Code*)			2パス目でのコード生成用。
static GTree* tree_pSnrTblStmt;		//(ST_SnrTblStmt*)を単一化して登録する。
static GTree* tree_pSnrSeqBody;		//(ST_SnrSeqBody*)を単一化して登録する。
static GTree* tree_pSnrSeqBody_Used;	//(ST_SnrSeqBody*)を単一化して登録する。	2パス目でのマーク用。
static GTree* tree_pSnrSeqBody_Code;	//(ST_SnrSeqBody*)⇒(ST_Code*)			2パス目でのコード生成用。
static GTree* tree_pSnrSeqStmt;		//(ST_SnrSeqStmt*)を単一化して登録する。
static GTree* tree_pTrigName_No;	//トリガ名⇒トリガ番号				1パス目で登録します。シナリオテーブルから再帰的に辿れないシナリオテーブルに含まれているトリガ名も出力対象とするためです。
static GTree* tree_pFuncName_No;	//関数名⇒関数番号				1パス目で登録します。シナリオテーブルから再帰的に辿れないシナリオシーケンスに含まれている関数名も出力対象とするためです。
static int endAddr;			//最終アドレス
//ローカルラベル
static int nAtmarkLocalLabel;			//'@'ローカルラベルの出現数		//'@@'が出現したら、'@%d'という形式の内部ローカルラベルに変換する。その後、+1する。要するに、次に出現する'@@'の番号を表していると見なせるので、'@F'からは、nAtmarkLocalLabelで参照できる。'@B'からは、(nAtmarkLocalLabel-1)で参照できる。
static const char* sDotLocalLabelPrefix = "";	//'.'ローカルラベルのプレフィクス	//'.～'が出現したら、'%s.～'という形式の内部ローカルラベルに変換する。グローバルラベルの定義が出現したら、sDotLocalLabelPrefixを更新する。結果として、グローバルラベル定義～グローバルラベル定義の間でのローカルラベルとなる。
//ラベル名のソート方法
int (*fnLabCmp)(const void*, const void*) = strcmp;	//'n',又は,'nl'オプションが指定されたらstrnatcmpに変更する。
//トリガ名のソート方法
int (*fnTrgCmp)(const void*, const void*) = strcmp;	//'n',又は,'nt'オプションが指定されたらstrnatcmpに変更する。
//関数名のソート方法
int (*fnFncCmp)(const void*, const void*) = strcmp;	//'n',又は,'nf'オプションが指定されたらstrnatcmpに変更する。
//{{進捗表示用
static int opt_q;
static int newMsgLen, oldMsgLen = 0;
//}}進捗表示用
/*---------------------------------------------------------------------------*/
//ローカル関数宣言
__declspec(noreturn) static void usage();
static int subr(int argc, char* argv[]);
static void pass2(int bOptimize);
static void optimize();
static void output(const char* sBinOut, const char* sTblOut, int bLabTbl);
/*---------------------------------------------------------------------------*/
int main(int argc, char* argv[]) {
	int exitCode;
	SEH_init();
	exitCode = subr(argc, argv);
	return exitCode;
}
/*---------------------------------------------------------------------------*/
static int subr(int argc, char* argv[]) {
	int opt, bOptimize = 1;		//'-d'オプションが指定されなければ最適化を行う。
	const char* sBinOut = NULL;	//'-o'オプションが指定されたらバイナリ出力ファイル名を設定する。
	const char* sTblOut = NULL;	//'-t'オプションが指定されたら関数テーブルファイル名を設定する。
	int bLabTbl = 0;		//0=ラベルテーブルを格納しない。1=ラベルテーブルを格納する。
#if     (YYDEBUG!=0)
//	yydebug = 1; //nonzero means print parse trace
#endif/*(YYDEBUG!=0)*/
	//コマンドラインオプションを処理する。
	opterr = 0; //オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。
	while((opt = getopt(argc, argv, "do:t:len::w::x:qh")) != -1) {
		switch(opt) {
		case 'd':
			bOptimize = 0;		//最適化を行わない。
			break;
		case 'o':
			sBinOut = optarg;	//バイナリ出力ファイル名を設定する。
			break;
		case 't':
			sTblOut = optarg;	//関数テーブルファイル名を設定する。
			break;
		case 'l':
			bLabTbl = 1;		//ラベルテーブルを格納する。
			break;
		case 'e':
			{
				//エラーログファイル名を作成する。
				// - カレントフォルダに'実行ファイル名.err'という名前で生成する事にした。この動作は、'lk33.exe'の仕様を参考にした。
				char fname[_MAX_FNAME];
				_splitpath(argv[0], NULL, NULL, fname, NULL);
				_makepath(err_path, NULL, NULL, fname, ".err");
				//'-e'オプションが指定されたら、最初に確実に、既存のエラーログファイルを削除しておく。
				//前回に生成したエラーログが残っていて、今回生成したエラーログと混同する危険を避けるためである。
				//尚、'-e'オプションが指定されなかった場合は、既存のエラーログファイルを削除する処理は行わない。
				remove(err_path);
			}
			break;
		case 'n':
			if(optarg) {
				     if(!strcmp(optarg, "l")) { fnLabCmp = strnatcmp; }	//ラベル名のソートにstrnatcmp()を使用する。
				else if(!strcmp(optarg, "t")) { fnTrgCmp = strnatcmp; }	//トリガ名のソートにstrnatcmp()を使用する。
				else if(!strcmp(optarg, "f")) { fnFncCmp = strnatcmp; }	//関数名のソートにstrnatcmp()を使用する。
				else { usage(); }
			} else {
				fnLabCmp = fnTrgCmp = fnFncCmp = strnatcmp;	//ラベル名とトリガ名と関数名のソートにstrnatcmp()を使用する。
			}
			break;
		case 'w':
			if(optarg) {
				char *optionp = optarg, *valuep;
				while(*optionp) {
					switch(getsubopt(&optionp, (char* const*)warn_tokens, &valuep)) {
					case WARN_CAST:
						if(valuep) { usage(); }
						warn |= (1<<WARN_CAST);
						break;
					default:
						usage();
					}
				}
			} else {
				warn = -1;
			}
			break;
		case 'x':
			opt_x = optarg;		//言語選択を設定する。
			if(strcmp(opt_x, "c") && strcmp(opt_x, "cs")) { usage(); }
			break;
		case 'q':
			opt_q = 1;
			break;
		case 'h':
		default:
			usage();
		}
	}
	//辞書を作成する。
	tree_pSnrTbl		= g_tree_new(fnLabCmp);
	tree_pSnrSeq		= g_tree_new(fnLabCmp);
	tree_pSnrSeq_Used	= g_tree_new(fnLabCmp);
	tree_pArg		= g_tree_new(Arg_Compar);
	tree_pArgList		= g_tree_new(ArgList_Compar);
	tree_pArgs		= g_tree_new(Args_Compar);
	tree_pArgs_Used		= g_tree_new(Args_Compar);
	tree_pArgs_Blob		= g_tree_new(Args_Compar);
	tree_pArgs_Code		= g_tree_new(Args_Compar);
	tree_pFunc		= g_tree_new(Func_Compar);
	tree_pCond		= g_tree_new(Cond_Compar);
	tree_pCondSubs		= g_tree_new(CondSubs_Compar);
	tree_pCondSubsList	= g_tree_new(CondSubsList_Compar);
	tree_pValueSubs		= g_tree_new(ValueSubs_Compar);
	tree_pValueSubsList	= g_tree_new(ValueSubsList_Compar);
	tree_pSnrTblBody	= g_tree_new(SnrTblBody_Compar);
	tree_pSnrTblBody_Code	= g_tree_new(SnrTblBody_Compar);
	tree_pSnrTblStmt	= g_tree_new(SnrTblStmt_Compar);
	tree_pSnrSeqBody	= g_tree_new(SnrSeqBody_Compar);
	tree_pSnrSeqBody_Used	= g_tree_new(SnrSeqBody_Compar);
	tree_pSnrSeqBody_Code	= g_tree_new(SnrSeqBody_Compar);
	tree_pSnrSeqStmt	= g_tree_new(SnrSeqStmt_Compar);
	tree_pTrigName_No	= g_tree_new(TrigName_Compar);
	tree_pFuncName_No	= g_tree_new(fnFncCmp);
	//--- 1パス目の処理 ---
	//ファイルが指定されていなければ、標準入力から読み込む。
	if(optind == argc) {
		init_location("-");	//{{2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。}}
		yylex_init(stdin);
	    //{{2015/02/23修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
	    //	if((yyparse() != 0) || (yynerrs != 0)) { die("エラーが発生しました。\n"); }
	    //↓2015/02/23修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
		if((yyparse() != 0) /*|| (yynerrs != 0)*/) { error(EXIT_FAILURE, 0, "エラーが発生しました。"); }	//{{2016/09/21変更:die(～)で終了していた箇所を、error(EXIT_FAILURE,～)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
	    //}}2015/02/23修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
	//ファイルが指定されていたら、各ファイルを読み込む。
	} else {
		int i;
		for(i = optind; i < argc; i++) {
			FILE* fp = fopen(argv[i], "r");
			if(!fp) { error(EXIT_FAILURE, errno, "%s が開けません。", argv[i]); }	//{{2016/09/21変更:die(～)で終了していた箇所を、error(EXIT_FAILURE,～)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
			init_location(argv[i]);	//{{2016/09/24追加:エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。}}
			yylex_init(fp);
		    //{{2015/02/23修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
		    //	if((yyparse() != 0) || (yynerrs != 0)) { die("%s: エラーが発生しました。\n", argv[i]); }
		    //↓2015/02/23修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
//{{2017/03/16変更:複数の入力ファイルを指定した時に、最後以外のファイルでエラーが発生した場合、当ツールの終了ステータスが0になっていたバグを修正しました。
//			if((yyparse() != 0) /*|| (yynerrs != 0)*/) { error(EXIT_FAILURE, 0, "%s: エラーが発生しました。", argv[i]); }	//{{2016/09/21変更:die(～)で終了していた箇所を、error(EXIT_FAILURE,～)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
//↓2017/03/16変更:複数の入力ファイルを指定した時に、最後以外のファイルでエラーが発生した場合、当ツールの終了ステータスが0になっていたバグを修正しました。
			{
				int save_yynerrs = yynerrs;	//yyparse()がyynerrsをクリアするので、その前に現在のyynerrsを保存しておく。
				if((yyparse() != 0) /*|| (yynerrs != 0)*/) { error(EXIT_FAILURE, 0, "%s: エラーが発生しました。", argv[i]); }	//{{2016/09/21変更:die(～)で終了していた箇所を、error(EXIT_FAILURE,～)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
				yynerrs += save_yynerrs;	//今回のyyparse()が0から数えたであろうyynerrsに対して、先ほど保存しておいたyynerrsを足し込む。
			}
//}}2017/03/16変更:複数の入力ファイルを指定した時に、最後以外のファイルでエラーが発生した場合、当ツールの終了ステータスが0になっていたバグを修正しました。
		    //}}2015/02/23修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
			fclose(fp);
		}
	}
    //{{進捗表示用
	if(!opt_q) {
		newMsgLen = fprintf(stderr, "\rpass1 ok");
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr); oldMsgLen = 0;
	}
    //}}進捗表示用
	//1パス目の処理でエラーが発生しても、2パス目の処理を行って、全てのセマンティクスエラーを報告する。
	//--- 2パス目の処理 ---
	//2パス目の処理を行う。
	pass2(bOptimize);
    //{{進捗表示用
	if(!opt_q) {
		newMsgLen = fprintf(stderr, "\rpass2 ok");
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } putc('\n', stderr); oldMsgLen = 0;
	}
    //}}進捗表示用
	if(yynerrs != 0) { error(EXIT_FAILURE, 0, "エラーが発生しました。"); }	//1パス目,又は,2パス目の処理でエラーが発生していたら、出力処理を行わない。	//{{2016/09/21変更:die(～)で終了していた箇所を、error(EXIT_FAILURE,～)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
	//--- 出力処理 ---
	//出力処理を行う。
	output(sBinOut, sTblOut, bLabTbl);
	if(yynerrs != 0) { error(EXIT_FAILURE, 0, "エラーが発生しました。"); }	//{{2016/09/21変更:die(～)で終了していた箇所を、error(EXIT_FAILURE,～)で終了するように変更しました。}}	//{{2016/09/28変更:error()の文字列の最後に余計な改行が付いていたのを削除しました。}}
	return EXIT_SUCCESS;
}
/*---------------------------------------------------------------------------*/
//使い方を表示して終了する。
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dSnrSeqC - シナリオシーケンサコンパイラ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2017-2018 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "  dSnrSeqC [option ...] [filename ...] \n");
	fprintf(stderr, "  ・filenameを指定しなければ、標準入力から読み込みます。\n");
	fprintf(stderr, "  ・filenameは、ワイルドカードによる複数指定も可能です。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "OPTIONS:\n");
	fprintf(stderr, "  -d             最適化を行いません。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、最適化を行います。\n");
	fprintf(stderr, "  -oファイル名   シナリオ制御のバイナリデータを、バイナリ形式でファイルへ出力します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、Cソース形式で標準出力へ出力します。\n");
	fprintf(stderr, "                 このオプションの指定に関らず、ラベルは常に標準出力へ出力します。\n");
	fprintf(stderr, "  -tファイル名   関数テーブルのC言語ソースを、ファイルへ出力します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、関数番号を標準出力へ出力します。\n");
	fprintf(stderr, "  -l             シナリオ制御データに、ラベルテーブルを格納します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、ラベルテーブルを格納しません。\n");
	fprintf(stderr, "  -e             エラーログファイルを生成します。\n");
	fprintf(stderr, "                 このオプションを指定しても、エラーが発生しなければ生成されません。\n");
	fprintf(stderr, "  -n             ラベル名とトリガ名と関数名のソートに、strnatcmp()を使用します。\n");
	fprintf(stderr, "  -nl            ラベル名のソートに、strnatcmp()を使用します。\n");
	fprintf(stderr, "  -nt            トリガ名のソートに、strnatcmp()を使用します。\n");
	fprintf(stderr, "  -nf            関数名のソートに、strnatcmp()を使用します。\n");
	fprintf(stderr, "                 これらのオプションを指定しなければ、strcmp()を使用します。\n");
	fprintf(stderr, "  -w             全ての警告を有効にします。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、個別に設定した警告のみが有効になります。\n");
	fprintf(stderr, "  -wcast         暗黙の型変換で誤差が生じたら、警告を表示し最終的にエラー終了します。\n");
	fprintf(stderr, "                 このオプションを指定しなければ、警告表示もエラー終了もしません。\n");
	fprintf(stderr, "  -xc            出力ソースをC言語形式とします。(既定値)\n");
	fprintf(stderr, "  -xcs           出力ソースをC#形式とします。\n");
	fprintf(stderr, "  -q             進捗表示を抑制します。\n");
	fprintf(stderr, "  -h             使い方を表示します。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "EXAMPLE:\n");
	fprintf(stderr, "  ①dSnrSeqC.exe SnrSeq.txt > SnrSeq.c\n");
	fprintf(stderr, "  　SnrSeq.txtをコンパイルして、SnrSeq.cへ出力します。\n");
	fprintf(stderr, "  ②dSnrSeqC.exe -oSnrSeq.bin SnrSeq.txt > SnrSeq.h\n");
	fprintf(stderr, "  　SnrSeq.txtをコンパイルして、ラベルをSnrSeq.hへ出力します。\n");
	fprintf(stderr, "  　シナリオ制御のバイナリデータを、SnrSeq.binへ出力します。\n");
	exit(EXIT_FAILURE);
}
/*---------------------------------------------------------------------------*/
//1パス目の処理
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int cast_dbl_to_int(double d) {
	int i = d;
	if(i != d) {
		if(warn & (1<<WARN_CAST)) {
			yyerror("切り捨て誤差が発生しました: %f → %d", d, i);
			yynerrs++;	//呼び出し元(main)に知らせるために。
			//全てのセマンティクスエラーを報告するために継続する。
		}
	}
	return i;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void addSnrTbl(ST_SnrTbl* pSnrTbl) {
	char* pSnrTblLabel = pSnrTbl->pSnrTblLabel;
    //{{進捗表示用
	if(!opt_q) {
		newMsgLen = fprintf(stderr, "\rpass1 %s", pSnrTblLabel);
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } oldMsgLen = newMsgLen;
	}
    //}}進捗表示用
	//このシナリオテーブルを登録する。
	if(g_tree_lookup(tree_pSnrTbl, pSnrTblLabel)) {
		yyerror("シナリオテーブルラベルが重複しています。(%s)", pSnrTblLabel);
		yynerrs++;	//呼び出し元(main)に知らせるために。
		return;		//全てのセマンティクスエラーを報告するために継続する。
	}
	g_tree_insert(tree_pSnrTbl, pSnrTblLabel, pSnrTbl);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
void addSnrSeq(ST_SnrSeq* pSnrSeq) {
	char* pSnrSeqLabel = pSnrSeq->pSnrSeqLabel;
    //{{進捗表示用
	if(!opt_q) {
		newMsgLen = fprintf(stderr, "\rpass1 %s", pSnrSeqLabel);
		if(oldMsgLen > newMsgLen) { fprintf(stderr, "%*s", oldMsgLen - newMsgLen, ""); } oldMsgLen = newMsgLen;
	}
    //}}進捗表示用
	//このシナリオシーケンスを登録する。
	if(g_tree_lookup(tree_pSnrSeq, pSnrSeqLabel)) {
		yyerror("シナリオシーケンスラベルが重複しています。(%s)", pSnrSeqLabel);
		yynerrs++;	//呼び出し元(main)に知らせるために。
		return;		//全てのセマンティクスエラーを報告するために継続する。
	}
	g_tree_insert(tree_pSnrSeq, pSnrSeqLabel, pSnrSeq);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
char* LabDef_New(char* pLabel) {
    //{{ローカルラベルの処理
	if(pLabel[0] == '@') {
		if(pLabel[1] == '@') {	//'@@'
			pLabel = strdup_printf("@%d", nAtmarkLocalLabel++);	//内部ローカルラベルに変換する。その後、+1する。
		} else {		//'@B','@F'
			yyerror("ラベル定義が不正です。(%s)", pLabel);
			return NULL;	//y.tab.yの処理でYYERRORを行う。
		}
	} else if(pLabel[0] == '.') {
		pLabel = strconcat(sDotLocalLabelPrefix, pLabel, NULL);		//内部ローカルラベルに変換する。
	} else {
		sDotLocalLabelPrefix = pLabel;					//グローバルラベルの定義が出現したら、sDotLocalLabelPrefixを更新する。
	}
    //}}ローカルラベルの処理
	return pLabel;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
char* LabRef_New(char* pLabel) {
    //{{ローカルラベルの処理
	if(pLabel[0] == '@') {
		if(pLabel[1] == 'B') {		//'@B'
			pLabel = strdup_printf("@%d", nAtmarkLocalLabel - 1);	//'@B'からは、(nAtmarkLocalLabel-1)で参照できる。もし'@@'が出現する前に'@B'を参照した場合は-1になってしまうが、2パス目に未定義ラベルとしてエラー検出できるはずであり、安全です。
		} else if(pLabel[1] == 'F') {	//'@F'
			pLabel = strdup_printf("@%d", nAtmarkLocalLabel);	//'@F'からは、nAtmarkLocalLabelで参照できる。もしこの後に'@@'が出現しなければ存在しない内部ローカルラベルを参照してしまうが、2パス目に未定義ラベルとしてエラー検出できるはずであり、安全です
		} else {			//'@@'
			yyerror("ラベル参照が不正です。(%s)", pLabel);
			return NULL;	//y.tab.yの処理でYYERRORを行う。
		}
	} else if(pLabel[0] == '.') {
		pLabel = strconcat(sDotLocalLabelPrefix, pLabel, NULL);		//内部ローカルラベルに変換する。
	}
    //}}ローカルラベルの処理
	return pLabel;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int TrigName_Compar(const void* _a, const void* _b) {
	char* a = (char*)_a;
	char* b = (char*)_b;
	if((!strcmp(a, "set")) && ( strcmp(b, "set"))) { return -1; }	//((a=="set")&&(b!="set"))⇒(a<b)
	if(( strcmp(a, "set")) && (!strcmp(b, "set"))) { return  1; }	//((a!="set")&&(b=="set"))⇒(a>b)
	if((!strcmp(a, "clr")) && ( strcmp(b, "clr"))) { return  1; }	//((a=="clr")&&(b!="clr"))⇒(a>b)
	if(( strcmp(a, "clr")) && (!strcmp(b, "clr"))) { return -1; }	//((a!="clr")&&(b=="clr"))⇒(a<b)
	return (*fnTrgCmp)(a, b);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewBit(int n) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	if((unsigned)n > 1) {
		yyerror("bit値が範囲外です。(%d)", n);
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pArg->iArgType		= ArgType_Bit;
	pArg->value.v_bit	= n;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewByte(int n) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	if((unsigned)n > UINT8_MAX) {
		yyerror("byte値が範囲外です。(%d)", n);
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pArg->iArgType		= ArgType_Byte;
	pArg->value.v_byte	= n;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewHalf(int n) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	if((unsigned)n > UINT16_MAX) {
		yyerror("half値が範囲外です。(%d)", n);
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pArg->iArgType		= ArgType_Half;
	pArg->value.v_half	= n;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewExp10(int n) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	if(Exp10_Encode(n) == -1) {
		yyerror("exp10値が範囲外です。(%d)", n);
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pArg->iArgType		= ArgType_Exp10;
	pArg->value.v_exp10	= n;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewWord(int n) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Word;
	pArg->value.v_word	= n;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
//{{2018/04/07追加:引数リストにBER圧縮整数も含められるようにしました。
ST_Arg* Arg_NewBer(int n) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Ber;
	pArg->value.v_ber	= n;
	return pArg;
}
//}}2018/04/07追加:引数リストにBER圧縮整数も含められるようにしました。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewFp16(double d) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Fp16;
	pArg->value.v_fp16	= d;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewFp32(double d) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Fp32;
	pArg->value.v_fp32	= d;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewFp64(double d) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Fp64;
	pArg->value.v_fp64	= d;
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewString(char* s) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_String;
	pArg->value.v_string	= (char*)intern_string(s);			//ポインタで比較出来るように、単一化して格納する。
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewFile(char* s) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_File;
	pArg->value.v_file	= (char*)intern_string(s);			//ポインタで比較出来るように、単一化して格納する。
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewTable(char* s) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Table;
	pArg->value.v_table	= (char*)intern_string(s);			//ポインタで比較出来るように、単一化して格納する。
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewTrig(char* s) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Trig;
	pArg->value.v_trig	= (char*)intern_string(s);			//ポインタで比較出来るように、単一化して格納する。
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_NewFunc(char* s) {
	ST_Arg* pArg = calloc(1, sizeof(ST_Arg));
	if(!pArg) { DIE(); }
	pArg->iArgType		= ArgType_Func;
	pArg->value.v_func	= (char*)intern_string(s);			//ポインタで比較出来るように、単一化して格納する。
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Arg* Arg_Intern(ST_Arg* pArg) {
	ST_Arg* pOldArg = g_tree_lookup(tree_pArg, pArg);
	if(pOldArg) { return pOldArg; }
	g_tree_insert(tree_pArg, pArg, pArg);
	return pArg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int Arg_Compar(const void* _a, const void* _b) {
	ST_Arg* a = (ST_Arg*)_a;
	ST_Arg* b = (ST_Arg*)_b;
	return memcmp(a, b, sizeof(ST_Arg));
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
GSList* ArgList_AddArg(GSList* pArgList, ST_Arg* pArg) {
	return g_slist_append(pArgList, Arg_Intern(pArg));			//ポインタで比較出来るように、単一化して追加する。
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
GSList* ArgList_Intern(GSList* pArgList) {
	GSList* pOldArgList = g_tree_lookup(tree_pArgList, pArgList);
	if(pOldArgList) { return pOldArgList; }
	g_tree_insert(tree_pArgList, pArgList, pArgList);
	return pArgList;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int ArgList_Compar(const void* _a, const void* _b) {
	GSList* a = (GSList*)_a;
	GSList* b = (GSList*)_b;
	return g_slist_compare_np(a, b);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Args* Args_New(GSList* pArgList/*NULL可*/) {
	ST_Args* pArgs = calloc(1, sizeof(ST_Args));
	if(!pArgs) { DIE(); }
    if(pArgList/*NULL可*/) {
	pArgs->pArgList		= ArgList_Intern(pArgList);			//ポインタで比較出来るように、単一化して格納する。
    }
	return pArgs;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Args* Args_Intern(ST_Args* pArgs) {
	ST_Args* pOldArgs = g_tree_lookup(tree_pArgs, pArgs);
	if(pOldArgs) { return pOldArgs; }
	g_tree_insert(tree_pArgs, pArgs, pArgs);
	return pArgs;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int Args_Compar(const void* _a, const void* _b) {
	ST_Args* a = (ST_Args*)_a;
	ST_Args* b = (ST_Args*)_b;
	return memcmp(a, b, sizeof(ST_Args));
}
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ST_Func* Func_New(char* pFuncName, ST_Args* pArgs) {
	ST_Func* pFunc = calloc(1, sizeof(ST_Func));
	if(!pFunc) { DIE(); }
	pFunc->pFuncName	= (char*)intern_string(pFuncName);		//ポインタで比較出来るように、単一化して格納する。
	pFunc->pArgs		= Args_Intern(pArgs);				//ポインタで比較出来るように、単一化して格納する。
	g_tree_insert(tree_pFuncName_No, pFuncName, NULL/*ダミー*/);		//1パス目で登録します。シナリオテーブルから再帰的に辿れないシナリオシーケンスに含まれている関数名も出力対象とするためです。
	return pFunc;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Func* Func_Intern(ST_Func* pFunc) {
	ST_Func* pOldFunc = g_tree_lookup(tree_pFunc, pFunc);
	if(pOldFunc) { return pOldFunc; }
	g_tree_insert(tree_pFunc, pFunc, pFunc);
	return pFunc;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int Func_Compar(const void* _a, const void* _b) {
	ST_Func* a = (ST_Func*)_a;
	ST_Func* b = (ST_Func*)_b;
	return memcmp(a, b, sizeof(ST_Func));
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Cond* Cond_New(int bNot, ST_Func* pFunc) {
	ST_Cond* pCond = calloc(1, sizeof(ST_Cond));
	if(!pCond) { DIE(); }
	pCond->bNot		= bNot;
	pCond->pFunc		= Func_Intern(pFunc);				//ポインタで比較出来るように、単一化して格納する。
	return pCond;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Cond* Cond_Intern(ST_Cond* pCond) {
	ST_Cond* pOldCond = g_tree_lookup(tree_pCond, pCond);
	if(pOldCond) { return pOldCond; }
	g_tree_insert(tree_pCond, pCond, pCond);
	return pCond;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int Cond_Compar(const void* _a, const void* _b) {
	ST_Cond* a = (ST_Cond*)_a;
	ST_Cond* b = (ST_Cond*)_b;
	return memcmp(a, b, sizeof(ST_Cond));
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_CondSubs* IfSubs_New(ST_Cond* pCond, ST_SnrSeqBody* pSnrSeqBody) {
	ST_CondSubs* pCondSubs = calloc(1, sizeof(ST_CondSubs));
	if(!pCondSubs) { DIE(); }
	pCondSubs->pCond	= pCond;
	pCondSubs->pSnrSeqBody	= SnrSeqBody_Intern(pSnrSeqBody);		//ポインタで比較出来るように、単一化して格納する。
	return pCondSubs;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_CondSubs* UnlessSubs_New(ST_Cond* pCond, ST_SnrSeqBody* pSnrSeqBody) {
	pCond = Cond_New(!pCond->bNot, pCond->pFunc);
	return IfSubs_New(pCond, pSnrSeqBody);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_CondSubs* ElifSubs_New(ST_Cond* pCond, ST_SnrSeqBody* pSnrSeqBody) {
	return IfSubs_New(pCond, pSnrSeqBody);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_CondSubs* CondSubs_Intern(ST_CondSubs* pCondSubs) {
	ST_CondSubs* pOldCondSubs = g_tree_lookup(tree_pCondSubs, pCondSubs);
	if(pOldCondSubs) { return pOldCondSubs; }
	g_tree_insert(tree_pCondSubs, pCondSubs, pCondSubs);
	return pCondSubs;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int CondSubs_Compar(const void* _a, const void* _b) {
	ST_CondSubs* a = (ST_CondSubs*)_a;
	ST_CondSubs* b = (ST_CondSubs*)_b;
	return memcmp(a, b, sizeof(ST_CondSubs));
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
GSList* CondSubsList_AddCondSubs(GSList* pCondSubsList, ST_CondSubs* pCondSubs) {
	return g_slist_append(pCondSubsList, CondSubs_Intern(pCondSubs));	//ポインタで比較出来るように、単一化して追加する。
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
GSList* CondSubsList_Intern(GSList* pCondSubsList) {
	GSList* pOldCondSubsList = g_tree_lookup(tree_pCondSubsList, pCondSubsList);
	if(pOldCondSubsList) { return pOldCondSubsList; }
	g_tree_insert(tree_pCondSubsList, pCondSubsList, pCondSubsList);
	return pCondSubsList;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int CondSubsList_Compar(const void* _a, const void* _b) {
	GSList* a = (GSList*)_a;
	GSList* b = (GSList*)_b;
	return g_slist_compare_np(a, b);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_ValueSubs* OfSubs_New(int iValue, ST_SnrSeqBody* pSnrSeqBody) {
	ST_ValueSubs* pValueSubs = calloc(1, sizeof(ST_ValueSubs));
	if(!pValueSubs) { DIE(); }
	if((unsigned)iValue > UINT8_MAX) {
		yyerror("値が範囲外です。(%d)", iValue);
		yynerrs++;	//呼び出し元(main)に知らせるために。
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pValueSubs->iValue	= iValue;
	pValueSubs->pSnrSeqBody	= SnrSeqBody_Intern(pSnrSeqBody);		//ポインタで比較出来るように、単一化して格納する。
	return pValueSubs;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_ValueSubs* ValueSubs_Intern(ST_ValueSubs* pValueSubs) {
	ST_ValueSubs* pOldValueSubs = g_tree_lookup(tree_pValueSubs, pValueSubs);
	if(pOldValueSubs) { return pOldValueSubs; }
	g_tree_insert(tree_pValueSubs, pValueSubs, pValueSubs);
	return pValueSubs;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int ValueSubs_Compar(const void* _a, const void* _b) {
	ST_ValueSubs* a = (ST_ValueSubs*)_a;
	ST_ValueSubs* b = (ST_ValueSubs*)_b;
	return memcmp(a, b, sizeof(ST_ValueSubs));
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static int ValueSubsList_AddValueSubs_compar(const void* _a, const void* _b) {
	ST_ValueSubs* a = (ST_ValueSubs*)_a;
	ST_ValueSubs* b = (ST_ValueSubs*)_b;
	if(a->iValue < b->iValue) { return -1; }
	if(a->iValue > b->iValue) { return  1; }
	return 0;
}
GSList* ValueSubsList_AddValueSubs(GSList* pValueSubsList, ST_ValueSubs* pValueSubs) {
	if(g_slist_find_custom(pValueSubsList, pValueSubs, ValueSubsList_AddValueSubs_compar)) {	//pValueSubsListはiValueに対して重複無く、g_slist_insert_sorted()を使って追加する。
		yyerror("値が重複しています。(%d)", pValueSubs->iValue);
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	return g_slist_insert_sorted(pValueSubsList, ValueSubs_Intern(pValueSubs), ValueSubsList_AddValueSubs_compar);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
GSList* ValueSubsList_Intern(GSList* pValueSubsList) {
	GSList* pOldValueSubsList = g_tree_lookup(tree_pValueSubsList, pValueSubsList);
	if(pOldValueSubsList) { return pOldValueSubsList; }
	g_tree_insert(tree_pValueSubsList, pValueSubsList, pValueSubsList);
	return pValueSubsList;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int ValueSubsList_Compar(const void* _a, const void* _b) {
	GSList* a = (GSList*)_a;
	GSList* b = (GSList*)_b;
	return g_slist_compare_np(a, b);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTbl* SnrTbl_New(char* pSnrTblLabel, ST_SnrTblBody* pSnrTblBody) {
	ST_SnrTbl* pSnrTbl = calloc(1, sizeof(ST_SnrTbl));
	if(!pSnrTbl) { DIE(); }
	pSnrTbl->pSnrTblLabel	= (char*)intern_string(pSnrTblLabel);		//必須ではないが、単一化して格納する。
	pSnrTbl->pSnrTblBody	= SnrTblBody_Intern(pSnrTblBody);		//最適化のために、単一化して格納する。
	return pSnrTbl;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblBody* SnrTblBody_New() {
	ST_SnrTblBody* pSnrTblBody = calloc(1, sizeof(ST_SnrTblBody));
	if(!pSnrTblBody) { DIE(); }
	return pSnrTblBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static char* SnrTblStmt_GetTrigName(ST_SnrTblStmt* pSnrTblStmt) {
	char* pTrigName;
	switch(pSnrTblStmt->iSnrTblStmtType) {
	default:DIE();	//もしここで停止したら当ツールのバグです。
	case SnrTblStmtType_OnUnlock:
		{
			ST_OnUnlockStmt* pOnUnlockStmt = &pSnrTblStmt->onUnlockStmt;
			{
				pTrigName = pOnUnlockStmt->pTrigName;
			}
		}
		break;
	case SnrTblStmtType_OnGoto:
		{
			ST_OnGotoStmt* pOnGotoStmt = &pSnrTblStmt->onGotoStmt;
			{
				pTrigName = pOnGotoStmt->pTrigName;
			}
		}
		break;
	case SnrTblStmtType_OnExec:
		{
			ST_OnExecStmt* pOnExecStmt = &pSnrTblStmt->onExecStmt;
			{
				pTrigName = pOnExecStmt->pTrigName;
			}
		}
		break;
	}
	return pTrigName;
}
static int SnrTblBody_AddSnrTblStmt_compar(const void* _a, const void* _b) {
	ST_SnrTblStmt* a = (ST_SnrTblStmt*)_a;
	ST_SnrTblStmt* b = (ST_SnrTblStmt*)_b;
	char* pTrigNameA = SnrTblStmt_GetTrigName(a);
	char* pTrigNameB = SnrTblStmt_GetTrigName(b);
	return TrigName_Compar(pTrigNameA, pTrigNameB);
}
ST_SnrTblBody* SnrTblBody_AddSnrTblStmt(ST_SnrTblBody* pSnrTblBody, ST_SnrTblStmt* pSnrTblStmt) {
	pSnrTblStmt = SnrTblStmt_Intern(pSnrTblStmt);				//pSnrTblStmtListは単一化しないが、pSnrTblStmtListの要素のpSnrTblStmtを、ポインタで比較出来るように単一化して追加する。
	if(g_slist_find_custom(pSnrTblBody->pSnrTblStmtList, pSnrTblStmt, SnrTblBody_AddSnrTblStmt_compar)) {	//pSnrTblStmtListはpTrigNameに対して重複無く、g_slist_insert_sorted()を使って追加する。
		char* pTrigName = SnrTblStmt_GetTrigName(pSnrTblStmt);
		yyerror("トリガが重複しています。(%s)", pTrigName);
		return NULL;	//y.tab.yの処理でYYERRORを行う。
	}
	pSnrTblBody->pSnrTblStmtList = g_slist_insert_sorted(pSnrTblBody->pSnrTblStmtList, pSnrTblStmt, SnrTblBody_AddSnrTblStmt_compar);
	return pSnrTblBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblBody* SnrTblBody_Intern(ST_SnrTblBody* pSnrTblBody) {
	ST_SnrTblBody* pOldSnrTblBody = g_tree_lookup(tree_pSnrTblBody, pSnrTblBody);
	if(pOldSnrTblBody) { return pOldSnrTblBody; }
	g_tree_insert(tree_pSnrTblBody, pSnrTblBody, pSnrTblBody);
	return pSnrTblBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int SnrTblBody_Compar(const void* _a, const void* _b) {
	ST_SnrTblBody* a = (ST_SnrTblBody*)_a;
	ST_SnrTblBody* b = (ST_SnrTblBody*)_b;
	return g_slist_compare_np(a->pSnrTblStmtList, b->pSnrTblStmtList);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblStmt* OnUnlockStmt_New(char* pTrigName) {
	ST_OnUnlockStmt* pOnUnlockStmt = calloc(1, sizeof(ST_SnrTblStmt));		//SnrTblStmt_Compar()にて(ST_SnrTblStmt*)として比較するので、sizeof(ST_OnUnlockStmt)ではなくsizeof(ST_SnrTblStmt)のサイズで確保する必要が有る。
	if(!pOnUnlockStmt) { DIE(); }
	pOnUnlockStmt->iSnrTblStmtType	= SnrTblStmtType_OnUnlock;
	pOnUnlockStmt->pTrigName	= (char*)intern_string(pTrigName);		//ポインタで比較出来るように、単一化して格納する。
	g_tree_insert(tree_pTrigName_No, pTrigName, NULL/*ダミー*/);			//1パス目で登録します。シナリオテーブルから再帰的に辿れないシナリオテーブルに含まれているトリガ名も出力対象とするためです。
	return (ST_SnrTblStmt*)pOnUnlockStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblStmt* OnGotoStmt_New(char* pTrigName, int bUnlock, char* pSnrSeqLabel, int nLock) {
	ST_OnGotoStmt* pOnGotoStmt = calloc(1, sizeof(ST_SnrTblStmt));			//SnrTblStmt_Compar()にて(ST_SnrTblStmt*)として比較するので、sizeof(ST_OnGotoStmt)ではなくsizeof(ST_SnrTblStmt)のサイズで確保する必要が有る。
	if(!pOnGotoStmt) { DIE(); }
	pOnGotoStmt->iSnrTblStmtType	= SnrTblStmtType_OnGoto;
	pOnGotoStmt->pTrigName		= (char*)intern_string(pTrigName);		//ポインタで比較出来るように、単一化して格納する。
	pOnGotoStmt->bUnlock		= bUnlock;
	pOnGotoStmt->pSnrSeqLabel	= (char*)intern_string(pSnrSeqLabel);		//ポインタで比較出来るように、単一化して格納する。
	pOnGotoStmt->nLock		= nLock;
	g_tree_insert(tree_pTrigName_No, pTrigName, NULL/*ダミー*/);			//1パス目で登録します。シナリオテーブルから再帰的に辿れないシナリオテーブルに含まれているトリガ名も出力対象とするためです。
	return (ST_SnrTblStmt*)pOnGotoStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblStmt* OnGotoStmt_NewInline(char* pTrigName, int bUnlock, int nLock, ST_SnrSeqBody* pSnrSeqBody) {
	ST_OnGotoStmt* pOnGotoStmt = calloc(1, sizeof(ST_SnrTblStmt));			//SnrTblStmt_Compar()にて(ST_SnrTblStmt*)として比較するので、sizeof(ST_OnGotoStmt)ではなくsizeof(ST_SnrTblStmt)のサイズで確保する必要が有る。
	if(!pOnGotoStmt) { DIE(); }
	{
		char *pLabDef, *pLabRef;
		ST_SnrSeq* pSnrSeq;
		{
			char* pSnrSeqLabel = strconcat(".", pTrigName, NULL);		//当処理にて内部的に生成するシナリオシーケンスラベルは、".トリガ名"というローカルラベルにする事にした。この名付け方は必須ではない。スクリプト内で明示的に定義されるローカルラベルと、衝突する危険性の低い名前ならば何でも良い。".トリガ名"よりももっと衝突する危険性の低い名前にする事も出来たが、これまで慣例的に".トリガ名"というローカルラベルを使って来たので、判り易さのために、当処理にて内部的に生成するシナリオシーケンスラベルもそれに合わせる事にした。
			if(!(pLabDef = LabDef_New(pSnrSeqLabel))) { return NULL; }	//y.tab.yの処理でYYERRORを行う。	//忘れないで!!SnrSeq_New()に直接pSnrSeqLabelを渡さないよう注意!!
			if(!(pLabRef = LabRef_New(pSnrSeqLabel))) { return NULL; }	//y.tab.yの処理でYYERRORを行う。	//忘れないで!!OnGotoStmt_New()に直接pSnrSeqLabelを渡さないよう注意!!
		}
		if(!(pSnrSeq = SnrSeq_New(pLabDef, pSnrSeqBody))) { return NULL; }	//y.tab.yの処理でYYERRORを行う。
		addSnrSeq(pSnrSeq);
		return OnGotoStmt_New(pTrigName, bUnlock, pLabRef, nLock);
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblStmt* OnExecStmt_New(char* pTrigName, int bUnlock, char* pSnrSeqLabel, int nLock) {
	ST_OnExecStmt* pOnExecStmt = calloc(1, sizeof(ST_SnrTblStmt));			//SnrTblStmt_Compar()にて(ST_SnrTblStmt*)として比較するので、sizeof(ST_OnExecStmt)ではなくsizeof(ST_SnrTblStmt)のサイズで確保する必要が有る。
	if(!pOnExecStmt) { DIE(); }
	pOnExecStmt->iSnrTblStmtType	= SnrTblStmtType_OnExec;
	pOnExecStmt->pTrigName		= (char*)intern_string(pTrigName);		//ポインタで比較出来るように、単一化して格納する。
	pOnExecStmt->bUnlock		= bUnlock;
	pOnExecStmt->pSnrSeqLabel	= (char*)intern_string(pSnrSeqLabel);		//ポインタで比較出来るように、単一化して格納する。
	pOnExecStmt->nLock		= nLock;
	g_tree_insert(tree_pTrigName_No, pTrigName, NULL/*ダミー*/);			//1パス目で登録します。シナリオテーブルから再帰的に辿れないシナリオテーブルに含まれているトリガ名も出力対象とするためです。
	return (ST_SnrTblStmt*)pOnExecStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblStmt* OnExecStmt_NewInline(char* pTrigName, int bUnlock, int nLock, ST_SnrSeqBody* pSnrSeqBody) {
	ST_OnExecStmt* pOnExecStmt = calloc(1, sizeof(ST_SnrTblStmt));			//SnrTblStmt_Compar()にて(ST_SnrTblStmt*)として比較するので、sizeof(ST_OnExecStmt)ではなくsizeof(ST_SnrTblStmt)のサイズで確保する必要が有る。
	if(!pOnExecStmt) { DIE(); }
	{
		char *pLabDef, *pLabRef;
		ST_SnrSeq* pSnrSeq;
		{
			char* pSnrSeqLabel = strconcat(".", pTrigName, NULL);		//当処理にて内部的に生成するシナリオシーケンスラベルは、".トリガ名"というローカルラベルにする事にした。この名付け方は必須ではない。スクリプト内で明示的に定義されるローカルラベルと、衝突する危険性の低い名前ならば何でも良い。".トリガ名"よりももっと衝突する危険性の低い名前にする事も出来たが、これまで慣例的に".トリガ名"というローカルラベルを使って来たので、判り易さのために、当処理にて内部的に生成するシナリオシーケンスラベルもそれに合わせる事にした。
			if(!(pLabDef = LabDef_New(pSnrSeqLabel))) { return NULL; }	//y.tab.yの処理でYYERRORを行う。	//忘れないで!!SnrSeq_New()に直接pSnrSeqLabelを渡さないよう注意!!
			if(!(pLabRef = LabRef_New(pSnrSeqLabel))) { return NULL; }	//y.tab.yの処理でYYERRORを行う。	//忘れないで!!OnExecStmt_New()に直接pSnrSeqLabelを渡さないよう注意!!
		}
		if(!(pSnrSeq = SnrSeq_New(pLabDef, pSnrSeqBody))) { return NULL; }	//y.tab.yの処理でYYERRORを行う。
		addSnrSeq(pSnrSeq);
		return OnExecStmt_New(pTrigName, bUnlock, pLabRef, nLock);
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int Lock_New(int nLock) {
	if((nLock < 1) || (nLock > UINT16_MAX)) {
		yyerror("ロック時間が範囲外です。(%d)", nLock);
		yynerrs++;	//呼び出し元(main)に知らせるために。
		return -1;	//y.tab.yの処理でYYERRORを行う。
	}
	return nLock;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrTblStmt* SnrTblStmt_Intern(ST_SnrTblStmt* pSnrTblStmt) {
	ST_SnrTblStmt* pOldSnrTblStmt = g_tree_lookup(tree_pSnrTblStmt, pSnrTblStmt);
	if(pOldSnrTblStmt) { return pOldSnrTblStmt; }
	g_tree_insert(tree_pSnrTblStmt, pSnrTblStmt, pSnrTblStmt);
	return pSnrTblStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int SnrTblStmt_Compar(const void* _a, const void* _b) {
	ST_SnrTblStmt* a = (ST_SnrTblStmt*)_a;
	ST_SnrTblStmt* b = (ST_SnrTblStmt*)_b;
	return memcmp(a, b, sizeof(ST_SnrTblStmt));
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeq* SnrSeq_New(char* pSnrSeqLabel, ST_SnrSeqBody* pSnrSeqBody) {
	ST_SnrSeq* pSnrSeq = calloc(1, sizeof(ST_SnrSeq));
	if(!pSnrSeq) { DIE(); }
	pSnrSeq->pSnrSeqLabel	= pSnrSeqLabel;					//必須ではないが、単一化して格納する。
	pSnrSeq->pSnrSeqBody	= SnrSeqBody_Intern(pSnrSeqBody);		//最適化のために、単一化して格納する。
	return pSnrSeq;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqBody* SnrSeqBody_New() {
	ST_SnrSeqBody* pSnrSeqBody = calloc(1, sizeof(ST_SnrSeqBody));
	if(!pSnrSeqBody) { DIE(); }
	return pSnrSeqBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqBody* SnrSeqBody_AddSnrSeqStmt(ST_SnrSeqBody* pSnrSeqBody, ST_SnrSeqStmt* pSnrSeqStmt) {
	pSnrSeqStmt = SnrSeqStmt_Intern(pSnrSeqStmt);				//pSnrSeqStmtListは単一化しないが、pSnrSeqStmtListの要素のpSnrSeqStmtを、ポインタで比較出来るように単一化して追加する。
	pSnrSeqBody->pSnrSeqStmtList = g_slist_append(pSnrSeqBody->pSnrSeqStmtList, pSnrSeqStmt);
	return pSnrSeqBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqBody* SnrSeqBody_Intern(ST_SnrSeqBody* pSnrSeqBody) {
	ST_SnrSeqBody* pOldSnrSeqBody = g_tree_lookup(tree_pSnrSeqBody, pSnrSeqBody);
	if(pOldSnrSeqBody) { return pOldSnrSeqBody; }
	g_tree_insert(tree_pSnrSeqBody, pSnrSeqBody, pSnrSeqBody);
	return pSnrSeqBody;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int SnrSeqBody_Compar(const void* _a, const void* _b) {
	ST_SnrSeqBody* a = (ST_SnrSeqBody*)_a;
	ST_SnrSeqBody* b = (ST_SnrSeqBody*)_b;
	return g_slist_compare_np(a->pSnrSeqStmtList, b->pSnrSeqStmtList);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* ExitStmt_New() {
	ST_ExitStmt* pExitStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_ExitStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pExitStmt) { DIE(); }
	pExitStmt->iSnrSeqStmtType	= SnrSeqStmtType_Exit;
	return (ST_SnrSeqStmt*)pExitStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* EscapeStmt_New() {
	ST_EscapeStmt* pEscapeStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_EscapeStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pEscapeStmt) { DIE(); }
	pEscapeStmt->iSnrSeqStmtType	= SnrSeqStmtType_Escape;
	return (ST_SnrSeqStmt*)pEscapeStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* WaitStmt_New(int nWaitCnt) {
	ST_WaitStmt* pWaitStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_WaitStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pWaitStmt) { DIE(); }
	pWaitStmt->iSnrSeqStmtType	= SnrSeqStmtType_Wait;
	pWaitStmt->nWaitCnt		= nWaitCnt;
	return (ST_SnrSeqStmt*)pWaitStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* WaitForStmt_New(ST_Cond* pCond) {
	ST_WaitForStmt* pWaitForStmt = calloc(1, sizeof(ST_SnrSeqStmt));	//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_WaitForStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pWaitForStmt) { DIE(); }
	pWaitForStmt->iSnrSeqStmtType	= SnrSeqStmtType_WaitFor;
	pWaitForStmt->pCond		= Cond_Intern(pCond);			//ポインタで比較出来るように、単一化して格納する。
	return (ST_SnrSeqStmt*)pWaitForStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int WaitCnt_New(int nWaitCnt) {
	if((nWaitCnt < 1) || (nWaitCnt > UINT16_MAX)) {
		yyerror("待ち時間が範囲外です。(%d)", nWaitCnt);
		yynerrs++;	//呼び出し元(main)に知らせるために。
		return -1;	//y.tab.yの処理でYYERRORを行う。
	}
	return nWaitCnt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* ForkStmt_New(ST_SnrSeqBody* pSnrSeqBody) {
	ST_ForkStmt* pForkStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_ForkStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pForkStmt) { DIE(); }
	pForkStmt->iSnrSeqStmtType	= SnrSeqStmtType_Fork;
	pForkStmt->pSnrSeqBody		= SnrSeqBody_Intern(pSnrSeqBody);	//ポインタで比較出来るように、単一化して格納する。
	return (ST_SnrSeqStmt*)pForkStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* HideStmt_New() {
	ST_HideStmt* pHideStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_HideStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pHideStmt) { DIE(); }
	pHideStmt->iSnrSeqStmtType	= SnrSeqStmtType_Hide;
	return (ST_SnrSeqStmt*)pHideStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* JoinStmt_New() {
	ST_JoinStmt* pJoinStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_JoinStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pJoinStmt) { DIE(); }
	pJoinStmt->iSnrSeqStmtType	= SnrSeqStmtType_Join;
	return (ST_SnrSeqStmt*)pJoinStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* GotoStmt_New(char* pSnrSeqLabel) {
	ST_GotoStmt* pGotoStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_GotoStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pGotoStmt) { DIE(); }
	pGotoStmt->iSnrSeqStmtType	= SnrSeqStmtType_Goto;
	pGotoStmt->pSnrSeqLabel		= (char*)intern_string(pSnrSeqLabel);	//ポインタで比較出来るように、単一化して格納する。
	return (ST_SnrSeqStmt*)pGotoStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* CallStmt_New(char* pSnrSeqLabel) {
	ST_CallStmt* pCallStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_CallStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pCallStmt) { DIE(); }
	pCallStmt->iSnrSeqStmtType	= SnrSeqStmtType_Call;
	pCallStmt->pSnrSeqLabel		= (char*)intern_string(pSnrSeqLabel);	//ポインタで比較出来るように、単一化して格納する。
	return (ST_SnrSeqStmt*)pCallStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* IfStmt_New(ST_CondSubs* pIfSubs, GSList* pElifSubsList/*NULL可*/, ST_SnrSeqBody* pElseSubs/*NULL可*/) {
	ST_IfStmt* pIfStmt = calloc(1, sizeof(ST_SnrSeqStmt));			//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_IfStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pIfStmt) { DIE(); }
	pIfStmt->iSnrSeqStmtType	= SnrSeqStmtType_If;
	pIfStmt->pIfSubs		= CondSubs_Intern(pIfSubs);		//ポインタで比較出来るように、単一化して格納する。
    if(pElifSubsList/*NULL可*/) {
	pIfStmt->pElifSubsList		= CondSubsList_Intern(pElifSubsList);	//pElifSubsListの要素のpCondSubsを、ポインタで比較出来るように単一化して追加し、最後に、pElifSubsListも単一化して格納する。
    }
    if(pElseSubs/*NULL可*/) {
	pIfStmt->pElseSubs		= SnrSeqBody_Intern(pElseSubs);		//ポインタで比較出来るように、単一化して格納する。
    }
	return (ST_SnrSeqStmt*)pIfStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* UnlessStmt_New(ST_CondSubs* pUnlessSubs, ST_SnrSeqBody* pElseSubs/*NULL可*/) {
	return IfStmt_New(pUnlessSubs, NULL, pElseSubs);	//既にpUnlessSubs->pCond->bNotはUnlessSubs_New()にて反転済みです。
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* CaseStmt_New(ST_Func* pFunc, GSList* pOfSubsList, ST_SnrSeqBody* pElseSubs/*NULL可*/) {
	ST_CaseStmt* pCaseStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_CaseStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pCaseStmt) { DIE(); }
	pCaseStmt->iSnrSeqStmtType	= SnrSeqStmtType_Case;
	pCaseStmt->pFunc		= Func_Intern(pFunc);			//ポインタで比較出来るように、単一化して格納する。
	pCaseStmt->pOfSubsList		= ValueSubsList_Intern(pOfSubsList);	//pOfSubsListの要素のpValueSubsを、ポインタで比較出来るように単一化して追加し、最後に、pOfSubsListも単一化して格納する。
    if(pElseSubs/*NULL可*/) {
	pCaseStmt->pElseSubs		= SnrSeqBody_Intern(pElseSubs);		//ポインタで比較出来るように、単一化して格納する。
    }
	return (ST_SnrSeqStmt*)pCaseStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* RepeatStmt_New(int nRepeatCnt, ST_SnrSeqBody* pSnrSeqBody) {
	ST_RepeatStmt* pRepeatStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_RepeatStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pRepeatStmt) { DIE(); }
	pRepeatStmt->iSnrSeqStmtType	= SnrSeqStmtType_Repeat;
	pRepeatStmt->nRepeatCnt		= nRepeatCnt;
	pRepeatStmt->pSnrSeqBody	= SnrSeqBody_Intern(pSnrSeqBody);	//ポインタで比較出来るように、単一化して格納する。
	return (ST_SnrSeqStmt*)pRepeatStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int RepeatCnt_New(int nRepeatCnt) {
	if((nRepeatCnt < 1) || (nRepeatCnt > (UINT16_MAX/*無限*/ - 1))) {
		yyerror("繰り返し回数が範囲外です。(%d)", nRepeatCnt);
		yynerrs++;	//呼び出し元(main)に知らせるために。
		return -1;	//y.tab.yの処理でYYERRORを行う。
	}
	return nRepeatCnt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* BreakStmt_New(int nBreakCnt) {
	ST_BreakStmt* pBreakStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_BreakStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pBreakStmt) { DIE(); }
	pBreakStmt->iSnrSeqStmtType	= SnrSeqStmtType_Break;
	pBreakStmt->nBreakCnt		= nBreakCnt;
	return (ST_SnrSeqStmt*)pBreakStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int BreakCnt_New(int nBreakCnt) {
	if((nBreakCnt < 1) || (nBreakCnt > UINT8_MAX)) {
		yyerror("ネストしたrepeatを抜ける数が範囲外です。(%d)", nBreakCnt);
		yynerrs++;	//呼び出し元(main)に知らせるために。
		return -1;	//y.tab.yの処理でYYERRORを行う。
	}
	return nBreakCnt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* WhileStmt_New(ST_Cond* pCond, ST_SnrSeqBody* pSnrSeqBody) {
	ST_WhileStmt* pWhileStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_WhileStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pWhileStmt) { DIE(); }
	pWhileStmt->iSnrSeqStmtType	= SnrSeqStmtType_While;
	pWhileStmt->pCond		= Cond_Intern(pCond);			//ポインタで比較出来るように、単一化して格納する。
	pWhileStmt->pSnrSeqBody		= SnrSeqBody_Intern(pSnrSeqBody);	//ポインタで比較出来るように、単一化して格納する。
	return (ST_SnrSeqStmt*)pWhileStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* UntilStmt_New(ST_Cond* pCond, ST_SnrSeqBody* pSnrSeqBody) {
	pCond = Cond_New(!pCond->bNot, pCond->pFunc);
	return WhileStmt_New(pCond, pSnrSeqBody);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* ActStmt_New(ST_Func* pFunc, int bEnsure) {
	ST_ActStmt* pActStmt = calloc(1, sizeof(ST_SnrSeqStmt));		//SnrSeqStmt_Compar()にて(ST_SnrSeqStmt*)として比較するので、sizeof(ST_ActStmt)ではなくsizeof(ST_SnrSeqStmt)のサイズで確保する必要が有る。
	if(!pActStmt) { DIE(); }
	pActStmt->iSnrSeqStmtType	= SnrSeqStmtType_Act;
	pActStmt->pFunc			= Func_Intern(pFunc);			//ポインタで比較出来るように、単一化して格納する。
	pActStmt->bEnsure		= bEnsure;
	return (ST_SnrSeqStmt*)pActStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_SnrSeqStmt* SnrSeqStmt_Intern(ST_SnrSeqStmt* pSnrSeqStmt) {
	ST_SnrSeqStmt* pOldSnrSeqStmt = g_tree_lookup(tree_pSnrSeqStmt, pSnrSeqStmt);
	if(pOldSnrSeqStmt) { return pOldSnrSeqStmt; }
	g_tree_insert(tree_pSnrSeqStmt, pSnrSeqStmt, pSnrSeqStmt);
	return pSnrSeqStmt;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int SnrSeqStmt_Compar(const void* _a, const void* _b) {
	ST_SnrSeqStmt* a = (ST_SnrSeqStmt*)_a;
	ST_SnrSeqStmt* b = (ST_SnrSeqStmt*)_b;
	return memcmp(a, b, sizeof(ST_SnrSeqStmt));
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
ST_Code* Code_New(int addr) {
	ST_Code* pCode = calloc(1, sizeof(ST_Code));
	if(!pCode) { DIE(); }
	pCode->addr	= addr;
	pCode->code	= g_byte_array_new();
	return pCode;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int Code_AddValue(ST_Code* pCode, int value, int size) {
	switch(size) {
	default:DIE();
	case 4: Code_AddValue(pCode,  value >> 24, 1); /* FALLTHRU */	//4バイトビッグエンディアン
	case 3: Code_AddValue(pCode,  value >> 16, 1); /* FALLTHRU */	//3バイトビッグエンディアン
	case 2: Code_AddValue(pCode,  value >>  8, 1); /* FALLTHRU */	//2バイトビッグエンディアン
	case 1: Code_AddData( pCode, &value,       1); break;		//1バイト
	}
	return size;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
int Code_AddData(ST_Code* pCode, const void* data, int size) {
	g_byte_array_append(pCode->code, data, size);
	return size;
}
/*---------------------------------------------------------------------------*/
//2パス目の処理
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//引数リストのBLOBを構築する。
static void* Args_BuildBlob(ST_Args* pArgs) {
	void* data = NULL;
	if(pArgs->pArgList/*NULL可*/) {
		GSList* pArgList = pArgs->pArgList;
		while(pArgList) {
			ST_Arg* pArg = pArgList->data;
			switch(pArg->iArgType) {
			default:DIE();	//もしここで停止したら当ツールのバグです。
			case ArgType_Bit:
				{
					data = blob_add_bit(data, pArg->value.v_bit);
				}
				break;
			case ArgType_Byte:
				{
					data = blob_add_byte(data, pArg->value.v_byte);
				}
				break;
			case ArgType_Half:
				{
					data = blob_add_half(data, pArg->value.v_half);
				}
				break;
			case ArgType_Exp10:
				{
					data = blob_add_exp10(data, pArg->value.v_exp10);
				}
				break;
			case ArgType_Word:
				{
					data = blob_add_word(data, pArg->value.v_word);
				}
				break;
//{{2018/04/07追加:引数リストにBER圧縮整数も含められるようにしました。
			case ArgType_Ber:
				{
					data = blob_add_ber(data, pArg->value.v_ber);
				}
				break;
//}}2018/04/07追加:引数リストにBER圧縮整数も含められるようにしました。
			case ArgType_Fp16:
				{
					data = blob_add_fp16(data, pArg->value.v_fp16);
				}
				break;
			case ArgType_Fp32:
				{
					data = blob_add_fp32(data, pArg->value.v_fp32);
				}
				break;
			case ArgType_Fp64:
				{
					data = blob_add_fp64(data, pArg->value.v_fp64);
				}
				break;
			case ArgType_String:
				{
					data = blob_add_string(data, pArg->value.v_string);
				}
				break;
			case ArgType_File:
				{
					FILE* fp;
					struct stat st;
					void* buf;
					if(!(fp = fopen(pArg->value.v_file, "rb"))) {	//バイナリモードで開く。
						yyerror("%s が開けません。", pArg->value.v_file);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						break;		//全てのセマンティクスエラーを報告するために継続する。
					}
					if(fstat(fileno(fp), &st)) { DIE(); }
					if(!(buf = malloc(st.st_size))) { DIE(); }
					if((int)fread(buf, 1, st.st_size, fp) != (int)st.st_size) { DIE(); }	//fread()の戻り値はunsigned型，st.st_sizeは(なぜか)signed型なので、そのまま比較すると警告が出る。警告を抑制するには片方をキャストするだけでも良いが、判り易さのために両方をキャストして比較する事にした。
					data = blob_add_data(data, buf, st.st_size);
					free(buf);
					fclose(fp);
				}
				break;
			case ArgType_Table:
				{
				
					ST_SnrTbl* pSnrTbl;
					if(!g_tree_lookup_extended(tree_pSnrTbl, pArg->value.v_table, NULL, &pSnrTbl)) {
						yyerror("シナリオテーブルラベルが定義されていません。(%s)", pArg->value.v_table);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						break;		//全てのセマンティクスエラーを報告するために継続する。
					}
					if((unsigned)pSnrTbl->iSnrTbl > UINT16_MAX) {
						yyerror("引数リストのシナリオテーブル番号が範囲外です。(%d)", pSnrTbl->iSnrTbl);	//シナリオテーブルを作成する数に制限は有りませんが、引数リストに指定出来るシナリオテーブル番号は65535以下に制限する事にしました。データ容量削減のために、引数リストのBLOBに2バイト値として格納するためです。一般的にはこれで十分だと思いますが、もしここで実際にエラー停止した場合は、4バイト値で格納するように変更する事を検討して下さい。
						yynerrs++;	//呼び出し元(main)に知らせるために。
						break;		//全てのセマンティクスエラーを報告するために継続する。
					}
					if(!pSnrTbl->iSnrTbl) { DIE(); }	//既にシナリオテーブルラベルにシナリオテーブル番号を割り当て済みであるはず。もしここで停止したら当ツールのバグです。
					data = blob_add_half(data, pSnrTbl->iSnrTbl);
				}
				break;
			case ArgType_Trig:
				{
					int iSnrTrg;
					if(!g_tree_lookup_extended(tree_pTrigName_No, pArg->value.v_trig, NULL, (void**)&iSnrTrg)) {	//ここではTrigName_GetNo()を使用してはいけません。引数リストには存在しないトリガ名が指定される可能性も有り、その場合も強制終了ではなく適切なエラーメッセージを表示する方が親切だからです。
						yyerror("トリガ名が定義されていません。(%s)", pArg->value.v_trig);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						break;		//全てのセマンティクスエラーを報告するために継続する。
					}
					data = blob_add_byte(data, iSnrTrg);
				}
				break;
			case ArgType_Func:
				{
					int iSnrFnc;
					if(!g_tree_lookup_extended(tree_pFuncName_No, pArg->value.v_func, NULL, (void**)&iSnrFnc)) {	//ここではFuncName_GetNo()を使用してはいけません。引数リストには存在しないトリガ名が指定される可能性も有り、その場合も強制終了ではなく適切なエラーメッセージを表示する方が親切だからです。
						yyerror("関数名が定義されていません。(%s)", pArg->value.v_func);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						break;		//全てのセマンティクスエラーを報告するために継続する。
					}
					data = blob_add_byte(data, iSnrFnc);
				}
				break;
			}
			pArgList = g_slist_next(pArgList);
		}
	}
	if(blob_get_size(data/*NULL可*/) >= UINT8_MAX) {
		yyerror("引数リストのサイズが超過しました。");
		yynerrs++;	//呼び出し元(main)に知らせるために。
		//全てのセマンティクスエラーを報告するために継続する。
	}
	return data/*NULL可*/;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
//シナリオシーケンスボディの参照先のシナリオシーケンスが存在する事を確認する。
static void SnrSeqBody_Verify(ST_SnrSeqBody* pSnrSeqBody) {
	if(pSnrSeqBody->pSnrSeqStmtList/*NULL可*/) {
		GSList* pSnrSeqStmtList = pSnrSeqBody->pSnrSeqStmtList;
		while(pSnrSeqStmtList) {
			ST_SnrSeqStmt* pSnrSeqStmt = pSnrSeqStmtList->data;
			switch(pSnrSeqStmt->iSnrSeqStmtType) {
			default:DIE();	//もしここで停止したら当ツールのバグです。
			case SnrSeqStmtType_Exit:
				{
					ST_ExitStmt* pExitStmt = &pSnrSeqStmt->exitStmt;
					/** no job **/
				}
				break;
			case SnrSeqStmtType_Escape:
				{
					ST_EscapeStmt* pEscapeStmt = &pSnrSeqStmt->escapeStmt;
					/** no job **/
				}
				break;
			case SnrSeqStmtType_Wait:
				{
					ST_WaitStmt* pWaitStmt = &pSnrSeqStmt->waitStmt;
					/** no job **/
				}
				break;
			case SnrSeqStmtType_WaitFor:
				{
					ST_WaitForStmt* pWaitForStmt = &pSnrSeqStmt->waitForStmt;
					/** no job **/
				}
				break;
			case SnrSeqStmtType_Fork:
				{
					ST_ForkStmt* pForkStmt = &pSnrSeqStmt->forkStmt;
					SnrSeqBody_Verify(pForkStmt->pSnrSeqBody);
				}
				break;
			case SnrSeqStmtType_Hide:
				{
					ST_HideStmt* pHideStmt = &pSnrSeqStmt->hideStmt;
					/** no job **/
				}
				break;
			case SnrSeqStmtType_Join:
				{
					ST_JoinStmt* pJoinStmt = &pSnrSeqStmt->joinStmt;
					/** no job **/
				}
				break;
			case SnrSeqStmtType_Goto:
				{
					ST_GotoStmt* pGotoStmt = &pSnrSeqStmt->gotoStmt;
					char* pSnrSeqLabel = pGotoStmt->pSnrSeqLabel;
					if(!g_tree_lookup(tree_pSnrSeq, pSnrSeqLabel)) {
						yyerror("シナリオシーケンスラベルが定義されていません。(%s)", pSnrSeqLabel);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						//全てのセマンティクスエラーを報告するために継続する。
					}
				}
				break;
			case SnrSeqStmtType_Call:
				{
					ST_CallStmt* pCallStmt = &pSnrSeqStmt->callStmt;
					char* pSnrSeqLabel = pCallStmt->pSnrSeqLabel;
					if(!g_tree_lookup(tree_pSnrSeq, pSnrSeqLabel)) {
						yyerror("シナリオシーケンスラベルが定義されていません。(%s)", pSnrSeqLabel);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						//全てのセマンティクスエラーを報告するために継続する。
					}
				}
				break;
			case SnrSeqStmtType_If:
				{
					ST_IfStmt* pIfStmt = &pSnrSeqStmt->ifStmt;
					SnrSeqBody_Verify(pIfStmt->pIfSubs->pSnrSeqBody);
					if(pIfStmt->pElifSubsList/*NULL可*/) {
						GSList* pElifSubsList = pIfStmt->pElifSubsList;
						while(pElifSubsList) {
							ST_CondSubs* pElifSubs = pElifSubsList->data;
							SnrSeqBody_Verify(pElifSubs->pSnrSeqBody);
							pElifSubsList = g_slist_next(pElifSubsList);
						}
					}
					if(pIfStmt->pElseSubs/*NULL可*/) {
						SnrSeqBody_Verify(pIfStmt->pElseSubs);
					}
				}
				break;
			case SnrSeqStmtType_Case:
				{
					ST_CaseStmt* pCaseStmt = &pSnrSeqStmt->caseStmt;
					{
						GSList* pOfSubsList = pCaseStmt->pOfSubsList;
						while(pOfSubsList) {
							ST_CondSubs* pOfSubs = pOfSubsList->data;
							SnrSeqBody_Verify(pOfSubs->pSnrSeqBody);
							pOfSubsList = g_slist_next(pOfSubsList);
						}
					}
					if(pCaseStmt->pElseSubs/*NULL可*/) {
						SnrSeqBody_Verify(pCaseStmt->pElseSubs);
					}
				}
				break;
			case SnrSeqStmtType_Repeat:
				{
					ST_RepeatStmt* pRepeatStmt = &pSnrSeqStmt->repeatStmt;
					SnrSeqBody_Verify(pRepeatStmt->pSnrSeqBody);
				}
				break;
			case SnrSeqStmtType_Break:
				{
					ST_BreakStmt* pBreakStmt = &pSnrSeqStmt->breakStmt;
					/** no job **/
				}
				break;
			case SnrSeqStmtType_While:
				{
					ST_WhileStmt* pWhileStmt = &pSnrSeqStmt->whileStmt;
					SnrSeqBody_Verify(pWhileStmt->pSnrSeqBody);
				}
				break;
			case SnrSeqStmtType_Act:
				{
					ST_ActStmt* pActStmt = &pSnrSeqStmt->actStmt;
					/** no job **/
				}
				break;
			}
			pSnrSeqStmtList = g_slist_next(pSnrSeqStmtList);
		}
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//このシナリオシーケンスボディ,及び,このシナリオシーケンスボディから辿れるシナリオシーケンス,シナリオシーケンスボディ,引数リストをマークする。
static void SnrSeqBody_Mark(ST_SnrSeqBody* pSnrSeqBody) {
	if(!g_tree_lookup(tree_pSnrSeqBody_Used, pSnrSeqBody)) {		//まだマークされていなければ…
		g_tree_insert(tree_pSnrSeqBody_Used, pSnrSeqBody, pSnrSeqBody);	//マークする。
		if(pSnrSeqBody->pSnrSeqStmtList/*NULL可*/) {
			GSList* pSnrSeqStmtList = pSnrSeqBody->pSnrSeqStmtList;
			while(pSnrSeqStmtList) {
				ST_SnrSeqStmt* pSnrSeqStmt = pSnrSeqStmtList->data;
				switch(pSnrSeqStmt->iSnrSeqStmtType) {
				default:DIE();	//もしここで停止したら当ツールのバグです。
				case SnrSeqStmtType_Exit:
					{
						ST_ExitStmt* pExitStmt = &pSnrSeqStmt->exitStmt;
						/** no job **/
					}
					break;
				case SnrSeqStmtType_Escape:
					{
						ST_EscapeStmt* pEscapeStmt = &pSnrSeqStmt->escapeStmt;
						/** no job **/
					}
					break;
				case SnrSeqStmtType_Wait:
					{
						ST_WaitStmt* pWaitStmt = &pSnrSeqStmt->waitStmt;
						/** no job **/
					}
					break;
				case SnrSeqStmtType_WaitFor:
					{
						ST_WaitForStmt* pWaitForStmt = &pSnrSeqStmt->waitForStmt;
						if(!g_tree_lookup(tree_pArgs_Used, pWaitForStmt->pCond->pFunc->pArgs)) {					//まだマークされていなければ…
							g_tree_insert(tree_pArgs_Used, pWaitForStmt->pCond->pFunc->pArgs, pWaitForStmt->pCond->pFunc->pArgs);	//マークする。
						}
					}
					break;
				case SnrSeqStmtType_Fork:
					{
						ST_ForkStmt* pForkStmt = &pSnrSeqStmt->forkStmt;
						SnrSeqBody_Mark(pForkStmt->pSnrSeqBody);
					}
					break;
				case SnrSeqStmtType_Hide:
					{
						ST_HideStmt* pHideStmt = &pSnrSeqStmt->hideStmt;
						/** no job **/
					}
					break;
				case SnrSeqStmtType_Join:
					{
						ST_JoinStmt* pJoinStmt = &pSnrSeqStmt->joinStmt;
						/** no job **/
					}
					break;
				case SnrSeqStmtType_Goto:
					{
						ST_GotoStmt* pGotoStmt = &pSnrSeqStmt->gotoStmt;
						char* pSnrSeqLabel = pGotoStmt->pSnrSeqLabel;
						if(!g_tree_lookup(tree_pSnrSeq_Used, pSnrSeqLabel)) {			//まだマークされていなければ…
							ST_SnrSeq* pSnrSeq = g_tree_lookup(tree_pSnrSeq, pSnrSeqLabel);	//マークする。
							if(!pSnrSeq) { DIE(); }	//既にシナリオシーケンスの参照先のシナリオシーケンスが存在する事を確認する事を確認済みであるはず。もしここで停止したら当ツールのバグです。
							g_tree_insert(tree_pSnrSeq_Used, pSnrSeqLabel, pSnrSeq);
							SnrSeqBody_Mark(pSnrSeq->pSnrSeqBody);
						}
					}
					break;
				case SnrSeqStmtType_Call:
					{
						ST_CallStmt* pCallStmt = &pSnrSeqStmt->callStmt;
						char* pSnrSeqLabel = pCallStmt->pSnrSeqLabel;
						if(!g_tree_lookup(tree_pSnrSeq_Used, pSnrSeqLabel)) {			//まだマークされていなければ…
							ST_SnrSeq* pSnrSeq = g_tree_lookup(tree_pSnrSeq, pSnrSeqLabel);	//マークする。
							if(!pSnrSeq) { DIE(); }	//既にシナリオシーケンスの参照先のシナリオシーケンスが存在する事を確認する事を確認済みであるはず。もしここで停止したら当ツールのバグです。
							g_tree_insert(tree_pSnrSeq_Used, pSnrSeqLabel, pSnrSeq);
							SnrSeqBody_Mark(pSnrSeq->pSnrSeqBody);
						}
					}
					break;
				case SnrSeqStmtType_If:
					{
						ST_IfStmt* pIfStmt = &pSnrSeqStmt->ifStmt;
						if(!g_tree_lookup(tree_pArgs_Used, pIfStmt->pIfSubs->pCond->pFunc->pArgs)) {						//まだマークされていなければ…
							g_tree_insert(tree_pArgs_Used, pIfStmt->pIfSubs->pCond->pFunc->pArgs, pIfStmt->pIfSubs->pCond->pFunc->pArgs);	//マークする。
						}
						SnrSeqBody_Mark(pIfStmt->pIfSubs->pSnrSeqBody);
						if(pIfStmt->pElifSubsList/*NULL可*/) {
							GSList* pElifSubsList = pIfStmt->pElifSubsList;
							while(pElifSubsList) {
								ST_CondSubs* pElifSubs = pElifSubsList->data;
								if(!g_tree_lookup(tree_pArgs_Used, pElifSubs->pCond->pFunc->pArgs)) {					//まだマークされていなければ…
									g_tree_insert(tree_pArgs_Used, pElifSubs->pCond->pFunc->pArgs, pElifSubs->pCond->pFunc->pArgs);	//マークする。
								}
								SnrSeqBody_Mark(pElifSubs->pSnrSeqBody);
								pElifSubsList = g_slist_next(pElifSubsList);
							}
						}
						if(pIfStmt->pElseSubs/*NULL可*/) {
							SnrSeqBody_Mark(pIfStmt->pElseSubs);
						}
					}
					break;
				case SnrSeqStmtType_Case:
					{
						ST_CaseStmt* pCaseStmt = &pSnrSeqStmt->caseStmt;
						if(!g_tree_lookup(tree_pArgs_Used, pCaseStmt->pFunc->pArgs)) {					//まだマークされていなければ…
							g_tree_insert(tree_pArgs_Used, pCaseStmt->pFunc->pArgs, pCaseStmt->pFunc->pArgs);	//マークする。
						}
						{
							GSList* pOfSubsList = pCaseStmt->pOfSubsList;
							while(pOfSubsList) {
								ST_ValueSubs* pOfSubs = pOfSubsList->data;
								SnrSeqBody_Mark(pOfSubs->pSnrSeqBody);
								pOfSubsList = g_slist_next(pOfSubsList);
							}
						}
						if(pCaseStmt->pElseSubs/*NULL可*/) {
							SnrSeqBody_Mark(pCaseStmt->pElseSubs);
						}
					}
					break;
				case SnrSeqStmtType_Repeat:
					{
						ST_RepeatStmt* pRepeatStmt = &pSnrSeqStmt->repeatStmt;
						SnrSeqBody_Mark(pRepeatStmt->pSnrSeqBody);
					}
					break;
				case SnrSeqStmtType_Break:
					{
						ST_BreakStmt* pBreakStmt = &pSnrSeqStmt->breakStmt;
						/** no job **/
					}
					break;
				case SnrSeqStmtType_While:
					{
						ST_WhileStmt* pWhileStmt = &pSnrSeqStmt->whileStmt;
						if(!g_tree_lookup(tree_pArgs_Used, pWhileStmt->pCond->pFunc->pArgs)) {						//まだマークされていなければ…
							g_tree_insert(tree_pArgs_Used, pWhileStmt->pCond->pFunc->pArgs, pWhileStmt->pCond->pFunc->pArgs);	//マークする。
						}
						SnrSeqBody_Mark(pWhileStmt->pSnrSeqBody);
					}
					break;
				case SnrSeqStmtType_Act:
					{
						ST_ActStmt* pActStmt = &pSnrSeqStmt->actStmt;
						if(!g_tree_lookup(tree_pArgs_Used, pActStmt->pFunc->pArgs)) {				//まだマークされていなければ…
							g_tree_insert(tree_pArgs_Used, pActStmt->pFunc->pArgs, pActStmt->pFunc->pArgs);	//マークする。
						}
					}
					break;
				}
				pSnrSeqStmtList = g_slist_next(pSnrSeqStmtList);
			}
		}
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//このシナリオテーブルボディから再帰的に辿れるシナリオシーケンスをマークする。
static void SnrTblBody_Mark(ST_SnrTblBody* pSnrTblBody) {
	GSList* pSnrTblStmtList = pSnrTblBody->pSnrTblStmtList;
	while(pSnrTblStmtList) {
		ST_SnrTblStmt* pSnrTblStmt = pSnrTblStmtList->data;
		switch(pSnrTblStmt->iSnrTblStmtType) {
		default:DIE();	//もしここで停止したら当ツールのバグです。
		case SnrTblStmtType_OnUnlock:
			{
				ST_OnUnlockStmt* pOnUnlockStmt = &pSnrTblStmt->onUnlockStmt;
				{
					/** no job **/
				}
			}
			break;
		case SnrTblStmtType_OnGoto:
			{
				ST_OnGotoStmt* pOnGotoStmt = &pSnrTblStmt->onGotoStmt;
				{
					char* pSnrSeqLabel = pOnGotoStmt->pSnrSeqLabel;
					ST_SnrSeq* pSnrSeq = g_tree_lookup(tree_pSnrSeq, pSnrSeqLabel);
					if(pSnrSeq) {
						if(!g_tree_lookup(tree_pSnrSeq_Used, pSnrSeqLabel)) {	//まだマークされていなければ…
							g_tree_insert(tree_pSnrSeq_Used, pSnrSeqLabel, pSnrSeq);
							SnrSeqBody_Mark(pSnrSeq->pSnrSeqBody);
						}
					} else {
						yyerror("シナリオシーケンスラベルが定義されていません。(%s)", pSnrSeqLabel);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						//全てのセマンティクスエラーを報告するために継続する。
					}
				}
			}
			break;
		case SnrTblStmtType_OnExec:
			{
				ST_OnExecStmt* pOnExecStmt = &pSnrTblStmt->onExecStmt;
				{
					char* pSnrSeqLabel = pOnExecStmt->pSnrSeqLabel;
					ST_SnrSeq* pSnrSeq = g_tree_lookup(tree_pSnrSeq, pSnrSeqLabel);
					if(pSnrSeq) {
						if(!g_tree_lookup(tree_pSnrSeq_Used, pSnrSeqLabel)) {	//まだマークされていなければ…
							g_tree_insert(tree_pSnrSeq_Used, pSnrSeqLabel, pSnrSeq);
							SnrSeqBody_Mark(pSnrSeq->pSnrSeqBody);
						}
					} else {
						yyerror("シナリオシーケンスラベルが定義されていません。(%s)", pSnrSeqLabel);
						yynerrs++;	//呼び出し元(main)に知らせるために。
						//全てのセマンティクスエラーを報告するために継続する。
					}
				}
			}
			break;
		}
		pSnrTblStmtList = g_slist_next(pSnrTblStmtList);
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//指定されたアドレスから、この引数リストの先頭アドレスへの、相対距離を求める。
//この引数リストがまだマークされていなければ、ダミーを返す。
//少なくとも、2回目の処理から呼び出された時点では、マークされているはずです。
static int Args_GetDist(ST_Args* pArgs, int addr) {
	ST_Code* pArgsCode = g_tree_lookup(tree_pArgs_Code, pArgs);
	int iArgsDist = pArgsCode ? (pArgsCode->addr - addr) : 0/*ダミー*/;
	if((iArgsDist < INT24_MIN) || (iArgsDist > INT24_MAX)) {
		yyerror("引数リストの相対距離が範囲外です。");
		DIE();	//継続しても無駄なので終了する。
	}
	return iArgsDist;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//指定されたアドレスから、このシナリオシーケンスボディの先頭アドレスへの、相対距離を求める。
//このシナリオシーケンスボディがまだマークされていなければ、ダミーを返す。
//少なくとも、2回目の処理から呼び出された時点では、マークされているはずです。
static int SnrSeqBody_GetDist(ST_SnrSeqBody* pSnrSeqBody, int addr) {
	ST_Code* pSnrSeqBodyCode = g_tree_lookup(tree_pSnrSeqBody_Code, pSnrSeqBody);
	int iSnrSeqBodyDist = pSnrSeqBodyCode ? (pSnrSeqBodyCode->addr - addr) : 0/*ダミー*/;
	if((iSnrSeqBodyDist < INT24_MIN) || (iSnrSeqBodyDist > INT24_MAX)) {
		yyerror("シナリオシーケンスボディの相対距離が範囲外です。");
		DIE();	//継続しても無駄なので終了する。
	}
	return iSnrSeqBodyDist;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//指定されたアドレスから、このシナリオシーケンスの先頭アドレスへの、相対距離を求める。
//このシナリオシーケンスがまだマークされていなければ、ダミーを返す。
//少なくとも、2回目の処理から呼び出された時点では、マークされているはずです。
static int SnrSeqLabel_GetDist(char* pSnrSeqLabel, int addr) {
	ST_SnrSeq* pSnrSeq = g_tree_lookup(tree_pSnrSeq_Used, pSnrSeqLabel);
	if(!pSnrSeq) { DIE(); }	//既にシナリオテーブルの参照先のシナリオシーケンスが存在する事を確認する事を確認済みであるはず。もしここで停止したら当ツールのバグです。
	return SnrSeqBody_GetDist(pSnrSeq->pSnrSeqBody, addr);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//トリガ番号を取得する。
static int TrigName_GetNo(char* pTrigName) {
	int iSnrTrg;
	if(!g_tree_lookup_extended(tree_pTrigName_No, pTrigName, NULL, (void**)&iSnrTrg)) { DIE(); }	//既にトリガ名にトリガ番号を割り当て済みであるはず。もしここで停止したら当ツールのバグです。
	return iSnrTrg;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//関数番号を取得する。
static int FuncName_GetNo(char* pFuncName) {
	int iSnrFnc;
	if(!g_tree_lookup_extended(tree_pFuncName_No, pFuncName, NULL, (void**)&iSnrFnc)) { DIE(); }	//既に関数名に関数番号を割り当て済みであるはず。もしここで停止したら当ツールのバグです。
	return iSnrFnc;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//シナリオテーブルボディのコードを生成する。
//1回目:仮コードを生成してアドレスを割り当てる。
//2回目:本コードを生成する。
static int SnrTblBody_CodeGen(ST_SnrTblBody* pSnrTblBody, int addr) {
	ST_Code* pCode = Code_New(addr);
	{
		GSList* pSnrTblStmtList = pSnrTblBody->pSnrTblStmtList;
		while(pSnrTblStmtList) {
			ST_SnrTblStmt* pSnrTblStmt = pSnrTblStmtList->data;
			switch(pSnrTblStmt->iSnrTblStmtType) {
			default:DIE();	//もしここで停止したら当ツールのバグです。
			case SnrTblStmtType_OnUnlock:
				{
					ST_OnUnlockStmt* pOnUnlockStmt = &pSnrTblStmt->onUnlockStmt;
					{
						int iSnrTrg = TrigName_GetNo(pOnUnlockStmt->pTrigName);
						addr += Code_AddValue(pCode, SnrTbl_on_unlock, 1);
						addr += Code_AddValue(pCode, iSnrTrg,          1);
					}
				}
				break;
			case SnrTblStmtType_OnGoto:
				{
					ST_OnGotoStmt* pOnGotoStmt = &pSnrTblStmt->onGotoStmt;
					{
						int iSnrTrg = TrigName_GetNo(pOnGotoStmt->pTrigName);
						int iSnrSeqBodyDist = SnrSeqLabel_GetDist(pOnGotoStmt->pSnrSeqLabel,             addr + 1 + 1 + 3 + 2);
						addr += Code_AddValue(pCode, pOnGotoStmt->bUnlock ? SnrTbl_on_unlock_goto : SnrTbl_on_goto, 1        );
						addr += Code_AddValue(pCode, iSnrTrg,                                                         1      );
						addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                                     3  );
						addr += Code_AddValue(pCode, pOnGotoStmt->nLock,                                                    2);
					}
				}
				break;
			case SnrTblStmtType_OnExec:
				{
					ST_OnExecStmt* pOnExecStmt = &pSnrTblStmt->onExecStmt;
					{
						int iSnrTrg = TrigName_GetNo(pOnExecStmt->pTrigName);
						int iSnrSeqBodyDist = SnrSeqLabel_GetDist(pOnExecStmt->pSnrSeqLabel,             addr + 1 + 1 + 3 + 2);
						addr += Code_AddValue(pCode, pOnExecStmt->bUnlock ? SnrTbl_on_unlock_exec : SnrTbl_on_exec, 1        );
						addr += Code_AddValue(pCode, iSnrTrg,                                                         1      );
						addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                                     3  );
						addr += Code_AddValue(pCode, pOnExecStmt->nLock,                                                    2);
					}
				}
				break;
			}
			pSnrTblStmtList = g_slist_next(pSnrTblStmtList);
		}
		addr += Code_AddValue(pCode, SnrTbl_end, 1);	//忘れないで!!
	}
	{
		ST_Code* pOldCode = g_tree_lookup(tree_pSnrTblBody_Code, pSnrTblBody);
		if(pOldCode && ((pOldCode->addr != pCode->addr) || (pOldCode->code->len != pCode->code->len))) { DIE(); }	//1回目も2回目もアドレスとコードサイズは一致するはず。もしここで停止したら当ツールのバグです。
		if(pCode->code->len != (addr - pCode->addr)) { DIE(); }	//生成したコードのサイズとアドレスの増分は一致するはず。もしここで停止したら当ツールのバグです。
		g_tree_replace(tree_pSnrTblBody_Code, pSnrTblBody, pCode);
	}
	return addr;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//シナリオシーケンスボディのコードを生成する。
//1回目:仮コードを生成してアドレスを割り当てる。
//2回目:本コードを生成する。
static int SnrSeqBody_CodeGen(ST_SnrSeqBody* pSnrSeqBody, int addr) {
	ST_Code* pCode = Code_New(addr);
	{
		GSList* pSnrSeqStmtList = pSnrSeqBody->pSnrSeqStmtList;
		while(pSnrSeqStmtList) {
			ST_SnrSeqStmt* pSnrSeqStmt = pSnrSeqStmtList->data;
			switch(pSnrSeqStmt->iSnrSeqStmtType) {
			default:DIE();	//もしここで停止したら当ツールのバグです。
			case SnrSeqStmtType_Exit:
				{
					ST_ExitStmt* pExitStmt = &pSnrSeqStmt->exitStmt;
					{
						addr += Code_AddValue(pCode, SnrSeq_exit, 1);
					}
				}
				break;
			case SnrSeqStmtType_Escape:
				{
					ST_EscapeStmt* pEscapeStmt = &pSnrSeqStmt->escapeStmt;
					{
						addr += Code_AddValue(pCode, SnrSeq_escape, 1);
					}
				}
				break;
			case SnrSeqStmtType_Wait:
				{
					ST_WaitStmt* pWaitStmt = &pSnrSeqStmt->waitStmt;
					{
						addr += Code_AddValue(pCode, SnrSeq_wait,         1);
						addr += Code_AddValue(pCode, pWaitStmt->nWaitCnt, 2);
					}
				}
				break;
			case SnrSeqStmtType_WaitFor:
				{
					ST_WaitForStmt* pWaitForStmt = &pSnrSeqStmt->waitForStmt;
					{
						int iSnrFnc = FuncName_GetNo(pWaitForStmt->pCond->pFunc->pFuncName);
						int iArgsDist = Args_GetDist(pWaitForStmt->pCond->pFunc->pArgs,                          addr + 1 + 1 + 3);
						addr += Code_AddValue(pCode, pWaitForStmt->pCond->bNot ? SnrSeq_wait_for_not : SnrSeq_wait_for, 1        );
						addr += Code_AddValue(pCode, iSnrFnc,                                                               1    );
						addr += Code_AddValue(pCode, iArgsDist,                                                                 3);
					}
				}
				break;
			case SnrSeqStmtType_Fork:
				{
					ST_ForkStmt* pForkStmt = &pSnrSeqStmt->forkStmt;
					{
						int iSnrSeqBodyDist = SnrSeqBody_GetDist(pForkStmt->pSnrSeqBody, addr + 1 + 3);
						addr += Code_AddValue(pCode, SnrSeq_fork,                               1    );
						addr += Code_AddValue(pCode, iSnrSeqBodyDist,                               3);
					}
				}
				break;
			case SnrSeqStmtType_Hide:
				{
					ST_HideStmt* pHideStmt = &pSnrSeqStmt->hideStmt;
					{
						addr += Code_AddValue(pCode, SnrSeq_hide, 1);
					}
				}
				break;
			case SnrSeqStmtType_Join:
				{
					ST_JoinStmt* pJoinStmt = &pSnrSeqStmt->joinStmt;
					{
						addr += Code_AddValue(pCode, SnrSeq_join, 1);
					}
				}
				break;
			case SnrSeqStmtType_Goto:
				{
					ST_GotoStmt* pGotoStmt = &pSnrSeqStmt->gotoStmt;
					{
						int iSnrSeqBodyDist = SnrSeqLabel_GetDist(pGotoStmt->pSnrSeqLabel, addr + 1 + 3);
						addr += Code_AddValue(pCode, SnrSeq_goto,                                 1    );
						addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                 3);
					}
				}
				break;
			case SnrSeqStmtType_Call:
				{
					ST_CallStmt* pCallStmt = &pSnrSeqStmt->callStmt;
					{
						int iSnrSeqBodyDist = SnrSeqLabel_GetDist(pCallStmt->pSnrSeqLabel, addr + 1 + 3);
						addr += Code_AddValue(pCode, SnrSeq_call,                                 1    );
						addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                 3);
					}
				}
				break;
			case SnrSeqStmtType_If:
				{
					ST_IfStmt* pIfStmt = &pSnrSeqStmt->ifStmt;
					{
						{
							int iSnrFnc = FuncName_GetNo(pIfStmt->pIfSubs->pCond->pFunc->pFuncName);
							int iArgsDist = Args_GetDist(pIfStmt->pIfSubs->pCond->pFunc->pArgs,              addr + 1 + 1 + 3 + 3);
							int iSnrSeqBodyDist = SnrSeqBody_GetDist(pIfStmt->pIfSubs->pSnrSeqBody,          addr + 1 + 1 + 3 + 3);
							addr += Code_AddValue(pCode, pIfStmt->pIfSubs->pCond->bNot ? SnrSeq_if_not : SnrSeq_if, 1            );
							addr += Code_AddValue(pCode, iSnrFnc,                                                       1        );
							addr += Code_AddValue(pCode, iArgsDist,                                                         3    );
							addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                                       3);
						}
						if(pIfStmt->pElifSubsList/*NULL可*/) {
							GSList* pElifSubsList = pIfStmt->pElifSubsList;
							while(pElifSubsList) {
								ST_CondSubs* pElifSubs = pElifSubsList->data;
								{
									int iSnrFnc = FuncName_GetNo(pElifSubs->pCond->pFunc->pFuncName);
									int iArgsDist = Args_GetDist(pElifSubs->pCond->pFunc->pArgs,                  addr + 1 + 1 + 3 + 3);
									int iSnrSeqBodyDist = SnrSeqBody_GetDist(pElifSubs->pSnrSeqBody,              addr + 1 + 1 + 3 + 3);
									addr += Code_AddValue(pCode, pElifSubs->pCond->bNot ? SnrSeq_elif_not : SnrSeq_elif, 1            );
									addr += Code_AddValue(pCode, iSnrFnc,                                                    1        );
									addr += Code_AddValue(pCode, iArgsDist,                                                      3    );
									addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                                    3);
								}
								pElifSubsList = g_slist_next(pElifSubsList);
							}
						}
						if(pIfStmt->pElseSubs/*NULL可*/) {
							int iSnrSeqBodyDist = SnrSeqBody_GetDist(pIfStmt->pElseSubs, addr + 1 + 3);
							addr += Code_AddValue(pCode, SnrSeq_else,                           1    );
							addr += Code_AddValue(pCode, iSnrSeqBodyDist,                           3);
						}
					}
				}
				break;
			case SnrSeqStmtType_Case:
				{
					ST_CaseStmt* pCaseStmt = &pSnrSeqStmt->caseStmt;
					{
						{
							int iSnrFnc = FuncName_GetNo(pCaseStmt->pFunc->pFuncName);
							int iArgsDist = Args_GetDist(pCaseStmt->pFunc->pArgs, addr + 1 + 1 + 3);
							addr += Code_AddValue(pCode, SnrSeq_case,                    1        );
							addr += Code_AddValue(pCode, iSnrFnc,                            1    );
							addr += Code_AddValue(pCode, iArgsDist,                              3);
						}
						{
							GSList* pOfSubsList = pCaseStmt->pOfSubsList;
							while(pOfSubsList) {
								ST_ValueSubs* pOfSubs = pOfSubsList->data;
								{
									int iSnrSeqBodyDist = SnrSeqBody_GetDist(pOfSubs->pSnrSeqBody, addr + 1 + 1 + 3);
									addr += Code_AddValue(pCode, SnrSeq_of,                               1        );
									addr += Code_AddValue(pCode, pOfSubs->iValue,                             1    );
									addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                 3);
								}
								pOfSubsList = g_slist_next(pOfSubsList);
							}
						}
						if(pCaseStmt->pElseSubs/*NULL可*/) {
							int iSnrSeqBodyDist = SnrSeqBody_GetDist(pCaseStmt->pElseSubs, addr + 1 + 3);
							addr += Code_AddValue(pCode, SnrSeq_else,                             1    );
							addr += Code_AddValue(pCode, iSnrSeqBodyDist,                             3);
						}
					}
				}
				break;
			case SnrSeqStmtType_Repeat:
				{
					ST_RepeatStmt* pRepeatStmt = &pSnrSeqStmt->repeatStmt;
					{
						int iSnrSeqBodyDist = SnrSeqBody_GetDist(pRepeatStmt->pSnrSeqBody, addr + 1 + 2 + 3);
						addr += Code_AddValue(pCode, SnrSeq_repeat,                               1        );
						addr += Code_AddValue(pCode, pRepeatStmt->nRepeatCnt,                         2    );
						addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                     3);
					}
				}
				break;
			case SnrSeqStmtType_Break:
				{
					ST_BreakStmt* pBreakStmt = &pSnrSeqStmt->breakStmt;
					{
						addr += Code_AddValue(pCode, SnrSeq_break,          1);
						addr += Code_AddValue(pCode, pBreakStmt->nBreakCnt, 1);
					}
				}
				break;
			case SnrSeqStmtType_While:
				{
					ST_WhileStmt* pWhileStmt = &pSnrSeqStmt->whileStmt;
					{
						int iSnrFnc = FuncName_GetNo(pWhileStmt->pCond->pFunc->pFuncName);
						int iArgsDist = Args_GetDist(pWhileStmt->pCond->pFunc->pArgs,                    addr + 1 + 1 + 3 + 3);
						int iSnrSeqBodyDist = SnrSeqBody_GetDist(pWhileStmt->pSnrSeqBody,                addr + 1 + 1 + 3 + 3);
						addr += Code_AddValue(pCode, pWhileStmt->pCond->bNot ? SnrSeq_while_not : SnrSeq_while, 1            );
						addr += Code_AddValue(pCode, iSnrFnc,                                                       1        );
						addr += Code_AddValue(pCode, iArgsDist,                                                         3    );
						addr += Code_AddValue(pCode, iSnrSeqBodyDist,                                                       3);
					}
				}
				break;
			case SnrSeqStmtType_Act:
				{
					ST_ActStmt* pActStmt = &pSnrSeqStmt->actStmt;
					{
						int iSnrFnc = FuncName_GetNo(pActStmt->pFunc->pFuncName);
						int iArgsDist = Args_GetDist(pActStmt->pFunc->pArgs,                      addr + 1 + 1 + 3);
						addr += Code_AddValue(pCode, pActStmt->bEnsure ? SnrSeq_act_ensure : SnrSeq_act, 1        );
						addr += Code_AddValue(pCode, iSnrFnc,                                                1    );
						addr += Code_AddValue(pCode, iArgsDist,                                                  3);
					}
				}
				break;
			}
			pSnrSeqStmtList = g_slist_next(pSnrSeqStmtList);
		}
		addr += Code_AddValue(pCode, SnrSeq_end, 1);	//忘れないで!!
	}
	{
		ST_Code* pOldCode = g_tree_lookup(tree_pSnrSeqBody_Code, pSnrSeqBody);
		if(pOldCode && ((pOldCode->addr != pCode->addr) || (pOldCode->code->len != pCode->code->len))) { DIE(); }	//1回目も2回目もアドレスとコードサイズは一致するはず。もしここで停止したら当ツールのバグです。
		if(pCode->code->len != (addr - pCode->addr)) { DIE(); }	//生成したコードのサイズとアドレスの増分は一致するはず。もしここで停止したら当ツールのバグです。
		g_tree_replace(tree_pSnrSeqBody_Code, pSnrSeqBody, pCode);
	}
	return addr;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//引数リストのコードを生成する。
//1回目:仮コードを生成してアドレスを割り当てる。
//2回目:本コードを生成する。
static int Args_CodeGen(ST_Args* pArgs, int addr) {
	ST_Code* pCode = Code_New(addr |= 3);	//【注意】引数リストの値の部分を4N境界に整列するために、サイズの部分を(4N+3)に格納するようにパディングする。
	{
		void* data/*NULL可*/;
		int   size/*0可*/;
		if(!g_tree_lookup_extended(tree_pArgs_Blob, pArgs, NULL, &data)) { DIE(); }	//既に引数リストのBLOBを構築済みであるはず。もしここで停止したら当ツールのバグです。
		size/*0可*/ = blob_get_size( data/*NULL可*/);
		addr += Code_AddValue(pCode,                 size/*0可*/, 1);	//(4N+3) サイズの部分
		addr += Code_AddData( pCode, data/*NULL可*/, size/*0可*/);	//4N境界 値の部分
	}
	{
		ST_Code* pOldCode = g_tree_lookup(tree_pArgs_Code, pArgs);
		if(pOldCode && ((pOldCode->addr != pCode->addr) || (pOldCode->code->len != pCode->code->len))) { DIE(); }	//1回目も2回目もアドレスとコードサイズは一致するはず。もしここで停止したら当ツールのバグです。
		if(pCode->code->len != (addr - pCode->addr)) { DIE(); }	//生成したコードのサイズとアドレスの増分は一致するはず。もしここで停止したら当ツールのバグです。
		g_tree_replace(tree_pArgs_Code, pArgs, pCode);
	}
	return addr;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void pass2(int bOptimize) {
	//シナリオテーブルラベルにシナリオテーブル番号を割り当てる。
	{
		int iSnrTbl = 0;
		GTreeIteratorNP iter;
		char* pSnrTblLabel;
		ST_SnrTbl* pSnrTbl;
		if(g_tree_first_np(tree_pSnrTbl, &iter, &pSnrTblLabel, &pSnrTbl)) {
			do {
				pSnrTbl->iSnrTbl = ++iSnrTbl;	//ST_SnrTbl構造体は辞書のキーにしないので作成後に内容を変更して問題無い。
			} while(g_tree_next_np(tree_pSnrTbl, &iter, &pSnrTblLabel, &pSnrTbl));
		}
	}
	//トリガ名にトリガ番号を割り当てる。
	{
		int iSnrTrg = SnrTrg_set;
		GTreeIteratorNP iter;
		char* pTrigName;
		if(g_tree_first_np(tree_pTrigName_No, &iter, &pTrigName, NULL)) {
			do {
				if(!strcmp(pTrigName, "set")) {
					g_tree_replace(tree_pTrigName_No, pTrigName, (void*)SnrTrg_set);	//g_tree_insert()でも同じだが、処理の意図を明確にするため、g_tree_replace()を使用した。
				} else if(!strcmp(pTrigName, "clr")) {
					g_tree_replace(tree_pTrigName_No, pTrigName, (void*)SnrTrg_clr);	//g_tree_insert()でも同じだが、処理の意図を明確にするため、g_tree_replace()を使用した。
				} else {
					if(++iSnrTrg >= SnrTrg_clr) {
						yyerror("トリガ名の数が制限を超えました。");
						DIE();	//継続しても無駄なので終了する。
					}
					g_tree_replace(tree_pTrigName_No, pTrigName, (void*)iSnrTrg);		//g_tree_insert()でも同じだが、処理の意図を明確にするため、g_tree_replace()を使用した。
				}
			} while(g_tree_next_np(tree_pTrigName_No, &iter, &pTrigName, NULL));
		}
	}
	//関数名に関数番号を割り当てる。
	{
		int iSnrFnc = 0;
		GTreeIteratorNP iter;
		char* pFuncName;
		if(g_tree_first_np(tree_pFuncName_No, &iter, &pFuncName, NULL)) {
			do {
				if(++iSnrFnc >= UINT8_MAX) {
					yyerror("関数名の数が制限を超えました。");
					DIE();	//継続しても無駄なので終了する。
				}
				g_tree_replace(tree_pFuncName_No, pFuncName, (void*)iSnrFnc);			//g_tree_insert()でも同じだが、処理の意図を明確にするため、g_tree_replace()を使用した。
			} while(g_tree_next_np(tree_pFuncName_No, &iter, &pFuncName, NULL));
		}
	}
	//引数リストのBLOBを構築する。
	// - この後でシナリオテーブルから再帰的に辿れない引数リストを除外するが、当処理はそれよりも前に行う事に注意せよ。
	//   削除される引数リストの中に不正な参照を含んだ引数リストが有る場合も、スクリプトとしてはエラーであるからです。
	{
		GTreeIteratorNP iter;
		ST_Args* pArgs;
		if(g_tree_first_np(tree_pArgs, &iter, &pArgs, NULL)) {
			do {
				void* data/*NULL可*/ = Args_BuildBlob(pArgs);		//┬引数リストが空だった場合、Args_BuildBlob()はNULLを返しますが・・・
				g_tree_insert(tree_pArgs_Blob, pArgs, data/*NULL可*/);	//┘ght_hash_table_tと違って、GTreeにはNULLの値も登録出来るので、NULLを特別扱いする必要は有りません。
			} while(g_tree_next_np(tree_pArgs, &iter, &pArgs, NULL));
		}
		if(yynerrs) { return; }	//エラーが発生していたら、ここまで。
	}
	//シナリオシーケンスの参照先のシナリオシーケンスが存在する事を確認する。
	// - この後でシナリオテーブルから再帰的に辿れないシナリオシーケンスを除外するが、当処理はそれよりも前に行う事に注意せよ。
	//   削除されるシナリオシーケンスの中に存在しないシナリオシーケンスが有る場合も、スクリプトとしてはエラーであるからです。
	{
		GTreeIteratorNP iter;
		ST_SnrSeq* pSnrSeq;
		if(g_tree_first_np(tree_pSnrSeq, &iter, NULL, &pSnrSeq)) {
			do {
				ST_SnrSeqBody* pSnrSeqBody = pSnrSeq->pSnrSeqBody;
				SnrSeqBody_Verify(pSnrSeqBody);
			} while(g_tree_next_np(tree_pSnrSeq, &iter, NULL, &pSnrSeq));
		}
		if(yynerrs) { return; }	//エラーが発生していたら、ここまで。
	}
	//シナリオテーブルから再帰的に辿れるシナリオシーケンスをマークする。
	{
		GTreeIteratorNP iter;
		ST_SnrTbl* pSnrTbl;
		if(g_tree_first_np(tree_pSnrTbl, &iter, NULL, &pSnrTbl)) {
			do {
				ST_SnrTblBody* pSnrTblBody = pSnrTbl->pSnrTblBody;
				SnrTblBody_Mark(pSnrTblBody);
			} while(g_tree_next_np(tree_pSnrTbl, &iter, NULL, &pSnrTbl));
		}
		if(yynerrs) { return; }	//エラーが発生していたら、ここまで。
	}
	//これ以降、もう、下記の辞書は参照しない。
	// - そのまま残しておいても構わないが、もし誤って参照した場合にすぐバグを発見出来るよう、NULLでクリアしておく事にした。
	{
	//使う	tree_pSnrTbl		= NULL;
		tree_pSnrSeq		= NULL;
	//使う	tree_pSnrSeq_Used	= NULL;
		tree_pArg		= NULL;
		tree_pArgList		= NULL;
		tree_pArgs		= NULL;
	//使う	tree_pArgs_Used		= NULL;
	//使う	tree_pArgs_Blob		= NULL;
	//使う	tree_pArgs_Code		= NULL;
		tree_pFunc		= NULL;
		tree_pCond		= NULL;
		tree_pCondSubs		= NULL;
		tree_pCondSubsList	= NULL;
		tree_pValueSubs		= NULL;
		tree_pValueSubsList	= NULL;
	//使う	tree_pSnrTblBody	= NULL;
	//使う	tree_pSnrTblBody_Code	= NULL;
		tree_pSnrTblStmt	= NULL;
		tree_pSnrSeqBody	= NULL;
	//使う	tree_pSnrSeqBody_Used	= NULL;
	//使う	tree_pSnrSeqBody_Code	= NULL;
		tree_pSnrSeqStmt	= NULL;
	//使う	tree_pTrigName_No	= NULL;
	//使う	tree_pFuncName_No	= NULL;
	}
	{
		//1回目:仮コードを生成してアドレスを割り当てる。
		//2回目:本コードを生成する。
		int i;
		for(i = 0; i < 2; i++) {
			int addr = 0;
			//シナリオテーブルボディ
			{
				GTreeIteratorNP iter;
				ST_SnrTblBody* pSnrTblBody;
				if(g_tree_first_np(tree_pSnrTblBody, &iter, &pSnrTblBody, NULL)) {
					do {
						addr = SnrTblBody_CodeGen(pSnrTblBody, addr);
					} while(g_tree_next_np(tree_pSnrTblBody, &iter, &pSnrTblBody, NULL));
				}
			}
			//シナリオシーケンスボディ
			{
				GTreeIteratorNP iter;
				ST_SnrSeqBody* pSnrSeqBody;
				if(g_tree_first_np(tree_pSnrSeqBody_Used, &iter, &pSnrSeqBody, NULL)) {
					do {
						addr = SnrSeqBody_CodeGen(pSnrSeqBody, addr);
					} while(g_tree_next_np(tree_pSnrSeqBody_Used, &iter, &pSnrSeqBody, NULL));
				}
			}
			//引数リスト
			{
				GTreeIteratorNP iter;
				ST_Args* pArgs;
				if(g_tree_first_np(tree_pArgs_Used, &iter, &pArgs, NULL)) {
					do {
						addr = Args_CodeGen(pArgs, addr);
					} while(g_tree_next_np(tree_pArgs_Used, &iter, &pArgs, NULL));
				}
			}
			//最終アドレスを格納する。
			if(i && (addr != endAddr)) { DIE(); }	//1回目も2回目も最終アドレスは一致するはず。もしここで停止したら当ツールのバグです。
			endAddr = addr;
		}
	}
	//最適化を行う。
	if(bOptimize) { optimize(); }
}
/*---------------------------------------------------------------------------*/
//最適化処理
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
static void optimize() {
	//最適化処理は有りません。
	//通常の処理で重複を取り除いてるので、通常の処理で最大限の最適化が行われているはずです。
	//今後、最適化機能を追加する場合のためのプレースホルダとして、関数のみ用意して有ります。
	//現在のところは、コマンドラインオプションに'-d'を指定してもしなくても違いは有りません。
}
/*---------------------------------------------------------------------------*/
//出力処理
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
static void output(const char* sBinOut, const char* sTblOut, int bLabTbl) {
	g_tree_remove(tree_pTrigName_No, "set");										//┬"set"と"clr"はライブラリ側で定義しているので、ここでは出力対象外とするために辞書から削除しておく。
	g_tree_remove(tree_pTrigName_No, "clr");										//┘ここでtree_pTrigName_Noを変更するので、当処理よりも後でtree_pTrigName_Noを参照しないよう注意せよ。
	//定義を出力する。
	{
		//C#形式
		if(!strcmp(opt_x, "cs")) {
			puts("static partial class Const {");
		}
		//ラベルを標準出力に出力する。
		{
			GTreeIteratorNP iter;
			char* pSnrTblLabel;
			ST_SnrTbl* pSnrTbl;
			puts("//シナリオテーブル");
			if(g_tree_first_np(tree_pSnrTbl, &iter, &pSnrTblLabel, &pSnrTbl)) {
				do {
					//C言語形式
					if(!strcmp(opt_x, "c")) {
						printf("#define SnrTblNo_%s %d\n", pSnrTblLabel, pSnrTbl->iSnrTbl);
					//C#形式
					} else if(!strcmp(opt_x, "cs")) {
						printf("public const int SnrTblNo_%s = %d;\n", pSnrTblLabel, pSnrTbl->iSnrTbl);
					} else {
						DIE();	//バグ
					}
				} while(g_tree_next_np(tree_pSnrTbl, &iter, &pSnrTblLabel, &pSnrTbl));
				//C言語形式
				if(!strcmp(opt_x, "c")) {
					printf("#define SnrTblNo_Max %d\n", pSnrTbl->iSnrTbl);					//シナリオテーブルが定義されている場合のみ最大値を出力する。
				//C#形式
				} else if(!strcmp(opt_x, "cs")) {
					printf("public const int SnrTblNo_Max = %d;\n", pSnrTbl->iSnrTbl);			//シナリオテーブルが定義されている場合のみ最大値を出力する。
				} else {
					DIE();	//バグ
				}
			}
		}
		//トリガ番号を標準出力に出力する。
		{
			GTreeIteratorNP iter;
			char* pTrigName;
			int iSnrTrg;
			if(g_tree_first_np(tree_pTrigName_No, &iter, &pTrigName, (void**)&iSnrTrg)) {
				puts("//トリガ");
				do {
					//C言語形式
					if(!strcmp(opt_x, "c")) {
						printf("#define SnrTrg_%s %d\n", pTrigName, iSnrTrg);
					//C#形式
					} else if(!strcmp(opt_x, "cs")) {
						printf("public const int SnrTrg_%s = %d;\n", pTrigName, iSnrTrg);
					} else {
						DIE();	//バグ
					}
				} while(g_tree_next_np(tree_pTrigName_No, &iter, &pTrigName, (void**)&iSnrTrg));
				//C言語形式
				if(!strcmp(opt_x, "c")) {
					printf("#define SnrTrg_Max %d\n", iSnrTrg);						//"set"と"clr"以外のトリガ名が定義されている場合のみ最大値を出力する。
				//C#形式
				} else if(!strcmp(opt_x, "cs")) {
					printf("public const int SnrTrg_Max = %d;\n", iSnrTrg);					//"set"と"clr"以外のトリガ名が定義されている場合のみ最大値を出力する。
				} else {
					DIE();	//バグ
				}
			}
		}
		//'-t'オプションが指定されていたら…
		if(sTblOut) {
			FILE* fp = fopen(sTblOut, "w");
			if(!fp) { error(EXIT_FAILURE, errno, "%s が作成できません。", sTblOut); }
			{
				GTreeIteratorNP iter;
				char* pFuncName;
				//C言語形式
				if(!strcmp(opt_x, "c")) {
					//関数宣言を標準出力に出力する。
					puts("//関数");
					if(g_tree_first_np(tree_pFuncName_No, &iter, &pFuncName, NULL)) {
						do {
							printf("#define SnrFnc_%s int SnrFnc_%s(struct _ST_SnrSeq* pSnrSeq, int iCh, int iSnrFnc, struct blob_reader* pArgs)\n", pFuncName, pFuncName);
						} while(g_tree_next_np(tree_pFuncName_No, &iter, &pFuncName, NULL));
						puts("#define SnrFnc_(name) SnrFnc_##name");										//関数名が定義されていなければ、SnrFnc_()マクロは定義しません。関数名が定義されていなければ、SnrFnc_()マクロの引数に指定する関数名も無いので、SnrFnc_()マクロを定義しても無駄だからです。
					}
					puts("#ifdef  __cplusplus");
					puts("extern \"C\" {");
					puts("#endif//__cplusplus");
					puts("struct _ST_SnrSeq;");		//P/ECE開発環境のCコンパイラ(GNU C Compiler for E0C33 Ver 2.7.2 (Rev 1.5))で、警告「warning: `struct _ST_SnrSeq' declared inside parameter list」が出るのを回避するために必要。
					puts("struct blob_reader;");		//P/ECE開発環境のCコンパイラ(GNU C Compiler for E0C33 Ver 2.7.2 (Rev 1.5))で、警告「warning: `struct blob_reader' declared inside parameter list」が出るのを回避するために必要。
					if(g_tree_first_np(tree_pFuncName_No, &iter, &pFuncName, NULL)) {
						do {
							printf("SnrFnc_(%s);\n", pFuncName);
						} while(g_tree_next_np(tree_pFuncName_No, &iter, &pFuncName, NULL));
					}
					puts("extern int (* const TBL_SnrFnc[])(struct _ST_SnrSeq* pSnrSeq, int iCh, int iSnrFnc, struct blob_reader* pArgs);");	//関数名が定義されていなくても、TBL_SnrFnc[]配列は定義します。関数の数が0(=TBL_SnrFnc[]の要素数が1)である事をアプリケーションが認識するために、TBL_SnrFnc[]を読み出す必要が有るからです。
					puts("#ifdef  __cplusplus");
					puts("}//extern \"C\"");
					puts("#endif//__cplusplus");
					//関数テーブルをファイルに出力する。
					fprintf(fp, "struct _ST_SnrSeq;\n");	//P/ECE開発環境のCコンパイラ(GNU C Compiler for E0C33 Ver 2.7.2 (Rev 1.5))で、警告「warning: `struct _ST_SnrSeq' declared inside parameter list」が出るのを回避するために必要。
					fprintf(fp, "struct blob_reader;\n");	//P/ECE開発環境のCコンパイラ(GNU C Compiler for E0C33 Ver 2.7.2 (Rev 1.5))で、警告「warning: `struct blob_reader' declared inside parameter list」が出るのを回避するために必要。
					if(g_tree_first_np(tree_pFuncName_No, &iter, &pFuncName, NULL)) {
						do {
							fprintf(fp, "int SnrFnc_%s(struct _ST_SnrSeq* pSnrSeq, int iCh, int iSnrFnc, struct blob_reader* pArgs);\n", pFuncName);
						} while(g_tree_next_np(tree_pFuncName_No, &iter, &pFuncName, NULL));
					}
					fprintf(fp, "int (* const TBL_SnrFnc[])(struct _ST_SnrSeq* pSnrSeq, int iCh, int iSnrFnc, struct blob_reader* pArgs)={(void*)%d", g_tree_nnodes(tree_pFuncName_No) + 1);	//先頭要素に関数配列の要素数を格納する。
					if(g_tree_first_np(tree_pFuncName_No, &iter, &pFuncName, NULL)) {
						do {
							fprintf(fp, "\n,SnrFnc_%s", pFuncName);
						} while(g_tree_next_np(tree_pFuncName_No, &iter, &pFuncName, NULL));
					}
					fprintf(fp, "};\n");
				//C#形式
				} else {
					//関数宣言を標準出力に出力する。	⇒C#にはヘッダファイルとソースファイルを分離する概念は無いので、関数宣言を標準出力に出力する処理は不要です。
					/** no job **/
					//関数テーブルをファイルに出力する。
					error(EXIT_FAILURE, errno, "'-t'オプションと'-xcs'オプションの併用は未実装です。");	//※TODO:未実装
				}
			}
			fclose(fp);
		//'-t'オプションが指定されていなければ…
		} else {
			//関数番号を標準出力に出力する。
			{
				GTreeIteratorNP iter;
				char* pFuncName;
				int iSnrFnc;
				if(g_tree_first_np(tree_pFuncName_No, &iter, &pFuncName, (void**)&iSnrFnc)) {
					puts("//関数");
					do {
						//C言語形式
						if(!strcmp(opt_x, "c")) {
							printf("#define SnrFnc_%s %d\n", pFuncName, iSnrFnc);
						//C#形式
						} else if(!strcmp(opt_x, "cs")) {
							printf("public const int SnrFnc_%s = %d;\n", pFuncName, iSnrFnc);
						} else {
							DIE();	//バグ
						}
					} while(g_tree_next_np(tree_pFuncName_No, &iter, &pFuncName, (void**)&iSnrFnc));
					//C言語形式
					if(!strcmp(opt_x, "c")) {
						printf("#define SnrFnc_Max %d\n", iSnrFnc);						//関数名が定義されている場合のみ最大値を出力する。
					//C#形式
					} else if(!strcmp(opt_x, "cs")) {
						printf("public const int SnrFnc_Max = %d;\n", iSnrFnc);					//関数名が定義されている場合のみ最大値を出力する。
					} else {
						DIE();	//バグ
					}
				}
			}
		}
		//C#形式
		if(!strcmp(opt_x, "cs")) {
			puts("}");
		}
	}
	//データを出力する。
	{
		GByteArray* pLabTblArr;
		GArray*     pAddrTbl;
		GByteArray* pCodeArr;
		//バイナリ形式とテキスト形式の共通処理…
		{
			//ラベルテーブルの配列を作成する。
			{
				pLabTblArr = g_byte_array_new();
				//シナリオテーブル
				{
					if(bLabTbl) {					//ラベルテーブルを格納するならば…
						GTreeIteratorNP iter;
						char* pSnrTblLabel;
						if(g_tree_first_np(tree_pSnrTbl, &iter, &pSnrTblLabel, NULL)) {
							do {
								g_byte_array_append(pLabTblArr, pSnrTblLabel, strlen(pSnrTblLabel) + 1/*nul*/);
							} while(g_tree_next_np(tree_pSnrTbl, &iter, &pSnrTblLabel, NULL));
						}
					}
					g_byte_array_append(pLabTblArr, "", 1/*nul*/);	//ラベルテーブルを格納しない場合も終端のnulは格納する事にした。アプリケーションの観点からは空のラベルテーブルとなり構造上は同じと見なせてアプリケーションが作り易くなるから。(nul×3+パディング)で4バイトのオーバーヘッドが生じるが問題無いだろう。
				}
				//トリガ
				{
					if(bLabTbl) {					//ラベルテーブルを格納するならば…
						GTreeIteratorNP iter;
						char* pTrigName;
						if(g_tree_first_np(tree_pTrigName_No, &iter, &pTrigName, NULL)) {
							do {
								g_byte_array_append(pLabTblArr, pTrigName, strlen(pTrigName) + 1/*nul*/);
							} while(g_tree_next_np(tree_pTrigName_No, &iter, &pTrigName, NULL));
						}
					}
					g_byte_array_append(pLabTblArr, "", 1/*nul*/);	//ラベルテーブルを格納しない場合も終端のnulは格納する事にした。アプリケーションの観点からは空のラベルテーブルとなり構造上は同じと見なせてアプリケーションが作り易くなるから。(nul×3+パディング)で4バイトのオーバーヘッドが生じるが問題無いだろう。
				}
				//関数
				{
					if(bLabTbl) {					//ラベルテーブルを格納するならば…
						GTreeIteratorNP iter;
						char* pFuncName;
						if(g_tree_first_np(tree_pFuncName_No, &iter, &pFuncName, NULL)) {
							do {
								g_byte_array_append(pLabTblArr, pFuncName, strlen(pFuncName) + 1/*nul*/);
							} while(g_tree_next_np(tree_pFuncName_No, &iter, &pFuncName, NULL));
						}
					}
					g_byte_array_append(pLabTblArr, "", 1/*nul*/);	//ラベルテーブルを格納しない場合も終端のnulは格納する事にした。アプリケーションの観点からは空のラベルテーブルとなり構造上は同じと見なせてアプリケーションが作り易くなるから。(nul×3+パディング)で4バイトのオーバーヘッドが生じるが問題無いだろう。
				}
				//命令コード内の引数リストの値の部分の4N境界への整列は、命令コードの先頭を基準にして行われているので、命令コードの先頭を4Nに整列しておく必要が有る。
				//従って、ラベルテーブルの配列のサイズを4Nまでパディングする。
				while(pLabTblArr->len & 3) { g_byte_array_append(pLabTblArr, "", 1/*nul*/); }
			}
			//アドレステーブルの配列を作成する。
			{
				pAddrTbl = g_array_new(1, 1, sizeof(int));
				{
					GTreeIteratorNP iter;
					ST_SnrTbl* pSnrTbl;
					int value = g_tree_nnodes(tree_pSnrTbl) + 1;	//TBL_SnrTblNo[0]=(SnrTblNo_Max+1)	ラベルは1ベースなので+1する事に注意せよ。
					g_array_append_val(pAddrTbl, value);
					if(g_tree_first_np(tree_pSnrTbl, &iter, NULL, &pSnrTbl)) {
						do {
							ST_Code* pSnrTblBodyCode = g_tree_lookup(tree_pSnrTblBody_Code, pSnrTbl->pSnrTblBody);
							if(!pSnrTblBodyCode) { DIE(); }	//もしここで停止したら当ツールのバグです。
							value = pLabTblArr->len + pSnrTblBodyCode->addr;
							g_array_append_val(pAddrTbl, value);
						} while(g_tree_next_np(tree_pSnrTbl, &iter, NULL, &pSnrTbl));
					}
				}
			}
			//命令コードの配列を作成する。
			{
				pCodeArr = g_byte_array_new();
				//シナリオテーブルボディ
				{
					GTreeIteratorNP iter;
					ST_SnrTblBody* pSnrTblBody;
					if(g_tree_first_np(tree_pSnrTblBody, &iter, &pSnrTblBody, NULL)) {
						do {
							ST_Code* pSnrTblBodyCode;
							if(!(pSnrTblBodyCode = g_tree_lookup(tree_pSnrTblBody_Code, pSnrTblBody))) { DIE(); }	//もしここで停止したら当ツールのバグです。
							if(pCodeArr->len != pSnrTblBodyCode->addr) { DIE(); }	//もしここで停止したら当ツールのバグです。
							g_byte_array_append(pCodeArr, pSnrTblBodyCode->code->data, pSnrTblBodyCode->code->len);
						} while(g_tree_next_np(tree_pSnrTblBody, &iter, &pSnrTblBody, NULL));
					}
				}
				//シナリオシーケンスボディ
				{
					GTreeIteratorNP iter;
					ST_SnrSeqBody* pSnrSeqBody;
					if(g_tree_first_np(tree_pSnrSeqBody_Used, &iter, &pSnrSeqBody, NULL)) {
						do {
							ST_Code* pSnrSeqBodyCode;
							if(!(pSnrSeqBodyCode = g_tree_lookup(tree_pSnrSeqBody_Code, pSnrSeqBody))) { DIE(); }	//もしここで停止したら当ツールのバグです。
							if(pCodeArr->len != pSnrSeqBodyCode->addr) { DIE(); }	//もしここで停止したら当ツールのバグです。
							g_byte_array_append(pCodeArr, pSnrSeqBodyCode->code->data, pSnrSeqBodyCode->code->len);
						} while(g_tree_next_np(tree_pSnrSeqBody_Used, &iter, &pSnrSeqBody, NULL));
					}
				}
				//引数リスト
				{
					GTreeIteratorNP iter;
					ST_Args* pArgs;
					if(g_tree_first_np(tree_pArgs_Used, &iter, &pArgs, NULL)) {
						do {
							ST_Code* pArgsCode;
							if(!(pArgsCode = g_tree_lookup(tree_pArgs_Code, pArgs))) { DIE(); }	//もしここで停止したら当ツールのバグです。
							{ static const unsigned char padding[3]; g_byte_array_append(pCodeArr, padding, ~pCodeArr->len & 3); }	//【注意】引数リストの値の部分を4N境界に整列するために、サイズの部分を(4N+3)に格納するようにパディングする。
							if(pCodeArr->len != pArgsCode->addr) { DIE(); }	//もしここで停止したら当ツールのバグです。
							g_byte_array_append(pCodeArr, pArgsCode->code->data, pArgsCode->code->len);
						} while(g_tree_next_np(tree_pArgs_Used, &iter, &pArgs, NULL));
					}
				}
				if(pCodeArr->len != endAddr) { DIE(); }	//もしここで停止したら当ツールのバグです。
			}
		}
		//バイナリ形式の場合…
		if(sBinOut) {
			FILE* fp = fopen(sBinOut, "wb");
			if(!fp) { error(EXIT_FAILURE, errno, "%s が作成できません。", sBinOut); }
			//アドレステーブルを出力する。
			{
				fwrite(pAddrTbl->data, sizeof(int), pAddrTbl->len, fp);
			}
			//ラベルテーブルを出力する。
			{
				fwrite(pLabTblArr->data, 1, pLabTblArr->len, fp);
			}
			//命令コードを出力する。
			{
				fwrite(pCodeArr->data, 1, pCodeArr->len, fp);
			}
			fclose(fp);
		//テキスト形式の場合…
		} else {
			//C#形式
			if(!strcmp(opt_x, "cs")) {
				puts("static partial class Const {");
			}
			//アドレステーブルを出力する。
			{
				//C言語形式
				if(!strcmp(opt_x, "c")) {
					printf("const int TBL_SnrTblNo[%d]={", pAddrTbl->len);
				//C#形式
				} else if(!strcmp(opt_x, "cs")) {
					printf("public static readonly int[/*%d*/] TBL_SnrTblNo={", pAddrTbl->len);
				} else {
					DIE();	//バグ
				}
				{
					int i;
					for(i = 0; i < pAddrTbl->len; i++) {
						if(!(i & 15)) { putchar('\n'); }
						printf("0x%08X", g_array_index(pAddrTbl, int, i));
						if(i != (pAddrTbl->len - 1)) { putchar(','); }
					}
				}
				puts("};");
			}
			//ラベルテーブルと命令コードを出力する。
			{
				//C言語形式
				if(!strcmp(opt_x, "c")) {
					printf("const unsigned char TBL_SnrSeq[%d+%d]={", pLabTblArr->len, endAddr);
				//C#形式
				} else if(!strcmp(opt_x, "cs")) {
					printf("public static readonly byte[/*%d+%d*/] TBL_SnrSeq={", pLabTblArr->len, endAddr);
				} else {
					DIE();	//バグ
				}
				{
					int i;
					if(!pLabTblArr->len) { DIE(); }	//バグ
					for(i = 0; i < pLabTblArr->len; i++) {
						if(!(i & 31)) { putchar('\n'); }
						printf("0x%02X", pLabTblArr->data[i]);
						if(i != (pLabTblArr->len - 1)) { putchar(','); }
					}
					if(pCodeArr->len) { putchar(','); }
					for(i = 0; i < pCodeArr->len; i++) {
						if(!(i & 31)) { putchar('\n'); }
						printf("0x%02X", pCodeArr->data[i]);
						if(i != (pCodeArr->len - 1)) { putchar(','); }
					}
				}
				puts("};");
			}
			//C#形式
			if(!strcmp(opt_x, "cs")) {
				puts("}");
			}
		}
	}
}
