【入門編】SUBSTR組み込み関数の内部挙動と引数省略時の仕様 – PL/Iの基本構文とデータ制御実践ガイド

PL/Iの「SUBSTR」関数、その奥深い世界へようこそ

こんにちは。メインフレームの現場で何十年もPL/Iと格闘してきた、システムアーキテクトです。

JavaやCOBOLの経験がある皆さんにとって、PL/Iは少し「自由すぎて怖い」言語に見えるかもしれません。特にPL/Iには「予約語」という概念がほぼ存在しないという、他言語エンジニアが腰を抜かすような仕様があります。例えば、`IF`や`THEN`さえも変数名に使えてしまう。コンパイラは文脈から「あ、これは命令だ」「こっちは変数だな」と空気を読んで判断するんです。まるで長年連れ添った夫婦の阿吽の呼吸ですよね。

そんなPL/Iの懐の深さを象徴する機能の一つが、文字列操作の要である`SUBSTR`関数です。今日はこの関数の「本当の姿」を、現場の視点から紐解いていきましょう。

SUBSTR関数の基本と「第3引数の省略」

まずは基本から。`SUBSTR(文字列, 開始位置, 長さ)`ですね。
ここまでは他の言語と変わりませんが、PL/Iの`SUBSTR`は第3引数(長さ)を省略できるという面白い特徴があります。

/i
DCL STR CHAR(20) INIT(‘IBM_MAINFRAME_POWER’);

/ 第3引数を省略すると「そこから末尾まで全部」という意味になります /
PUT SKIP LIST(SUBSTR(STR, 5));
/ 結果: ‘MAINFRAME_POWER’ が出力されます /

この「省略=残り全部」という挙動、実はとても便利です。固定長文字列を扱うとき、「末尾まで」という指定を明示的に長さを計算して書く必要がないからです。

固定長(CHAR)と可変長(VARYING)のメモリ操作の違い

ここからが少しだけディープな話です。PL/Iには`CHAR(N)`(固定長)と`CHAR(N) VARYING`(可変長)という二種類の文字列があります。この違いを理解しておかないと、バッチ処理で思わぬメモリのゴミを拾うことになります。

1. 固定長 (CHAR(N)) の場合

固定長の場合、メモリ上には「宣言された長さ分」が常に確保されています。`SUBSTR`で切り出した結果もまた固定長として扱われます。

/i
DCL FIX_STR CHAR(10) INIT(‘ABCDE’);
/ 実際にはメモリ上で ‘ABCDE ‘ (後ろにスペース) となっています /

/ SUBSTRで切り出しても、残りの領域はスペースで埋められます /
DCL RESULT CHAR(5);
RESULT = SUBSTR(FIX_STR, 1, 3);
/ RESULTには ‘ABC ‘ が入ります。スペースが残る点に注意! /

2. 可変長 (CHAR(N) VARYING) の場合

`VARYING`がつくと、PL/Iは賢くなります。メモリの先頭に「現在の長さ」を保持する2バイトの領域が隠されており、そこを自動管理してくれるのです。

/i
DCL VAR_STR CHAR(10) VARYING INIT(‘ABCDE’);
/ メモリ上では [長さ:5][‘A’,’B’,’C’,’D’,’E’, …] となっています /

/ SUBSTRで切り出す際、VARYING属性なら「純粋な文字数」だけが抽出されます /
DCL RESULT_V CHAR(5) VARYING;
RESULT_V = SUBSTR(VAR_STR, 1, 3);
/ RESULT_V は ‘ABC’ となり、長さ情報も3になります /

現場で役立つ「なぜ?」を解決するために

初学者の皆さんが最も戸惑うのは、「なぜSUBSTRの代入でデータが化けるのか?」というトラブルです。

特に、`SUBSTR`を左辺(代入先のターゲット)に使う場合、PL/Iはメモリを直接書き換えます。

/i
DCL DATA CHAR(10) INIT(‘1234567890’);

/ DATAの3文字目から3バイト分を’XYZ’で上書きする /
SUBSTR(DATA, 3, 3) = ‘XYZ’;

/ 結果: ’12XYZ67890′ となる /

この「文字列の一部をピンポイントで書き換える」操作は、COBOLでいうところの`MOVE`や`STRING`命令よりも直感的ですが、「元の変数の長さ」を超えて書き込もうとすると、バッファオーバーランや意図しないデータ破壊を招くことがあります。PL/Iは「あなたがそうしたいなら、そうしてあげるよ」と、警告なしにメモリを上書きしてくれる、良くも悪くも忠実な言語なんです。

まとめ:怖がらなくて大丈夫です

PL/Iの`SUBSTR`は、単なる関数ではなく「メモリをどう扱うか」というエンジニアの意図をダイレクトに反映するツールです。

  • 第3引数省略: 「末尾まで」という便利なショートカット。
  • CHAR vs VARYING: 固定長は「箱のサイズ重視」、可変長は「中身の長さ重視」。この違いを意識するだけで、バグの8割は防げます。

最初は慣れない構文に驚くかもしれませんが、PL/Iは一度そのロジックを理解すれば、これほどパワフルで思い通りに動く言語はありません。もしコードを書いていて「あれ、思った結果と違うぞ?」と思ったら、それはコンパイラのせいではなく、メモリのどこかをのぞき込むチャンスです。

これからも、このレガシーな世界の深淵を一緒に紐解いていきましょう。何か詰まったら、いつでも聞いてくださいね。

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