PL/Iの「予約語がない」という衝撃と、SUBSTR関数が裏側で行っていること
こんにちは。メインフレームの世界へようこそ。
JavaやCOBOLを触ってきた方にとって、PL/Iは最初、少し「自由すぎて怖い」と感じるかもしれません。しかし、その自由度こそが、何十年もの間、銀行の勘定系システムや航空会社の予約システムを支え続けてきた理由でもあります。
今回は、PL/Iの不思議な命名規則と、文字列操作の代表選手である`SUBSTR`関数の「裏側の挙動」について、現場の視点から紐解いていきましょう。
—
1. 「予約語」という概念がない世界
JavaやC言語では、`if`や`while`といったキーワードを変数名に使うことはできませんよね。コンパイラが「それは命令文だ!」と混乱してしまうからです。
しかし、PL/Iには「予約語」というものが存在しません。
例えば、こんな宣言が可能です。
/i
DCL IF CHAR(10) INIT(‘HELLO’); / 変数名を IF にする /
DCL THEN CHAR(10) INIT(‘WORLD’); / 変数名を THEN にする /
IF = THEN; / 変数IFに変数THENを代入する、という構文 /
「えっ、コンパイラは混乱しないの?」と思いますよね。実はPL/Iのコンパイラは、文脈(コンテキスト)を非常に賢く読み解きます。単語の出現位置や、その後の記号(代入記号の`=`があるか等)を見て、「これは制御文のIFなのか、それともユーザーが宣言した変数IFなのか」を厳密に判別するのです。
初心者の皆さんへのアドバイス:
これは「何でもできる」という自由の裏返しですが、可読性は最悪になります。「`DCL IF FIXED BIN(31);`」なんてコードに出くわしても、驚かないでくださいね。現場の達人はあえてこんなことはしませんが、歴史あるコードには時折この手の「遊び心」が潜んでいます。
—
2. SUBSTR関数の内部で起きている「魔法」
文字列を切り出す`SUBSTR`関数。普段何気なく使っていますが、実はその背後では、コンパイラが私たちのために懸命なバックアップ作業を行っています。
特に注意が必要なのが、「ソース(元データ)」と「ターゲット(代入先)」がメモリ上で重複している場合です。
内部の一時領域確保(Temporary Storage)
例えば、以下のようなコードを考えてみましょう。
/i
DCL STR CHAR(10) INIT(‘ABCDEFGHIJ’);
/ STRの一部を、同じSTRに上書きする /
SUBSTR(STR, 1, 5) = SUBSTR(STR, 4, 5);
もし、あなたがコンピュータの立場ならどう動きますか?
1. `STR`の4文字目から5文字(’DEFGH’)を読み取る。
2. それを`STR`の1文字目に書き込む。
この時、もし単純に左から順に書き込んでいくと、元のデータが書き換わってしまい、後半のコピーが正しく行われませんよね。
PL/Iのコンパイラは、この「重複」を検知すると、「一時領域(テンポラリ・ストレージ)」をメモリ上にこっそり確保します。
1. まず、読み取るべきデータ(’DEFGH’)を一時領域に退避させる。
2. 準備が整ったところで、その一時領域から`STR`の先頭へコピーする。
この仕組みがあるおかげで、私たちはメモリの重なりを気にせず、直感的に文字列操作ができるのです。メインフレームのコンパイラは、ただの翻訳機ではなく、こうした「安全装置」を裏側に隠し持っているのですね。
—
3. ポインタ演算とデータ制御の深淵
PL/Iが「汎用機(General Purpose)」と呼ばれる所以は、このデータ制御の柔軟さにあります。`SUBSTR`は関数として使うだけでなく、「擬似変数(Pseudo-variable)」としても機能します。つまり、代入の左側に書くことができるのです。
これは、メモリ上の特定のアドレスを直接指し示して、そこを書き換えるという、C言語のポインタ操作に近いことを安全に行っていることと同義です。
/i
/ 例:特定のオフセット位置にある文字だけを差し替える /
DCL MY_DATA CHAR(20) INIT(‘0001:USER_NAME’);
/ 6文字目から5文字を置き換える /
SUBSTR(MY_DATA, 6, 5) = ‘ADMIN’;
このとき、PL/Iは`MY_DATA`というメモリ領域の先頭から5バイトオフセットした位置を計算し、そこに直接`ADMIN`を書き込みます。この「アドレス計算」と「長さチェック」をコンパイラが一貫して制御しているため、アセンブラのような低レイヤーの操作を、高水準言語の書き味で行えるのです。
—
まとめ:怖がる必要はありません
PL/Iのコードを初めて読むとき、その独特の構文に圧倒されるかもしれません。しかし、一つずつ紐解いていけば、それは「プログラマがやりたいことを、極限まで柔軟に叶えようとした歴史の結晶」であることが分かります。
- 予約語がないこと=文脈を理解するコンパイラの知恵
- SUBSTRの挙動=メモリの重複を守るための自動的な一時領域確保
これらを理解しておけば、レガシーシステムのバッチ改修も、ただの「古いコード」ではなく「緻密に設計されたロジックの解読」として楽しめるようになるはずです。
もし現場で「このコード、動きが怪しいな…」と思ったときは、コンパイラが裏でどんな一時領域を作っているのか、少しだけ想像してみてください。きっと、解決の糸口が見えてくるはずですよ。
それでは、また次回のメインフレーム講座でお会いしましょう!
