リスト8−1を見てください。C言語のようであって、そうでなさそうな、とにかく奇妙なコー ディングです。関数本体の開始の{もなければ、終了の }もありません。どうも、その代わりに、 BEGINと ENDがあるみたいです。その他にも、THEN, ELSE, ENDIF などの、本来C言語では使うは ずのないものがいっぱいあるからです。これを書いたプログラマは正気なのでしょうか。
リスト8−1 Pascal みたいな C |
1 chkarg( argc , argv ) /* Parameters check */ 2 3 int argc ; 4 char *argv[] ; 5 6 BEGIN 7 8 int argn /* Number of arguments */ 9 , opt ; /* option character */ 10 11 for ( argn = 1, paramnum = 0 ; argn < argc ; argn++ ) 12 BEGIN 13 if ( *argv[argn] == OPTION ) /* Option? */ 14 THEN 15 if ( opt = *++argv[argn] & ASCII ) 16 THEN 17 switch ( isalpha ( opt ) ? toupper ( opt ) : opt ) 18 BEGIN 19 case 'E' : if (*++argv[argn] == '=') 20 THEN 21 dspsttid = atoi (++argv[argn]); 22 argv[argn] = index (argv[argn], NULL); 23 ELSE 24 xexit (E_IFORKP); 25 ENDIF 26 break; 27 case 'W' : if (*++argv[argn] == '=') 28 THEN 29 dirname = ++argv[argn]; 30 argv[argn] = index(argv[argn], NULL); 31 ELSE 32 xexit (E_IFORKP); 33 ENDIF 34 break; 35 case 'F' : switch (*++argv[argn]) 36 BEGIN 37 case '0': if (*++argv[argn] == '=') 38 THEN 39 f0pathlist = ++argv[argn]; 40 argv[argn] = index (argv[argn], NULL); 41 ELSE 42 if (*argv[argn] == '0' && *++argv[argn] == '=') 43 THEN 44 f00pathlist = ++argv[argn]; 45 argv[argn] = index (argv[argn], NULL); 46 ELSE 47 xexit (E_IFORKP); 48 ENDIF 49 ENDIF 50 break; 51 case '1': if (*++argv[argn] == '6' && *++argv[argn] == '=') 52 THEN 53 f16pathlist= ++argv[argn]; 54 argv[argn] = index (argv[argn], NULL); 55 ELSE 56 xexit (E_IFORKP); 57 ENDIF 58 break; 59 case '2': if (*++argv[argn] == '=') 60 THEN 61 f2pathlist = ++argv[argn]; 62 argv[argn] = index (argv[argn], NULL); 63 ELSE 64 xexit (E_IFORKP); 65 ENDIF 66 break; 67 case '3': if (*++argv[argn] == '=') 68 THEN 69 f3pathlist = ++argv[argn]; 70 argv[argn] = index (argv[argn], NULL); 71 ELSE 72 xexit (E_IFORKP); 73 ENDIF 74 break; 75 case '4': if (*++argv[argn] == '=') 76 THEN 77 f4pathlist = ++argv[argn]; 78 argv[argn] = index (argv[argn], NULL); 79 ELSE 80 xexit (E_IFORKP); 81 ENDIF 82 break; 83 default: break; 84 ENDSWITCH 85 break ; 86 case '?' : syntax (); exit ( NO_ERROR ) ; 87 default : syntax (); exit ( E_IFORKP ) ; 88 ENDSWITCH 89 ENDIF 90 ELSE 91 if ( paramnum < PARAM_MAX ) 92 THEN /* Set parameter pointer */ 93 param[paramnum++] = argv[argn] 94 ELSE 95 ENDIF 96 ENDIF 97 ENDFOR 98 99 if ( paramnum < PARAM_MIN ) /* No parameter ? */ 100 THEN /* Display syntax */ 101 syntax () ; 102 exit ( NO_ERROR ) 103 ELSE 104 ENDIF 105 jobid = atoi (param[JOB_ID]); /* Set Job-ID (task-ID) */ 106 END |
実は、これらのマクロはプログラムの先頭でリスト8−2のマクロ定義により、
BEGIN は { END は ;}というように、予約語や記号に置換され、C言語として扱われるのです。
リスト8−2 予約語のマクロ定義 |
1 #define BEGIN { 2 #define END ;} 3 #define THEN BEGIN 4 #define ELSE END else BEGIN 5 #define ENDIF END 6 #define ENDWHILE END 7 #define DO do BEGIN 8 #define WHILE END while( 9 #define ENDDO ); 10 #define REPEAT DO 11 #define UNTIL WHILE!( 12 #define ENDREPEAT )ENDDO 13 #define ENDFOR END 14 #define NEXT END 15 #define LOOP for(;;)BEGIN 16 #define ENDLOOP END 17 #define ENDSWITCH END |
謎はすぐに解けましたが、「なぜ」このようなマクロ定義をしたのでしょうか。なぜ、C言語ら しさがまったくなくなるような細工をしたのでしょうか。つねに、BEGINとENDで囲みたがっている ところは、C言語を、何とかPascalのように書きたいように見えます。また、英大文字の予約語が 増えると、BASICのようにも見えてきます。つまり、リスト8−2のようにマクロ定義すると、ま るで PascalとBASICの「合いの子」のようにも書けるのですね。おもしろいマクロの使い方ですね。
このような特殊なコーディングをしてしまうと、エディタの括弧のバランスとか、字下げを自動 的にしてくれる便利な機能が働かなくなります。だから、眼力に頼るか、コンパイルしてエラーを 出すことで括弧バランスの崩れを見つけざるを得なくなります。これでは、とても私のように「楽」 をしたいと日々思い悩んでいる者にはできないし、そのようなプログラムを見せられたら、逃げ出 してしまいます。エディタの機能を抹殺するようなコーディングだけは止めましょう。
それとも、これを書いたプログラマは、プリントアウトしたリストを見て、この書法が良いと判 断したのでしょうか。10年前の、リストはコーディング用紙に書いて、パンチャーにカードを打っ てもらう大昔ならともかく、誰もがスクリーンエディタを使っている今日、スクリーンエディタの 機能を生かせないような方法は考えられません。そういえば、昔、画面だけでエディトしているの では不安らしく、必ずカードで作業していた上司がいました。
また、当然のことですが、C言語のプログラムを書く以上、C言語の作法から極度に逸脱してし まうと、世のCプログラマから一切相手にされなくなります。「村八分」になってしまいます。自 分の作ったプログラムは永久に自分しか見ないような場合には、どんなコーディングをしようと勝 手ですが、仕事で作るプログラムでは、そんな身勝手は許されません。
このような方法を紹介して喜んでいる本も巷にはあるようですが、けっしてこのような書き方は まねないようにしましょう。無人島でただ一人でプログラミングしていて、外界と隔絶されている ような場合は本人の勝手でしょう。しかし、Cプログラマの世界から破門されたくなかったら、今 すぐ改宗しましょう。
ということで、リスト8−1は、ばっさり書き換えてしまいましょう。