/*****************************************************************************
 * Bison/Flexプログラム部分をテストするための、Windowsアプリケーションの雛型 *
 * □ビルド・実行方法:                                                       *
 * ┃"C:\Program Files (x86)\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT"  *
 * ┃make -f winapp.mk run                                                   *
 *****************************************************************************/
#ifndef __WINAPP_H__
#define __WINAPP_H__
/*{{定型コード:winapp.h======================================================*/
#include <clip.h>
/* y.tab.y */
extern int yynerrs;
#if     (YYDEBUG!=0)
extern int yydebug;
#endif/*(YYDEBUG!=0)*/
int yyparse();
void yyerror(const char* fmt, ...);
/* lex.yy.l */
extern FILE* yyin;
extern FILE* yyout;
extern int yylineno;
int yylex();
void yylex_init(FILE* input_file);
/*}}定型コード:winapp.h======================================================*/
/*---------------------------------------------------------------------------*/
/* 構造体定義 */
typedef struct _ST_Table {
	struct _ST_LabelRow*	labelRow;
	struct _ST_Blocks*	blocks;
} ST_Table;
typedef struct _ST_Blocks {
	int			n;
	struct _ST_Block**	TBL_block/*[n]*/;
} ST_Blocks;
typedef struct _ST_Block {
	struct _ST_Header*	header;
	struct _ST_Body*	body;
} ST_Block;
typedef struct _ST_Header {
	int			n;
	struct _ST_HeaderRow**	TBL_headerRow/*[n]*/;
} ST_Header;
typedef struct _ST_Body {
	int			n;
	struct _ST_BodyRow**	TBL_bodyRow/*[n]*/;
} ST_Body;
typedef struct _ST_LabelRow {
	int			line;		//行番号。エラーメッセージのためだけに使用する。
	char*			label;
} ST_LabelRow;
typedef struct _ST_HeaderRow {
	int			line;		//行番号。エラーメッセージのためだけに使用する。
	struct _ST_Values*	colIds;
} ST_HeaderRow;
typedef struct _ST_BodyRow {
	int			line;		//行番号。エラーメッセージのためだけに使用する。
	int			hitVal;
	struct _ST_Values*	weights;
} ST_BodyRow;
typedef struct _ST_Values {
	int			n;
	int*			TBL_value/*[n]*/;	//-1=空白
} ST_Values;
/*---------------------------------------------------------------------------*/
/* グローバル関数宣言 */
ST_Table* Table_newBlocks(ST_LabelRow* labelRow, ST_Blocks* blocks);
ST_Table* Table_newBody(ST_LabelRow* labelRow, ST_Body* body);
ST_Blocks* Blocks_add(ST_Blocks* blocks, ST_Block* block);
ST_Block* Block_new(ST_Header* header, ST_Body* body);
ST_Header* Header_add(ST_Header* header, ST_HeaderRow* headerRow);
ST_Body* Body_add(ST_Body* body, ST_BodyRow* bodyRow);
ST_LabelRow* LabelRow_new(char* label);
ST_HeaderRow* HeaderRow_new(ST_Values* colIds);
ST_BodyRow* BodyRow_new(int hitVal, ST_Values* weights);
ST_Values* Values_add(ST_Values* values, int value);
int ColId_new(int num);
int HitVal_new(int num);
int Weight_new(int num);
char* LabDef_new(char* lab);
int LabRef_new(char* lab);	//{{抽選表idを自己参照できるように。}}
void add_table(ST_Table* table);
/*---------------------------------------------------------------------------*/
/*--- 変更履歴 ---*/
// * Mon Feb 16 21:32:48 JST 2015 Naoyuki Sawa
// - 1st リリース。
// * Sat Feb 21 13:26:55 JST 2015 Naoyuki Sawa
// - 前バージョンでは、シフト還元衝突が起きていたのを見落としていました。
//   具体的には、allの「all eols」と、bodyRowの「hitVal ',' weights eols」が衝突していました。
//   前者を「eols」に変更して修正しました。
// - colId,hitVal,weightに、抽選表idを自己参照できるようにしました。
//   そのために、labelRowは先頭に':'を必要とするよう、文法を変更しました。
//   labelRowを明示する方法が無いと、bodyRowの継続とlabelRowを区別できず、シフト還元衝突が発生するからです。
//   本当は「labelRow : T_LAB ':' T_EOL」にしたいのですが、これではT_LABを読んだ時点でシフト還元衝突します。
//   仕方無く「labelRow : ':' T_LAB T_EOL」にしました。DOSのバッチっぽい書き方なので不自然ではないでしよう。
// - 当ツール自身が抽選表idを扱うようになったので、「clip/tool/MkLotTblNo.awk,MkLotTblNo.bat」は不要になりました。
//   もう、MkLotTblNo.awk,MkLotTblNo.batは不要なのですが、これまで安定して動作していたので、
//   今後の参考のために、「clip/keep/12_MkLotTblNo_bat_MkLotTblNo_awk_削除前保存.20150221」に保存しておきました。
// * Sun Feb 22 10:11:58 JST 2015 Naoyuki Sawa
// - '-o'オプションを追加しました。
//   これまでは、バイナリデータが必要な場合、Cソース形式で出力してからCSrc2Rom.bat等でバイナリ変換していましたが、
//   今後は、当ツールから直接バイナリデータを出力することが出来るようになりました。
// - これまで、1パス目でセマンティクスエラーが発生した時に、継続せずに終了してしまっていました。
//   1パス目の処理を修正し、致命的なエラーが発生した場合(yyparse()!=0)のみ、処理を打ち切るように修正しました。
//   セマンティクスエラー(yynerrs!=0)だけならば、全てのセマンティクスエラーを報告するために、処理を継続します。
// * Sun Mar 01 22:44:33 JST 2015 Naoyuki Sawa
// - 最適化のバグを修正しました。
//   前回のバージョンまでは、最適化処理にてTBL_TableData[]をmemcmp()する比較サイズをsizeof(uint16_t)倍するのを忘れていて、一致しないテーブルデータまで一致と見なして最適化してしまっていました。
//   今回のバージョンで上記を修正し、sizeof(uint16_t)倍するようにして、正しく比較するようになりました。
// - 先行して「`」を書くと数字で始められるラベル定義方法，'@'ローカルラベル，'.'ローカルラベルを対応しました。
//   これらの仕様は他のツール(dDirSeqC.exe等)と同じですので、それらのコメントを参照してください。
// - ローカルラベルの使用方法としては、抽選表の当選値や重み値に抽選表idを入れる時に、それらの抽選表idをローカルラベルとして定義する事が出来ます。
//   こうすると、大分類/小分類の抽選表を作成する時に、小分類の抽選表の名前を短くする事ができます。
//   大分類a,小分類a1,小分類a2,小分類a3,大分類b,小分類b1,小分類b2,小分類b3の順で抽選表を定義すれば、小分類の抽選表をローカルラベルとする事で、名前が被っていても良く、名前を短く出来るからです。
// - ローカルラベルは#defineには出力されませんが、LotTblNo_Maxの数には含まれ、アドレステーブルにも出力される事に注意してください。
//   詳しくは、output()の「アドレステーブルを出力する。」の部分のコメントを参照してください。
// * Mon Mar 02 21:47:20 JST 2015 Naoyuki Sawa
// - TBL_LotTblNo[0]に(LotTblNo_Max+1)を格納するようにしました。
//   アプリケーションは「TBL_LotTbl=&TBL_LotTblNo[TBL_LotTblNo[0]]」でデータの先頭位置を求められるようになりました。
//   ヘッダファイルを見なくてもバイナリだけを見て処理できるようにするためです。
//   尚、LotTblNo_Maxの定義もこれまで通りヘッダファイルに出力していますので、LotTblNo_Maxもこれまで通り使用可能です。
//   LotTblNo_Maxを使ってデータの先頭位置を求める場合は「TBL_LotTbl=&TBL_LotTblNo[(LotTblNo_Max+1)]」としてください。
// * Fri Mar 06 21:00:56 JST 2015 Naoyuki Sawa
// - '-e'オプションを追加しました。
//   標準エラー出力をリダイレクトすると、進捗表示と混ざって見づらかったので、ログファイルを生成できるようにしました。
// * Sun Mar 15 21:44:53 JST 2015 Naoyuki Sawa
// - 当選値を昇順にソートして出力する事にしました。変更箇所はpass2()の中です。変更理由は以下の通りです。
//   抽選表の行が極端に多い場合に、LOT_get_column_weight(),及び,それを呼び出す各関数の実行時間が極端に長くなる問題が生じました。
//   問題を回避するために、LOT_get_column_weight()をリニアサーチ⇒バイナリサーチに変更しました。
//   LOT_get_column_weight()がバイナリサーチを行うために、当選値が昇順に並んでいる必要が有るので、当ツールの処理も変更しました。
// - 当選値が重複していたらエラーとする事にしました。変更箇所はpass2()の中です。変更理由は以下の通りです。
//   これまで、当選値が重複していても、エラーも警告も発する事は無くそのまま出力していました。
//   当選値が重複していても処理上の問題は無く、LOT_draw_column()は行の順に処理するだけですし、LOT_get_column_weight()は同じ当選値の先に現れた行を参照するだけだからです。
//   しかし実際には、当選値が重複している抽選表は、入力バグである可能性が高く、早めに検出しておく方が良いと思ったからです。
//   LOT_draw_column()やLOT_get_column_weight()の処理上は当選値が重複していても問題無いのですが、敢えて、重複した当選値をエラーとして検出する事にしました。
// - '-i'オプションを追加しました。上記を警告に留めエラーとしません。
//   意図的に重複した当選値の行を含む抽選表を変換する場合は、'-i'オプションを指定してください。
//   ただし、重複した当選値の行を含む抽選表に対してLOT_get_column_weight()を使用すると、間違った結果になる危険が高いので注意してください。
//   例えば、(当選値1,重み値2)の列と、(当選値1,重み値3)の行が有り、後者に当選した場合に、LOT_get_column_weight(当選値1)を行うと、どちらの重み値が返されるかが判らないからです。
// * Mon Mar 16 21:19:10 JST 2015 Naoyuki Sawa
// - '抽選表idの自己参照を解決する処理'を、'抽選列idの重複チェック','当選値を昇順にソート','当選値の重複チェック'より先に行うように修正しました。
//   これまでは、それらよりも後で行っていたため、'抽選表idの自己参照を解決した結果'が'値で指定された抽選列id'に偶然一致した場合に、重複エラーを検出できないというバグが有りました。
//   また、当選値として'抽選表idの自己参照'を使用していた場合に、当選値を昇順にソートした結果が不正になるというバグが有りました。
//   いずれのバグも、抽選列idや当選値として'抽選表idの自己参照'を使用した場合のみ顕在化するバグであり、実際に問題が出た事は無かったのですが、バグはバグなので修正する事にしました。
// * Tue Mar 24 21:58:56 JST 2015 Naoyuki Sawa
// - Weight_new()のエラーメッセージが間違っていたので修正しました。
/* バージョン定義 */
#define VERSION "20150324"
/*---------------------------------------------------------------------------*/
#endif/*__WINAPP_H__*/
