【入門編】CEEHDLRによるユーザー定義エラーハンドラの登録 – PL/Iの基本構文とデータ制御実践ガイド

こんにちは!メインフレームの世界へようこそ。
JavaやCOBOLといったモダン、あるいはビジネスチルドレンな言語をバリバリ書いてきた方にとって、IBMメインフレームの「PL/I(ピーエルワン)」は、最初ちょっと近寄りがたい、ぶっきらぼうな古強者のように見えるかもしれません。

特に「何やら凄そうな名前の制御ブロック」や「レガシー特有の作法」が出てくると、冷や汗が出てしまいますよね。でも、大丈夫です!怖がる必要は全くありません。一つひとつの部品を解体して覗いてみれば、「ななんだ、こういうことね」とすんなり腑に落ちるはずです。

今回は、そんなPL/Iの世界でも一際ディープで頼もしい機能、Language Environment(LE)の `CEEHDLR` を使ったユーザー定義エラーハンドラの登録について、たっぷりとお話ししていきましょう。

1. JavaやCOBOLの「例外処理」と何が違うの?

Javaでエラー(例外)といえば `try-catch` ブロックですよね。「ここで何かが起きるかもしれないから、網を張っておこう」というアレです。COBOLでも、近年は `USE AFTER STANDARD EXCEPTION` や条件判定で泥臭くハンドリングしたりします。

では、PL/I(というかその下で動くIBMの実行基盤である Language Environment:LE)はどうでしょうか?

LEのスタックフレーム(プログラムが呼び出されてメモリ上に積まれるお部屋のようなもの)の世界では、プログラムが突然変異的なエラー(例えば、ゼロ割り算やポインタの不正参照など)を起こしたとき、「OSやランタイムに丸投げするのではなく、自分で用意した専用のお手伝いさん(エラーハンドラ)にまず片付けをさせたい!」というワガママを叶えてくれます。

そのお手伝いさんを動的に登録する魔法の呪文が、今回主役の `CEEHDLR`(Condition Enable Handler) です。

2. その前にちょっと寄り道:PL/Iの「優しい」変数名ルールと予約語の秘密

本題に入る前に、PL/Iのちょっとユニークで初学者に優しい仕様について触れておきましょう。

JavaやC言語だと、「えっ、この単語は予約語だから変数名に使えないの!?」とイライラさせられることがよくありますよね。でも、PL/Iには厳密な意味での「予約語」がほとんどありません

どういうことかと言うと、`IF` や `READ` といったキーワードであっても、文脈から判断できるため、変数名として使えてしまうんです(※もちろん、可読性を考えると絶対にやめたほうがいいですが!)。
変数名の命名規則もシンプルで、英字で始まり、英数字とアンダースコア(`_`)を組み合わせて最大31文字まで使えます。COBOLのような「ハイフンは使えるけどピリオドに気をつけろ」といった呪縛から解放されて、非常に素直にコードが書ける言語なんですよ。

3. `CEEHDLR` の仕組みを「旅館の仲居さん」に例えてみる

さて、`CEEHDLR` のお話に戻りましょう。
イメージしやすいように、ちょっとたとえ話をしますね。

あなたは今、由緒正しい旅館(メインフレームのプログラム)の大きなお部屋に泊まっています。
このお部屋(サブルーチンやブロック)で、もし「天井から水漏れがする!」とか「金庫が開かない!」といった大事件(例外=Condition)が発生したとしましょう。

パニックになって宿全体が大騒ぎになる前に、あなた専属の「優秀な仲居さん(エラーハンドラ・ルーチン)」を部屋の入り口にスタンバイさせておきます。これが `CEEHDLR` によるハンドラの登録作業です。

何かトラブルが起きた瞬間、宿の主人がいきなり怒鳴り込んでくる前に、まずその専属仲居さんが飛んできて、「お客様、お怪我はありませんか?こちらのタオルをどうぞ。事態はこちらで収めておきますね」と、スマートに事後処理をしてくれる――これがLEのエラーハンドリングの仕組みです。

4. 実践! `CEEHDLR` を使ったエラーハンドラのPL/Iコード

百聞は一見にしかず。実際にどのようなコードを書くのか、実務の現場ですぐに使えるサンプルを見てみましょう。大文字ベースの伝統的なスタイルで記述しています。

/ /
/ プログラム名: ERRH01 /
/ テーマ: CEEHDLR を用いたユーザー定義エラーハンドラの動的登録 /
/ /
ERRH01: PROC OPTIONS(MAIN);

DCL CEEHDLR ENTRY( / エラーハンドラ登録用LEサービス /
ENTRY, / 登録するハンドラ・ルーチンのポインタ/
POINTER, / ユーザーデータのポインタ /
POINTER / フィードバック・コード(結果) /
) OPTIONS(ASM INTER(CBL));

DCL CEEHDLS ENTRY( / エラーハンドラ登録解除用LEサービス/
ENTRY, / 解除するハンドラ・ルーチンのポインタ/
POINTER / フィードバック・コード(結果) /
) OPTIONS(ASM INTER(CBL));

DCL 01 FC, / フィードバック・コード構造体 /
03 C_SEV FIXED BIN(13),
03 C_MSGNO FIXED BIN(13),
03 C_FLAGS BIT(8),
03 C_IC FIXED BIN(31);

DCL USER_DATA CHAR(20) INIT(‘MY_CONTEXT_DATA’);
DCL MY_RET_CODE FIXED BIN(31);

/ 1. ここで独自の「お部屋の仲居さん(エラーハンドラ)」を登録します /
CALL CEEHDLR(MY_ERROR_HANDLER, ADDR(USER_DATA), FC);

IF C_SEV ^= 0 THEN DO;
PUT SKIP LIST(‘エラーハンドラの登録に失敗しました…’);
GOTO PROGRAM_END;
END;

PUT SKIP LIST(‘— 正常処理を開始します —‘);

/ わざとゼロ割り算(例外)を起こしてみましょう /
BEGIN;
DCL A FIXED BIN(31) INIT(10);
DCL B FIXED BIN(31) INIT(0);
DCL C FIXED BIN(31);

C = A / B; <-- ここでシステム異常(ゼロ割り)が発生! END; PUT SKIP LIST('この行には到達しません'); PROGRAM_END: / 2. プログラムを抜ける前に、必ずハンドラの登録を解除します / CALL CEEHDLS(MY_ERROR_HANDLER, FC); RETURN; END ERRH01;

エラーハンドラ(仲居さん)本体のルーチン

では、先ほどの登録された `MY_ERROR_HANDLER` は、裏でどう動いているのでしょうか。その実体がこちらです。

/ /
/ エラーハンドラ・サブルーチン(実際に呼ばれる処理) /
/ —————- /
MY_ERROR_HANDLER: PROC(
/ LEから渡される引数群(お約束の作法です) /
TOKEN, / ユーザー定義データのポインタ /
RESULT, / 処理結果の指示 /
NEW_COND, / 新たな条件 /
FC / フィードバックコード /
) OPTIONS(NOSAVE, RETCODE);

DCL TOKEN POINTER;
DCL RESULT POINTER;
DCL NEW_COND POINTER;
DCL FC POINTER;

PUT SKIP LIST(‘>>> [LE Handler] ユーザー定義エラーをキャッチしました!’);

/ ここでログを出力したり、ファイルの後始末をしたり、 /
/ 必要に応じて異常終了コードを整えて優雅にクリーンアップします。 /

/ 今回は「エラー処理は完了したよ(続行せず終了する等)」とLEに伝えます /
/ ※実際の業務ではRESULTポインタを通じて制御を戻したりします /

RETURN;
END MY_ERROR_HANDLER;

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