FORTRAN77 のマイナー命令
Yahoo 知恵袋の質問で FORTRAN77 の ENTRY 文で困っている人がいたようなので、ENTRY 文の使い方を見てみます。
ついでに、文法書ではよくENTRY 文と対になって出てくるけど、使い方は全然関係ない ALTERNATE RETURN 文についても見てみます。
ENTRY 文は MODULE の祖型、ALTERNATE RETURN は例外処理の祖型と見なせますが、登場が早すぎて(規格に入ったのは FORTRAN77 からですが、ベンダー拡張として 1960年代中葉 FORTRAN IV/66 の頃までには、一部処理系には導入されていました)機能は限定的で、使い方が難しく、ユーザー側も使い方の本質を理解できずに終わった機能だと思います。
Modern Fortran 規格ではいずれも廃止になったか、廃止勧告が出ています。
文法的比較
ENTRY 文は SUBROUTINE または FUNCTION の内部に記述出来て、SUBROUTINE/FUNCTION を呼び出すとき、先頭からではなくENTRY 文のある途中から実行できる機能です。
ALTERNATE RETURN は SUBROUTINE または FUNCTION から RETURN で戻る時に、呼び出し場所ではなく、指定の行番号の場所に戻れるという機能です。
文法書をみると、行きと帰りの分岐で対称的になっているような気がするせいか、並んで出てきたりします。しかし、現在の視点から眺めれば機能的な意味・目的は全く異なるものだと思います。
以下で実例を見てゆきます。
ENTRY の MODULE 的用法
ここでは SUBROUTINE MODULE の中に、ZERO,LIN,APPLY,PRNT の4つの ENTRY を設けて、これらを Fortran90 以降の Module procedure のように使います。親名前の SUBROUTINE MODULE は呼び出しません。宣言した変数は、各 ENTRY で共有された PRIVATE 属性の MODULE 変数相当のものになります。PRIVATE になるのは、外から直接アクセスできないためです。
ソース・プログラム
シンタックス・カラリングで、第一カラムの C がコメント行と認識されないので見にくいですが、構造としては Fortran90 の Module とよく似ています。
ENTRY の入れ物の副プログラムを SUBROUTINE で宣言すると、ENTRY になるのは SUBROUTINE だけ、FUNCTION の場合は FUNCTION だけしか許されません。また各 ENTRY 毎のローカル変数宣言も許されません。
C
C ENTRY AS MODULE PROCEDURE
C
SUBROUTINE MODULE()
C MODULE VARIABLES : NMAX, X PRIVATE
PARAMETER (NMAX = 17)
REAL X(NMAX)
SAVE X
EXTERNAL FUN
C CONTAINS
ENTRY ZERO()
DO 10 I = 1, NMAX
X(i) = 0.0
10 CONTINUE
RETURN
C END ZERO
ENTRY LIN()
DO 11 I = 1, NMAX
X(i) = REAL(I)
11 CONTINUE
RETURN
C END LIN
ENTRY APPLY(FUN)
DO 12 I = 1, NMAX
X(I) = FUN(X(I))
12 CONTINUE
RETURN
C END APPLY
ENTRY PRNT()
M = 5
DO 13 I = 1, NMAX, M
I1 = MIN(I + 4, NMAX)
PRINT *, (X(J), J = I, I1)
13 CONTINUE
RETURN
C END PRNT
END
C END MODULE
C
C FUNCTIONS
C
FUNCTION SQR(X)
SQR = X * X
RETURN
END
C
FUNCTION SQROOT(X)
SQROOT = SQRT(X)
RETURN
END
C
C MAIN PROGRAM
C
PROGRAM MAIN
PARAMETER (NMAX = 17)
EXTERNAL SQR, SQROOT
CALL LIN()
CALL APPLY(SQROOT)
CALL PRNT()
PRINT *
CALL APPLY(SQR)
CALL PRNT()
CALL ZERO()
END
実行結果
ここでは、関数を引数とするサブルーチンによって、MODULE 変数 X に対する ELEMENTAL 処理を行っています。1から17までの数のルートをとりまた二乗して元に戻しています。
1.000000 1.414214 1.732051 2.000000 2.236068
2.449490 2.645751 2.828427 3.000000 3.162278
3.316625 3.464102 3.605551 3.741657 3.872983
4.000000 4.123106
1.000000 2.000000 3.000000 4.000000 5.000000
6.000000 7.000000 8.000000 9.000000 10.00000
11.00000 12.00000 13.00000 14.00000 15.00000
16.00000 17.00000
ALTERNATE RETURN の例外処理的用法
ここでは I/O 処理を例として、例外処理を見てみることにします。ALTERNATE RETURN の前に、まずは READ/WRITE 文組み込みの例外処理の祖型を見てみます。
READ/WRITE END=xx/ERR=xx
大き目のバッファ配列を用意しておき、サイズの不明なデータを読み込みます。ファイルの最後まで来て EOF (End Of File) が出たら、行番号 99 へ例外処理的に脱出します。なお EOF 以外の error が発生した場合は、行番号 999 へ飛んで、IOSTAT のエラー番号を書き出して実行終了します。
なお FORTRAN の慣例では 99, 999, 9999 などの行番号は、例外処理的な場合に使われることが多いです。
ソース・プログラム
C
C PSEUDO EXCEPTION I/O
C
PROGRAM MAIN
PARAMETER (NMAX = 10, MAXBUF = 9999)
REAL X(NMAX), BUFF(MAXBUF)
DO 10 I = 1, NMAX
X(I) = I
10 CONTINUE
WRITE(9, *) X
CLOSE(9)
C
C TRY
READ(9, *, END=99, ERR=999, IOSTAT=IO) (BUFF(I), I = 1, MAXBUF)
C EXCEPT EOF
99 CONTINUE
CLOSE(9)
PRINT *, 'EOF AT RECORD =', I
NX = I - 1
PRINT *, 'NUMBER OF DATA =', NX
GOTO 20
C EXCEPT ERROR
999 CONTINUE
CLOSE(9)
PRINT *, 'I/O ERROR: READING FILE 9'
PRINT *, 'IOSTAT =', IO
STOP
20 CONTINUE
C END TRY
PRINT *, (X(I), I = 1, NX)
END
実行例
EOF AT RECORD = 11
NUMBER OF DATA = 10
1.000000 2.000000 3.000000 4.000000 5.000000
6.000000 7.000000 8.000000 9.000000 10.00000
ALTERNATE RETURN
次に、alternate return での例外処理をみてみます。上の例で I/O をサブルーチンの中で行っている状況で、メインルーチン側でエラー処理などをしたい場合、alternate return の出番です。引数として、例外処理用の行番号を渡してやれば、サブルーチン内での RETURN n で渡した行番号へ直接戻ることが出来ます。
ソース・プログラム
C
C PSEUDO EXCEPTION
C ALTERNATE RETURN
C
SUBROUTINE IOSUB(BUF, NX, *, *)
REAL BUF(*)
READ(9, *, END=99, ERR=999, IOSTAT=IO) (BUF(I), I = 1, 9999)
C EOF
99 NX = I - 1
RETURN 1
C ERROR
999 CONTINUE
PRINT *, 'I/O ERROR IOSTAT =', IO
RETURN 2
END
C
C
C
PROGRAM MAIN
PARAMETER (MX=10, NMAX = 9999)
REAL X(MX), BUF(NMAX)
C
DO 10 I = 1, MX
X(I) = I
10 CONTINUE
WRITE(9, *) X
CLOSE(9)
C
CALL IOSUB(BUF, NX, *99, *999)
STOP
C
C EXCEPTION END OF FILE
99 PRINT *, 'NUMBER OF DATA =', NX
PRINT *, (X(I), I = 1, NX)
STOP 'NORMAL END'
C
C EXCEPTION I/O ERROR
999 STOP 'ABNORMAL END'
END
実行例
NUMBER OF DATA = 10
1.000000 2.000000 3.000000 4.000000 5.000000
6.000000 7.000000 8.000000 9.000000 10.00000
NORMAL END
まとめ
以上の実例から、FORTRAN77 以前から FORTRAN では、モジュラー型のプログラミングや、例外処理による例外的な状況を、通常処理から隔離して記述するような試みを行っていたことを見てきました。
しかしながら、使ってみればわかりますが、色々と制約が多くて使いづらく、文法的にも理解しにくい所があります。
結局、Fortran90 で MODULE 構文が導入されるまでは、ENTRY 文で変数共有するよりは COMMON 文を使って変数を共有させた方がよいとされていましたし、多分それが事実でしょう。
また ALTERNATE RETURN ですが、本質的に大域 GOTO 文であって、かつもしエラー番号を運ぶとするなら、何らかの手段で大域変数を持たなければならないので、局所解決を目指した構造化プログラミングとは相容れない構文であることが分かります。
このため alternate return はその後の規格からの廃止項目となり、例外処理は Modern Fortran には採用されてこなかったものと思われます。