こんにちは!メインフレームの世界へようこそ。
JavaやCOBOLといったモダン、あるいはビジネスの現場でバリバリ活躍されている言語のご経験がある方にとって、IBMメインフレームの世界、そして「PL/I(ピーエルワン)」という言語は、ちょっとお堅くて近寄りがたい要塞のように見えるかもしれません。
特に、JCL(Job Control Language)から渡されるパラメータを、PL/Iプログラムの中で数値として受け取ろうとしたとき……。
画面の向こうで「うわ、なんだこのデータ型と変換エラーの嵐は!」と頭を抱えていませんか?
大丈夫です、怖くないですよ。一つずつ紐解いていけば、COBOLやJavaとの違いもスッと腑に落ちるはずです。今回は、JCLのPARM引数をPL/Iの「固定小数点数(FIXED)」で安全に受け取り、料理する方法を一緒に見ていきましょう!
—
1. そもそもJCLのPARMってどんな形をして届くの?
Javaで言えば `public static void main(String[] args)` の `args`、COBOLなら `LINKAGE SECTION` の入り口にあたる部分ですね。
メインフレームでは、JCLのEXECステートメントで以下のようにパラメータを渡します。
//STEP01 EXEC PGM=MYPROG,PARM=’12345′
ここで絶対に覚えておいてほしい鉄則があります。
「JCLのPARMで渡されるデータは、どんなに数字っぽく見えても、すべて『文字(CHARACTER)』である」ということです。
『12345』は、数値の 12,345 ではなく、文字の ‘1’、’2’、’3’、’4’、’5′ が横一列に並んだただの文字列なんですね。これをPL/Iの中で計算に使いたい場合、私たちは「文字」から「固定小数点数(`FIXED`)」へ、綺麗に変換してあげる必要があります。
—
2. PL/Iの固定小数点数(FIXED BINARY / DECIMAL)のきほん
PL/Iの数値データ型には、大きく分けて2つの顔があります。
1. `FIXED DECIMAL`(10進FIXED):
COBOLの `COMP-3`(パック十進数)や通常のゾーン10進数に近い仲間です。人間にとって直感的な10進数で正確に計算したいとき(お金の計算など)に使います。
2. `FIXED BINARY`(2進FIXED):
Javaの `int` や `short` のようなものです。メインフレームのCPUが一番得意とする、純粋な2進数の世界です。
例えば、PL/Iで以下のように宣言します。
1
DCL WK_COUNT FIXED BIN(31) INIT(0); / 31ビットの符号付き整数 /
DCL WK_MONEY FIXED DEC(9,2) INIT(0); / 全体9桁、小数点以下2桁の10進固定小数点 /
「なんだかカッコいいけれど、文字をここに直接放り込んだらどうなるの?」
……鋭いですね。実は、PL/Iは非常に親切(時にオ節介)な言語なので、データ型が違う代入を行っても、コンパイラや実行時環境が「よし、勝手に型変換しとくね!」と裏でこっそり頑張ってくれます。
しかし! ここに大きな落とし穴があるのです。
—
3. 「勝手に変換」の罠と、恐ろしいABEND(異常終了)
もし、JCLから渡されたPARMが `PARM=’ABCDE’` だったり、あるいは空白が混じっていたり、想定より長かったりしたらどうなるでしょうか?
うっかり十分なバリデーション(妥当性確認)をせずに、文字のPARMをそのまま `FIXED` 型の変数に放り込むと、プログラムは突然のS0C7(データ例外:Data Exception)などのシステムABENDを引き起こし、夜間バッチを盛大にクラッシュさせてしまいます。メインフレーム運用者から冷や汗モノの電話がかかってくる瞬間ですね。
だからこそ、JCLからのインプットを受け取る際は、「文字列として受け取り、中身が本当に数字かチェックした上で、安全にFIXED型へ変換する」という大人のアプローチが絶対に不可欠なのです。
—
4. 実践!安全なバリデーションとFIXED変換のコード例
百聞は一見に如かず。実際にJCLのPARMを受け取り、安全にバリデーションを行って `FIXED BINARY` に変換するPL/Iのサンプルプログラムを見てみましょう。
1
/ ================================================= /
/ プログラム名: PARMCONV /
/ 概要: JCLからの文字PARMを安全にFIXED型に変換する /
/ ================================================= /
PARMCONV: PROC(P_PARM) OPTIONS(MAIN);
/ — 1. 宣言部 — /
/ JCLからの引数は必ず CHARACTER VARYING で受け取るのが安全 /
Dcl P_PARM Char(100) Var;
/ 作業用変数 /
Dcl WK_NUM_STR Char(5) Init(”);
Dcl WK_FIXED Fixed Bin(31) Init(0);
Dcl I Fixed Bin(15);
Dcl ERR_FLG Bit(1) Init(‘0’b);
Put Skip List(‘— 処理開始 —‘);
/ — 2. パラメータの長さチェック — /
/ 桁数が想定(例: 5桁)と違う場合はエラー処理へ /
If Length(P_PARM) ^= 5 Then Do;
Put Skip List(‘【エラー】パラメータの桁数が不正です。 Length = ‘, Length(P_PARM));
GoTo ERROR_RTN;
End;
/ — 3. 1文字ずつ数値かどうかをチェック(バリデーション) — /
Do I = 1 To Length(P_PARM);
/ VERIFY関数で ‘0123456789’ 以外の文字が含まれていないかチェック /
If Verify(Substr(P_PARM, I, 1), ‘0123456789’) ^= 0 Then Do;
Put Skip Edit (‘【エラー】数値以外の文字が含まれています: ‘, Substr(P_PARM, I, 1)) (A, A);
ERR_FLG = ‘1’b;
Leave; / ループを抜ける /
End;
End;
If ERR_FLG Then GoTo ERROR_RTN;
/ — 4. 安全に FIXED BINARY 型へ変換 — /
/ バリデーションを通過しているので、ビクビクせずに代入・変換できます /
WK_FIXED = P_PARM; / ここで文字からFIXEDへの型キャスト(自動変換)が発生 /
Put Skip Edit(‘【成功】数値への変換に成功しました! 値 = ‘, WK_FIXED) (A, F(10));
/ 通常終了処理 /
Return;
ERROR_RTN:
/ 異常終了時のハンドリング(戻り値に非ゼロを設定する等) /
Put Skip List(‘【異常終了】処理を中断します。’);
/ ※実務ではここで適切なRC(リターンコード)を設定して終了します /
End PARMCONV;
コードのポイント解説
1. `Char(100) Var` で受け取る理由
JCLのPARMは最大100バイト程度(環境により異なりますが)の可変長文字列として渡されます。`VARYING` 属性(`Var`)をつけておくことで、実際に渡された文字の長さを `Length()` 関数で正確に取得できます。
2. `VERIFY` 関数の便利さ
PL/Iの `VERIFY(文字列, 検索文字セット)` は、「検索文字セットに含まれない文字が最初に現れる位置」を返してくれます。つまり、戻り値が `0` ならば、その文字列は指定した文字(今回は ‘0’ から ‘9’)だけで構成されていることが一発で分かる、非常に優秀なバリデーション関数です。
3. きれいな型変換
安全確認が終わったあとの `WK_FIXED = P_PARM;` では、PL/Iのコンパイラが裏側で適切に十進文字をバイナリ値へと翻訳してくれます。
—
5. さいごに
いかがでしたでしょうか?
「JCLのPARM=文字」「固定小数点数=FIXED(DECIMAL / BINARY)」という基本の棲み分けさえ押さえてしまえば、PL/Iでのデータ制御は決して怖いものではありません。むしろ、言語仕様が非常にカチッとしている分、ルール通りに書いてあげればこれほど頼もしい相棒もいません。
レガシー移行や保守の現場でPL/Iに出会ったとき、「あ、あのブログに書いてあった通り、まずは文字としてバリデーションすればいいんだな」と思い出していただければ幸いです。
あなたのメインフレームライフが、快適でエラーフリーなものになりますように。それではまた次回の技術解説でお会いしましょう!
