/*****************************************************************************
 * Bison/Flexプログラム部分をテストするための、Windowsアプリケーションの雛型 *
 * □ビルド・実行方法:                                                       *
 * ┃"C:\Program Files (x86)\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT"  *
 * ┃make -f winapp.mk run                                                   *
 *****************************************************************************/
#include "winapp.h"
/*---------------------------------------------------------------------------*/
#define Label_Max   50000	/* ラベル登録最大数 */		//調整可
#define Inst_Max  1000000	/* 命令登録最大数 */		//調整可
typedef struct _ST_Inst {
	uint16_t line;		/* 行番号 */			//1パス目で格納する。エラーメッセージのためだけに使用する。
	uint16_t op;		/* 命令コード */		//1パス目で格納する。goto,callの場合は、相対位置フィールドを0にしておき、2パス目で設定する。
	char* lab;		/* 分岐先ラベル */		//goto,callの場合に、1パス目で格納する。
} ST_Inst;
static ST_Inst TBL_Inst[Inst_Max];	/* 命令配列 */
static int nInst;			/* 命令配列の格納数 */
static char* TBL_Label[Label_Max];	/* ラベル配列 */
static int nLabel;			/* ラベル配列の格納数 */
//ローカルラベル
static int nAtmarkLocalLabel;		/* '@'ローカルラベルの出現数 */		//'def @@'が出現したら、'@%d'という形式の内部ローカルラベルに変換して、ハッシュテーブルに登録する。その後、+1する。要するに、次に出現するローカルラベルの番号を表していると見なせるので、'goto @F'や'call @F'からは、nAtmarkLocalLabelで参照できる。'goto @B'や'call @B'からは、(nAtmarkLocalLabel-1)で参照できる。
static char* sDotLocalLabelPrefix = "";	/* '.'ローカルラベルのプレフィクス */	//'.～'が出現したら、'%s.～'という形式の内部ローカルラベルに変換する。グローバルラベルの定義が出現したら、sDotLocalLabelPrefixを更新する。結果として、グローバルラベル定義～グローバルラベル定義の間でのローカルラベルとなる。
/*---------------------------------------------------------------------------*/
//エラーログ用
static char err_path[_MAX_PATH];	//'-e'オプションが指定されたら、エラーログファイル名を格納する。
static FILE* fp_err;			//最初のエラーログを記録する時に、エラーログファイルを作成する。
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) { die("%s が作成できません。\n", err_path); }
		//エラーログファイルの出力ストリームは、バッファリング無しとする。
		// - die()で終了した時(abort()時)に、バッファ分がフラッシュされないようなので、こうしておく必要が有る。
		//   別の案として、この下の処理で毎回fflush()する方法も有るが、バッファリング無しとする方が簡単だろう。
		setbuf(fp_err, NULL);
	}
	//エラーメッセージ(,及び,エラーログ)を出力する。
	             fprintf(stderr, "### error at line %d : ", yylineno);	//エラーメッセージ
	if(fp_err) { fprintf(fp_err, "### error at line %d : ", yylineno); }	//エラーログ
	{
		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); }	//エラーログ
}
/*---------------------------------------------------------------------------*/
/* ローカル関数宣言 */
__declspec(noreturn) static void usage();
static ST_Inst* add_inst();
static void pass2(int bOptimize);
static void optimize();
static void output(char* sPrefix, char* sBinOut);
/*---------------------------------------------------------------------------*/
int main(int argc, char* argv[]) {
	int opt, bOptimize = 1;	//'-d'オプションが指定されなければ最適化を行う。
	char* sPrefix = "";	//'-p'オプションが指定されたらプレフィクス文字列を設定する。
	char* sBinOut = NULL;	//'-o'オプションが指定されたらバイナリ出力ファイル名を設定する。
#if     (YYDEBUG!=0)
//	yydebug = 1; /* nonzero means print parse trace */
#endif/*(YYDEBUG!=0)*/
	/* コマンドラインオプションを処理する。 */
	opterr = 0; /* オプションエラーは当プログラム内で処理するので、getopt()内でのエラー表示は不要。 */
	while((opt = getopt(argc, argv, "dp:o:eh")) != -1) {
		switch(opt) {
		case 'd':
			bOptimize = 0;		//最適化を行わない。
			break;
		case 'p':
			sPrefix = optarg;	//プレフィクス文字列を設定する。
			break;
		case 'o':
			sBinOut = optarg;	//バイナリ出力ファイル名を設定する。
			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 'h':
		default:
			usage();
		}
	}
	/* ラベルを登録するためのハッシュテーブルを作成する。 */
	hcreate(Label_Max);
	/* 判り易さのために、命令位置0は使用しないことにした。命令位置0には、ダミーのend命令を置くことにした。 */
	inst_end();
	//--- 1パス目の処理 ---
	/* ファイルが指定されていなければ、標準入力から読み込む。 */
	if(optind == argc) {
		yylex_init(stdin);
	    //{{2015/02/24修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
	    //	if((yyparse() != 0) || (yynerrs != 0)) { die("エラーが発生しました。\n"); }
	    //↓2015/02/24修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
		if((yyparse() != 0) /*|| (yynerrs != 0)*/) { die("エラーが発生しました。\n"); }
	    //}}2015/02/24修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
	/* ファイルが指定されていたら、各ファイルを読み込む。 */
	} else {
		int i;
		for(i = optind; i < argc; i++) {
			FILE* fp = fopen(argv[i], "r");
			if(!fp) { die("%s が開けません。\n", argv[i]); }
			yylex_init(fp);
		    //{{2015/02/24修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
		    //	if((yyparse() != 0) || (yynerrs != 0)) { die("%s: エラーが発生しました。\n", argv[i]); }
		    //↓2015/02/24修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
			if((yyparse() != 0) /*|| (yynerrs != 0)*/) { die("%s: エラーが発生しました。\n", argv[i]); }
		    //}}2015/02/24修正:致命的なエラーが発生した場合(yyparse()!=0)のみ中断する。セマンティクスエラー(yynerrs!=0)だけならば全てのセマンティクスエラーを報告するために継続する。
			fclose(fp);
		}
	}
	//1パス目の処理でエラーが発生しても、2パス目の処理を行って、全てのセマンティクスエラーを報告する。
	//--- 2パス目の処理 ---
	pass2(bOptimize);
	if(yynerrs != 0) { die("エラーが発生しました。\n"); }	//1パス目,又は,2パス目の処理でエラーが発生していたら、出力処理を行わない。
	//--- 出力処理 ---
	output(sPrefix, sBinOut);
	if(yynerrs != 0) { die("エラーが発生しました。\n"); }
	return EXIT_SUCCESS;
}
/*---------------------------------------------------------------------------*/
/* 使い方を表示して終了する。 */
__declspec(noreturn) static void usage() {
	fprintf(stderr, "dRudSeqC - パルスモーターの台形制御シーケンサコンパイラ (%s)\n", VERSION);
	fprintf(stderr, "Copyright (C) 2015 Naoyuki Sawa\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "USAGE:\n");
	fprintf(stderr, "  dRudSeqC [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, "  -p文字列     ラベルに、プレフィクス文字列を追加します。\n");
	fprintf(stderr, "               このオプションを指定しなければ、プレフィクス文字列を追加しません。\n");
	fprintf(stderr, "  -oファイル名 モーター制御のバイナリデータを、バイナリ形式でファイルへ出力します。\n");
	fprintf(stderr, "               このオプションを指定しなければ、Cソース形式で標準出力へ出力します。\n");
	fprintf(stderr, "               このオプションの指定に関らず、ラベルは常に標準出力へ出力します。\n");
	fprintf(stderr, "  -e           エラーログファイルを生成します。\n");
	fprintf(stderr, "               このオプションを指定しても、エラーが発生しなければ生成されません。\n");
	fprintf(stderr, "  -h           使い方を表示します。\n");
	fprintf(stderr, "\n");
	fprintf(stderr, "EXAMPLE:\n");
	fprintf(stderr, "  ①dRudSeqC.exe -pRudSeqNo_ RudDef.txt > RudDef.c\n");
	fprintf(stderr, "  　RudDef.txtをコンパイルして、RudDef.cへ出力します。\n");
	fprintf(stderr, "  　ラベルのプレフィクス文字列として、RudSeqNo_を追加します。\n");
	fprintf(stderr, "  ②dRudSeqC.exe -pRudSeqNo_ -oRudDef.bin RudDef.txt > RudDef.h\n");
	fprintf(stderr, "  　RudDef.txtをコンパイルして、ラベルをRudDef.hへ出力します。\n");
	fprintf(stderr, "  　モーター制御のバイナリデータを、RudDef.binへ出力します。\n");
	exit(EXIT_FAILURE);
}
/*---------------------------------------------------------------------------*/
/* 1パス目の処理 */
#define s10_Min (( int16_t)0xFE00)	/*{{2014/11/28追加:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。}}*/
#define s10_Max (( int16_t)0x01FF)	/*{{2014/11/28追加:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。}}*/
#define u10_Max (( int16_t)0x03FF)	/*{{2014/11/28追加:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。}}*/
#define s12_Min (( int16_t)0xF800)
#define s12_Max (( int16_t)0x07FF)
#define u12_Max ((uint16_t)0x0FFF)
#define u15_Max ((uint16_t)0x7FFF)
static ST_Inst* add_inst() {
	ST_Inst* pInst;
	if((unsigned)nInst >= Inst_Max) {
		yyerror("命令数が制限を超えました。(%d)", Inst_Max);
		exit(EXIT_FAILURE);
	}
	pInst = &TBL_Inst[nInst++];
	pInst->line = yylineno;		/* 行番号 */
	return pInst;
}
void inst_def(char* lab) {
	ENTRY item;
    //{{ローカルラベルの処理
	if(lab[0] == '@') {
		if(lab[1] == '@') {	//'@@'
			lab = strdup_printf("@%d", nAtmarkLocalLabel++);	//内部ローカルラベルに変換して、ハッシュテーブルに登録する。その後、+1する。
		} else {		//'@B','@F'
			yyerror("defのラベル定義が不正です。(%s)", lab);
			yynerrs++;	/* 呼び出し元(main)に知らせるために */
			/* 全てのセマンティクスエラーを報告するために継続する */
		}
	} else if(lab[0] == '.') {
		lab = strconcat(sDotLocalLabelPrefix, lab, NULL);		//内部ローカルラベルに変換する。
	} else {
		sDotLocalLabelPrefix = lab;					//グローバルラベルの定義が出現したら、sDotLocalLabelPrefixを更新する。
	}
    //}}ローカルラベルの処理
	item.key = (char*)lab;
	if(hsearch(item, FIND)) {
		yyerror("defのラベル定義が重複しています。(%s)", lab);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	item.data = (void*)nInst;
	if(!hsearch(item, ENTER)) {
		yyerror("ラベル数が制限を超えました。(%d)", Label_Max);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
    //{{ローカルラベルの処理
	if((lab[0] == '@') ||			//'@'ローカルラベル('@%d')		//┬内部ローカルラベルは、#defineに出力しない。
	   strchr(lab, '.')) { return; }	//'.'ローカルラベル('%s.～')		//┘
    //}}ローカルラベルの処理
	if(nLabel < Label_Max) {
		TBL_Label[nLabel++] = lab;	//hsearch()はイテレーションの機能が無いので、後でイテレートするためにはキー配列を別に作成しておく必要が有る。
	}
}
void inst_end() {
	ST_Inst* pInst = add_inst();
	pInst->op = RudSeq_Inst_end;
}
void inst_goto(char* lab) {
	ST_Inst* pInst = add_inst();
    //{{ローカルラベルの処理
	if(lab[0] == '@') {
		if(lab[1] == 'B') {		//'@B'
			lab = strdup_printf("@%d", nAtmarkLocalLabel - 1);	//'goto @B'や'call @B'からは、(nAtmarkLocalLabel-1)で参照できる。もし'def @@'が出現する前に@Bを参照した場合は-1になってしまうが、2パス目に未定義ラベルとしてエラー検出できるはずであり、安全です。
		} else if(lab[1] == 'F') {	//'@F'
			lab = strdup_printf("@%d", nAtmarkLocalLabel);		//'goto @F'や'call @F'からは、nAtmarkLocalLabelで参照できる。もしこの後に'def @@'が出現しなければ存在しない内部ローカルラベルを参照してしまうが、2パス目に未定義ラベルとしてエラー検出できるはずであり、安全です
		} else {			//'@@'
			yyerror("gotoのラベル参照が不正です。(%s)", lab);
			yynerrs++;	/* 呼び出し元(main)に知らせるために */
			/* 全てのセマンティクスエラーを報告するために継続する */
		}
	} else if(lab[0] == '.') {
		lab = strconcat(sDotLocalLabelPrefix, lab, NULL);		//内部ローカルラベルに変換する。
	}
    //}}ローカルラベルの処理
	pInst->op = RudSeq_Inst_goto(0);	/* 相対位置フィールドは、2パス目で設定する。 */
	pInst->lab = lab;
}
void inst_call(char* lab) {
	ST_Inst* pInst = add_inst();
    //{{ローカルラベルの処理
	if(lab[0] == '@') {
		if(lab[1] == 'B') {		//'@B'
			lab = strdup_printf("@%d", nAtmarkLocalLabel - 1);	//'goto @B'や'call @B'からは、(nAtmarkLocalLabel-1)で参照できる。もし'def @@'が出現する前に@Bを参照した場合は-1になってしまうが、2パス目に未定義ラベルとしてエラー検出できるはずであり、安全です。
		} else if(lab[1] == 'F') {	//'@F'
			lab = strdup_printf("@%d", nAtmarkLocalLabel);		//'goto @F'や'call @F'からは、nAtmarkLocalLabelで参照できる。もしこの後に'def @@'が出現しなければ存在しない内部ローカルラベルを参照してしまうが、2パス目に未定義ラベルとしてエラー検出できるはずであり、安全です
		} else {			//'@@'
			yyerror("callのラベル参照が不正です。(%s)", lab);
			yynerrs++;	/* 呼び出し元(main)に知らせるために */
			/* 全てのセマンティクスエラーを報告するために継続する */
		}
	} else if(lab[0] == '.') {
		lab = strconcat(sDotLocalLabelPrefix, lab, NULL);		//内部ローカルラベルに変換する。
	}
    //}}ローカルラベルの処理
	pInst->op = RudSeq_Inst_call(0);	/* 相対位置フィールドは、2パス目で設定する。 */
	pInst->lab = lab;
}
void inst_repeat(int num) {
	ST_Inst* pInst = add_inst();
//{{2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
//	if((unsigned)num > u12_Max) {
//↓2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
	if((unsigned)num > u10_Max) {
//}}2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
		yyerror("repeatの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_repeat(num);
}
void inst_speed(int num) {
	ST_Inst* pInst = add_inst();
//{{2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
//	if((unsigned)num > u12_Max) {
//↓2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
	if((unsigned)num > u10_Max) {
//}}2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
		yyerror("speedの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_speed(num);
}
void inst_move_init() {
	ST_Inst* pInst = add_inst();
	pInst->op = RudSeq_Inst_move_init;
}
void inst_move_rel(int num) {
	ST_Inst* pInst = add_inst();
//{{2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
//	if((num < s12_Min) || (num > s12_Max)) {
//↓2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
	if((num < s10_Min) || (num > s10_Max)) {
//}}2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
		yyerror("move relの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_move_rel(num);
}
void inst_move_abs(int num) {
	ST_Inst* pInst = add_inst();
//{{2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
//	if((num < s12_Min) || (num > s12_Max)) {
//↓2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
	if((num < s10_Min) || (num > s10_Max)) {
//}}2014/11/28変更:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。
		yyerror("move absの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_move_abs(num);
}
void inst_move_stop() {
	ST_Inst* pInst = add_inst();
	pInst->op = RudSeq_Inst_move_stop;
}
void inst_wait_rel(int num) {
	ST_Inst* pInst = add_inst();
	if((unsigned)num > u12_Max) {
		yyerror("wait relの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_wait_rel(num);
}
void inst_wait_abs(int num) {
	ST_Inst* pInst = add_inst();
	if((unsigned)num > u15_Max) {
		yyerror("wait absの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_wait_abs(num);
}
void inst_wait_stop() {
	ST_Inst* pInst = add_inst();
	pInst->op = RudSeq_Inst_wait_stop;
}
void inst_user(int num) {
	ST_Inst* pInst = add_inst();
	if((unsigned)num > (u12_Max - 4)) {
		yyerror("userの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_user(num);
}
/*{{2014/11/28追加:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。*/
void inst_move_direct(int num, int if_cond, int until_cond) {
	ST_Inst* pInst = add_inst();
	if((num < s10_Min) || (num > s10_Max)) {
		yyerror("move directの引数が範囲外です。(%d)", num);
		yynerrs++;	/* 呼び出し元(main)に知らせるために */
		/* 全てのセマンティクスエラーを報告するために継続する */
	}
	pInst->op = RudSeq_Inst_move_direct(num, if_cond, until_cond);
}
/*}}2014/11/28追加:パルスモーターの直接制御を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。*/
/*{{2014/12/12追加:条件分岐'if on','if off'を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。*/
void inst_if_on() {
	ST_Inst* pInst = add_inst();
	pInst->op = RudSeq_Inst_if_on;
}
void inst_if_off() {
	ST_Inst* pInst = add_inst();
	pInst->op = RudSeq_Inst_if_off;
}
/*}}2014/12/12追加:条件分岐'if on','if off'を追加したことに伴い、シーケンサの命令セット,命令コード,命令コード定義用マクロを変更しました。*/
/*---------------------------------------------------------------------------*/
/* 2パス目の処理 */
static void pass2(int bOptimize) {
	int iInst, iDist;
	//全ての命令の相対位置ラベル名を、相対位置ラベルが指す命令へのポインタに変換する。
	for(iInst = 0; iInst < nInst; iInst++) {
		ST_Inst* pInst = &TBL_Inst[iInst];
		yylineno = pInst->line;		/* yyerrorのために */
		/* goto,又は,callならば… */
		if(pInst->lab) {
			ENTRY item, *pEntry;
			item.key = (char*)pInst->lab;
			if(!(pEntry = hsearch(item, FIND))) {
				yyerror("goto,又は,callのラベルが未定義です。(%s)", pInst->lab);
				yynerrs++;	/* 呼び出し元(main)に知らせるために */
				/* 全てのセマンティクスエラーを報告するために継続する */
			} else {
				iDist = (int)pEntry->data - iInst;
				if((iDist < s12_Min) || (iDist > s12_Max)) {
					yyerror("goto,又は,callの距離が範囲外です。(%s)", iDist);
					yynerrs++;	/* 呼び出し元(main)に知らせるために */
					/* 全てのセマンティクスエラーを報告するために継続する */
				} else {
					if(pInst->op & u12_Max) { DIE(); } /* バグ */
					pInst->op |= (iDist & u12_Max);
				}
			}
		}
	}
}
static void optimize() {
	//2015/02/24現在、最適化処理は有りません。
	//今後、最適化機能を追加する場合のためのプレースホルダとして、関数のみ用意して有ります。
	//現在のところは、コマンドラインオプションに'-d'を指定してもしなくても違いは有りません。
}
/*---------------------------------------------------------------------------*/
/* 出力処理 */
static int Label_compar(const void* x, const void* y) {
	return strcmp(*(char**)x, *(char**)y);
}
static void output(char* sPrefix, char* sBinOut) {
	int iLabel, iInst;
	ENTRY item, *pEntry;
	//ラベル定義を名前の昇順にソートする。
	qsort(TBL_Label, nLabel, sizeof(char*), Label_compar);
	//--- ラベルを標準出力に出力する ---
	for(iLabel = 0; iLabel < nLabel; iLabel++) {				//名前の昇順	ラベル=0(ダミー)は定義しない。
		char* label = TBL_Label[iLabel];
		printf("#define %s%s %d\n", sPrefix, label, iLabel + 1);	//ラベルは1ベース
	}
	if(*sPrefix) { printf("#define %sMax %d\n", sPrefix, nLabel); }		//プレフィクス文字列が有る場合のみ最大値を定義する。(プレフィクス文字列が無ければ定義しない。'Max'という単純なマクロ定義になり問題が有るから。)
	//--- データを出力する ---
	//バイナリ形式の場合…
	if(sBinOut) {
		FILE* fp = fopen(sBinOut, "wb");
		if(!fp) { die("%s が作成できません。\n", sBinOut); }
		//アドレステーブルを出力する。
		for(iLabel = -1; iLabel < nLabel; iLabel++) {
			int addr;
			if(iLabel < 0) {
    //{{2015/03/02変更:TBL_RudSeqNo[0]に(RudSeqNo_Max+1)を格納するようにしました。
    //				addr = 0;					//ラベル番号=0(ダミー)
    //↓2015/03/02変更:TBL_RudSeqNo[0]に(RudSeqNo_Max+1)を格納するようにしました。
				addr = nLabel + 1;				//TBL_RudSeqNo[0]=(RudSeqNo_Max+1)	ラベルは1ベースなのでnLabelではなく(nLabel+1)とする事に注意せよ。
    //}}2015/03/02変更:TBL_RudSeqNo[0]に(RudSeqNo_Max+1)を格納するようにしました。
			} else {
				char* label = TBL_Label[iLabel];
				item.key = label;
				if(!(pEntry = hsearch(item, FIND))) { DIE(); }	//バグ
				addr = (int)pEntry->data;
			}
			fwrite(&addr, sizeof(int), 1, fp);
		}
		//命令コードの出力を行う。
		for(iInst = 0; iInst < nInst; iInst++) {
			ST_Inst* pInst = &TBL_Inst[iInst];
			int data = pInst->op;
			fwrite(&data, sizeof(unsigned short), 1, fp);
		}
		fclose(fp);
	//テキスト形式の場合…
	} else {
		//アドレステーブルを出力する。
		printf("const int TBL_RudSeqNo[%d]={", nLabel + 1);
		for(iLabel = -1; iLabel < nLabel; iLabel++) {
			int addr;
			if(iLabel < 0) {
    //{{2015/03/02変更:TBL_RudSeqNo[0]に(RudSeqNo_Max+1)を格納するようにしました。
    //				addr = 0;					//ラベル番号=0(ダミー)
    //↓2015/03/02変更:TBL_RudSeqNo[0]に(RudSeqNo_Max+1)を格納するようにしました。
				addr = nLabel + 1;				//TBL_RudSeqNo[0]=(RudSeqNo_Max+1)	ラベルは1ベースなのでnLabelではなく(nLabel+1)とする事に注意せよ。
    //}}2015/03/02変更:TBL_RudSeqNo[0]に(RudSeqNo_Max+1)を格納するようにしました。
			} else {
				char* label = TBL_Label[iLabel];
				item.key = label;
				if(!(pEntry = hsearch(item, FIND))) { DIE(); }	//バグ
				addr = (int)pEntry->data;
			}
			if((iLabel & 15) == 15)    { putchar('\n'); }
			printf("0x%08X", addr);
			if(iLabel != (nLabel - 1)) { putchar(',' ); }
		}
		puts("};");
		//命令コードの出力を行う。
		printf("const unsigned short TBL_RudSeq[%d]={", nInst);
		for(iInst = 0; iInst < nInst; iInst++) {
			ST_Inst* pInst = &TBL_Inst[iInst];
			int data = pInst->op;
			if(  iInst      ) { putchar(',' ); }
			if(!(iInst & 31)) { putchar('\n'); }
			printf("0x%04X", data);
		}
		puts("};");
	}
}
