/*
 *	clipfsm.h
 *
 *	有限状態機械
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Sat Jun 20 18:44:16 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sun Jun 21 22:22:12 JST 2015 Naoyuki Sawa
 *	- 当モジュールで使用するデータを生成するための、有限状態機械マップコンパイラを作りました。
 *	  /clip/tool/dFsmMapC/を参照してください。
 *	* Mon Jun 29 21:48:11 JST 2015 Naoyuki Sawa
 *	- 遷移の名前が同じで、ガード条件が異なる、遷移セットを定義出来るようにしました。
 *	  優先順位は、「SMC - The State Machine Compiler」(http://smc.sourceforge.net/)を参考にさせて頂きました。
 *	    1-1-1. 現在の状態の、指定された遷移の、ガードが有る遷移で、ガード条件が成立した遷移	複数有る場合は順不同。現在の実装ではガード名の順としているが、その挙動に依存してはいけない。
 *	    1-1-2. 現在の状態の、指定された遷移の、ガードが無い遷移
 *	    1-2-1. 状態マップの、指定された遷移の、ガードが有る遷移で、ガード条件が成立した遷移	複数有る場合は順不同。現在の実装ではガード名の順としているが、その挙動に依存してはいけない。
 *	    1-2-2. 状態マップの、指定された遷移の、ガードが無い遷移
 *	    2-1-1. 現在の状態の、デフォルト遷移の、ガードが有る遷移で、ガード条件が成立した遷移	複数有る場合は順不同。現在の実装ではガード名の順としているが、その挙動に依存してはいけない。
 *	    2-1-2. 現在の状態の、デフォルト遷移の、ガードが無い遷移
 *	    2-2-1. 状態マップの、デフォルト遷移の、ガードが有る遷移で、ガード条件が成立した遷移	複数有る場合は順不同。現在の実装ではガード名の順としているが、その挙動に依存してはいけない。
 *	    2-2-2. 状態マップの、デフォルト遷移の、ガードが無い遷移
 *	  上記の順に検索して、実行できる遷移がなかった場合は、エラー停止します。
 *	  詳細は、/clip/tool/dFsmMapC/Sample/Sample.txt の例を参照してください。
 *	* Wed Jul 01 21:16:16 JST 2015 Naoyuki Sawa
 *	- FsmObj_CancelTrans()を追加しました。
 *	  FsmObj_ApplyTrans()から呼び出された、Act関数の中から、遷移をキャンセル出来るようになりました。
 *	- 原則として遷移をキャンセルするのは、Guard関数で判断すべきです。
 *	  しかし実際には、Act関数まで処理が進んでから、遷移をキャンセルしたいケースも有ります。(エラー検出や例外処理など)
 *	  そのようなケースに対応するために、FsmObj_CancelTrans()を追加する事にしました。
 *	- Act関数がFsmObj_CancelTrans()を使って遷移をキャンセルする事と、Guard関数が遷移を受け入れない事は、等価ではありません。
 *	  Act関数がFsmObj_CancelTrans()を使って遷移をキャンセルした場合、上記の優先順位に従った次の遷移を検索する動作は行われない事に注意してください。
 *	- FsmObj_CancelTrans()を呼び出せるのは、Act関数の中からだけです。
 *	  Enter関数,Leave関数,Guard関数の中から、呼び出してはいけません。
 *	- Act関数の中で、遷移をキャンセルすると共に、明示的に状態をセット(又は,プッシュ,ポップ)を行う事も可能です。
 *	  <例>
 *	  │Map1
 *	  │  State1
 *	  │    Trans1 State2 {}
 *	  │  end
 *	  │  State2
 *	  │    ...
 *	  │  end
 *	  │  StateE
 *	  │    ...
 *	  │  end
 *	  │end
 *	  ├────────────────────────────────────────
 *	  │void FsmFunc_Map1_State1_act(ST_FsmObj* pFsmObj, int iTrans, void* pParam) {
 *	  │  if(例外判定) {
 *	  │    FsmObj_SetState(pFsmObj, FsmState_StateE);┬明示的に状態'StateE'をセットし、
 *	  │    FsmObj_CancelTrans(); ──────────┘State2への遷移をキャンセルする。
 *	  │} }
 *	* Fri Jul 03 21:00:32 JST 2015 Naoyuki Sawa
 *	- FsmObj_CancelTrans()を削除しました。
 *	  今後は構造化例外処理(SEH)を使用してください。
 *	  構造化例外処理(SEH)を使用する方が、より柔軟に制御出来ます。
 *	  <例1>
 *	  │//Act関数側で、遷移キャンセル後のエラー状態も設定する例
 *	  │void Sample1() {
 *	  │  SEH_try {
 *	  │    FsmObj_ApplyTrans(&stFsmObj, FsmTrans_Trans1, NULL);
 *	  │  } SEH_catch(&stFsmObj) {
 *	  │  } SEH_end
 *	  │}
 *	  │void FsmFunc_Map1_State1_act(ST_FsmObj* pFsmObj, int iTrans, void* pParam) {
 *	  │  if(例外判定) {
 *	  │    FsmObj_SetState(pFsmObj, FsmState_StateE);┬明示的に状態'StateE'をセットし、
 *	  │    SEH_throw(pFsmObj); ───────────┘State2への遷移をキャンセルする。
 *	  │  }
 *	  │}
 *	  <例2>
 *	  │//呼び出し側で、遷移キャンセル後のエラー状態を設定する例
 *	  │void Sample2() {
 *	  │  SEH_try {
 *	  │    FsmObj_ApplyTrans(&stFsmObj, FsmTrans_Trans1, NULL);
 *	  │  } SEH_catch(&stFsmObj) {───────────┬遷移'Trans1'がキャンセルされたら…
 *	  │    FsmObj_SetState(&stFsmObj, FsmState_StateE);┘明示的に状態'StateE'をセットする。
 *	  │  } SEH_end
 *	  │}
 *	  │void FsmFunc_Map1_State1_act(ST_FsmObj* pFsmObj, int iTrans, void* pParam) {
 *	  │  if(例外判定) {
 *	  │    SEH_throw(pFsmObj); ─────────────遷移をキャンセルする。
 *	  │  }
 *	  │}
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'～'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Wed Jan 06 21:02:12 JST 2016 Naoyuki Sawa
 *	- 2015/07/03にFsmObj_CancelTrans()を削除した時に、コメント化して残していたコードを、完全に削除して整理しました。
 *	  もし見返す必要が生じた場合は、前回以前のアーカイブを参照して下さい。
 *	* Wed Jan 06 22:02:30 JST 2016 Naoyuki Sawa
 *	- Enter関数に、'変更前の状態'を示す引数を追加しました。
 *	  ただし特例ケースとして、FsmObj_Init()経由でEnter関数を呼び出す場合のみ、'変更前の状態'が存在しないので(-1)を渡します。	←←■■重要■■
 *	- Leave関数に、'変更後の状態'を示す引数を追加しました。
 *	  上述のEnter関数の特例ケースと違って、Leave関数の場合は'変更後の状態'は常に存在しているので、(-1)を渡す事は有りません。
 *	- これらの引数を追加した理由は、Enter関数の中で移行元の状態によって処理を少し変えたり、Leave関数の中で移行先の状態によって処理を少し変えたいケースが多かったからです。
 *	  厳密には、そのような処理は有限状態機械の設計としては望ましくないのですが、実用性を優先して引数を追加する事にしました。
 *	* Wed Jan 20 21:28:09 JST 2016 Naoyuki Sawa
 *	- Suspend関数/Resume関数を追加しました。
 *	  ・これまで、Push遷移時は、変更前の状態に対して通知が行われませんでした。
 *	    意味上はそれでも正しいのですが、実用上使い辛いという問題が有りました。
 *	    そこで、Push遷移時は変更前の状態に対して、Suspend関数を呼び出すようにしました。
 *	  ・これまで、Pop遷移時は、変更後の状態に対して通知が行われませんでした。
 *	    意味上はそれでも正しいのですが、実用上使い辛いという問題が有りました。
 *	    そこで、Pop遷移時は変更後の状態に対して、Resume関数を呼び出すようにしました。
 *	- 既存のEnter関数/Leave関数の名前を変更し、Start関数/Stop関数としました。
 *	  FSMの用語としては、Enter/Leave(又は,より正確にはEntry/Exit)の方が正しいのですが、Suspend/Resumeとの対比上、Enter/LeaveよりStart/Stopの方が判り易いと思ったからです。
 *	  この変更点については、名前の変更だけであり、動作には変更は有りません。
 *	* Wed Feb 17 21:39:25 JST 2016 Naoyuki Sawa
 *	- 既存のStart関数/Stop関数の名前を変更し、Entry関数/Exit関数としました。
 *	  2016/01/20のコメントの理由でStart関数/Stop関数としていたのですが、やはり一般的なFSMの用語に合わせる方が良いと考え直して、Entry関数/Exit関数に変更する事にしました。
 *	* Fri Feb 26 21:51:12 JST 2016 Naoyuki Sawa
 *	- FsmObj_ApplyTrans_l(),FsmObj_ApplyTrans_a(),FsmObj_ApplyTrans_v()を追加しました。
 *	  用途は、clipfsm.c内の、上記の関数の実装箇所の、コメントを参照して下さい。
 *	* Sat Feb 27 21:21:24 JST 2016 Naoyuki Sawa
 *	- 有限状態機械の初期状態を指定する方法を変更しました。
 *	- 変更前は、アプリケーションプログラムが、FsmObj_Init()の引数として、初期状態を明示的に指定していました。
 *	  変更後は、状態マップ毎のレジストリに初期状態の状態番号を格納しておき、FsmObj_Init()がその値を読み出して初期状態を取得するようにしました。
 *	- このように変更した理由は、アプリケーションプログラムの組み易さのためです。
 *	  普通は、状態マップ毎の初期状態は一種類であり、FsmObj_Init()の引数として初期状態を明示的に指定する事のメリットは、ほとんどありませんでした。
 *	  それよりも、アプリケーションが各状態マップの正しい初期状態を把握しておかなければいけない事と、もし間違えると発見しづらいバグが生じるデメリットがありました。
 *	  変更後は、アプリケーションが各状態マップの正しい初期状態を把握しておく必要は無くなり、FsmObj_Init()の引数も一つ減って、上記の問題が解決しました。
 *	- 変更後のデメリットとしては、異なる初期状態で有限状態機械を初期化する事は出来なくなった事です。
 *	  とは言え、前述のとおり、そのような事をする必要は滅多にないので、普通は問題になりません。
 *	  もしそのような事をする必要が有ったとしても、ダミーの初期状態を一つ用意して、ダミーの初期状態に初期化した後に、明示的にFsmObj_SetState()を使えば同じ事が実現出来ます。
 *	  従って、実用上、変更後のデメリットはほぼ無いと言えます。
 *	- 今回の変更に伴い、/clip/tool/dFsmMapC/ も変更しました。
 *	  有限状態機械スクリプト上での、初期状態の指定方法については、上記のツールのソースの、同日の変更点を参照して下さい。
 *	* Thu Mar 03 21:33:11 JST 2016 Naoyuki Sawa
 *	- FsmObj_ApplyTrans()関数に、Fsm_Trans_noreqフラグを追加しました。
 *	  FsmObj_ApplyTrans()関数を呼び出している他の関数(FsmObj_ApplyTrans_l(),ActObj_ApplyTransToTree_l()等)でも使えます。
 *	- これまでは、iTrans引数で指定した遷移番号に対する実行可能な遷移が無かった場合(存在する遷移が全てガード条件で否定された場合も含む)は、エラー停止していました。
 *	  原則的にはそれで良いのですが、ActObj_ApplyTransToTree()等で、オブジェクトツリー全体に遷移を適用する場合、一部のオブジェクトが遷移を実装していないケースが生じました。
 *	  それらのオブジェクトに、'何もしないダミー遷移'を実装してエラーを回避するよりも、FsmObj_ApplyTrans()関数側で対応する方が自然だと考えて、今回のフラグ追加を行いました。
 *	  尚、今回の行った変更は、UnityのGameObject.SendMessage関数の、DontRequireReceiverフラグ指定を見て、思い付きました。
 *	- Fsm_Trans_noreqフラグを乱用しないように、注意して下さい。
 *	  プログラムの意図として'存在するべき'遷移が存在しなかった場合はエラー停止する方が妥当であり、そのような遷移に対してもFsm_Trans_noreqフラグを指定すると、エラーが発生せずにバグを見落とす恐れが有るからです。
 *	  Fsm_Trans_noreqフラグを指定する対象としては、前述のような、オブジェクトツリー全体に対して遷移を適用するケース,かつ,
 *	  ほとんどのオブジェクトが実装している汎用的な遷移(Draw,Exec等)を一部のオブジェクトだけが意図的に実装していないことが事前に判っていてエラーを避ける場合や、	…下記の使用例④に相当
 *	  ほとんどのオブジェクトが実装していない特殊な遷移を実装している一部のオブジェクトだけに対してメッセージを送りたい場合等に、限定して使用するのが安全です。	…下記の使用例⑤に相当
 *	- <使用例>
 *	  ① FsmObj_ApplyTrans(pFsmObj, FsmTrans_Draw, NULL);					//pFsmObjに実行可能なDraw遷移,又は,default遷移が無ければ、エラー停止する。				…これまでと同じ
 *	  ② FsmObj_ApplyTrans(pFsmObj, FsmTrans_Draw|Fsm_Trans_noreq, NULL);			//pFsmObjに実行可能なDraw遷移,又は,default遷移が無ければ、何もしない。					…今回追加した動作
 *	  ③ ActObj_ApplyTransToTree(pActObj, FsmTrans_Draw, NULL);				//オブジェクトツリーの中に、FsmTrans_Drawを実装していないオブジェクトが有れば、エラー停止する。		…これまでと同じ
 *	  ④ ActObj_ApplyTransToTree(pActObj, FsmTrans_Draw|Fsm_Trans_noreq, NULL);		//オブジェクトツリーの中に、FsmTrans_Drawを実装していないオブジェクトが有っても、エラー停止しない。	…今回追加した動作
 *	  ⑤ ActObj_ApplyTransToTree(pActObj, FsmTrans_SpecialTrans|Fsm_Trans_noreq, NULL);	//オブジェクトツリーの中で、FsmTrans_SpecialTransを実装しているオブジェクトだけに、メッセージを送る。	…今回追加した動作
 *	* Sat Apr 02 23:34:06 JST 2016 Naoyuki Sawa
 *	- ARRAY_SIZE()マクロの変更に伴い、VC++6.0でintとunsignedの比較に対する警告が厳密に出るようになったので、警告が出ないように明示的なキャストを追加しました。
 *	  動作自体はこれまでと変わりません。
 *	  詳細はclipmisc.hの同日のコメントを参照して下さい。
 *	* Fri Jul 08 21:19:03 JST 2016 Naoyuki Sawa
 *	- ST_FsmArg型の構造体を追加しました。
 *	  FsmObj_ApplyTrans_l(),FsmObj_ApplyTrans_a(),FsmObj_ApplyTrans_v()を使って有限状態機械のAct関数を呼び出した場合は、Act関数へのpParam引数はこの型の構造体へのポインタとなります。
 *	  これまでは、argvだけをAct関数へのpParam引数としていたので、Act関数側でargcを参照する事が出来ませんでした。
 *	  今後は、argcもST_FsmArg型の構造体に格納してAct関数へのpParam引数となるので、Act関数側でargcを参照する事が出来るようになりました。
 *	- 上記はあくまでも、FsmObj_ApplyTrans_l(),FsmObj_ApplyTrans_a(),FsmObj_ApplyTrans_v()を使って有限状態機械のAct関数を呼び出した場合です。
 *	  直接FsmObj_ApplyTrans()を使って有限状態機械のAct関数を呼び出した場合は、Act関数へのpParam引数はこれまで通りアプリケーション定義の任意のデータとなる事に注意して下さい。
 *	- 上記と同じ変更を、clipact.cモジュールの、ActObj_ApplyTrans_l(),ActObj_ApplyTransToChildren_l(),ActObj_ApplyTransToTree_l()等に対しても適用しました。
 *	  詳細は、clipact.cモジュールの、同日のコメントを参照して下さい。
 *	- 余談ですが、これまで、上記の関数のアセンブラ版の実装は、スタック操作のバグが有った事に気付きました。
 *	  今回の変更に合わせて、スタック操作のバグも修正しました。
 *	* Sat Jul 09 21:38:42 JST 2016 Naoyuki Sawa
 *	- FsmObj_CallStateFunc()関数の仮引数iStateの名前を、iAltStateに変更しました。
 *	  FsmObj_CallStateFunc()関数の仮引数は、現在の状態を示しているのではなく、遷移先状態,又は,遷移元状態を示している事を強調するためです。
 *	  clipfsm.c内のローカル関数の仮引数名の変更のみであり、動作は変わりません。
 *	- 上記と同様に、dFsmMapC.exeが出力する関数プロトタイプの仮引数名も変更しました。
 *	  詳細は、/clip/tool/dFsmMapC/winapp.hの同日のコメントを参照して下さい。
 *	* Mon Aug 29 21:46:36 JST 2016 Naoyuki Sawa
 *	- FsmObj_IsState(),FsmObj_IsState_l(),FsmObj_IsState_a(),FsmObj_IsState_v(),FsmObj_StateIn_l(),FsmObj_StateIn_a(),FsmObj_StateIn_v()を追加しました。
 *	* Tue Aug 30 21:54:03 JST 2016 Naoyuki Sawa
 *	- FsmObj_StateIn_v()のアルゴリズムを少し変更して高速化しました。
 *	- FsmObj_IsState(),FsmObj_IsState_l(),FsmObj_IsState_a(),FsmObj_IsState_v(),FsmObj_StateIn_l(),FsmObj_StateIn_a(),FsmObj_StateIn_v()をアセンブラ化しました。
 *	* Fri Jan 06 23:24:43 JST 2017 Naoyuki Sawa
 *	- レジストリ構造を変更して、状態マップに初期化Act関数を定義出来るようにしました。
 *	  変更した理由は、以下の通りです。
 *	- これまでは、FsmObj_Init()にパラメータを渡せなかったので、有限状態機械に付随するデータ(アクターオブジェクト等)に可変の初期値を格納する事が出来ませんでした。
 *	  FsmObj_Init()にパラメータを渡せなかった理由は、FsmObj_Init()によって呼び出される関数が、初期状態のEntry関数のみであり、Entry関数にはパラメータは渡せないからです。
 *	  回避策としては、初期状態として'InitState'等を定義し、FsmObj_Init()にて初期状態'InitState'へ遷移した後、明示的に'InitTrans'等の遷移を行って、そのAct関数へパラメータを渡して初期値を格納する必要が有りました。
 *	- 今回、FsmObj_Init()時に呼び出される初期化Act関数を、新たに定義しました。
 *	  有限状態機械スクリプト上では、以下のように記述する事が出来ます。
 *	  │Map0 {`printf("Map0 initAct called")`} InitState
 *	  │    InitState
 *	  │        …
 *	  初期化Act関数は、これまでのAct関数と同じシグネチャを持つので、任意のパラメータを渡す事が出来ます。
 *	  ただし、初期化Act関数のiTrans引数には、ダミーの遷移番号として'-1'が渡される事に注意して下さい。
 *	- 関数が呼び出される順序は、以下の通りです。
 *	  │1. アプリケーションが、FsmObj_Init()を呼び出す。
 *	  │2.   FsmObj_Init()が、有限状態機械に初期状態の状態番号を格納する。
 *	  │3.   初期化Act関数が有れば、FsmObj_Init()が、アプリケーション定義の初期化Act関数を呼び出す。(即ち、この時点でFsmObj_GetState()は、初期状態の状態番号を返します。)
 *	  │4.   初期状態のEntry関数が有れば、FsmObj_Init()が、アプリケーション定義のEntry関数を呼び出す。
 *	  │5. FsmObj_Init()が、処理を返す。
 *	  3.と4.の順序に注意して下さい。
 *	  Entry関数よりも先に初期化Act関数を呼び出す事にした理由は、既存の仕様におけるAct関数と遷移先状態のEntry関数の呼び出し順序に合わせる方が、判り易いと思ったからです。
 *	* Sat Jan 07 21:53:42 JST 2017 Naoyuki Sawa
 *	- FsmObj_Init_l(),FsmObj_Init_a(),FsmObj_Init_v()を追加しました。
 *	  2017/01/06に初期化Act関数を追加した事に伴い、初期化Act関数のpParamにも可変引数を渡せるようにするためです。
 *	  使用方法は、既存のFsmObj_ApplyTrans_l(),FsmObj_ApplyTrans_a(),FsmObj_ApplyTrans_v()と同様です。
 *	- FsmArg_New_l(),FsmArg_New_a(),FsmArg_New_v()を追加しました。
 *	  clipfsm.cモジュールを直接使用する場合はこれらの関数は特に必要無いのですが、clipact.cモジュールを経由して使用する場合に使い易くするためのユーティリティ関数です。
 *	  具体的には、ActObj_New()の引数pParamのST_ActObj_New_Param構造体のpFsmInitParamフィールドに、可変引数を指定する際に使用する事を祖想定したユーティリティ関数です。
 *	  ActObj_New()の引数は、ST_ActObj_New_Param構造体を経由するため、ActObj_New()自体の'_l','_a','_v'等の可変引数バージョンを作る事が出来ません。
 *	  その代わりとして、ST_ActObj_New_Param構造体のpFsmInitParamフィールドに可変引数を指定するユーティリティ関数として、FsmArg_New_l(),FsmArg_New_a(),FsmArg_New_v()を用意する事にしました。
 *	  ■使用例
 *	  │ST_ActObj_New_Param param;
 *	  │memset(&param, 0, sizeof param);
 *	  │param.pFsmKey = pFsmKey;
 *	  │param.iFsmMap = FsmMap_Test;
 *	  │param.pFsmInitParam = FsmArg_New_l(2, "Hello", (intptr_t)123);
 *	  │ST_ActObj* aoTest = ActObj_New(&param);
 *	  │free(param.pFsmInitParam); //忘れないで!!
 *	* Sun Jan 08 21:43:34 JST 2017 Naoyuki Sawa
 *	- Fsm_Initの値を、0x8000⇒0xFFFFに変更しました。
 *	  変更した理由は、以下の通りです。
 *	- Fsm_Initは、状態マップのレジストリキーに属するキーの名前として、何らかの値を割り当てる必要が有ります。
 *	  状態マップのレジストリキーに属するキーの名前は、全ての値が既に意味を持っているのですが、その中からどれかの値を予約せざるを得ません。
 *	  ・0              デフォルト遷移のキーの名前(Fsm_Trans_default)であり、既に予約済みですから、0はFsm_Initに割り当てる候補には成り得ません。
 *	  ・1～0x7FFF      アプリケーション定義の遷移のキーの名前です。dFsmMapC.exeを使って生成すれば、遷移番号は1から振られて、普通は大きな値は使用されないので、0x7FFFはFsm_Initに割り当てる候補に成り得ます。
 *	  ・0x8000         状態番号0のキーの名前に相当します。しかし、dFsmMapC.exeを使って生成すれば、状態番号は1から振られて、状態番号0は使用されないので、0x8000はFsm_Initに割り当てる候補に成り得ます。
 *	  ・0x8001～0xFFFF アプリケーション定義の状態のキーの名前に相当します。dFsmMapC.exeを使って生成すれば、遷移番号は1から振られて、普通は大きな値は使用されないので、0xFFFFはFsm_Initに割り当てる候補に成り得ます。
 *	  従って、候補は0x7FFF,0x8000,0xFFFFであり、この中からFsm_Initにどの値を割り当てるかを、検討する事にしました。
 *	- 昨日までは、Fsm_Initに0x8000を割り当てていたのですが、問題が有る事に気付きました。
 *	  アプリケーションプログラムが、バグ等で間違って状態番号0を使用してしまった場合に、たまたまFsm_Initキーがヒットしてしまうという問題です。
 *	  すぐにエラー停止せずにバグが見つけづらくなったり、Fsm_InitキーのFsm_InitActやFsm_InitStateのエントリをFsm_EntryやFsm_Exitと見なしてしまって、意図していない関数が呼び出されてしまう可能性が有ります。
 *	  例えば、「FsmObj_SetState(&foApp,0)」はエラー停止してほしいのですが、エラー停止せずに予期しない動作をしてしまう恐れが有ります。
 *	  また、ST_FsmObj.TBL_Stack[...]を間違ってゼロフィルしてしまった場合にも、エラー停止せずに予期しない動作をしてしまう恐れが有ります。
 *	  このように、アプリケーションプログラムのバグが見つけづらくなるのは避けたいので、Fsm_Initに0x8000を割り当てるのはやめる事にしました。
 *	- 残った候補は、0x7FFFと0xFFFFです。
 *	  どちらも、dFsmMapC.exeを使って生成すれば普通は使用されない値であり、どちらを使っても大差は無いのですが、あえて比較すれば0xFFFFの方が良いと思いました。
 *	  そう思った理由は、以下の通りです。
 *	  0x7FFFは、遷移番号32767のキーの名前として完全に使用可能な値であり、遷移番号32767まで使う事はまず無いとは言え、潰すのは惜しい気もします。
 *	  一方、0xFFFFは、状態番号32767のキーの名前として使用可能な値ではありますが、状態番号32767はプッシュ遷移としては使用出来ない遷移番号であり(ポップ遷移の値と被るから)、元々使いづらい遷移番号です。
 *	  どちらかを潰すならば、状態番号32767を潰す方が惜しくないので、Fsm_Initには0xFFFFを割り当てる事にしました。
 *	- 前述した、「FsmObj_SetState(&foApp,間違った遷移番号)」がエラー検出されなくなる問題について、補足します。
 *	  Fsm_Initに0xFFFFを割り当てた場合でも、間違って「FsmObj_SetState(&foApp,32767)」や「FsmObj_SetState(&foApp,65535)」を実行してしまうと、やはりエラー検出されず意図しない動作になる恐れは有ります。
 *	  とは言え、偶然に「FsmObj_SetState(&foApp,0)」を実行してしまう可能性に比べれば、偶然に「FsmObj_SetState(&foApp,32767)」や「FsmObj_SetState(&foApp,65535)」を実行してしまう可能性は低いと思います。
 *	  同様に、偶然にST_FsmObj.TBL_Stack[...]をゼロフィルしてしまう可能性に比べれば、偶然にST_FsmObj.TBL_Stack[...]を32767や65535でフィルしてしまう可能性は低いと思います。
 *	  従って、変更前のFsm_Initに0x8000を割り当てていた時よりも、変更後のFsm_Initに0xFFFFを割り当てる方が、アプリケーションプログラムのバグが見つけづらくなる問題は小さいです。
 */
#ifndef __CLIP_FSM_H__
#define __CLIP_FSM_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	
 ****************************************************************************/
//状態,又は,状態マップのレジストリキーに属する、キーの名前
#define Fsm_Trans_default	0		//デフォルト遷移
//{{2017/01/06変更:レジストリ構造を変更して、状態マップに初期化Act関数を定義出来るようにしました。
////状態マップのレジストリキーに属する、値の名前
//#define Fsm_State_init		0		//初期状態
//↓2017/01/06変更:レジストリ構造を変更して、状態マップに初期化Act関数を定義出来るようにしました。
////状態マップのレジストリキーに属する、キーの名前
//#define Fsm_Init		0x8000		//初期化情報キー	必須
////初期化情報キーに属する、値の名前
//#define Fsm_InitAct		1		//初期化Act関数		任意
//#define Fsm_InitState		2		//初期状態		必須
////↓2017/01/08変更:Fsm_Initの値を、0x8000⇒0xFFFFに変更しました。
//状態マップのレジストリキーに属する、キーの名前
#define Fsm_Init		0xFFFF		//初期化情報キー	必須
//初期化情報キーに属する、値の名前
#define Fsm_InitAct		1		//初期化Act関数		任意
#define Fsm_InitState		2		//初期状態		必須
//}}2017/01/08変更:Fsm_Initの値を、0x8000⇒0xFFFFに変更しました。
										//	┌-初期化--┐ ┌-通常遷移┐ ┌-Push遷移┐ ┌-Pop遷移-┐
//状態,又は,状態マップのレジストリキーに属する、値の名前			//	遷移元 遷移先 遷移元 遷移先 遷移元 遷移先 遷移元 遷移先
#define Fsm_Entry		1		//Entry関数			//	  －     ○     －     ○     －     ○     －     －  
#define Fsm_Exit		2		//Exit関数			//	  －     －     ○     －     －     －     ○     －  
#define Fsm_Suspend		3		//Suspend関数			//	  －     －     －     －     ○     －     －     －  
#define Fsm_Resume		4		//Resume関数			//	  －     －     －     －     －     －     －     ○  
										//	└-初期化--┘ └-通常遷移┘ └-Push遷移┘ └-Pop遷移-┘
//遷移のレジストリキーに属する、値の名前
//#define Fsm_Guard		(3N+0)		//Guard関数
//#define Fsm_Act		(3N+1)		//Act関数
//#define Fsm_State		(3N+2)		//遷移先状態
/*--------------------------------------------------------------------------*/
#define FsmObj_StackSize	3		//状態スタックの要素数(調整可)
//FSMオブジェクト
typedef struct _ST_FsmObj {
	const void*	pMapKey;						//+ 0,4 状態マップのレジストリキー
	uint16_t	iStack;							//+ 4,2 状態スタックのスタックポインタ
	uint16_t	TBL_Stack[FsmObj_StackSize];				//+ 6,6 状態スタック				TBL_Stack[iStack]が、現在の状態に相当します。
} ST_FsmObj;									//=12
/*--------------------------------------------------------------------------*/
//アプリケーション定義の関数配列。
//先頭要素に、関数配列の要素数を格納する事。
extern const void* const TBL_FsmFunc[];
//配列要素の関数は以下のいずれかの形式です。					//状態変更	FsmObj_GetState()が返す状態	備考
typedef void FsmFunc_entry(  ST_FsmObj* pFsmObj, int iPrevState);		//不可		変更後の状態			現在の状態を変更した後に、この関数を呼びます。
typedef void FsmFunc_exit(   ST_FsmObj* pFsmObj, int iNextState);		//不可		変更前の状態			この関数を呼んでから、現在の状態を変更します。
typedef void FsmFunc_suspend(ST_FsmObj* pFsmObj, int iNextState);		//不可		変更前の状態			この関数を呼んでから、現在の状態を変更します。
typedef void FsmFunc_resume( ST_FsmObj* pFsmObj, int iPrevState);		//不可		変更後の状態			現在の状態を変更した後に、この関数を呼びます。
typedef int  FsmFunc_guard(  ST_FsmObj* pFsmObj, int iTrans, void* pParam);	//不可		変更前の状態			Guard関数が(0)を返したら、この遷移を行わない。
typedef void FsmFunc_act(    ST_FsmObj* pFsmObj, int iTrans, void* pParam);	//可		変更前の状態			遷移後状態へ移行する前に、この関数を呼びます。
/****************************************************************************
 *	基本的な関数
 ****************************************************************************/
//{{2017/01/06変更:レジストリ構造を変更して、状態マップに初期化Act関数を定義出来るようにしました。
//void FsmObj_Init(      ST_FsmObj* pFsmObj, const void* pFsmKey, int iMap);
//↓2017/01/06変更:レジストリ構造を変更して、状態マップに初期化Act関数を定義出来るようにしました。
void FsmObj_Init(      ST_FsmObj* pFsmObj, const void* pFsmKey, int iMap, void* pParam);
//}}2017/01/06変更:レジストリ構造を変更して、状態マップに初期化Act関数を定義出来るようにしました。
int  FsmObj_GetState(  ST_FsmObj* pFsmObj);
void FsmObj_SetState(  ST_FsmObj* pFsmObj, int iState);
void FsmObj_PushState( ST_FsmObj* pFsmObj, int iState);
void FsmObj_PopState(  ST_FsmObj* pFsmObj);
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define Fsm_Trans_noreq 0x8000 //iTrans引数にこのフラグをOrすると、実行可能な遷移が無くてもエラー停止しない。
void FsmObj_ApplyTrans(ST_FsmObj* pFsmObj, int iTrans, void* pParam);				//─pParamがそのまま、Act関数へのpParam引数となります。
/****************************************************************************
 *	ユーティリティ関数
 ****************************************************************************/
//FsmObj_ApplyTrans_l(),FsmObj_ApplyTrans_a(),FsmObj_ApplyTrans_v()を使って有限状態機械のAct関数を呼び出した場合は、Act関数へのpParam引数はこの型の構造体へのポインタとなります。
//ただし、直接FsmObj_ApplyTrans()を使って有限状態機械のAct関数を呼び出した場合は、Act関数へのpParam引数はこれまで通りアプリケーション定義の任意のデータとなる事に注意して下さい。
typedef struct _ST_FsmArg {
	int		argc;			//+0,4
	void**		argv/*[argc]*/;		//+4,4
} ST_FsmArg;					//=8
/*--------------------------------------------------------------------------*/
//{{2017/01/07追加:FsmObj_Init_l(),FsmObj_Init_a(),FsmObj_Init_v()を追加しました。
void FsmObj_Init_l(      ST_FsmObj* pFsmObj, const void* pFsmKey, int iMap, int argc, ...);			//┐
void FsmObj_Init_a(      ST_FsmObj* pFsmObj, const void* pFsmKey, int iMap, int argc, va_list ap);		//├可変引数の情報をST_FsmArg型の構造体に格納して、初期化Act関数へのpParam引数となります。
void FsmObj_Init_v(      ST_FsmObj* pFsmObj, const void* pFsmKey, int iMap, int argc, void* argv[/*argc*/]);	//┘
//}}2017/01/07追加:FsmObj_Init_l(),FsmObj_Init_a(),FsmObj_Init_v()を追加しました。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void FsmObj_ApplyTrans_l(ST_FsmObj* pFsmObj, int iTrans,                    int argc, ...);			//┐
void FsmObj_ApplyTrans_a(ST_FsmObj* pFsmObj, int iTrans,                    int argc, va_list ap);		//├可変引数の情報をST_FsmArg型の構造体に格納して、Act関数へのpParam引数となります。
void FsmObj_ApplyTrans_v(ST_FsmObj* pFsmObj, int iTrans,                    int argc, void* argv[/*argc*/]);	//┘
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//{{2017/01/07追加:FsmArg_New_l(),FsmArg_New_a(),FsmArg_New_v()を追加しました。
ST_FsmArg* FsmArg_New_l(                                                    int argc, ...);			//┐
ST_FsmArg* FsmArg_New_a(                                                    int argc, va_list ap);		//├ST_FsmArg構造体とargvを格納するメモリを1ブロックで確保し、可変引数の情報を格納します。呼び出し側にてfree()で解放して下さい。
ST_FsmArg* FsmArg_New_v(                                                    int argc, void* argv[/*argc*/]);	//┘
//}}2017/01/07追加:FsmArg_New_l(),FsmArg_New_a(),FsmArg_New_v()を追加しました。
/*--------------------------------------------------------------------------*/
int FsmObj_IsState(  ST_FsmObj* pFsmObj, int iState);
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int FsmObj_IsState_l(ST_FsmObj* pFsmObj, ...);
int FsmObj_IsState_a(ST_FsmObj* pFsmObj, va_list ap);
int FsmObj_IsState_v(ST_FsmObj* pFsmObj, const int* aState/*[[[[state,]state],…,]state,]-1*/);
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int FsmObj_StateIn_l(int iState, ...);
int FsmObj_StateIn_a(int iState, va_list ap);
int FsmObj_StateIn_v(int iState, const int* aState/*[[[[state,]state],…,]state,]-1*/);
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__CLIP_FSM_H__
