こんにちは、現場の皆さん。数々の大規模バッチ改修や、冷や汗をかくような深夜の障害対応をくぐり抜けてきた、メインフレーム・システムアーキテクトの私だ。
今日もどこかの基幹システムで、夜間バッチがうなりを上げ、あるいは若手エンジニアが「なぜか変数の値が取れません!」と頭を抱えていることだろう。
今回は、PL/Iの基本構文と切っても切り離せない、「TESTコンパイラオプションとSYMテーブルの生成」について徹底的に解説しよう。
デバッガ(IBM z/OS Debugger、昔で言うDTWやDebug Tool)を使ったステッピング実行や変数の書き換えを行う際、この「SYMテーブル(シンボル情報)」の仕組みを理解しているかどうかで、トラブルシューティングのスピードが文字通り10倍変わってくる。
さあ、現場の知恵を総動員して、この深いテーマを紐解いていこう。
—
1. 予約語を持たないPL/Iと識別子の世界、そしてデバッグの現実
PL/Iという言語の最大の特徴であり、時として悪名高い仕様が「予約語を持たない(厳密には文脈依存キーワード)」という点だ。
例えば、`IF`や`READ`といった単語であっても、プログラマが変数名として定義することが許されてしまう。コンパイラは前後の文脈(コンテキスト)から「これは命令なのか、それともユーザー定義の変数名なのか」を判断している。
1
/ 悪い冗談のような変数名の例。しかしPL/Iコンパイラは文法エラーにしない /
DECLARE IF FIXED BIN(31) INIT(10);
IF = IF + 1;
こんな変態的なコードを書く者はいないと信じたいが、こうした自由度の高さゆえに、PL/Iのコンパイルおよびリンクの仕組みは非常に複雑だ。そして、いざ本番稼働後のバッチabend(異常終了)や、複雑なデータ変換ロジックのデバッグを行うとき、我々を助けてくれるのがIBM z/OS Debuggerである。
ここで問題になるのが、「コンパイル時にシンボル情報をどう保持させるか」という点だ。最適化された本番ロードモジュールには、通常、変数名などの人間用の情報は残っていない。機械語のオフセットだけが存在する世界だ。そこに命を吹き込むのが、`TEST`コンパイラオプションなのだ。
—
2. TESTオプションとSYMテーブルの深い関係
コンパイラオプションに `TEST` を指定すると、コンパイラはオブジェクトモジュール(およびロードモジュール)の中に、ソースコードの変数名、配列の次元、構造体のレイアウト、さらにはステートメント番号とマシン語命令の対応表といった「シンボル情報(SYMテーブル)」を埋め込む。
現場でよく使われる指定の組み合わせを見てみよう。
//STEP1 EXEC PGM=IEL0AA登場(IBM Enterprise PL/I Compiler),
// PARM=’RENT,APOST,TEST(SYM,SECT,EJPD)’
ここで、`TEST` サブパラメータの意味を正確に理解しているか?
- `SYM`: 変数名、構造体、配列などのシンボルテーブルを生成する。デバッガ上で `LIST 顧客マスタ.氏名` のように変数名で中身を覗くために絶対不可欠なオプションだ。
- `SECT`: セクション(ブロックやプロシージャ)の情報を生成する。
- `EJPD`: フック(Hook:デバッガが処理を一時停止するためのコードの切れ目)を挿入する。現代の z/OS Debugger では、必ずしもソースの全行にフックを埋め込む必要はなく、フックなし(No-hook)デバッグが主流になりつつあるが、SYMテーブル自体は変数解決のために必要となる。
⚠️ 注意すべき「ロードモジュールサイズへの影響」
ここでシニアアーキテクトとして厳重に警告しておきたい。
`TEST(SYM)` を指定してコンパイルされたプログラムは、シンボル情報の分だけロードモジュール(およびSYSUT1/SYSLIN等のワークファイル)のサイズが跳ね上がる。
数千ステップの巨大なマスター更新バッチプログラム等で `TEST` を安易に全モジュールへ付与したまま本番リリースするとどうなるか?
PDS(Partitioned Data Set)の容量を圧迫し、最悪の場合、リンクエディット時に領域不足(B37エラーなど)を引き起こしたり、ロード時の仮想ストレージ(LPAやCSA周辺)を無駄に消費したりする原因になる。
鉄則:
- 開発・結合テスト環境: `TEST(SYM)` は常時付与し、デバッグ効率を最優先する。
- 本番環境: 原則として `NOTEST` でコンパイルし、ロードモジュールを軽量化する。本番障害(PPRCや夜間緊急対応)でどうしてもソースレベルデバッグが必要な場合のみ、該当モジュールを一時的に `TEST` 付きで再コンパイル・適用する。
—
3. 実践:VSAMファイルを叩くバッチプログラムとシンボル情報
百聞は一見に如かず。実際に現場でよくある、VSAM KSDS(Key-Sequenced Data Set)のレコードを読み込み、条件判定を行ってエラー処理(ONユニット活用)を行う実用的なPL/Iコードを見てみよう。
このコードを `TEST` オプション付きでコンパイルしておけば、デバッガ上で `WK_KOUZA_ZAKYAKU_FLG` の中身をリアルタイムに監視できる。
1
TEST_VSAM_PRC: PROC OPTIONS(MAIN);
//
/ プログラム名: TEST_VSAM_PRC /
/ 概要: 口座マスター(VSAM KSDS)を読み込み、残高を検証する /
/ ONユニットによる例外処理とシンボルデバッグの例 /
//
/ VSAMマスターのレコードレイアウト定義(構造体) /
DECLARE 1 KOUZA_MASTER,
5 WK_KOUZA_NO CHAR(8), / 口座番号 /
5 WK_KOUZA_NAME CHAR(30), / 口座名義 /
5 WK_KOUZA_ZANDAKA FIXED BIN(31),/ 預金残高 /
5 WK_KOUZA_STAT CHAR(1); / 状態フラグ /
/ ワーキング変数 /
DECLARE WK_READ_COUNT FIXED BIN(31) INIT(0);
DECLARE EOF_FLG BIT(1) INIT(‘0’B);
/ ファイル定義 (VSAM KSDS) /
DECLARE KOUZA_FILE FILE RECORD
INPUT
ENVIRONMENT(
BUFND(4)
BUFNI(2)
);
//
/ ONユニット: 入出力エラーおよびレコード不在時の制御フロー /
//
ON ENDFILE(KOUZA_FILE)
BEGIN;
EOF_FLG = ‘1’B; / 読み込み完了フラグを立てる /
END;
ON UNDEFINEDFILE(KOUZA_FILE)
BEGIN;
DISPLAY(‘【SEVERE】口座マスターファイルのオープンに失敗しました。’);
SIGNAL ERROR;
END;
/ 処理開始 /
DISPLAY(‘【INFO】口座残高検証バッチ処理を開始します。’);
OPEN FILE(KOUZA_FILE);
/ 初回レコード読み込み /
READ FILE(KOUZA_FILE) INTO(KOUZA_MASTER);
DO WHILE (^EOF_FLG);
WK_READ_COUNT = WK_READ_COUNT + 1;
/ ビジネスロジックの検証(ここでデバッガをブレークさせると効果的) /
IF WK_KOUZA_ZANDAKA < 0 THEN
DO;
DISPLAY('【WARNING】マイナス残高を検知: 口座番号 = ' || WK_KOUZA_NO);
END;
/ 次のレコード読み込み /
READ FILE(KOUZA_FILE) INTO(KOUZA_MASTER);
END;
CLOSE FILE(KOUZA_FILE);
DISPLAY('【INFO】処理正常終了。総読み込み件数 = ' || TRIM(WK_READ_COUNT));
RETURN;
END TEST_VSAM_PRC;
このコードのポイントとデバッグ時のアプローチ
1. 構造体 (`DECLARE 1 KOUZA_MASTER …`) の可視性:
`TEST(SYM)` が有効な状態でこのプログラムを z/OS Debugger で動かすと、`LIST KOUZA_MASTER` と打つだけで、`WK_KOUZA_NO` や `WK_KOUZA_ZANDAKA` の値が綺麗に階層表示される。もし `NOTEST` でコンパイルしていると、これらは単なるメモリアドレス(オフセット)の塊に見えてしまい、人間が手動で16進数をデコードする地獄の作業が待っている。
2. ONユニットと制御フロー:
`ENDFILE` や `UNDEFINEDFILE` などの条件が発生した際、デバッガのブレークポイントをONユニットの `BEGIN` ブロック内に仕掛けておくと、例外発生瞬間の変数の状態(例えば、なぜファイルオープンに失敗したのかのDD名やステータスコード)を完璧に捉えることができる。
—
4. シニアアーキテクトからの実務アドバイス
最後に、保守・開発現場で後輩たちによく指導している「デバッグとコンパイルオプションの黄金律」を授けよう。
1. JCLのプロシージャを賢く使い分けろ
開発用JCLプロシージャと本番用JCLプロシージャで、コンパイルステップの `PARM` 値を明確に分離すること。「うっかり本番に `TEST(SYM)` のままの重たいモジュールを乗せてしまった」というインシデントは、笑い話のようでいてレガシー現場では時々起こる。コンフィグ管理を徹底しよう。
2. コンパイラのバージョンアップ(Enterprise PL/Iへの移行)時の注意
古いOS/VS PL/IからIBM Enterprise PL/Iへのマイグレーション案件では、古いコードに残っている方言や、変数名のスコープの曖昧さが `TEST` オプション付きのコンパイル時にエラーとして顕在化することがよくある。コンパイラが吐き出す診断メッセージを恐れず、シンボルテーブルを正しく生成できるクリーンなコードを維持することが、結果的にシステムの寿命を延ばす。
PL/Iは奥が深く、そして何十年も日本の金融・基幹を支えてきた堅牢な言語だ。
その言語仕様と、最新のz/OS Debuggerが提供する強力なシンボル機能(SYMテーブル)を両方とも手中に収めれば、どんな複雑なバグも恐れるに足りない。
日々の保守・開発作業、ご苦労様だ。健闘を祈る!
