【実務・中級編】CICS環境下におけるEXEC CICSコマンドのプリコンパイルと変換プロセス – PL/Iの基本構文とデータ制御実践ガイド

おい、最近入った若手が「PL/Iって変数名に予約語が使えない制限が緩くて逆に怖いんですが、CICSの展開部はどうなってるんですか?」って聞いてきたんだよ。

いいかい、よく聞いてくれ。PL/Iという言語はな、IBMが1960年代に「科学技術計算も事務処理も、俺たちが全部一つの言語で統一してやるぜ!」っていう野望を持って生み出した化け物だ。だからこそ、他の言語(COBOLやCなど)とは一味も二味も違う独特の思想を持っている。

今回は、その中でもCICS(Customer Information Control System)環境に焦点を当てる。オンライン画面からバチバチとトランザクションを叩くあの世界で、俺たちが書いた `EXEC CICS` が裏でどう料理され、コンパイルされて動いているのか。現場のシニアとして、その裏側のカラクリを徹底的に叩き込んでやる。

—

1. PL/Iの識別子と「予約語を持たない」という狂気

まず大前提として、PL/Iの変数名の命名規則についておさらいしておこう。
PL/Iの識別子は、最大31文字(最近のコンパイラではもっと長いのもいけるが)、英字で始まり、英数字とアンダースコア(`_`)が使える。ここまでは普通のプログラミング言語と同じだ。

だがな、PL/Iの最大にして最強の、そして時には悪夢のような特徴は「言語仕様としての予約語(Reserved Words)を持たない」ということだ。

どういうことか? COBOLなら `IF` や `MOVE`、`DISPLAY` なんてのは絶対に変数名に使えないよな? でもPL/Iでは、理論上は以下のようなコードが書けてしまう。

DECLARE IF FIXED BIN(31); / 変数名に “IF” を使っている! /
IF = 10;

「じゃあコンパイラはどうやって `IF` が条件分岐なのか変数なのか判断するんだ?」って?
それはコンテキスト(文脈)で判断しているのさ。コンパイラは文脈から「これはキーワードだ」「ここはユーザー定義の変数だな」と空気を読んで解釈する。

この「予約語がない」という仕様は、一見すると自由度が高くて最高にクールに思えるだろ? だがな、CICSのプリコンパイルや大規模な保守開発の現場では、これが大惨事の引き金になる。
もしプログラマがうっかり `EXEC` や `CICS`、さらには `RESPONSE` なんていう単語を変数名に使ってみろ。プリプロセッサやコンパイラが盛大に誤解を起こし、身も凍るようなコンパイルエラー(あるいは、もっとタチの悪いサイレントバグ)を引き起こす。だからこそ、現場のコーディング標準では「ビルトイン関数名やCICS関連のキーワードっぽいものは絶対に変数名に使うな!」と厳しくマニュアルで縛っているのさ。

—

2. DFHECP1によるプリコンパイルの裏側

オンラインのCICSプログラムを書くとき、俺たちはソースコードの中にこんな風に書くよな。

EXEC CICS SEND MAP(‘MENUMAP’)
MAPSET(‘MENUSET’)
FROM(W-MENU-DATA);

だが、IBMのPL/Iコンパイラ(Enterprise PL/Iなど)は、そのままではこの `EXEC CICS` なんていう構文を理解できない。
コンパイルの第1ステップとして、CICS翻訳プログラム(DFHECP1)という名のプリプロセッサが走る。こいつがソースコードを舐め回し、人間が書いた `EXEC CICS` 構文を、PL/Iコンパイラがコンパイル可能な標準の `CALL` 文やデータ構造へと綺麗に翻訳(トランスレート)してくれるんだ。

生成されるインターフェース領域とDFHEIVAR

プリコンパイルを経た後のソースコード(正確にはコンパイラに渡る直前の展開イメージ)を見ると、お馴染みの面々が登場する。

1. DFHCOMMAREA や各種リンケージセクションの定義
2. DFHEIVAR(またはそれに類するCICS内部変数群)の呼び出し
3. 実際のCICS基盤モジュール(DFHICollなど)への `CALL` 文への置き換え

`EXEC CICS` の中に書いたオプション(例えば `MAP`, `FROM`, `LENGTH` など)は、すべてDFHECP1によって適切な引数リストに変換され、レジストリを介してCICSのエグゼクティブ・インターフェースに渡される。これが、あの黒い画面の裏側で行われている現実のプロセスだ。

—

3. 実践:CICS環境下でのPL/Iプログラム構造とVSAMアクセス

口ばかりじゃ信用されないだろうからな。CICS環境下で動く、典型的なPL/Iのオンラインプログラムの骨組みを書いて見せよう。
ここでは、VSAM(KSDS)ファイルからのレコード読み込み(`READ`)と、エラー時の `ON` ユニットによる制御、そしてバルトイン関数の活用を盛り込んだ実用的なコードだ。

/================================================================
/ プログラムID: OHLI010P
/ 概要 : CICSオンライン顧客マスター照会バッチ/オンライン
/================================================================/
OHLI010P: PROC OPTIONS(MAIN) REENTRANT;

/ — 1. ワークエリアおよびCICS通信エリアの定義 — /
DCL 1 CUST-COMMAREA,
5 CA-CUST-ID CHAR(8), / 顧客ID /
5 CA-RETURN-CD CHAR(2), / 応答コード /
5 CA-CUST-NAME CHAR(40); / 顧客名 /

DCL W-CUST-KEY CHAR(8);
DCL W-RESP-CD FIXED BIN(31); / 応答コード格納用 /
DCL W-LENG FIXED BIN(15); / 長さ格納用 /

/ VSAMレコードマッピング用構造体 /
DCL 1 CUST-REC,
5 R-CUST-ID CHAR(8),
5 R-CUST-NAME CHAR(40),
5 R-FILLER CHAR(52);

/ — 2. 状態監視(ONユニット)の設定 — /
/ エラー発生時の割り込み処理を設定しておくのがプロの技だ /
ON ERROR
BEGIN;
PUT SKIP LIST(‘ 予期せぬエラーが発生しました ‘);
/ 異常終了の処理をここに記述 /
END;

/ — 3. CICSトランザクションのメイン処理 — /

/ 通信エリア(COMMAREA)のアドレスを取得・判定 /
/ EIBCALEN はCICSが自動生成するビルトイン的な変数のひとつ /
IF EIBCALEN = 0 THEN
DO;
/ 初回起動時:初期画面の送信処理 /
EXEC CICS SEND MAP(‘CUSTMP1’)
MAPSET(‘CUSTMS1’)
ERASE;
RETURN;
END;
ELSE
DO;
/ 2回目以降:画面からの入力値受け取り /
EXEC CICS RECEIVE MAP(‘CUSTMP1’)
MAPSET(‘CUSTMS1’)
INTO(CUST-COMMAREA);

W-CUST-KEY = CA-CUST-ID;

/ VSAM(KSDS)ファイルからのレコード読み込み /
/ EXEC CICS READ の裏側もDFHECP1によってCALLに展開される /
EXEC CICS READ FILE(‘CUSTFILE5′)
RIDFLD(W-CUST-KEY)
INTO(CUST-REC)
LENGTH(W-LENG)
RESP(W-RESP-CD);

/ 応答コードのチェック(DFHRESPビルトインは使わず数値や定数で評価) /
IF W-RESP-CD = 0 THEN
DO;
CA-CUST-NAME = R-CUST-NAME;
CA-RETURN-CD = ’00’;
END;
ELSE IF W-RESP-CD = 13 / DFHRESP(NOTFND)に相当 / THEN
DO;
CA-CUST-NAME = ‘顧客データが見つかりません’;
CA-RETURN-CD = ’04’;
END;
ELSE
DO;
CA-CUST-NAME = ‘システムエラー発生’;
CA-RETURN-CD = ’99’;
END;

/ 結果を画面に送り返す /
EXEC CICS SEND MAP(‘CUSTMP1’)
MAPSET(‘CUSTMS1’)
FROM(CUST-COMMAREA);
END;

/ トランザクションの正常終了と画面返却 /
EXEC CICS RETURN
TRANSID(‘CUST’)
COMMAREA(CUST-COMMAREA);

END OHLI010P;

—

4. 現場のシニアからのデバッグのコツと教訓

このコードを見て、「おっ、スッキリしてて分かりやすいな」と思ったなら大正解だ。だがな、実務の現場ではここからが本番なんだよ。

1. プリコンパイルリスト(SYSUT3/SYSUT4などの展開結果)を見ろ!
もしCICSのバージョンアップ時や、コンパイラをEnterprise PL/Iにマイグレーションした際に「謎のコンパイルエラー」が出たら、迷わずDFHECP1が吐き出した中間コード(展開後のPL/Iソース)を確認しろ。自分が書いた覚えのない `CALL DFHEIVS(…)` みたいなコードがずらっと並んでいるはずだ。エラー行がその展開後のコードのどこを指しているのかを追うのが、メインフレームエンジニアの基本スキルだ。

2. 変数のスコープと `REENTRANT` 属性を忘れるな
CICS環境下で動くPL/Iプログラムには、原則として `REENTRANT`(再入可能)属性を付与する必要がある。複数の端末から同時に同じトランザクションが叩かれるオンラインの世界では、プログラム内の静的領域(STATIC)にデータを保持させると、他のユーザーのデータが上書きされるという地獄のようなバグ(データ汚染)を引き起こす。ワークエリアは必ず自動変数(Automatic)としてスタック上に展開されるように書くこと。

3. ONユニットは万能薬ではない
サンプルに入れた `ON ERROR` だが、CICS環境ではCICS側の異常終了処理(ABEND)やハンドル条件(HANDLE ABEND / HANDLE CONDITION)との兼ね合いがある。PL/I独自の `ON` ユニットに頼りすぎると、CICSのトランザクション異常終了ハンドリングとケンカして挙動がおかしくなることがある。オンラインでは `RESP` オプションを丁寧に受けて、戻り値で制御するのが最も堅牢でトラブルが少ない。

PL/Iの深い歴史とCICSの泥臭い仕組み、その両方を理解して初めて、お前は一人前のメインフレーム・アーキテクトになれる。
明日からのコーディング、変数名に `CICS` なんてうっかり付けないように気をつけろよ!

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