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
このループ内で、関数は以下のアクションを実行します。
  1. 入力レコードの最初のフィールドで、残りのデータの構造を識別するコードを確認する。
  2. その入力レコードまたは 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 レコード定義で、usBillingDateeuroBillingDate が、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

フィードバック