PL/Iの「自由」は「規律」から生まれる:識別子の深淵とコンパイラを出し抜くコーディング術
若手のエンジニアからよく相談されるのが、「PL/Iの識別子(変数名)ってどこまで自由に使っていいんですか?」という質問だ。確かに、C言語やJavaのように厳格な予約語(Reserved Words)のリストを暗記しなくてもいいというPL/Iの仕様は、初心者には非常に寛容に映るだろう。
しかし、ベテランの視点から言わせてもらえば、「予約語がない」ことは「何をやってもいい」という意味ではない。 むしろ、コンパイラがどのように識別子を解釈しているかの「文脈」を理解していないと、大規模なバッチ改修の現場で、一生見つからないような不可解なバグに足元を掬われることになる。
今日は、PL/Iの識別子命名の流儀と、コンパイラを味方につけるための作法について語ろうと思う。
—
1. 識別子の「国別文字」というスパイス
PL/Iでは、英字(A-Z)、数字(0-9)に加え、国別文字(`@`, `#`, `$`)を識別子に使用できる。これはメインフレームの古いコードを読んでいると頻繁に遭遇するはずだ。
- ルール: 先頭は必ず英字または国別文字。
- 現場の知恵: `$`, `#`, `@` は、特定のデータ型や用途を識別するために使うのが暗黙の了解だ。例えば、バッチの内部変数とVSAMから取得したフィールド名を分けるために、`$VAL` のように `$` を付与するルールを設けると、コードの可読性が格段に上がる。
ただし、注意が必要だ。言語仕様上は予約語が存在しないため、`IF` や `THEN` といったキーワードを自作の変数名に設定することもできてしまう。
1
/ 悪い例:可読性を著しく損なう /
IF = 10;
THEN = 20;
IF IF = THEN THEN …
こんなコードを書けば、レビューで門前払いされるのは間違いない。コンパイラは動くが、人間には読めない。PL/Iの設計思想は「プログラマの意図を汲み取る」ことにあるが、あまりに極端な命名はデバッグを困難にするだけだ。
—
2. 識別子の有効範囲(スコープ)とコンパイラの優先順位
PL/Iの識別子は、宣言されたブロック内でのみ有効だ。ここで重要なのは、「コンパイラはどうやって変数の場所を特定しているか」という点だ。
特に、`BUILTIN` 関数と同じ名前の変数を定義してしまった場合、コンパイラはどのような挙動をとるか知っているだろうか?
`SUBSTR` という変数を定義した直後に、文字列操作で `SUBSTR` を使おうとすると、コンパイラは混乱する。これを防ぐには、宣言部で明確に属性を与える必要がある。
—
3. 実践:VSAMアクセスとONユニットを交えたコーディング標準
実際に、保守現場でよくある「VSAMファイルを読み込み、エラー時にはONユニットで捕捉する」という構造を例に、命名と制御フローを確認しよう。
1
/ —————————————————————— /
/ PROCEDURE: BATCH001 /
/ 目的: VSAMファイル読み込みとエラーハンドリング /
/ —————————————————————— /
BATCH001: PROC OPTIONS(MAIN);
/ 変数宣言:国別文字を活用した命名の工夫 /
DCL $REC_KEY CHAR(10); / VSAM検索キー /
DCL $FILE_STATUS FIXED BIN(15); / ファイルステータス /
DCL #ERR_COUNT FIXED DEC(5) INIT(0); / エラーカウンタ /
/ ONユニットによる例外制御の定義 /
ON ENDFILE(VSAM_FILE) BEGIN;
PUT SKIP LIST(‘ EOF REACHED ‘);
END;
ON ERROR BEGIN;
PUT SKIP LIST(‘ SYSTEM ERROR DETECTED ‘);
/ 異常終了時の後処理をここに記述 /
END;
/ VSAMからのレコード取得 /
READ FILE(VSAM_FILE) INTO(DATA_AREA) KEY($REC_KEY);
/ 組み込み関数の活用:LENGTH関数などは予約語ではないが注意 /
IF LENGTH(TRIM($REC_KEY)) > 0 THEN DO;
/ 何らかのロジック処理 /
END;
END BATCH001;
ここがデバッグの分かれ道:
1. BUILTIN関数の保護: もし自作の関数名と組み込み関数が被る可能性があるなら、`GENERIC` 属性や `BUILTIN` 属性を明示的に宣言すること。これでコンパイラの解釈の揺らぎを完全に排除できる。
2. ONユニットのスコープ: `ON ERROR` は、そのブロック内で発生した全ての意図しないエラーを拾う。識別子をグローバルに定義しすぎると、エラー発生時にどの変数がどの値を保持しているのか追跡不能になる。変数のスコープは「必要最小限」が鉄則だ。
—
ベテランからのアドバイス
PL/Iは、他の言語に比べて「何でもできる」自由度が高い。しかし、大規模マイグレーションの現場では、その自由度が「一貫性の欠如」という名の技術負債に変わる。
- 命名規則はプロジェクト全体で統一せよ: 個人の好みで `#` を使ったり使わなかったりするのはNGだ。
- コンパイラの警告を無視するな: 特に変数名の重複や、型変換(`FIXED BIN` と `FIXED DEC` の意図しない混在など)に関する警告は、将来のバグの芽だ。
PL/Iのコードは、適切に書けば数十年動き続ける強靭な資産となる。識別子一つにこだわりを持ち、コンパイラに「曖昧な判断」をさせないコーディングを心がけてほしい。それが、長年この世界で生き残るシステムエンジニアの嗜みというものだ。
