こんにちは!メインフレームの世界へようこそ。
JavaやCOBOLといった他のプログラミング言語の経験がある方にとって、IBMの汎用機(メインフレーム)やPL/Iという言語は、どこか要塞のようで近寄りがたく感じられるかもしれません。「なんだか昔の言葉だし、ルールが厳しそう…」なんて、怖くなっていませんか?
でも、安心してくださいね。一つひとつの仕組みを丁寧に紐解いていけば、PL/Iは非常に合理的で、かつての人たちが知恵を絞って作り上げた美しい言語であることが分かります。
今回は、そんなPL/Iの数ある特徴の中でも、少しディープで、しかし実務の現場では「知っていると救われる」こと請け合いのテーマ、「LENGTH関数の記述子(Descriptor)参照」について、一緒に優しく覗いていきましょう。
—
そもそもPL/Iには「予約語」がないって本当?
JavaやCOBOLを触ってきた方なら、「この単語はシステム変数だから変数名に使っちゃダメ」「この命令語は予約されているから……」という苦い経験が一度はあるはずです。
ところが、PL/Iの驚くべき(そして少しお茶目な)特徴として、「言語としての厳密な予約語(Reserved Words)が存在しない」という仕様があります。
どういうことかと言うと、極端な話、計算や条件分岐で使う `IF` や `THEN` といったキーワードですら、あなたが変数名として使おうと思えば使えてしまうのです。(※もちろん、コンパイラが混乱するので実務でそんな名前をつけるのはご法度ですが!)
コンパイラは、前後の文脈(Context)を見て、「あ、ここで出てきた `IF` は命令じゃなくて変数名だな」と空気を読んで判断してくれます。なんだか、人間の言葉に近い柔軟さを持っていますよね。
—
VARYING属性の文字列って、裏側でどうなっているの?
さて、今回の本丸であるVARYING属性のお話です。
COBOLにはない、PL/IやC言語(の文字列)に似た便利な機能として、可変長文字列を扱う `CHAR(n) VARYING` という宣言があります。
例えば、最大50文字入るけれど、実際には「山田太郎」の4文字しか入っていない場合、メモリの無駄を省くために実際の長さを動的に保持してくれます。
Javaの `String` オブジェクトの長さ(`.length()`)や、COBOLの `OCCURS DEPENDING ON` などに慣れていると、「可変長って、裏でどうやって長さを覚えてるんだろう?」と気になりませんか?
ここで登場するのが、今回のテーマである「記述子(Descriptor)」です。
メモリ上の構造を覗いてみよう
VARYING属性を持つ文字列変数がメモリ上でどう格納されているか、イメージ図を頭に思い浮かべてみてください。
PL/Iがメモリ上に確保する領域は、ざっくり言うとこんな構造になっています。
1. 接頭辞(プレフィックス):文字列の「現在の実効長」を格納するエリア(通常は2バイトのバイナリ整数)。
2. 本体エリア:実際の文字データが詰まっているエリア。
Javaのオブジェクトのように「長さを管理するメソッド」を呼び出しているわけではなく、文字列本体のすぐ頭(直前)に、こっそり長さの数字がメモ書きされているイメージです。
—
LENGTH関数と記述子の関係
ここでPL/Iの `LENGTH` 関数が登場します。
「文字列の長さを取得する」という非常にシンプルな機能ですが、この `LENGTH` 関数が裏側で何をしているかを知ると、PL/Iのメモリ管理の妙に思わず唸ってしまいます。
固定長(`CHAR(50)` など)の文字列に対して `LENGTH` を使うと、コンパイル時に決まった最大長(この場合は50)を即座に返します。これはメモリを見に行く必要すらない定数扱いです。
しかし、VARYING属性を持つ変数に対して `LENGTH` を使う場合、プログラムは実行時にその変数の直前にある「記述子(先頭の2バイト)」をチラッと覗きに行って、そこに書かれている数字を読み取っているのです。
—
実務で役立つ!PL/Iコード例
百聞は一見にしかず。実際にVARYING変数宣言と、その長さを扱うコードを見てみましょう。
レガシーな現場の雰囲気を出すために、すべて大文字で記述しています。
—————————————————————-
- VARYING文字列の宣言とLENGTH関数の動きを確認するサンプルプログラム
—————————————————————-
DEMO_PGM: PROC OPTIONS(MAIN);
— 変数の宣言 —
- 宣言時は最大50バイトだが、VARYINGによって可変長になる
DCL USER_NAME CHAR(50) VARYING;
— 数値保持用の変数 —
DCL CURRENT_LEN FIXED BIN(31);
— 値の代入 —
USER_NAME = ‘IBM_MAINFRAME’;
— LENGTH関数による長さの取得 —
- 実行時、USER_NAMEの直前にある記述子(Descriptor)を参照し、
- 文字列の実際の長さ(この場合は13)を動的に取得する。
CURRENT_LEN = LENGTH(USER_NAME);
— 結果の出力(イメージ) —
DISPLAY(‘現在の文字列: ‘ || USER_NAME);
DISPLAY(‘現在の長さ: ‘ || CURRENT_LEN);
END DEMO_PGM;
このコードを実行すると、`CURRENT_LEN` には最大値の「50」ではなく、実際に代入された文字列 `’IBM_MAINFRAME’` の長さである 13 が格納されます。
裏側では、`USER_NAME` という変数がメモリ上に展開された瞬間、その先頭2バイトの領域にバイナリ値で `13` が書き込まれており、`LENGTH` 関数はそれを秒速で拾い上げている――そう想像すると、機械と対話している実感が湧いてきて少しワクワクしませんか?
—
まとめ:怖がらなくて大丈夫、PL/Iはロマンにあふれている
今回は、PL/Iの構文の柔軟さと、VARYING文字列が隠し持つ「記述子(Descriptor)」の秘密についてお話しました。
「記述子」という言葉を聞くと、なんだか難しそうなコンパイラの内部処理に思えますが、要するに「変数のすぐ隣に、自分のサイズをメモした付箋が貼ってある」というだけのシンプルな仕組みです。
他言語の経験があるあなたなら、このメモリ構造さえ掴んでしまえば、PL/Iのデータ制御は怖くありません。むしろ、ハードウェアの動きに直結した効率的な仕組みに、レガシー言語ならではのロマンを感じていただけるはずです。
日々のバッチ改修やマイグレーション調査でPL/Iのコードに出会ったら、「おっ、今この変数の記述子を読みに行っているんだな」と、頭の中でメモリの動きを優しくイメージしてみてくださいね。あなたのメインフレームライフを、心から応援しています!
