len_trim
関数の代替品2018/04/15
FORTRAN77 を C/C++ に変換する(ただし人間には unreadable な出力しか出せない) f2c は、構造化 do
ループ記述に必要な cycle
文(C の continue
相当)と exit
文(文脈依存で C の break
相当、プログラムを終了させる exit()
関数とは異なる)に対応していません。これらは本来 FORTRAN77 規格外の拡張構文なので、対応していないこと自体はやむを得ませんが、多くの FORTRAN77 コンパイラでデファクトスタンダード拡張構文としてサポートされています。これらが f2c でも使えるようになれば、古いプログラムのメンテナンス(再コンパイルだけでなく、修正やリファクタリング)をするうえで役に立ちます。
また、FORTRAN77 で書かれた古いプログラムを(特に64bitで)コンパイルするにあたり、GNU GPL v.3 の感染回避策手段としても f2c を使うことができます。
最新の gfortran は実行時に不可分なランタイムライブラリDLLが GNU GPL v.3 である。GPL v.2 まで存在していたランタイムライブラリ例外は GPL v.3 にはないと解釈する方が法的に安全側のため、このような課題が生じてしまう。また 64bit の FORTRAN コンパイラは現時点で MinGW-w64 project の gcc に含まれる gfortran くらいしか選択肢がない(Intel Fortran は知らん)。一方、32bit でよいなら GCC-3.4.5 がまだあることはあるが、近年では周囲環境の変化でインストールに手古摺るようになり、古いランタイムのサポートや周辺ツールの相性にも不安がある。
そこで、cycle
/ exit
を goto
と continue
に置き換えて f2c の対応枠内に収めるような、最低限のプリプロセッサを作ってみました。
実用プログラムを記述する際に便利というより必須な関数として len_trim
が挙げられます。これもまた FORTRAN77 規格外の関数で、g77/gfortran には組み込まれているが f2c ではサポートされていません。f2c で変換したときには代替品が必要になります。C言語で作成したので、併せて掲載します。
(len_trim
に関する別解は こちら)
f2c およびそれに必要な libf2c は Netlib にあります。未だに、時々メンテナンスされているようです。
len_trim
関数の代替品
詳細な解説は割愛します。perl スクリプトをご覧ください。改良すべき点は山ほどあります。気が向いたら改良するかもしれませんし、放置するかもしれません。
需要や使い方は人それぞれである上に、至極あたりまえのことを愚直にやっているだけですので、何も主張しません。ご自由にお使いください。(zlibライセンスから3つの要求箇条を取り除いたものと考えてください…って、なんじゃそりゃ。)
ダウンロード:for2c.pl [2018/04/15]
以下の事を行います。
cycle
並びに exit
を goto
と continue
の組み合わせに置き換える。その際、ソースコード内に既にある文番号は避け、自動で文番号を付与する。
INCLUDE
文で取り込んでいる先のファイルには関知しない。
do
foobar(baz)
enddo
と記述してある場合(FORTRAN77 規格外、g77 など多くのコンパイラで許容されているが f2c は文法違反と判断してしまう)、これを f2c が対応している記述である(これもFORTRAN77 規格外だが)
do while(.true.)
foobar(baz)
enddo
に置き換える。
do
ループはそのまま放置。
len_trim
関数の代替品ダウンロード:len_trim.c
これも、ご自由にお使いください。
なお別解として、f2c において len_trim
自体を組み込み関数としてしまう方法は こちら をご覧ください。
libf2c は32bit/64bit各々同じ手順でコンパイル可能です。f2c の変換出力に対して64bitのCコンパイラを使えば、FORTRAN77のプログラムの64bit化も条件次第で可能です。
行 | 修正箇所 | 説明 | |
9 |
修正前 |
CFLAGS = -DUSE_CLOCK -DMSDOS -DNO_ONEXIT -Ot1 -DNO_My_ctype -DNO_ISATTY |
※長いので改行可指定を使っていますが実際は1行です。-MD でランタイムをダイナミックリンクにする(MSVCR*.DLL を使う)。デバッグビルドの場合は -MD を -MDd に変えればよい。-Ot1 は -Ot に -O1 (機械語サイズ最小・低速)を上書きと解釈されて意図と真逆の指定になるので、-O2 (最高速度)に修正する(ただし、大した差は出ない)。ssize_t という unix 由来の typedef (→通信用語の基礎知識)は MS-VC++ には無いので、マクロ NO_SSIZE_T を定義してそれを伝える。-DWANT_LEAD_0 と -nologo はお好みで構いません。前者はwrite文で浮動小数点数を出力するときに先行ゼロを省略しない(C/C++と親和性が高い表記)、後者はMS-VC++の著作権表示の抑止(コンソールの表示がすっきり)。
|
修正後 |
CFLAGS = -MD -DUSE_CLOCK -DMSDOS -DNO_ONEXIT -O2 -DNO_My_ctype -DNO_ISATTY -DNO_SSIZE_T -DWANT_LEAD_0 -nologo |
192 |
修正前 |
comptry.bat $(CC) $(CFLAGS) -DNO_FPINIT arithchk.c |
※長いので改行可指定を使っていますが実際は1行です。 バッチファイル comptry.bat は、 long long 型がまだ無い頃の古い MS-VC++ においてコンパイルエラーが生じた時には -DNO_LONG_LONG を加えて arithchk.c のコンパイルを再試行するためのもの。MS-VC++2005 以降では long long 型が定義済みなのでこのハックは不要であり、直接実行に修正する。
|
修正後 |
$(CC) $(CFLAGS) -DNO_FPINIT arithchk.c |
||
183-184 |
修正前 |
vcf2c.lib: $w lib -out:vcf2c.lib @libf2c.lbc |
この追記は 32bit と 64bit を作り分けるときに便利ですが必須ではありません。詳細は下の方の「ビルド」を参照。-out: では成果物のファイル名を指定します。私は以下のようにしています。
arith.h とオブジェクトファイルを消してしまいます。理由は、arith.h は FORTRAN の変数型が C のどの変数型に対応するかを規定する動的自動生成のヘッダファイルであり、32bit ビルドと 64bit ビルドで中身が異なるためです。 |
修正後 |
vcf2c.lib: $w lib -out:vcf2c64.lib @libf2c.lbc del arith.h *.obj |
※ ssize_t
について:signed size_t という意味ととれば良いでしょう。FORTRAN および Fortran には符号なし整数の概念が原則存在しない(処理系依存)という事情もあります。C言語との混合言語プログラミングにおけるインターフェイスでは文字列長の受け渡しなどにおいて size_t
(符号なし)との変換が求められることがあり、下手をするとバッファオーバーランになるため特に注意を要します。
詳細は libf2c のバグ を参照してください。
ファイルやコンソールから READ 文で読み込み時に US-ASCII 以外(文字コード128以上)の文字を扱う可能性がある場合は、読み込み文字種判定に関する未定義動作と配列添字オーバーランのバグを修正しておくことを推奨します。
以下の2か所
に
extern int ungetc(int, FILE*); /* for systems with a buggy stdio.h */
というのがある。これはMS-VC++では(特に /MD または /MDd の場合)かえって正しいプロトタイプ宣言を上書きしてしまい「warning C4273: 'ungetc' : dll リンクが一貫していません。」が発生する。MS-VC++は昔から正しい宣言がされているので、以下のようにする。
#ifndef _MSC_VER // to avoid warning C4273 with compiler option /MD or /MDd
extern int ungetc(int, FILE*); /* for systems with a buggy stdio.h */
#endif
そのほか致命的ではないものの、以下の問題もあります。どうするかは、各自で判断するしかありません。
/sdl
を指定すると(Visual Studio IDEのデフォルト)"error C4996: 'access': The POSIX name for this item is deprecated." などというメッセージがいくつか出ます。これは /sdl
を外すか、コマンドラインオプション /wd4996
を設定すれば回避できます。
/RTC1
を指定すると(Visual Studio IDEのデフォルト) open.c 58行目や rsne.c 112行目において "error C4703: 初期化されていない可能性のある…" というのが出る場合があります。アルゴリズム的にはそこに到達しないが、それをコンパイラが認識できないためです。 /RTC1
を無効にすれば回避はできるが、本来であればソースコードを直すべきでしょう。
再ビルドするときはその前に del arith.h *.obj
を実行すること。arith.h は動的自動生成のヘッダファイルであり一時的に存在する arithchk.exe によって作られ、いくつかのソースファイルがこれを #include している。このため、再ビルド前後で 32bit と 64bit が混在するとおかしなことになる。
あとは、nmake -f makefile.vc
を実行で行けます。成果物のファイル名は makefile.vc のオリジナルのままでは vcf2c.lib となります。このファイル名は makefile.vc の183-184行目で指定されており、32bit と 64bit、Release と Debug など、必要に応じて成果物ファイル名を変更した makefile を用意しておくと便利です。
次のようにリンカーオプションでコンソールプログラムであることを指定してください。vcf2c.lib の中にある main.obj が使われるようになります。
cl /MD foobar.c vcf2c.lib /link /SUBSYSTEM:CONSOLE
Windows XP でも実行可能にする場合(実機がないため検証してません):
cl /MD foobar.c vcf2c.lib /link /SUBSYSTEM:CONSOLE,5.01
メインルーチンを含むソースコードをf2cで変換した出力には明示的な main() がなく、代わりにFORTRANメインルーチンを表す int MAIN__(void) があります。unix系OS由来の Mingw-gcc (-mwindows や -shared を付けなければ -mconsole が自動で仮定される)と使い勝手が異なるところです。
len_trim
に関する別解 を言及。本文は変更無し。
トップページ /
計算機関係の雑多なこと /
f2c の tips - DO ループの CYCLE文・EXIT文に対応させるプリプロセッサとlen_trim関数の代替品
このサイトについて・著者連絡先