こんにちは。長年、金融や流通の基幹システムでIBMメインフレームと向き合ってきたシステムアーキテクトの私だ。
君たちが日々保守しているCOBOLやPL/Iの巨大なバッチ群。その中で、帳票出力や外部連携ファイル(VSAMやKSDS、あるいは順次ファイル)のレイアウト定義において、最も頭を悩ませるポイントの一つが「PICTURE句による数値編集」ではないだろうか。
特に、金額フィールドなどでよく見かける小数点 `.` とカンマ `,` の挿入・分離のメカニズム。そして、PL/Iが持つ「予約語を持たない」という非常にユニークな文脈フリーの思想が、これらの編集文字とどう絡み合っているのか。今回は、この泥臭くも美しいPL/Iのデータ制御の真髄を、実務の現場目線で徹底的に紐解いていこう。
—
1. PL/Iの「予約語がない」世界と識別子の自由度
まず大前提として、PL/Iという言語の特殊性を理解しておかなければならない。C言語やJava、あるいはCOBOLには、変数名として使ってはならない「予約語(Reserved Words)」のリストが存在する。しかし、PL/Iにはキーワードとしての厳密な予約語が存在しない。
例えば、`IF` や `THEN`、さらには今回解説する `PICTURE` や `DECIMAL` といった言葉すら、コンテキスト(文脈)によって変数名やプロシージャ名として定義することが理論上は可能だ(※実務でそんな混乱を招く命名をするプログラマがいたら、今すぐ私のところに連れて来たまえ)。
コンパイラは、ソースコードを左から右へスキャンする際、その位置と言語の構文規則(文脈)から、「これはキーワードか? それとも単なる識別子(変数名)か?」を動的に判断している。
この「文脈依存性」の思想は、PICTURE句の中身を解釈する際にも深く関わっている。コンパイラは、`PIC` または `PICTURE` というキーワードに続く文字列を見た瞬間から、通常算術演算を行う「内部十進(COMP-3など)」や「ゾーン十進(DISPLAY)」の領域から、文字列表現を扱う「編集(EDITED)データ」のモードへと頭を切り替えているのだ。
—
2. PICTURE編集文字 `.` と `,` の内部表現と分離・結合のメカニズム
実務において、VSAMファイルや固定長ファイルからデータを読み込む際、私たちはよく以下のような定義に出会う。
1
DCL 1 W-KENSY-REC,
3 W-KINGAKU-ED PIC ‘ZZZ,ZZZ,ZZ9.99’;
この `PIC ‘ZZZ,ZZZ,ZZ9.99’` という定義を見たとき、君たちは内部で何が起きていると想像するだろうか?
内部表現への「結合」と「分離」
- 編集前(内部データ):
コンパイル時に計算や保持を行うための純粋な数値データ(例: パック十進数 `FIXED DECIMAL(9,2)` など)は、ゾーンやパックの形式でメモリ上に存在している。この状態では、カンマやピリオドといった視覚的な装飾文字は1ビットも存在しない。
- 編集後(外部データ・文字型):
しかし、この数値を `EDIT` 形式の変数(あるいは `PUT` ストリーム、ファイル出力用のバッファ)に代入した瞬間、PL/Iのランタイムは数値の各桁を右詰めで文字に変換し、指定された位置にカンマ `,` とピリオド `.` を動的に挿入(結合)する。
逆に、画面や外部ファイルから入力された `123,456.78` という文字列を数値項目に受け入れる(`GET` や代入を行う)場合は、ランタイムが挿入文字である `,` と `.` をパースして除去(分離)し、純粋な数値の符号と絶対値として内部の算術レジスタや変数へ格納するのだ。
ここで注意すべき実務上の罠がある。もし入力データの桁あふれや、想定外の位置にカンマ以外の文字(例えばスペースや英字)が混入していた場合、PL/Iではおなじみの `ON CONVERSION` 条件 が発火する。このエラー制御を適切に組んでいないと、バッチ全体が異常終了(U4038など)を引き起こすため、後述するONユニットの活用が不可欠となる。
—
3. 実践コード:VSAMファイル入出力とONユニットによる例外制御
百聞は一見に如かず。実際のメインフレーム環境(Enterprise PL/Iコンパイラ)を想定した、実用的なバッチプログラムの骨組みを見てほしい。
ここでは、入力された編集済み金額データ(カンマ・ピリオド付き)を安全に数値演算用変数に受け渡し、合計を計算して出力する処理を記述している。
1
—————————————————————-
- プログラム名: CALC01 – 金額編集とエラー制御のサンプルバッチ
—————————————————————-
CALC: PROC OPTIONS(MAIN);
DCL SYSIN FILE STREAM INPUT;
DCL SYSPRINT FILE STREAM OUTPUT;
— 入力レコード構造(外部表現: カンマ・ピリオドを含む編集文字) —
DCL 1 IN-RECORD,
5 IN-ID CHAR(5),
5 IN-AMT-ED CHAR(12); 例: ‘ 123,456.78’
— 内部演算用変数(純粋な数値) —
DCL W-AMT-NUM FIXED DECIMAL(11,2) INIT(0);
DCL W-TOTAL-AMT FIXED DECIMAL(13,2) INIT(0);
— 制御フラグ —
DCL EOF-FLAG BIT(1) INIT(‘0’B);
— 変換エラー(CONVERSION)発生時のONユニット定義 —
ON CONVERSION BEGIN;
PUT SKIP EDIT (‘【警告】数値変換エラー発生: ‘, IN-AMT-ED)
(A(23), A(12));
- エラー時は強制的にゼロとみなして続行するなどのリカバリ
W-AMT-NUM = 0;
GOTO CONV-ERR-CONT;
END;
- ファイルオープン(実際はVSAMや順次ファイル)
OPEN FILE(SYSIN) INPUT, FILE(SYSPRINT) OUTPUT;
- メインループ
DO WHILE(^EOF-FLAG);
GET FILE(SYSIN) EDIT (IN-ID, IN-AMT-ED) (A(5), A(12));
IF / 終了条件やファイルのEOD検知処理 / (ENDFILE(SYSIN)) THEN
EOF-FLAG = ‘1’B;
ELSE DO;
- 編集済み文字型から数値型への代入(ここでピリオド・カンマが自動分離される)
W-AMT-NUM = IN-AMT-ED;
CONV-ERR-CONT:;
- 累計計算(BUILTIN関数のROUNDやSUM的処理のベース)
W-TOTAL-AMT = W-TOTAL-AMT + W-AMT-NUM;
END;
END;
- 最終結果を編集文字(ピリオド・カンマ付き)で出力
PUT FILE(SYSPRINT) EDIT (‘合計金額: ‘, W-TOTAL-AMT)
(A(10), PICTURE ‘ZZZ,ZZZ,ZZZ,ZZ9.99’);
CLOSE FILE(SYSIN), FILE(SYSPRINT);
END CALC;
—
4. ベテランから後輩エンジニアへ送るデバッグのコツ
このコードとデータ制御の仕組みにおいて、現場でよく直面するトラブルシューティングの勘所をいくつか伝授しておこう。
1. 暗黙の型変換(Coercion)のコストを甘く見るな
`W-AMT-NUM = IN-AMT-ED;` という一見シンプルな代入文。裏側では、ランタイムが文字単位でスキャンを行い、`,`, `.` の位置を確認し、有効数字を切り出して数値型へ変換している。数百万件を処理する基幹バッチの内部ループでこれを大量に行うと、CPU時間の肥大化(オーバーヘッド)を招く。大量データのインターフェースでは、可能な限り内部表現同士でデータを渡し、帳票や画面出力の直前(I/Oの境界)で初めて `PICTURE` 編集を適用すべきだ。
2. ロケール(小数点文字の解釈)の罠
モダンなPL/Iや言語環境では、環境変数やセッションのロケール設定によって、小数点にピリオド `.` ではなくカンマ `,` を使う文化圏(欧州など)を意識させられることがある。IBMメインフレームの標準的なバッチ基盤であれば、基本はANSI/IBM仕様の `.`(ピリオド)がデリミタとして機能するが、海外支店とのデータ連携モジュールなどを改修する際は、この「文字の分離・結合のルールが逆転していないか」を必ずJCLのPARMやコンパイルオプション、ランタイムオプション(CEEOPTS等)で確認する癖をつけなさい。
3. ON CONVERSIONは逃げ場ではない
先ほどのサンプルコードで `ON CONVERSION` を使ってエラーをトラップしたが、実務の金融系バッチにおいて、金額項目のゴミデータを勝手に「0」に丸めて処理を続行することは、監査上ご法度であることが多い。エラーが発生した場合は、トランザクションをログ(SYSOUT)に詳細に出力し、適切なエラートランザクション用ファイル(スプールや別ファイル)へ退避させる設計(あるいはアボートさせる設計)が必須であることを忘れてはならない。
—
おわりに
PL/Iの `.` と `,` の編集文字の挙動は、単なる「見た目を整える装飾」ではない。背後にあるデータ型、コンテキストの解釈、そしてランタイムによる分離・結合の泥臭いバイナリ処理の歴史そのものだ。
この言語の挙動を熟知していれば、どんなに古びたレガシーコードの改修であっても、デバッガの画面やスナップショット(CEE3DMP等)を見ただけで「今、内部十進と編集文字のどこでミスマッチが起きているか」が手に取るようにわかるはずだ。
基幹システムの命脈を握るエンジニアとして、表面的なコーディングだけでなく、この「内部表現の妙」をマスターし、後輩たちにその背中で見せていってほしい。期待しているぞ。
