1. 導入
メインフレームのPL/I開発において、動的なデータ構造を扱う際に避けて通れないのが「BASED構造体」と「自己参照ポインタ」です。この技術は、リスト構造やツリー構造といった、あらかじめサイズが決まっていないデータをメモリ上に柔軟に展開するために必須となります。本記事では、この仕組みを正しく理解し、安全に実装するためのポイントを解説します。
2. 基礎知識
PL/IのBASEDストレージは、宣言時にメモリが割り当てられず、ポインタ変数を介して明示的に制御する領域を指します。
ここで重要なのが「自己参照」の概念です。構造体定義の中に、その構造体型を指すPOINTER型のメンバを持たせることで、論理的に無限の深さを持つ「チェーン構造(連結リスト)」を構築できます。これは現代のオブジェクト指向言語における「ノードクラス」と同等の役割を果たします。
3. 実装/解決策
実装の肝は、ロケータ(ポインタ)の管理です。
1. 構造体をBASED属性で宣言し、ポインタメンバを定義します。
2. ALLOCATE文でメモリを確保し、現在のポインタを更新します。
3. 次の要素へポインタを繋ぐことでチェーンを形成します。
メモリ管理において重要なのは、領域の解放(FREE)を行う際、必ず「次の要素へのポインタ」を退避させてから実行することです。これを怠ると、リストの残りの要素が迷子になり、メモリリークを招きます。
4. サンプルプログラム
以下は、単純な連結リストを作成し、データを順次格納するサンプルコードです。
/ ノード構造の定義: Pをロケータとして使用 /
DCL 1 NODE BASED(P),
2 NEXT_PTR POINTER, / 次のノードを指すポインタ /
2 DATA_VAL FIXED BIN(31); / 格納データ /
DCL ROOT_PTR POINTER INIT(NULL()); / リストの先頭 /
DCL CURR_PTR POINTER; / 現在処理中のポインタ /
DCL TEMP_PTR POINTER; / 一時作業用 /
/ 新規ノードの追加処理 /
ALLOCATE NODE SET(TEMP_PTR);
TEMP_PTR->DATA_VAL = 100;
TEMP_PTR->NEXT_PTR = ROOT_PTR; / 先頭に挿入 /
ROOT_PTR = TEMP_PTR; / ルートを更新 /
/ メモリの安全な解放 /
DO WHILE(ROOT_PTR ^= NULL());
TEMP_PTR = ROOT_PTR;
ROOT_PTR = ROOT_PTR->NEXT_PTR; / 次のポインタを退避 /
FREE TEMP_PTR->NODE; / 解放 /
END;
5. 応用・注意点
現場で最も注意すべきは「ポインタの浮遊(Dangling Pointer)」です。FREEした後のポインタを誤って参照し続けると、システム異常終了(ABEND)や、最悪の場合はデータの破壊を招きます。
また、将来的にJavaやC#といった他言語へロジックを移行することを想定している場合、PL/Iのポインタ操作をラップするような「アクセサ関数」を作成しておくことを推奨します。これにより、ポインタのNULLチェックを強制する仕組みを組み込みやすくなり、言語移行時のバグ混入リスクを大幅に低減できます。常に「ポインタは初期化されているか」「解放後にクリアされているか」を意識したコーディングを心がけましょう。

コメント