【入門編】ON条件におけるSUBSCRIPTRANGEのデバッグ活用 – PL/Iの基本構文とデータ制御実践ガイド

こんにちは!メインフレームの荒波へようこそ。
JavaやCOBOLの経験を積んで「さあ、次はPL/Iだ!」と意気込んでいるものの、目の前に広がる独特な大文字のコードや、C言語ともCOBOLとも違う空気に、ちょっぴり圧倒されていませんか?

「変数名に予約語がないってどういうこと?」
「配列の範囲外アクセスって、COBOLみたいに勝手に止まってくれないの?」

そんな不安を抱えているあなたへ。大丈夫ですよ、一つずつ紐解けばPL/Iは決して怖くありません。むしろ、その懐の深さと強力な機能を知れば、きっと好きになります。今回は、PL/Iのちょっと変わった識別子のルールに触れつつ、バグ退治の最強の相棒である`SUBSCRIPTRANGE`(サブスクリプト・レンジ)について、現場の知見を交えてたっぷり解説していきますね。

1. 予約語がない!?PL/Iの自由すぎる識別子ルール

JavaやCOBOLを触ってきた人にとって、一番最初に「えっ?」と驚くポイントがこれです。PL/Iには、いわゆる「絶対に変数名として使ってはいけない予約語」というものが原則として存在しません。

例えば、COBOLなら `MOVE` や `DISPLAY` は変数名に使えませんよね。でも、PL/Iの世界では、こんなコードが書けてしまいます。

1
DCL IF FIXED BIN(31); / 「IF」という名前の変数 /
DCL THEN FLOAT; / 「THEN」という名前の変数 /

IF = 10;

「えっ、コンパイラはどうやって `IF` が条件分岐の `IF` なのか、変数なのかを判断しているの?」と思いますよね。
実はPL/Iのコンパイラは、その前後の文脈(コンテキスト)をものすごく賢く読み取っています。人間が文章を読むとき、「『りんご』を食べた」の「りんご」が名詞だと自然に理解するのと同じです。

ただ、自由度が高いからといって、わざわざ `IF` や `DO` を変数名にするのは、後からコードを読むメンテナンス担当者(あるいは未来のあなた)を絶望させるだけなので絶対にやめましょうね(笑)。

2. 配列の「うっかり」を救う SUBSCRIPTRANGE

さて、本題に入りましょう。基幹システムのバッチプログラムを改修していて、最も恐ろしいバグの一つが「配列の添字(サブスクリプト)溢れ」です。

例えば、10個しか要素がない配列 `DCL WORK_TBL(10) FIXED BIN(31);` なのに、ループのカウンタが狂って `11番目` にアクセスしてしまったとします。
C言語なんかだと、運が悪いとそのままメモリの違う領域を破壊し、全然関係ない場所で謎の異常終了(セグメンテーション違反)を起こしたりしますよね。

PL/Iには、こうしたメモリ破壊を防ぎ、配列の境界チェックを行ってくれる神機能があります。それが `SUBSCRIPTRANGE` 条件です。

デフォルトでは無効になっている理由

「え、じゃあ最初から有効にしといてよ!」と思いますよね。
しかし、メインフレームの世界では「実行時パフォーマンス(CPU時間)」が神様です。すべての配列アクセスに対して「今、範囲内か?」とチェックを行っていると、何百万件もループを回す巨大なバッチ処理では、目に見えて処理速度が落ちてしまいます。

そのため、PL/Iではデフォルトではこのチェックがオフになっています。本番環境のスピードを優先するためですね。

3. デバッグの現場で SUBSCRIPTRANGE を有効にする方法

では、テスト環境で「なんだか変なデータが取れるぞ」「原因不明のABEND(異常終了)が起きるぞ」という怪奇現象に遭遇したときはどうすればいいでしょうか?

答えは簡単、プログラムの中でこの監視を「オン」にしてやればいいのです。

実際のコード例を見てみましょう。

1
/ ———————————————— /
/ SUBSCRIPTRANGE デバッグ活用のサンプルプログラム /
/ ———————————————— /
TEST_PROG: PROC OPTIONS(MAIN);

/ コンパイル時および実行時に範囲チェックを有効化する宣言 /
(SUBSCRIPTRANGE): プレフィックス(接頭辞)で範囲チェックを指定します /
(SUBSCRIPTRANGE) BEGIN;

DCL ITEM_CNT FIXED BIN(31) INIT(5);
DCL PRICE_LIST(10) FIXED BIN(31); / 要素数10の配列 /
DCL I FIXED BIN(31);

/ わざと10を超える範囲にアクセスするバグを仕込んでみます /
DO I = 1 TO 12;
PRICE_LIST(I) = I 100; / I=11 や I=12 の時に溢れます /
END;

END;

END TEST_PROG;

このコードを実行すると、`I = 11` になった瞬間にコンパイラが提供するONユニット(例外処理機構)が働き、「IBMZ などの環境で `IBM0221S SUBSCRIPTRANGE condition was raised`」といった分かりやすいエラーメッセージを出して、プログラムを安全に止めてくれます。

どこで配列がはみ出たのか一発で特定できるため、デバッグの効率が劇的に跳ね上がります。

4. アーキテクトからの実務アドバイス

ここで、現場のシニアエンジニアからの大切なアドバイスを一つ。

「便利だからといって、本番稼働するプログラムに `(SUBSCRIPTRANGE)` をつけっぱなしにするのは絶対にやめましょう。」

本番環境の膨大なトランザクション処理において、すべての配列アクセスに監視コストを支払うのは、システム全体のスループット低下(CPU使用率の高騰)を招きます。

おすすめの運用フローはこうです:
1. 開発・単体テスト・結合テスト環境: コンパイルオプション(またはプログラム内のプレフィックス)で `SUBSCRIPTRANGE` を常に有効にしておく。
2. 本番環境: テストを通過し、品質が担保されたコードであることを前提に、このチェックは外して(無効化して)ビルド・リリースする。

PL/Iは、私たちがしっかりと手綱を握ってあげれば、これほど頼もしく、かつ高速にデータを処理してくれる言語はありません。ルールや仕様で分からないところに出会ったら、「昔のプログラマは、どうやってマシンを効率よく動かそうとしたんだろう?」と背景に思いを馳せてみてくださいね。

それでは、快適なメインフレーム・ライフを!次回の解説もお楽しみに。

タイトルとURLをコピーしました