redefines
他のレコード変数を再定義するレコード変数の宣言
既に他のレコード変数に割り当てられているメモリー領域を再定義するレコード変数を宣言することができます。
例えば、ある検索と次の検索で取り出すデータの構造が異なっていても、次のように、
シリアル・ファイルからデータ域を次々に読み取るループを記述することができます。
Record RecordA type SerialRecord
{ fileName = "myFile" }
record_type char(1);
field1 char(20);
end
Record RecordB type BasicRecord
10 record_type char(1);
10 field2 bigint;
10 field3 decimal(7);
10 field4 char(8);
end
Program ProgramX type basicProgram
myRecordA RecordA;
myRecordB RecordB {redefines = myRecordA};
function main();
get next myRecordA;
while (myRecordA not endOfFile)
if (myRecordA.record_type == "A")
myFunction01(myRecordA.field1);
else
myFunction02(myRecordB.field2, myRecordB.field3, myRecordB.field4);
end
get next myRecordA;
end
end
end
このループ内で、関数は以下のアクションを実行します。
- 入力レコードの最初のフィールドで、残りのデータの構造を識別するコードを確認する。
- その入力レコードまたは 2 番目の基本レコードのいずれかを使用して、 取り出されたデータの他のフィールドを処理する。2 番目のレコードは、入力レコードと同じメモリー領域を参照しますが、構造が異なります。
あるレコード変数を他のレコード変数の再定義として宣言するには、redefines プロパティーを使用します。 このプロパティーは他のレコード変数の名前を受け入れます。このプロパティーは、 レコード変数宣言でのみ使用することができます。 レコード・パーツ定義では使用できません。
オリジナルのレコードおよびオーバーレイ・レコードには任意の型の構造化されたレコードを使用することができますが、以下の制限事項があります。
- レコードは同じ範囲にあること。例えば、最初のレコードをレコードを収容するフィールドとして宣言する場合、最初のレコードを再定義するレコードも同じ収容レコード内のフィールドとして宣言する必要があります。
同様に、あるレコードをライブラリー (ただし、関数の外側) で宣言する場合は、他のレコードも同じライブラリーで、また関数の外側でも宣言する必要があります。Record StructuredRecordA 10 x INT; end Record StructuredRecordB 10 y INT; end Record TestRecord myRec1 StructuredRecordA; myRec2 StructuredRecordB { redefines=myRec1}; end - オーバーレイ・レコードの長さが、オリジナルのレコードと同じか、またはそれ以下であること。 この制限事項のため、再定義するメモリー領域内にないオーバーレイ・レコード内の領域にコードからアクセスすることはできません。
- 一部の Record ステレオタイプでは、非表示のバイトが必要になる場合があります。 詳しくは、個々のレコード・タイプの資料を参照してください。
オリジナルのレコードに割り当てられたプロパティーはオーバーレイ・レコードに影響しません。メモリー域のみが再定義されます。
I/O に対してオーバーレイ・レコードを使用することはできません。
同一レコードから、他のフィールドを再定義するフィールドの宣言
以下の環境においてのみ、redefines プロパティーをフィールドに適用することができます。
- 再定義するフィールドと再定義されるフィールドが同じレコード内にある。
- レコードが構造化されている。
- 両方のフィールドが同じレベルにあり、同じ親を持っている。
- 再定義するフィールドの長さは、再定義されるフィールドの長さ以下である。
2 つのフィールドは異なる型でもかまいませんが、レコードを渡したり初期化する場合には再定義されるレコードの型のみが保存されます。次の例はこれを示します。
Record exampleRecord1
10 a INT;
20 aa INT;
20 ab CHAR(4) { redefines = a.aa };
10 b CHAR(4) { redefines = a };
end
call 文の exampleRecord1 に基づく変数を渡す場合、再定義される領域のデータは CHAR(4) ではなく、INT であったものとして変換されます。a.ab を初期化 (例えば set empty 文を使用) する場合、再定義される領域のデータはブランクではなく、2 進ゼロに設定されます。
再定義を行うフィールドは、子フィールドや再定義を無視して、再定義されるフィールドのすぐ後ろになければなりません。次の 2 つの例は、両方とも有効です。
Record exampleRecord2
10 a int;
20 x int;
10 b char(4) { redefines = a };
20 z char(4);
10 c char(4) { redefines = a };
end
配列として定義されたフィールドは再定義されない場合があります。親の 1 つが配列であるためにフィールドが配列である場合は、再定義されることがあります。
Record exampleRecord3
10 a int[2];
10 b char(2) { redefines = a }; // a が配列であるため正しくありません
end
Record exampleRecord4
10 a bigint;
10 b char(1)[8] { redefines = a }; // これは有効です
end
Record exampleRecord5
10 top char(4)[3];
20 a int;
20 b smallint { redefines = a }; // a は配列ですが有効です
end
Record exampleRecord6
10 top char(12)[5];
20 middle char(4)[3];
30 a int;
30 b smallint { redefines = a }; // a は配列ですが有効です
end
次に詳細な例を示します。ここでは、フィールドの再定義を使用することによって、米国の日付 (月が最初) をヨーロッパの日付 (日が最初) に正規化します。
RecC レコード定義で、usBillingDate と euroBillingDate が、billingDate の下でインデントされますが、3 つとも同じレベル番号 (10) になっています。インデントは、同じレベル番号でありながら、3 つのフィールドすべてが同じスペースを占めることを示すビジュアル・キューです。
再定義するフィールドは、常に再定義されるフィールドを上書きします。
package com.companyb.customer;
Record RecC type basicRecord
10 dateFormat SMALLINT;
10 billingDate CHAR(8);
10 usBillingDate CHAR(8) {redefines=billingDate};
20 month CHAR(2);
20 day CHAR(2);
20 year CHAR(4);
10 euroBillingDate CHAR(8) {redefines=billingDate};
20 day CHAR(2);
20 month CHAR(2);
20 year CHAR(4);
10 deliveryDate CHAR(8);
10 usDeliveryDate CHAR(8) {redefines=deliveryDate};
20 month CHAR(2);
20 day CHAR(2);
20 year CHAR(4);
10 euroDeliveryDate CHAR(8) {redefines=deliveryDate};
20 day CHAR(2);
20 month CHAR(2);
20 year CHAR(4);
End
program RedefinesExample type BasicProgram (
inDateFormat SMALLINT,
inDeliveryMonth CHAR(2),
inDeliveryDay CHAR(2),
inDeliveryYear CHAR(4),
inBillingMonth CHAR(2),
inBillingDay CHAR(2),
inBillingYear CHAR(4))
{alias="REDXMP3"}
// aRec は、構造化レコードです。ここで billingDate と deliveryDate 項目
// が、副構造で、他の 2 つの項目によってそれぞれが再定義されており、
// それらのレベルは同じで、同じ親です。
aRec RecC;
const USDateFormat SMALLINT=1;
const EURODateFormat SMALLINT=2;
function main()
aRec.dateFormat = inDateFormat;
// 日付が米国形式になる場合
if ( inDateFormat == USDateFormat )
usBillingDate.month = inBillingMonth;
usBillingDate.day = inBillingDay;
usBillingDate.year = inBillingYear;
usDeliveryDate.month = inDeliveryMonth;
usDeliveryDate.day = inDeliveryDay;
usDeliveryDate.year = inDeliveryYear;
else // 日付はヨーロッパ形式です
euroBillingDate.month = inBillingMonth;
euroBillingDate.day = inBillingDay;
euroBillingDate.year = inBillingYear;
euroDeliveryDate.month = inDeliveryMonth;
euroDeliveryDate.day = inDeliveryDay;
euroDeliveryDate.year = inDeliveryYear;
end
end
end