【入門編】CEE3204S(固定小数点オーバーフロー)の制御とON条件 – PL/Iの基本構文とデータ制御実践ガイド

こんにちは!IBMメインフレームの世界へようこそ。
JavaやCOBOLといったモダン、あるいはビジネスで広く使われている言語の経験がある方にとって、初めて目にするPL/I(ピーエルワン)のソースコードは、ちょっと独特で驚きの連続かもしれませんね。

「変数名にルールはあるの?」
「なんか見慣れない英単語がたくさんあるけど、これって全部予約語なの?」

大丈夫です、怖がる必要は全くありませんよ。一つずつ紐解いていけば、PL/Iほど懐が深く、合理的に作られた言語はありません。今回は、JavaやCOBOLの感覚でいると突然足元をすくわれる、メインフレーム特有のランタイムエラー「CEE3204S(固定小数点オーバーフロー)」と、そのスマートな手なずけ方について、実務の現場の空気感を交えながら優しく解説していきますね。

1. ちょっと待って!PL/Iには「予約語」がないって本当?

他の言語(JavaやCOBOLなど)を触ってきた方なら、「この名前はシステムが予約しているから変数に使えないんだよな」という経験が一度はあるはずです。COBOLなら `DATE` や `VALUE`、Javaなら `class` や `public` などですね。

ところが、PL/Iの言語仕様における最もユニーク(そして最初はちょっと戸惑う)な特徴が、「PL/Iには真の意味での予約語が存在しない」という点です。

例えば、極端な話ですが、こんな変数宣言もPL/Iではエラーになりません。

1
/ こんな変数名、他の言語なら怒られますよね /
DCL IF FIXED BIN(31);
DCL THEN FIXED BIN(31);

「えっ、じゃあコンパイラはどうやって `IF` が条件分岐なのか、変数なのかを判断しているの?」と思いますよね。
PL/Iのコンパイラは、その文脈(Context)を非常に優秀に読み取ります。これを文脈依存(Contextual)のルールと呼びます。人間が前後の文脈から言葉の意味を自然に理解するのと似ていますね。

ただし、実務の現場では、コンパイラを混乱させないため、そして何より後からコードを読む人間のメンタルを守るために、キーワードを変数名に使うのはタブーとされています。「できるからといってやってはいけない」というのは、レガシーシステムの美しい不文律です。

2. 突然やってくる悪夢:夜間バッチを止める「CEE3204S」の正体

さて、本題に入りましょう。
夜間の大型バッチ処理が突如としてアブノーマル・エンド(異常終了)、いわゆる「abend(アベン)」を起こしたとき、sysout(ログ)を覗くとこんなメッセージが残されています。

> CEE3204S THE OFFSET … WAS INTERRUPTED BY A FIXED-POINT OVERFLOW EXCEPTION.

Javaの `ArithmeticException` や、COBOLの大小比較・算術エラーに怯えた経験はありませんか?
PL/Iにおけるこの `FIXEDOVERFLOW`(略して `FOFL`)は、「計算結果が、あなたが宣言した変数の入れ物に入り切らなくなったよ!」という悲鳴です。

なぜオーバーフローは起きるのか?(イメージで理解する)

例えば、あなたが小さな「お猪口(おちょこ)」を用意したとします。このお猪口には、せいぜい二口分くらいのお酒しか入りませんよね。そこに、一升瓶からドバドバとお酒を注いだらどうなるでしょうか?当然、溢れ出しますよね。

コンピュータの計算もこれと同じです。
PL/Iで以下のようなデータ定義をしたとしましょう。

1
Dcl SHO_ZAIKO Fixed Dec(3) Init(900); / 3桁の数字が入るお猪口 /
Dcl KNY_SURYO Fixed Dec(3) Init(200); / こちらも3桁 /
Dcl GOKEI_SURYO Fixed Dec(3); / 結果を入れる3桁のお猪口 /

/ 在庫と購入数を足し算してみる /
GOKEI_SURYO = SHO_ZAIKO + KNY_SURYO;

お気づきでしょうか?
$900 + 200 = 1100$ です。結果は4桁になります。しかし、受け皿である `GOKEI_SURYO` は `Fixed Dec(3)`、つまり最大でも `999` までしか入らないお猪口です。

この瞬間、PL/Iのランタイムは「桁あふれが発生しました!」として、容赦なくプログラムを強制終了(CEE3204S)させます。これが固定小数点オーバーフローのメカニズムです。

3. ON条件(ON-UNIT)で例外を優しくコントロールする

「じゃあ、計算結果が溢れそうになったら、毎回プログラムが落ちちゃうの?そんなの怖くて夜も眠れないよ!」
ご安心ください。PL/Iには、こうした予期せぬ例外(シグナル)を優しく、かつエレガントに捕捉・制御するための強力な仕組みが備わっています。それが「ON条件(ON-UNIT)」です。

Javaの `try-catch` ブロックをイメージしてもらうと非常に分かりやすいかもしれません。PL/Iでは、条件が発生したときの「振る舞い」をあらかじめ宣言しておくことができます。

実際のコード例を見てみましょう。実務でそのまま使える書き方になっています。

1
————————————————————–

  • 固定小数点オーバーフロー制御のサンプルプログラム

————————————————————–
OVERFLOW_SAMPLE: PROC OPTIONS(MAIN);

/ 変数の宣言(あえて小さなお猪口を用意します) /
DCL SHO_ZAIKO FIXED DEC(3) INIT(900);
DCL KNY_SURYO FIXED DEC(3) INIT(200);
DCL GOKEI_SURYO FIXED DEC(3);

DCL ERROR_FLG BIT(1) INIT(‘0’B);

/ —【ここがポイント】ON条件の定義 — /
/ FIXEDOVERFLOWが発生したときの「身代わりの処理」を指示する /
ON FIXEDOVERFLOW
BEGIN;
DISPLAY(‘【警告】計算結果が桁あふれを起こしました!処理を継続します。’);
ERROR_FLG = ‘1’B; / エラーフラグを立てる /

/ 溢れた場合のデフォルト値として、最大値を強制的に詰めるなどのリカバリ /
GOKEI_SURYO = 999;
END;

DISPLAY(‘処理を開始します。’);

/ 意図的にオーバーフローを引き起こす計算 /
GOKEI_SURYO = SHO_ZAIKO + KNY_SURYO;

/ オーバーフローが発生していなければ正常メッセージ /
IF ^ERROR_FLG THEN
DISPLAY(‘計算成功! 合計は ‘ || GOKEI_SURYO);
ELSE
DISPLAY(‘例外を正常にトラップし、安全に処理をバイパスしました。’);

DISPLAY(‘処理を正常に終了します。’);

END OVERFLOW_SAMPLE;

このコードの素晴らしいところ

1. プログラムがクラッシュしない
通常であれば `CEE3204S` で異常終了するところを、`ON FIXEDOVERFLOW` が盾となって受け止めてくれます。
2. 独自のリカバリができる
「落ちる」代わりに、ログにメッセージを残したり、ダミーの最大値(`999`)を代入して後続の処理へバトンタッチさせたりといった「大人の対応」が可能です。
3. スコープの管理
PL/IのON条件は、そのブロック内(あるいは動的な呼び出し関係)で有効です。エラー処理が終わったあとは、何事もなかったかのように次の行へ進みます。

4. アーキテクトからの実務アドバイス:エラーを「隠す」べきか「落とす」べきか

最後に、システムアーキテクトとしての現場の知見を少しだけ共有させてください。

ON条件を使ってオーバーフローを捕捉できるからといって、すべての計算エラーをここで握りつぶしていいわけではありません。
金融系の金利計算や、在庫の数量管理などにおいて、勝手に数値を丸めて処理を続けたら、大和証券の誤発注事件のような大惨事になりかねませんよね。

  • お金や数量などのクリティカルなデータ

そもそもオーバーフローが起きないように、あらかじめ十分な桁数(例: `FIXED DEC(15,2)` など)でデータ定義(DCL)を行う設計が基本です。

  • ログや統計、多少の欠損が許容されるセンサーデータ等

今回紹介した `ON FIXEDOVERFLOW` を活用して、例外をトラップし、エラーログをファイルに出力した上で「安全に処理をスキップ・継続」させるのがベストプラクティスです。

PL/Iは古い言語と言われることもありますが、こうした例外処理のきめ細かさは、現代のモダン言語の祖先呼ぶにふさわしい洗練された思想を持っています。

「変数の入れ物の大きさを意識すること」
「もし溢れたときのセーフティネット(ON条件)を用意しておくこと」

この2つさえ押さえておけば、もうメインフレームの数値演算で怯える必要はありませんよ。明日からのPL/Iコーディング、ぜひ自信を持って楽しんでくださいね!

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