はじめに
皆様、こんにちは!メインフレーム技術者の皆様は、日々複雑なシステム開発に携わっていることと思います。今回は、プログラム開発における「ちょっとした工夫」が、開発効率や保守性を大きく向上させるプリプロセッサ機能についてご紹介します。特に、外部ファイルを参照する `%INCLUDE` 文で、参照先のファイルが存在しない場合にエラーとならず、処理をスキップさせたいというニーズに応える方法です。これは、開発環境や実行環境によって利用できる共通部品が異なる場合に、柔軟な対応を可能にするための重要なテクニックとなります。
基礎知識:`%INCLUDE` とプリプロセッサ
メインフレームのCOBOLやPL/Iなどの言語では、ソースコードの一部を別のファイルに記述し、それを呼び出す機能として `%INCLUDE` がよく利用されます。これにより、共通のデータ定義やサブルーチンなどを一元管理し、コードの再利用性を高めることができます。
一方、プリプロセッサとは、コンパイル(プログラムを機械語に変換する作業)の前にソースコードを処理するプログラムのことです。 `%INCLUDE` の展開や、条件によってコードの一部を含めたり除外したりする処理(条件付きコンパイル)など、様々な処理を実行できます。今回ご紹介する機能も、このプリプロセッサの機能の一つです。
実装/解決策:`FILE_EXISTS` 関数で存在チェック
参照したい `%INCLUDE` メンバ(ファイル)が、必ずしも全ての開発環境や実行環境に存在するとは限りません。そのような場合に、ファイルが存在しないことを理由にコンパイルエラーが発生してしまうと、開発が滞ってしまいます。
この問題を解決するために、プリプロセッサには `FILE_EXISTS` という便利な関数が用意されています。この関数は、引数に指定されたファイル名が存在するかどうかをチェックし、存在すれば真(TRUE)、存在しなければ偽(FALSE)を返します。
これを利用して、 `%IF FILE_EXISTS(‘ファイル名’) %THEN %INCLUDE ファイル名;` のように記述することで、ファイルが存在する場合にのみ `%INCLUDE` を実行することができます。これにより、オプションのメンバが存在しない場合でも、プログラムは正常にコンパイルされるようになります。
サンプルプログラム
ここでは、PL/Iを例に、オプションのデータ定義ファイル (`OPTIONAL_DCL`) が存在しない場合に、それを無視してコンパイルを進めるサンプルコードを示します。
//
/ /
/ サンプルプログラム:オプションのインクルードファイルの処理 /
/ /
//
%PAGE; / ページ送りを指示(コンパイラによっては不要) /
//
/ OPTIONAL_DCL が存在する場合のみ、このデータ定義をインクルードする /
//
%IF FILE_EXISTS(‘OPTIONAL_DCL’) %THEN %INCLUDE OPTIONAL_DCL;
//
/ メイン処理 /
//
START:
BEGIN;
DECLARE (MY_VAR, ANOTHER_VAR) FIXED BINARY;
/ OPTIONAL_DCL に定義された変数がある場合(存在した場合)は、 /
/ ここで利用できる。存在しない場合は、この部分は無視される。 /
/ 例:IF EXISTS(OPTIONAL_VAR) THEN … /
MY_VAR = 10;
ANOTHER_VAR = MY_VAR 2;
PUT SKIP LIST(‘MY_VAR =’, MY_VAR);
PUT SKIP LIST(‘ANOTHER_VAR =’, ANOTHER_VAR);
END START;
解説:
- `%IF FILE_EXISTS(‘OPTIONAL_DCL’) %THEN %INCLUDE OPTIONAL_DCL;`
- `FILE_EXISTS(‘OPTIONAL_DCL’)` で、`OPTIONAL_DCL` という名前のファイルが存在するかどうかをチェックします。
- ファイルが存在すれば、`%THEN` の後の `%INCLUDE OPTIONAL_DCL;` が実行され、`OPTIONAL_DCL` の内容がこの位置に展開されます。
- ファイルが存在しなければ、この `%IF` 文全体が無視され、`%INCLUDE` は実行されません。
- `DECLARE (MY_VAR, ANOTHER_VAR) FIXED BINARY;`
- これは、`OPTIONAL_DCL` が存在するかどうかにかかわらず、必ずコンパイルされる標準的なデータ宣言です。
- コメント部分で、`OPTIONAL_DCL` に定義された変数(例: `OPTIONAL_VAR`)が存在した場合に利用できることを示唆していますが、これはあくまで例です。実際の処理は `OPTIONAL_DCL` の内容に依存します。
このサンプルコードは、`OPTIONAL_DCL` ファイルがなくてもコンパイルが成功します。`OPTIONAL_DCL` が存在する場合のみ、そのファイルの内容がプログラムに組み込まれる、という動的な処理が可能になります。
応用・注意点
シングルソース・マルチプラットフォーム対応
この `FILE_EXISTS` を活用した `%INCLUDE` の条件分岐は、まさに「シングルソース・マルチプラットフォーム対応」の強化に繋がります。異なるOSやミドルウェアに依存する共通部品を、環境ごとに用意しておき、ビルド時に適切なものを選択させる、といった運用が容易になります。
移行時の検討事項
現代的な開発手法では、「Optional Dependency(オプション依存)」や「条件付きコンパイル」といった考え方が一般的です。メインフレームのプログラムをモダンな環境へ移行する際には、この `FILE_EXISTS` を利用した `%INCLUDE` の処理を、インターフェースのデフォルトメソッド(Javaなど)や、実行時の環境検知(例: Javaの `Class.forName()`)といった、より柔軟な仕組みに置き換えることが検討されるでしょう。
陥りやすいバグ
- ファイル名のタイプミス: `FILE_EXISTS` の引数に指定するファイル名を間違えると、意図した通りにファイルが存在しないと判断されてしまいます。大文字・小文字の区別にも注意が必要です。
- パスの指定: ファイル名だけでなく、必要に応じてパスの指定も適切に行う必要があります。プリプロセッサが参照できるパスが限られている場合、ファイルが見つからないという問題が発生する可能性があります。
- 依存関係の複雑化: あまりにも多くのオプションファイルや条件分岐を導入すると、コードの可読性や保守性が低下する可能性があります。どこまでをオプションとし、どこからを必須とするかの線引きは慎重に行う必要があります。
まとめ
`%INCLUDE` メンバの存在チェック機能は、メインフレーム開発における柔軟性と効率性を高めるための強力なツールです。今回ご紹介した `FILE_EXISTS` 関数と `%IF` 文の組み合わせを理解し、適切に活用することで、より洗練されたプログラム開発が可能になります。ぜひ、日々の開発業務で試してみてください。

コメント