/*****************************************************************************
 * 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.c */
void push_location(const char* path);
void pop_location();
/*}}定型コード:winapp.h======================================================*/
//-----------------------------------------------------------------------------
//構造体定義
//-----------------------------------------------------------------------------
//列挙型ライン
typedef struct _ST_EnumLine {
	char*		pSym;				//シンボル				NULL不可
	int		bIncr;				//0=値指定,1=オートインクリメント
	int		iVal;				//値					bIncr=1(オートインクリメント)の場合はiVal=0(ダミー)とする。
	char*		pDesc;				//説明文				NULL不可。説明文無しならば""とする。
} ST_EnumLine;
//列挙型ボデイ
typedef struct _ST_EnumBody {
	int		nEnumLine;			//列挙型ライン数
	ST_EnumLine*	aEnumLine[/*nEnumLine*/];	//列挙型ライン配列
} ST_EnumBody;
//列挙型
typedef struct _ST_Enum {
	char*		pLabel;				//ラベル				NULL不可
	ST_EnumBody*	pEnumBody;			//列挙型ボディ				NULL不可
} ST_Enum;
//-----------------------------------------------------------------------------
//グローバル関数宣言
//-----------------------------------------------------------------------------
int cast_dbl_to_int(double d);
void addEnum(ST_Enum* pEnum);
ST_Enum* Enum_new(char* pLabel, ST_EnumBody* pEnumBody);
//{{2016/07/07変更:空の列挙型を許容するように変更しました。
//ST_EnumBody* EnumBody_new(ST_EnumLine* pEnumLine);
//↓2016/07/07変更:空の列挙型を許容するように変更しました。
ST_EnumBody* EnumBody_new();
//}}2016/07/07変更:空の列挙型を許容するように変更しました。
ST_EnumBody* EnumBody_addEnumLine(ST_EnumBody* pEnumBody, ST_EnumLine* pEnumLine);
ST_EnumLine* EnumLine_new(char* pSym, int bIncr, int iVal, char* pDesc);
//-----------------------------------------------------------------------------
//変更履歴
//-----------------------------------------------------------------------------
// * Fri Jan 01 21:14:34 JST 2016 Naoyuki Sawa
// - 作成開始。
// * Sat Jan 02 21:26:28 JST 2016 Naoyuki Sawa
// - ラベル番号を出力しないようにしました。
// - これまでは、当ツールがラベルに連番を振って出力していましたが、今後は、ラベルに番号を振るのはレジストリスクリプトコンパイラに任せる事にしました。
//   変更した理由は、アプリケーションのビルド全体で、当ツールを複数回使用出来るようにするためです。
//   当ツールがラベルに連番を振ると、アプリケーションのビルド全体で、当ツールを一回しか使えません。
//   変更後は、複数の列挙定義スクリプトに対して個別に複数回当ツールを適用し、その結果をまとめてレジストリスクリプトコンパイラに投入する事が出来ます。
// * Sun Jan 03 21:17:56 JST 2016 Naoyuki Sawa
// - セパレータ文字列を固定にしました。
//   しばらく使ってみて、セパレータ文字列を変更する必要性は無いと思ったからです。
//   この変更に伴い、'-s'オプションを廃止しました。
// * Sun Jan 10 21:20:52 JST 2016 Naoyuki Sawa
// - 列挙定義のラベルを、名前の昇順にソートして出力するようにしました。
//   意味上の影響は有りません。出力テキストの見易さのためだけです。
// - '-n'オプションを追加しました。
//   ソートを行うようになった事に伴い、ソート方法を選択するためです。
// * Sun Feb 21 21:02:01 JST 2016 Naoyuki Sawa
// - libclipのライブラリ化の伴い、以下の変更を行いました。
//   ・extclip.hとextclip.cを削除しました。extclip.hとextclip.cはlibclipに含まれるようになったからです。
//   ・"CLiP Files"を削除しました。CLiPライブラリの各モジュールはlibclipに含まれるようになったからです。
//   当ツールの動作には変更有りません。
// * Tue Mar 01 21:34:55 JST 2016 Naoyuki Sawa
// - clipstd.hにてC4131の警告レベルを引き上げましたが、Bison/Flexの生成コードには旧スタイルの宣言が使われているので、Bison/Flexの生成コードのみ警告レベルを元に戻しました。
// * Sun Apr 24 21:05:43 JST 2016 Naoyuki Sawa
// - 2016/04/23に、/clip/clipstd.hにparsonとLibYAMLのインクルードを追加した事に伴い、当プロジェクトにもparsonとLibYAMLのインクルードパスとライブラリパスの設定を追加しました。
//   当プロジェクトはparsonもLibYAMLも使用していませんが、インクルードパスとライブラリパスの設定を追加しないとビルドエラーになるからです。
// - libclip.lib,gc.lib,pthreadVC2(d).lib,sqlite.lib,pdcurses.libのリンク指定を、/clip/libclip/extclip.hで指定するようにし、個別のアプリケーション設定からは削除しました。
//   parson.lib,yaml.libのリンク指定を、/clip/clipstd.hで指定するようにし、個別のアプリケーション設定からは削除しました。
// * Mon Apr 25 22:45:55 JST 2016 Naoyuki Sawa
// - 実数の計算式に対応しました。
//   暗黙の型変換のルールは、C言語と同じです。
//   キャスト演算子は、'(int)'と'(double)'のみ対応しています。
// - あくまでも途中計算で実数の計算式が使えるだけであり、最終的には整数にキャストする必要が有る事に注意して下さい。
//   例は、/clip/tool/dTexDefC/winapp.hの同日のコメントを参照して下さい。
// * Tue Apr 26 22:39:26 JST 2016 Naoyuki Sawa
// - 実数の計算式から、整数引数への、暗黙の型変換を対応しました。
//   '-w'オプションを指定しなければ、C言語と同様に、警告無しで処理します。
//   '-w'オプション,又は,'-wcast'オプションを指定すると、暗黙の型変換によって誤差が発生した時のみ警告を表示し、最終的にエラー終了します。
//   C言語と違って、誤差が発生しなかった時は警告を表示しない事に注意して下さい。
// - 上記の変更のために、'-w'オプションを処理する仕組みとして、getsubopt()を導入しました。
//   今後、他の種類の警告を追加する時は、この仕組みを使って警告を追加出来ます。
// * Thu Jun 09 21:26:53 JST 2016 Naoyuki Sawa
// - lex.yy.lにて、数値(T_NUM)の解析を、既存の10進数と16進数に加えて、新しく8進数と2進数も解析出来るようにしました。
// * Sat Jul 02 21:34:21 JST 2016 Naoyuki Sawa
// - 2016/06/14に、/clip/clipstd.hに'#pragma comment(lib, "liblua.lib")'を追加した事に伴い、当プロジェクトにもlibluaのライブラリパスの設定を追加しました。
//   現在の所、当プロジェクトはlibluaを使用していませんが、インクルードパスとライブラリパスの設定を追加しないとビルドエラーになるからです。
//   尚、libluaのインクルードパスは以前から設定していたので、今回、追加したのはlibluaのライブラリパスのみです。
// - 2016/07/01に、/clip/libclip/extclip.hに'#include <sqlite3.h>'と'#pragma comment(lib, "sqlite3.lib")'を追加した事に伴い、当プロジェクトにもsqlite3のインクルードパスとライブラリパスの設定を追加しました。
//   現在の所、当プロジェクトはsqlite3を使用していませんが、インクルードパスとライブラリパスの設定を追加しないとビルドエラーになるからです。
// * Thu Jul 07 21:12:07 JST 2016 Naoyuki Sawa
// - 空の列挙型を許容するように変更しました。
//   これまでは、
//   │Foo
//   │end
//   のような空の列挙型を定義すると、エラーとしていました。(厳密には、y.tab.yのルールで弾いていました。)
//   今後は、上記のような空の列挙型も許容するように、y.tab.yのルール,及び,winapp.cの処理を変更しました。
// - 変更した理由は、スプライトやAfxBinの列挙定義で、それらが一つも無い場合でも、プログラムが列挙定義のレジストリキーを参照するために、レジストリキーは生成したい場合が生じたからです。
//   具体的には、空の列挙定義:
//   │Foo
//   │end
//   から、空のレジストリテーブル:
//   │EnmDef
//   │  Foo
//   │  end
//   │end
//   を生成して、レジストリコンパイラにRegKey_Fooを生成させたい場合が生じました。
//   レジストリコンパイラは既に、空のレジストリテーブルを許容している(最適化してデータからは削除するがRegKey_Fooの定義は出力する)ので、問題無いのですが、
//   列挙定義コンパイラが空の列挙型を許容していなかったので、列挙定義コンパイラがエラーになる問題が生じました。
//   そこで、列挙定義コンパイラが空の列挙型を許容するように変更しました。
// - 今後は、空の列挙型に対して、列挙定義コンパイラはエラーとせず、上記のような空のレジストリテーブルを生成するようになりました。
//   また、最大値の定義としては、「#define ラベル_Max -1」を出力します。
//   通常は特に支障は無いと思うのですが、もし、アプリケーションが最大値を"符号無し"で比較すると予期しない結果になる恐れが有るので、注意して下さい。
// * Sun Jul 10 11:29:13 JST 2016 Naoyuki Sawa
// - y.tab.yのint_argの文法規則の最後に、「;」が抜けていたミスを修正しました。
//   bison.exeはこのような単純なミスを自動的に補ってくれるので、bison.exeのエラーにもならず、生成したプログラムの動作上も問題無く、これまで気付きませんでした。
//   しかし、間違った記述であった事には違い無いので、修正しておく事にしました。
// * Sun Sep 11 21:23:51 JST 2016 Naoyuki Sawa
// - 空の列挙型の警告メッセージが、進捗表示で上書きされて消えてしまっていた問題を修正しました。
//   これまでは改行していなかったのを、改行するように変更しただけです。
// * Fri Sep 16 21:30:10 JST 2016 Naoyuki Sawa
// - '-q'オプションを追加しました。
//   /clip/test.win/を元にしたプロジェクトで、VC++6.0のカスタムビルドから呼び出された場合に、'\r'による同じ行の重ね書きが上手く認識されず、VC++6.0の出力ペインに進捗表示が多く出過ぎて、その他の重要なエラーが見づらくなってしまう問題を避けるためです。
//   基本的には、VC++6.0のカスタムビルドから呼び出す場合だけに'-q'オプションを使用し、コマンドラインから呼び出す場合はこれまで通り'-q'オプションは指定しなくて構いません。
// * Wed Sep 21 21:20:16 JST 2016 Naoyuki Sawa
// - die(〜)で終了していた箇所を、error(EXIT_FAILURE,〜)で終了するように変更しました。
//   変更した理由は、以下の通りです。
// - die()は、標準エラー出力がコンソールでなければ、エラーメッセージをメッセージボックスで表示します。
//   通常はそれが望ましい動作なのですが、VC++6.0やVS2015のカスタムビルドとして当ツールを呼び出した場合に、使い辛い問題が生じます。
//   VC++6.0やVS2015は、カスタムビルドとして呼び出すツールの標準エラー出力をリダイレクトして、アウトプットウインドウに表示します。
//   標準エラー出力がコンソールでないので、当ツールはエラー終了する場合に、メッセージボックスを表示します。
//   結果として、カスタムビルドとして呼び出したツールがエラーになると、いちいちメッセージボックスを表示して停止し、使い辛い問題が生じました。
//   元々、die()が標準エラー出力がコンソールでなければエラーメッセージをメッセージボックスで表示するようにした理由は、コマンドプロンプトを持たないウインドウアプリケーションのためであり、
//   当ツールのようなコンソールアプリケーションの標準エラー出力がリダイレクトされた場合にメッセージボックスを表示する必要はあまり有りません。
//   そこで、当ツールがエラー終了する時にdie()を呼び出すのをやめて、error()で終了するように変更する事にしました。
// * Sun Sep 25 21:05:26 JST 2016 Naoyuki Sawa
// - /clip/test.win/lex.yy.lの'popen'対応処理を、当ツールのlex.yy.lにマージしました。
//   当ツールの'popen'対応は必須ではないのですが、本日dFsmMapC.exeに上記の変更を行ったついでに当ツールも対応しておく事にしました。
// - エラーメッセージに、現在の行番号だけでなく、現在のファイル名も表示するようにしました。
//   エラーメッセージの形式は、VC++6.0に合わせて、「ファイル名(行番号) : エラーメッセージ」としました。
// * Wed Sep 28 21:26:44 JST 2016 Naoyuki Sawa
// - error()の文字列の最後に余計な改行が付いていたのを削除しました。
//   error()は指定された文字列の後に(もし有ればエラー名を挟んで)自動的に改行を出力するので、アプリケーション側で文字列の最後に改行を付けると、文字列とエラー名の間に余計な改行が出力されたり、二回改行してしまう問題が生じていました。
// * Sun Oct 02 21:48:17 JST 2016 Naoyuki Sawa
// - ";"によるマルチステートメントに対応しました。
//   変更箇所は、lex.yy.lの「\n { return T_EOL; }」の上の行に、「";" |」を追加しただけです。
// - マルチステートメント対応が必要になった理由は、主にdDirSeqC.exeのためです。
//   Cプリプロセッサで一つのマクロで複数のact命令を生成する時に、Cプリプロセッサの制限のために複数行に分けられないからです。
//   今回マルチステートメントを対応した事によって、「act 〜; act 〜; act 〜」のように一行で複数のact命令が可能になりました。
//   dDirSeqC.exe以外のツールについては、今すぐにマルチステートメント対応が必要な訳ではないのですが、上述の通り変更箇所は少ないので、他のツールも一緒に変更しておく事にしました。
// * Mon Feb 27 22:08:56 JST 2017 Naoyuki Sawa
// - '-xc','-xcs'オプションを追加しました。
//   詳細は、/clip/tool/dRegTblC/winapp.hの同日のコメントを参照して下さい。
// * Thu Mar 16 23:39:55 JST 2017 Naoyuki Sawa
// - 複数の入力ファイルを指定した時に、最後以外のファイルでエラーが発生した場合、当ツールの終了ステータスが0になっていたバグを修正しました。
//   正しくは一つの入力ファイルででもエラーが発生したら、当ツールの終了ステータスを非0とするのが正しい動作です。
//   今回の修正によって、正しい動作になりました。
//   バグが発生していた原因は、以下の通りです。
// - 「yyparse()がyynerrsを0にリセットする」という事を、これまで知りませんでした。	←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←【【【【【重要】】】】】
//   これまで、yyparse()を複数回呼び出してもyynerrsはリセットされず累積されて行くと思っていたのですが、それは間違いでした。
//   上記の勘違いのために、1パス目の処理において複数回yyparse()を呼び出した場合に、毎回yynerrsがリセットされており、最後のyyparse()以外でyynerrsがセットされた場合、次のyyparse()呼び出しで(意図せず)yynerrsがクリアされてしまっていました。
//   (これまで気づかなかった理由は、dEnmDefC.exeを直接呼び出さずにMkEnmDef.batを経由して使用しており、MkEnmDef.batは入力ファイルを一つに連結してdEnmDefC.exeするので、たまたまバグが顕在化していなかったからです。)
//   前述の通り、「yyparse()がyynerrsを0にリセットする」というのが実際のBison/Flexの生成コードの動作なので、複数回yyparse()を呼び出す場合は、アプリケーション側で明示的にyynerrsを累積する必要が有るのでした。
//   今回の修正では、yyparse()を呼び足す前にyynerrsを保存しておき、yyparse()が処理を返した後に(今回のyyparse()が0から数えたであろう)yynerrsに対して、先ほど保存しておいたyynerrsを足し込むという方法を取りました。
//   アプリケーション側でyynerrsを累積する新たな変数を設けなかった理由は、アプリケーション側のコードでyynerrsを参照している箇所が多く、それらを新たな変数への参照に書き換えるのは変更箇所が多くなり過ぎて危険だと思ったからです。
//   動作の結果としては、今回の修正方法でも同じ結果になるはずなので、動作上は問題有りません。
// - ちなみに、「if((yyparse() != 0) /*|| (yynerrs != 0)*/) { 」としている処理の、後半のコメントアウトを解除しても今回のバグは修正出来るのですが、その方法は取りませんでした。
//   後半のコメントアウトの理由は、致命的なエラーが発生しない限り全てのファイルをパースして出来るだけ多くのエラーをまとめて検出したいのでそうしていたという経緯があり、その動作は変更したくないからです。
// - 前述の通り、「yyparse()がyynerrsを0にリセットする」という事をこれまで知らなかったのが、今回のバグの原因なのですが、改めてWeb上の情報等を探してみても、そのような説明がなされている資料を見付ける事が出来ませんでした。
//   もしかすると、Bison/Flexのバージョンによって、異なる動作をする可能性も有ります。
//   現在使用しているBison/Flexのバージョンは、UnxUtilsに入っていたBison「GNU Bison version 1.28」，Flex「flex version 2.5.4」ですが、もし今後Bison/Flexのバージョンを変更する場合は、動作が違わないか要注意です。
//   (とは言え、万一、別のバージョンのBison/Flexで、yyparse()がyynerrsをリセットしなくなったとしても、今回の変更による影響は、エラー回数を二重に足し込んでしまう事になるだけで、ツールの動作上は問題無いはずです。)
//-----------------------------------------------------------------------------
//バージョン定義
//-----------------------------------------------------------------------------
#define VERSION "20170316"
//-----------------------------------------------------------------------------
#endif/*__WINAPP_H__*/
