はじめに:なぜ BUILTIN 属性が重要なのか?
PL/I を開発していると、思わぬところで「名前の衝突」に悩まされることがあります。特に、PL/I が標準で提供する組み込み関数(BUILTIN 関数)と同じ名前の変数を定義してしまった場合、意図しない動作を引き起こす可能性があります。本記事では、この名前衝突を防ぎ、コードの安全性を高めるための「BUILTIN 属性」について、実務で役立つ知識を解説します。
PL/I では、`DATE` や `ADDR`、`SUBSTR` といった、日付取得、アドレス取得、部分文字列取得など、様々な便利な組み込み関数が用意されています。これらはコンパイラによって特別な処理が行われるため、開発者はこれらの関数を意識せずに利用できます。しかし、もしあなたがこれらの組み込み関数と同じ名前の変数(例えば `DATE` という名前の変数)を定義してしまうと、コンパイラはどちらを指しているのか混乱し、予期せぬエラーやバグの原因となります。
`BUILTIN` 属性は、この問題を解決するための強力な手段です。この属性を付けることで、「この変数は、PL/I が標準で提供する組み込み関数であることを明示します」とコンパイラに伝えることができます。これにより、意図しない名前の衝突を防ぎ、コードの堅牢性を向上させることができます。
PL/I の BUILTIN 関数の基礎知識
PL/I の組み込み関数は、プログラム内で特別な宣言なしに呼び出すことができる、コンパイラに組み込まれた機能群です。これらの関数は、数値計算、文字列操作、入出力制御、システム情報取得など、多岐にわたる処理を簡潔に記述するために利用されます。
例えば、現在のシステム日付を取得する `DATE` 関数、変数のメモリアドレスを取得する `ADDR` 関数、文字列の一部を取り出す `SUBSTR` 関数などは、非常に頻繁に利用される組み込み関数です。
これらの組み込み関数は、通常、予約語として扱われます。しかし、PL/I の設計思想として、ある程度の柔軟性を持たせているため、ユーザー定義の変数名がこれらの組み込み関数名と衝突する可能性がゼロではありません。
BUILTIN 属性の実装と解決策
`BUILTIN` 属性を使用することで、コンパイラに対して、特定の識別子が組み込み関数であることを明示的に伝えることができます。これにより、ユーザー定義の変数名との名前衝突を防ぎます。
構文は非常にシンプルです。変数を宣言する際に `BUILTIN` 属性を追加するだけです。
例えば、`ADDR` という名前の組み込み関数が存在しますが、もし `ADDR` という名前の変数を使いたい場合(通常は避けるべきですが、例として)、以下のように宣言します。
DCL ADDR BUILTIN;
この宣言により、コンパイラはこの `ADDR` が組み込み関数であることを認識し、ユーザー定義の変数として扱われることを防ぎます。
そして、組み込み関数 `ADDR` を呼び出す際は、通常通り引数を与えて使用します。
DCL VAR CHARACTER(10);
DECLARE ADDR_VAR POINTER;
ADDR_VAR = ADDR(VAR); / ここで組み込み関数 ADDR が使用される /
この例では、`DCL ADDR BUILTIN;` という宣言は、厳密には `ADDR` という 識別子 が組み込み関数であることをコンパイラに再確認させるためのものです。もし `ADDR` という名前で 別の変数 を定義したい場合は、この `BUILTIN` 属性は使用しません。しかし、組み込み関数そのものを参照したい場合や、万が一の名前衝突を防ぐために明示したい場合にこの属性が有効になります。
また、`BUILTIN` 属性は、コンパイラによるコードの最適化を促す効果もあります。コンパイラは、`BUILTIN` 属性が付与された識別子が組み込み関数であることを認識できるため、インライン展開などの最適化を適用しやすくなります。これにより、実行パフォーマンスの向上が期待できます。
サンプルプログラム:BUILTIN 属性の利用例
ここでは、`DATE` という組み込み関数と、同名のユーザー定義変数が衝突しないように `BUILTIN` 属性を使用する例を示します。
//
/ BUILTIN 属性の利用例 /
/ DATE という組み込み関数と、同名のユーザー定義変数との名前衝突を防ぐ /
//
PROGRAM_START: PROC OPTIONS(MAIN);
/ DATE という名前の組み込み関数であることを明示 /
DCL DATE BUILTIN;
/ ユーザー定義の変数。日付を表すための文字列 /
DCL MY_DATE_VAR CHARACTER(8);
/ 組み込み関数 DATE を呼び出して、システム日付を取得 /
MY_DATE_VAR = DATE; / ここで組み込み関数 DATE が使われる /
/ 取得した日付を表示 /
PUT SKIP LIST(‘System Date: ‘ || MY_DATE_VAR);
/ 別の例:ADDR 組み込み関数の利用 /
DCL MY_STRING CHARACTER(20) VARYING;
DECLARE MY_STRING_ADDR POINTER;
MY_STRING = ‘Hello PL/I’;
MY_STRING_ADDR = ADDR(MY_STRING); / 組み込み関数 ADDR を使用 /
PUT SKIP LIST(‘Address of MY_STRING: ‘ || MY_STRING_ADDR);
END PROGRAM_START;
コードの解説:
- `DCL DATE BUILTIN;`: ここで、`DATE` という識別子が PL/I の組み込み関数であることをコンパイラに明示しています。これにより、もし `DCL DATE CHARACTER(8);` のような宣言を後続で行ったとしても、`DATE` は組み込み関数として参照されるようになります。
- `MY_DATE_VAR = DATE;`: この行では、`MY_DATE_VAR` にシステム日付が代入されます。`DATE` は `BUILTIN` 属性によって組み込み関数として正しく認識され、実行されます。
- `ADDR(MY_STRING)`: 同様に、`ADDR` も組み込み関数として機能し、`MY_STRING` 変数のメモリアドレスを取得します。
このサンプルコードを実行すると、現在のシステム日付と `MY_STRING` 変数のメモリアドレスが表示されます。
応用と注意点
`BUILTIN` 属性は、コードの安全性を高める上で非常に有効ですが、いくつか注意すべき点があります。
現代言語との比較
現代的なプログラミング言語の多くでは、標準ライブラリの関数名やキーワードは予約語として扱われ、ユーザー定義の変数名として使用できないように設計されています。これにより、名前衝突のリスクは低減されています。しかし、PL/I は、その柔軟性ゆえに、ユーザー定義の識別子が組み込み関数名と衝突する可能性が残されています。そのため、PL/I では `BUILTIN` 属性による明示的な保護が、より重要になる場合があります。
移行ツールのパースミスに注意
古い PL/I コードを新しい環境に移行する際や、コード解析ツール(パースツール)を使用する際には、`BUILTIN` 属性の扱いに注意が必要です。ツールが `BUILTIN` 属性を正しく解釈できず、予期せぬエラーを引き起こす可能性があります。特に、`BUILTIN` 属性が付与された識別子をユーザー定義変数として扱おうとするようなパースミスには注意が必要です。
過剰な使用は避ける
`BUILTIN` 属性は、名前衝突を防ぐための強力な手段ですが、必要以上に多用するとコードの可読性を損なう可能性があります。基本的には、組み込み関数名と明確に衝突する可能性がある場合や、コードの意図をより明確にしたい場合に限定して使用するのが良いでしょう。
代替案:名前空間の活用
もし、`BUILTIN` 属性を使わずに名前衝突を避けたい場合は、変数名にプレフィックスを付けるなどの命名規則を導入することも有効です。例えば、組み込み関数 `DATE` を参照したいが、`DCL DATE CHARACTER(8);` という変数も定義したい場合、`DCL MY_DATE_VAR CHARACTER(8);` のように、変数名に `MY_` などのプレフィックスを付けることで、名前の衝突を避けることができます。
PL/I の `BUILTIN` 属性を理解し、適切に活用することで、より安全で保守性の高いプログラムを作成することができます。ぜひ、日々の開発業務で意識して使ってみてください。

コメント