プリプロセッサー
本章では、プリプロセッサーの基本概念と使用方法について説明します。
1. 概要
プリプロセッサーは、プリプロセッサー・ステートメントによってソース・プログラムの一部を変更して出力します。プリプロセッサーの出力は、コンパイラーの入力として使用されます。
プリプロセッサーが入力として受けるソース・プログラムは、次の3つの要素で構成されます。
-
プリプロセッサー・ステートメント
プリプロセッサー・ステートメントは、パーセント記号(%)で始まる必要があります。ただし、プリプロセッサー・プロシージャに記述されているステートメントは、パーセント記号を付けません。プリプロセッサー・ステートメントはソース・プログラムに記述されている順に実行されます。
プリプロセッサー・ステートメントにより、入力テキストに以下の処理を行うことができます。
-
プリプロセッサーはプリプロセッサー・ステートメントを順次実行して入力テキストを変更します。
-
プリプロセッサー・ステートメントにより入力テキストを変更するかどうかを決定できます。
-
他のファイルやライブラリに保存されている文字列をプリプロセッサー入力に含めることができます。
以下は、プリプロセッサー・ステートメントにより実行できる作業についての説明です。
ステートメント 説明 プリプロセッサーで使用する変数名と属性を設定できます。
%ACTIVATEステートメントが実行されたものと見なし、その変数をアクティブ状態として扱います。変数を明示的に宣言しない場合は、CHARACTER属性で宣言され、非アクティブ状態として扱います。
入力テキストの文字列をプリプロセッサー変数の値で変換するかどうかを指定できます。
-
%ACTIVATE: 有効化
-
%DEACTIVATE: 無効化
他のファイルに保存されている文字列をプリプロセッサー入力に含めることができます。
プリプロセッサーの実行順序を変更できます。
プリプロセッサー変数の値を変更できます。
%PROCEDURE
プリプロセッサー・プロシージャを定義して使用できます。
-
-
リスト制御ステートメント
プログラム出力のレイアウトを設定できます。OpenFrame PL/Iでは入力として受けるだけで、出力には反映しません。
-
入力テキスト
プリプロセッサー入力において、上述したプリプロセッサー・ステートメント、リスト制御ステートメントを除くすべての文字列を指します。入力テキストとして、PL/Iソース・プログラムと共に他の形式の文字列も使用できます。PL/I定数は変更せずにそのまま出力します。アクティブ状態のプリプロセッサー変数の名前に対応する文字列はその変数の値で変換されます。
プリプロセッサー変数のオプションとしては、RESCANまたはNORESCANオプションを指定できます。NORESCANオプションを指定している場合は、該当する変数の値に一度だけ変換します。RESCANオプションを指定している場合には、変換後に該当する名前の変数があるかを探して変更作業を繰り返します。
変数とデータ
プリプロセッサー変数は%DECLAREステートメントで宣言することができ、FIXED属性とCHARACTER属性を与えることができます。すべての変数はSTATICストレージを持ちます。
プリプロセッサーのデータ・タイプは、以下のように区分されます。
区分 | 説明 |
---|---|
FIXED |
Linux C++の整数型にマッピングされます。 |
CHARACTER |
Linux C++のstd::string型にマッピングされます。 |
数値定数は、スケールなしの整数型のみをサポートします。文字列の反復因数は指定できません。 |
参照と式
プリプロセッサーの参照と式は、式で説明した方法で計算されます。
その他の特異事項は以下のとおりです。
-
式のオペランドは、プリプロセッサー変数、プロシージャ参照、固定小数点定数、ビット定数、文字定数、およびプリプロセッサー組み込み関数参照を含みます。
-
プリプロセッサー・プロシージャの外部で宣言された配列は、様々なプロシージャで参照されることができますが、プロシージャの外部からは参照することができません。
-
累乗演算記号(**)は使用できません。
-
整数演算の結果が小数点になる場合、小数点以下は切り捨てます。たとえば、3/5は0.6ではなく、0で保存されます。
-
算術演算に文字列を使用できます。この場合、算術値に変換される文字列は整数型の値である必要があります。
-
ヌル文字列はゼロに変換されます。
-
固定小数点値を文字列に変換する場合、常に長さ8の文字列に変換されます。
名前の有効範囲
プリプロセッサーで使用される名前の有効範囲は、名前が宣言された場所によって決定されます。
プロシージャ内で宣言された名前の有効範囲は、そのプロシージャに限ります。組み込まれた文字列内で宣言された名前の有効範囲は、その文字列と、その文字列が組み込まれた後で走査されたすべての入力テキストになります。その他のすべての名前の有効範囲は、プリプロセッサー入力全体になります。ただし、同じ名前で宣言されたプリプロセッサー・プロシージャは除きます。
2. プロシージャ
本節では、プリプロセッサー・プロシージャの基本概念と規則について説明します。
以下は、プリプロセッサー・プロシージャの基本文法です。

プリプロセッサー・プロシージャを使用するには、パラメータを渡す方法と戻り値を処理する方法を理解する必要があります。
パラメータは、位置パラメータとキーワード・パラメータで渡す方法があります。キーワード・パラメータで渡す場合は、パラメータ名に対応する引数を渡します。位置パラメータで渡す場合は、引数を順番にパラメータとマッチングします。引数とパラメータの数は同じでないこともあります。パラメータの数より引数の数が多い場合、余分の引数は無視します。その逆の場合は、初期値でパラメータの値を設定します。FIXED属性の初期値はゼロ、CHARACTER属性の初期値はヌルです。
関数参照が入力テキストで参照される場合に、引数はコンマ(,)または右括弧で区切ります。ただし、対になっている引用符や括弧の間にあるコンマや右括弧は、区切り文字として使用されません。
たとえば、(A(B,C),D)は、A(B,C)とDの2つの引数で構成されています。引数をパラメータに渡す前に、変換が可能な場合は先に変換を行います。この作業は引数の数に影響を及びません。つまり、変換によって引数内にコンマや括弧が挿入されても、区切り文字ではなく単に文字として見なします。たとえば、A(B,C)がE, Fに変換され、E, F, Dになっても、引数はE, FとDの2つです。
参照が入力テキスト内に存在し、ステートメント・オプションを指定している場合は、引数を位置引数に指定することも、キーワード参照によって指定することもできます。参照の終わりは、セミコロン(;)で区分しますが、セミコロンは出力には表示されません。
以下は、プリプロセッサー・プロシージャ宣言の例です。
%FIND:PROC(A,B,C) STATEMENT;
上記のように宣言された場合、FINDは以下のように参照できます。下の例はすべて同じ意味を持ちます。
FIND(X,Y,Z);
FIND B(Y) C(Z) A(X);
FIND(X) C(Z) B(Y);
FIND(,Y,Z) A(X);
関数プロシージャによって返される値の属性を指定するために、CHARACTER属性またはFIXED属性を設定します。
RETURNS属性を持つプリプロセッサー・プロシージャには、少なくとも1つ以上のRETURNステートメントが必要です。RETURNステートメントは制御を呼び出し位置に返し、対応する参照にRETURNステートメントに設定した値で置き換えます。
プリプロセッサー・プロシージャを使用するには、以下の事項を考慮する必要があります。
-
プリプロセッサー・プロシージャは、%PROCEDUREと%ENDステートメントで区切ります。
-
プロシージャがRETURNS属性を持たない場合は、RETURNステートメントを持つことができません。逆に、プロシージャが関数である場合は、RETURNステートメントを1つ以上含む必要があります。
-
プリプロセッサー・プロシージャ内のプリプロセッサー・ステートメントは、パーセント記号(%)で始まりません。
-
プリプロセッサー・プロシージャはネストすることができません。
-
プリプロセッサー・プロシージャ内にプリプロセッサーENTRY宣言があってはなりません。
-
プリプロセッサー・プロシージャ・入り口名と、そのプロシージャに渡される引数を関数参照と言います。プリプロセッサー式内の関数参照によって、プリプロセッサー・プロシージャを呼び出すことができます。
-
プリプロセッサー・プロシージャの入り口名は、%DECLAREステートメントで宣言する必要がありません。
-
入り口名が有効である場合は、プリプロセッサー・プロシージャを呼び出す前に処理する必要がありません。ただし、そのプロシージャはプリプロセッサー入力に含まれているか、呼び出す前に挿入された文字列に組み込まれていなければなりません。
-
プリプロセッサー・プロシージャ関数は関数参照を関数の戻り値で変換します。
3. ステートメント
本節では、プリプロセッサー・ステートメントの使用方法について説明します。すべてのプリプロセッサー・ステートメントにはラベルを付けることができます。
3.1. %ACTIVATEステートメント(略語: %ACT)
%ACTIVATEステートメントは、変数を有効な状態にして入力テキスト変換を行えるようにします。
変数が有効な間は、以降検出されるすべての入力テキストの変数が変換されます。すでに有効な状態の変数には影響しません。

項目 | 説明 |
---|---|
identifier |
プリプロセッサー変数、プロシージャ、組み込み関数の名前を指定します。 配列変数の名前は指定できません。 |
RESCAN |
変換値がプリプロセッサー名である場合、マッピングされる有効な名前がなくなるまで変換を繰り返します。 |
SCAN |
一度だけ変換します。 |
NORESCAN |
SCANと同じ結果を返します。 |
3.2. %assignmentステートメント
%assignmentステートメントは、プリプロセッサー式を計算し、その結果をプリプロセッサー変数に割り当てます。

複合割り当てと多重割り当ては、許可されていません( +=、-=、または a = b = c )。配列は、引数のターゲットになれません。
3.3. %DEACTIVATEステートメント(略語: %DEACT)
%DEACTIVATEステートメントは、変数を無効にします。

項目 | 説明 |
---|---|
identifier |
プリプロセッサー変数、プロシージャ、組み込み関数の名前を指定します。 |
変数を無効にすると、入力テキストの変数を変換しませんが、プリプロセッサー変数が持つ値は失われません。したがって、変数を再び有効化するときに、値を割り当てる必要がありません。すでに無効な状態の変数を無効化しても影響はありません。
3.4. %DECLAREステートメント
%DECLAREステートメントは、プリプロセッサー変数、プロシージャ、組み込み関数の識別子を定義します。また、変数の走査状況を設定することができます。(略語: %DCL for DECLARE、CHAR for CHARACTER、INT for INTERNAL、EXT for EXTERNAL)

または

項目 | 説明 |
---|---|
identifier_description |
プリプロセッサー識別子の名前と属性を設定します。 |
BUILTIN |
この識別子が同じ名前を持つプリプロセッサー組み込み関数であることを指定します 。 |
ENTRY |
この識別子がプリプロセッサー・プロシージャであることを指定します。この宣言は対応する入り口名を有効にします。 %PROCEDUREステートメントのラベルに指定した名前で、プリプロセッサー・プロシージャ入り口名を明示的に宣言できます。ただし、宣言された名前は無効な状態で初期化されます。 |
identifier_description:
dimension :
attributes :
項目 | 説明 |
---|---|
CHARACTER |
Linux C++のstd::string型にマッピングされます。 |
FIXED |
Linux C++の整数型にマッピングされます。 |
SCAN |
識別子を有効な状態に設定し、一度だけ変換します。 |
RESCAN |
識別子を有効な状態に設定し、変換値がまたプリプロセッサー名である場合は、変換を繰り返します。 |
NOSCAN |
識別子を無効な状態に設定します。 |
3.5. %DOステートメント
%DOステートメントは、%ENDステートメントと一緒に使用されて、プリプロセッサーDOグループを定義します。
タイプ1:

タイプ2:

specification1:
タイプ3:

specification2 :
タイプ4:

%DOステートメントについての説明は、DOステートメントを参照してください。
プリプロセッサーの%DOステートメントがコンパイラーのDOステートメントと異なる点は、以下のとおりです。
-
%DOステートメントには、UPTHRUとDOWNTHRUがありません。
-
%DOステートメントには、タイプ3のspecification1、specification2を繰り返し設定できません。
-
%DOステートメントでは、DOステートメントにはない%DO SKIPステートメントをサポートします。%DO SKIPステートメントは対になる%ENDステートメントまでのコードをコメント処理します。
プリプロセッサーDOグループはネストすることができます。また、プリプロセッサー・ステートメント、入力テキスト、リスト制御ステートメントをすべてDOグループ内で使用できます。 |
3.6. %ENDステートメント
%ENDステートメントは、%DO、%SELECT、%PROCEDUREステートメントと一緒に使用されて、グループまたはプロシージャを定義します。ENDの後ろのラベルは、%PROCEDURE、%DO、%SELECTステートメントのラベルである必要があります。

3.7. %GO TOステートメント
%GO TOステートメントは、走査を続行するラベルを設定します。指定されたラベルの場所から走行を行います。

項目 | 説明 |
---|---|
label |
プリプロセッサー・プロシージャ内の%GOTOステートメントの後ろに指定するラベルは、そのプロシージャに含まれている必要があります。 組み込みファイル内の%GOTOステートメントのラベルは、そのファイルに含まれている必要があります。 |
3.8. %IFステートメント
%IFステートメントはプリプロセッサー式の値によって、次に実行するステートメントを制御します。%IFステートメントはネストすることができます。

項目 | 説明 |
---|---|
preprocessor_expression |
式を計算した後、その値をtrueまたはfalseに一時設定します。 条件式でない場合には、その値がゼロの場合はfalse、ゼロでない場合にはtrueに設定します。 preprocessor_expressionの値がtrueの場合はunit1を、falseの場合はunit2を実行します。 |
preprocessor_unit |
%DECLARE、%PROCEDURE、%END、%DOステートメントを除いて、DOグループ、SELECTグループを含むすべてのプリプロセッサー・ステートメントを使用できます。 |
3.9. %INCLUDEステートメント
%INCLUDEステートメントで指定された外部テキストをプリプロセッサー入力の%INCLUDEステートメントの位置に含めます。含まれた外部テキストは、組み込み済みテキストと言います。
%INCLUDEステートメントはネストすることができます。つまり、組み込み済みテキスト内にまた別の%INCLUDEステートメントが存在できます。
組み込み済みテキスト内のDOグループ、SELECTグループ、そして他のステートメント(%IFなど)は、テキスト内で定義される必要があります。つまり、対応する%ENDステートメントが同じテキスト内に存在しなければなりません。組み込まれるファイル名は、8桁に制限します。

3.10. %INSCANステートメント
%INSCANステートメントは、%INCLUDEステートメントと同様に外部テキストをプリプロセッサー入力の%INSCANステートメントの位置に含みます。%INCLUDEステートメントと異なる点は、組み込まれるファイル名をプリプロセッサー変数で指定できることです。

3.11. %ITERATEステートメント
%ITERATEステートメントは、このステートメントを含むDOグループの%ENDステートメントにスキップします。これにより、現在行われている%DOステートメントの繰り返しを終了し、必要な場合は次の繰り返しを続けます。

項目 | 説明 |
---|---|
label_constant |
DOグループのラベルである必要があります。省略した場合、最新の%ENDステートメントにスキップします。 |
3.12. %LEAVEステートメント
%LEAVEステートメントは、このステートメントを含むDOグループ、またはそのグループのすべての繰り返しを終了します。以降、現在のDOグループが%ENDステートメントに達して終了したときのように、次の作業を続行します。

項目 | 説明 |
---|---|
label_constant |
DOグループのラベルである必要があります。 指定するラベルを持つDOグループのすべての繰り返しをを終了します。省略した場合、最新のDOグループを終了します。 |
4. プリプロセッサー組み込み関数
関数参照により、プリプロセッサー組み込み関数を呼び出すことができます。プリプロセッサー組み込み関数はプログラマーが定義した関数を呼び出す場合と同じ方法で呼び出すことができますが、引数の数が一致しなければならない点が異なります。
入力テキストで組み込み関数を呼び出すには、組み込み関数の名前が有効である必要があります。組み込み関数の名前は、%DECLAREステートメントと%ACTIVATEステートメントにより有効化できます。一方、プリプロセッサー・ステートメントでの組み込み関数の名前は常に有効な状態です。組み込み関数の名前がユーザー定義のプロシージャ名である場合は、組み込み関数ではなく、そのプロシージャを参照します。
以下は、プリプロセッサー組み込み関数についての説明です。詳細については、該当節を参照してください。
関数 | 説明 |
---|---|
日付と時間を含む18桁の文字列を返します。 |
|
浮動小数点数字を含む5桁の文字列を返します。 |
|
yと一致するサブ文字列のx内の開始位置をFIXEDタイプで返します。 |
|
指定したx文字列の長さをFIXEDタイプで返します。 |
|
指定したパラメータがプロシージャの呼び出し時に設定されたかどうかを返します。 |
|
xのy, zによって指定されたサブ文字列を返します。 |
4.1. COMPILETIME
COMPILETIMEは、日付と時間を含む18桁の文字列を返します。

-
戻り値
戻り値は、次の形式で返されます。
DD.MMM.YYbHH.MM.SS
以下は、戻り値の例です。
01.JAN.14 12.01.59
4.2. COUNTER
COUNTERは、浮動小数点数字を含む5桁の文字列を返します。

最初の呼び出しでは00001を返し、以降1ずつ増加します。COUNTERが99999回呼び出された後は、次の呼び出しでは00000が返されます。
4.3. INDEX
INDEXは、yと一致するサブ文字列のx内の開始位置をFIXEDタイプで返します。また、比較を開始する位置を指定することもできます。

-
引数
項目 説明 x
検索する対象文字列です。
CHARACTERタイプでない場合は、CHARACTERタイプに変換されます。
y
検索に使用される文字列です。
CHARACTERタイプでない場合は、CHARACTERタイプに変換されます。
n
検索を開始するx内の位置です。
FIXEDタイプでない場合は、FIXEDタイプに変換されます。
-
戻り値
-
yがx内にないか、xまたはyの長さがゼロである場合は、ゼロが返されます。
-
nはゼロより大きく、かつ xの長さ + 1 より小さくなければなりません。nが xの長さ + 1と同じである場合は、ゼロが返されます。
-
4.5. PARMSET
PARMSETは、指定したパラメータがプロシージャの呼び出し時に設定されたかどうかを0または1で返します。

-
引数
項目 説明 x
プリプロセッサー・プロシージャのパラメータである必要があります。
-
戻り値
-
xが設定されている場合、1を返します。
-
4.6. SUBSTR
SUBSTRは、xのy, zによって指定されたサブ文字列を返します。

-
引数
項目 説明 x
サブ文字列を抽出する文字列を指定する式です。
CHARACTERタイプでない場合は、CHARACTERタイプに変換されます。
y
xのサブ文字列を抽出する開始位置を指定する式です。
FIXEDタイプでない場合は、FIXEDタイプに変換されます。
z
xのサブ文字列の長さを指定する式です。
FIXEDタイプでない場合は、FIXEDタイプに変換されます。zが0の場合は、ヌル文字列を返し、zが省略されている場合は、xの位置yからxの終わりまでを返します。
zの値は負数でなければならず、yとzの値はxのサブ文字列を抽出できる範囲内に存在する必要があります。
-
戻り値
-
y = LENGTH(x) + 1 かつ z = 0である場合、ヌル文字列が返されます。
-