EXCEPT.C
[目次 | 関数 | マクロ]
1|/***************************************************************************
2|* 1. <<< 例外処理シュミレート (Except) >>>
3|*
4|*・C 言語で例外処理をサポートします。
5|*・C++ の例外処理と互換性はありませんが、それに近い文法を採用しています。
6|*・次の2種類の例外型を実装しています。
7|* ・Except_Base 型 例外 [Except_...]
8|* ・Except_Std 型 例外 [Except_..., Except_Std_...]
9|*
10|*--------------------------------------------------------------------------
11|*
12|* 2. <<<【解説】例外処理をする >>>
13|*
14|* 例外処理は、おおよそ次のような構文をとります。
15|*
16|* void foo()
17|* {
18|* try { // try ブロック開始
19|* exceptable_func(); trys; // try ブロック内のチェッカー
20|* if ( err )
21|* throw_trys( Except_s( "msg" ) ); // try ブロック内の throw
22|* normality_func();
23|* }
24|* catch ( msg ) { // catch ブロック開始
25|* if ( strcmp( ((Except_Std*)msg)->arg_str, "EOF" ) != 0 )
26|* return;
27|* Except_print( msg );
28|* } catch_end;
29|* }
30|*
31|*・try に続く中カッコで囲まれた部分(try ブロック)の中の関数の内部から
32|* 投げられた例外(異常)を catch ブロックで受け取ります。上の場合、例外が
33|* 投げられる可能性のある関数 exceptable_func() の内部から例外が投げられ
34|* ると、次に実行されるはずの if 文に続かずに直接 catch ブロックの中へ
35|* ジャンプします。
36|*・投げられた例外は catch ブロックの msg に渡されます。
37|*・例外が投げられる可能性のある関数は、必ず try ブロックの中に入れ、関数の
38|* 直後に trys; を置きます。
39|*・catch ブロックの終わりには、catch_end; を必ず置きます。
40|*・try ブロックの中から例外を投げる場合は、throw_trys 文を用います。投げる
41|* 例外を引数に渡します。
42|*・try ブロックと catch ブロックのペアは、 1関数あたり1ペアしか使うことが
43|* できません。
44|*
45|*・例外処理を、コール元の関数に委譲する場合、
46|* void foo()
47|* {
48|* exceptable_func(); throws;
49|* }
50|*
51|* または
52|* int foo()
53|* {
54|* exceptable_func(); throws_r(2);
55|* }
56|*
57|* のようにします。例外が投げられる可能性のある関数の直後に、 throws または
58|* throws_r を置きます。throws と throws_r は、返り値を指定するかどうかの
59|* 違いだけです。
60|*
61|*・C++ の例外処理は、自動的にオブジェクトを delete しますが、この例外処理
62|* では、delete しないので、自動的にメモリの開放をしたり、ファイルを閉じたり
63|* することはありません。(その対処法は未定です。)
64|*
65|*--------------------------------------------------------------------------
66|*
67|* 3. <<<【解説】例外を投げる >>>
68|*
69|*・if 文などで、エラーを判定たら例外を投げます。構文は次の通りです。
70|* void foo()
71|* {
72|* if ( error ) throw( Except_s( "msg" ) );
73|* }
74|*
75|* または
76|* int foo()
77|* {
78|* if ( error ) throw_r( Except_s( "msg" ), 2 );
79|* }
80|*
81|*・throw または throw_r 文で例外を投げます。上の場合、Except_s 関数の返り値
82|* である Except 型の例外(例外オブジェクト)を投げています。throw と throw_r
83|* は、返り値を指定するかどうかの違いだけです。
84|*・このような例外を投げる可能性のある関数は、「〜型の例外を投げる可能性がある
85|* 」ことをドキュメントに明示しておくことを薦めます。
86|*・try ブロックの中から例外を投げる場合は、throw_trys 文を用います。投げる
87|* 例外を引数に渡します。
88|*・catch ブロックの中から例外を投げることも出来ます。この場合、コール元の
89|* 関数に例外が投げられます。
90|*
91|*・C++ の例外処理は、自動的にオブジェクトを delete しますが、この例外処理では、
92|* delete しないので、自動的にメモリの開放をしたり、ファイルを閉じたりすること
93|* はありません。一度 catch して開放してから再び throw します。
94|*
95|*--------------------------------------------------------------------------
96|*
97|* 4. <<< Except_Std クラス(Except 関数)>>>
98|*
99|*・一般的な例外オブジェクトです。
100|*
101|* if ( error ) throw( Except() );
102|* のように Except 型例外を(生成し)投げて、
103|* catch ( msg ) {
104|* Except_print( msg );
105|* } catch_end;
106|* のように、一般的なエラー情報を表示します。
107|*
108|*・Except 型例外を生成する関数は次のものがあります。
109|* void* Except();
110|* void* Except_i( int hint );
111|* void* Excpet_s( char* hint );
112|* hint は、エラー情報のヒントで、Except_print 関数により表示されます。
113|*
114|*・例外オブジェクトは、Except_Base 型から派生させる必要があります。
115|* Except_Std 型も、Except_Base 型から派生しています。
116|*・新しくクラス(型)を作ったら、 Except_Id 型に新しい要素を追加します。
117|****************************************************************************/
118|
119|#include <stdio.h>
120|#include <all.h>
121|
122|#ifdef _STDLIB
123| #define Except_outPrintf /* printf 表示 */
124|#else
125| #define Except_outWatch /* watch 表示 */
126| #ifndef USES_WATCH
127| #error
128| #endif
129|#endif
130|
131|
132|/**************************************************************************
133|* 5. <<< Except_Base 型 例外 [Except] >>>
134|***************************************************************************/
135|
136|void* Except_msg = NULL; /* 例外オブジェクト用・スタック */
137|char* Except_file; /* ファイル名 */
138|int Except_line; /* 行番号 */
139|
140|
141|/**************************************************************************
142|* 6. <<< ファイル名と行番号を設定する [Except_setFileLine()] >>>
143|***************************************************************************/
144|void Except_setFileLine( char* file, int line )
145|{
146| Except_file = file;
147| Except_line = line;
148|}
149|
150|
151|/**************************************************************************
152|* 7. <<< デフォルトの例外表示 [Except_print()] >>>
153|***************************************************************************/
154|void Except_print( void* m )
155|{
156| #ifdef Except_outWatch
157| switch ( ((Except_Base*)m)->type ) {
158| case Except_idStd:
159| Except_Std_print( m );
160| break;
161| default:
162| watch( 0xECEF, __LINE__ );
163| break;
164| }
165| #endif /* Except_outWatch */
166| #ifdef Except_outPrintf
167| printf("\n");
168| switch ( ((Except_Base*)m)->type ) {
169| case Except_idStd:
170| Except_Std_print( m );
171| break;
172| default:
173| printf( "Unknown Error in %s (%d) : %d\n",
174| Except_file, Except_line );
175| break;
176| }
177| #endif /* Except_outPrintf */
178|}
179|
180|
181|/**************************************************************************
182|* 8. <<< Except_Std 型 例外 [Except_Std] >>>
183|***************************************************************************/
184|
185|Except_Std Except_std = { Except_idStd, "Error", 0, NULL, 0 };
186|
187|
188|/**************************************************************************
189|* 9. <<< Except_Std 型 例外を発生させる [Except(), Except_s(), Except_i()] >>>
190|***************************************************************************/
191|void* Except()
192|{
193| Except_std.arg_type = 0;
194| return &Except_std;
195|}
196|
197|void* Except_s( char* msg )
198|{
199| Except_std.arg_type = 1;
200| Except_std.arg_str = msg;
201| return &Except_std;
202|}
203|
204|void* Except_i( int msg )
205|{
206| Except_std.arg_type = 2;
207| Except_std.arg_num = msg;
208| return &Except_std;
209|}
210|
211|
212|/**************************************************************************
213|* 10. <<< デバッグ表示 [Except_Std_print()] >>>
214|*【補足】
215|*・SDV デバッガでは、次のように出力されます。
216|* -dw w
217|* ECE0 0000004C ECE1 00004354 // ID, 型の名前
218|* ECE2 00004374 ECE3 0000006E // 例外が発生したファイル、行
219|* ECE4 00004370 // メッセージ
220|***************************************************************************/
221|void Except_Std_print( void* m )
222|{
223| #ifdef Except_outWatch
224| watch( 0xECE0, __LINE__ );
225| watch( 0xECE1, (int)((Except_Std*)m)->str );
226| watch( 0xECE2, (int)Except_file );
227| watch( 0xECE3, Except_line );
228| switch( ((Except_Std*)m)->arg_type ) {
229| case 0:
230| break;
231| case 1:
232| watch( 0xECE4, (int)((Except_Std*)m)->arg_str );
233| break;
234| case 2:
235| watch( 0xECE4, ((Except_Std*)m)->arg_num );
236| break;
237| }
238| #endif /* Except_outWatch */
239| #ifdef Except_outPrintf
240| printf( "%s in %s (%d)", ((Except_Std*)m)->str,
241| Except_file, Except_line );
242| switch( ((Except_Std*)m)->arg_type ) {
243| case 0:
244| printf( "\n" );
245| break;
246| case 1:
247| printf( " : %s\n", ((Except_Std*)m)->arg_str );
248| break;
249| case 2:
250| printf( " : %d\n", ((Except_Std*)m)->arg_num );
251| break;
252| }
253| #endif /* Except_outPrintf */
254|}
255|
256|