参考其他结构的共同结构

时间:2012-04-02 13:48:06

标签: cobol

我需要定义copybook,描述我的文件格式。在我的文件中,有不同格式的行,但所有行的第一部分是相同的。如何只定义一次公共结构并从其他结构中引用它? 我需要这样的东西:

01 Header.
  02 Id PIC X(2).
  02 Name PIC X(10).
01 LineA.
  02 Header.  "how can I reference the above Header, to not define it in every LineA, Line B?**
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.
01 LineA.
  02 Header.
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.
  ...

感谢。

2 个答案:

答案 0 :(得分:3)

我想你可能正在寻找COBOL REDEFINE。这允许相同的数据结构 有不同的内部结构,您可以在运行时选择。

例如:

  01 TRANSACTION.
     05 TRANS-SQNBR              PIC 9(5).
     05 TRANS-TIMESTAMP          PIC X(26).
     05 TRANS-TYPE               PIC X(2).
        88 TRANS-PO              VALUE '01'.
        88 TRANS-MO              VALUE '02'.
     05 TRANS-DATA.
        10                       PIC X(220).
     05 PO-TRANS REDEFINES TRANS-DATA.
        10 PURCHASE-ORDER-ID     PIC X(10).
        10 CLIENT-ID             PIC X(7).
        10 SHIP-BY-DATE          PIC X(10).
        10 CLIENT-REF-ID         PIC X(30).
        10 .... more Purchase Order data
     05 MO-TRANS REDEFINES TRANS-DATA.
        10 CLIENT-NAME           PIC X(45).
        10 SHIP-ADDRESS-1        PIC X(40).
        10 SHIP-ADDRESS-2        PIC X(40).
        10 SHIP-CITY             PIC X(30).
        10 SHIP-POST-CODE        PIC X(6).
        10 .... More Mail Order Data  

上述记录布局描述了某种交易。前几个字段很常见 到所有类型的事务(TRANS-SQNBR,TRANS-TIMESTAMP和TRANS-TYPE)。 TRANS-TYPE 具有相关联的88级别,用于确定记录的其余部分 解释。当TRANS-TYPE的值为'01'(TRANS-PO为真)时,PO-TRANS的记录布局 将描述记录的其余部分。当TRANS-TYPE为'02'(TRANS-MO为真)时,MO-TRANS记录布局 应该使用。

TRANS-DATA,PO-TRANS和MO-TRANS记录布局是相互排斥的,因为它们 都将占据相同的物理记忆。也就是说,上面的总记录长度 示例是公共数据项长度(5 + 26 + 2 = 33)加上长度的总和 TARNS-DATA(220,受后续REDEFINES影响的数据项)。这给出了总记录 长度为33 + 220 = 253. REDEFINEING TRANS-DATA的记录长度不能 超过TRANS-DATA的长度(它们可能更短,但不会更长)。

请注意,TRANS-DATA有一个未命名的从属级别10。有时这被命名为FILLER,但是 不需要给出一个名字。这个项目的目的是定义的长度 备用记录定义中的最长区域。基本上它只是一个假的占位符。

PO-TRANS重新定义分配用于保存TRANS-DATA的内存,完全给出它 不同的解释。同样,MO-TRANS重新定义了TRANS-DATA。

TRANS-TYPE下的88级别名称并不是真正需要,而是提供文档和 一组定义的值,用于在备选记录布局中进行选择。

要使用此记录布局,您可以填充它(可能通过READ语句)。 TRANS-SQNBR,TRANS-TIMESTAMP和TRANS-TYPE将直接提供 名。为了解释记录的其余部分,您需要测试TRANS-TYPE和 然后根据需要使用其他数据名称。例如:

 EVALUATE TRUE
    WHEN TRANS-PO
       MOVE PURCHASE-ORDER-ID TO whatever...
       ...
    WHEN TRANS-MO
       MOVE CLIENT-NAME TO whatever...
    WHEN OTHER
       PERFORM UNKNOWN-RECORD-TYPE-ERROR
 END-EVALUATE 

当使用如上所示的多个记录布局时,总是一个好主意 如果输入错误,则会出现错误catch-all,因此上面显示的是UNKNOWN-RECORD-TYPE-ERROR。

对评论的回应

您问题中的记录结构有点问题,因为02 Header.没有PICTURE子句或从属数据项 所以不是有效的声明。 如果你喜欢:

01 Generic-Header.
  02 Id PIC X(2).
  02 Name PIC X(10).
01 LineA.
  02 Header     PIC X(12).
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.
01 LineB.
  02 Header     PIC X(12).
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.

您可以执行以下操作:

MOVE Header OF LineA to Generic-Header

现在,您可以从Generic-Header中引用IdName。但是你只有一个 Generic-Header记录,如果您需要同时使用LineALineB Generic-Header可以同时拥有一个或另一个但不能同时拥有两个!如在

MOVE Header of LineA to Generic-Header
IF Id = Current-Id  <== This is the Id from LineA
   work with LineA
END-IF

MOVE Header of LineB to Generic-Header
IF Id = Current-Id  <== This is the Id from LineB
   work with LineB
END-IF

以上情况很好,但如果您需要将LineA的Id与LineB的Id进行比较,会发生什么。只有一个 Generic-Header的单个实例,所以这有点问题。

我不是说这是一个糟糕的方法,但要注意可能的限制。

对第二条评论的回应

也许您正在寻找COPY

公共代码可能会放入另一个源文件,我们称之为GENHDR。 GENHDR的内容可能看起来像 类似的东西:

  02 Id PIC X(2).
  02 Name PIC X(10).

你的主程序将在一个单独的文件中,我们称之为MYPROG。该文件的一部分看起来 类似的东西:

01 LineA.
  COPY GENHDR.
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.
01 LineB.
  COPY GENHDR.
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.

编译MYPROG时,会在找到COPY指令的地方插入GENHDR的副本。编译 列表看起来像:

01 LineA.
  02 Id PIC X(2).
  02 Name PIC X(10).
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.
01 LineB.
  02 Id PIC X(2).
  02 Name PIC X(10).
  02 SomeField1 PIC X.
  02 SomeField2 PIC X.

在程序的其余部分中,您可以将各个字段引用为:

LineA的Id,LineA的SomField1,LineB的Id等。

答案 1 :(得分:2)

您可以使用IN关键字(或其同义词OF)来引用具有相同名称的不同结构的结构成员。

    05  FORMAT-CODE           PIC X(1).
        88  FORMAT-IS-CUSTOMER    VALUE "C".
        88  FORMAT-IS-EMPLOYEE    VALUE "E".
    05  CUSTOMER-LAYOUT.
        07  FIRST-NAME        PIC X(10).
        07  STREET-ADDRESS    PIC X(30).
        07  CUSTOMER-ID       PIC X(7).
* * * 
    05  EMPLOYEE-LAYOUT       REDEFINES CUSTOMER-LAYOUT.
        07  FIRST-NAME        PIC X(10).
        07  STREET-ADDRESS    PIC X(30).
        07  EMPLOYEE-ID       PIC 9(5).
* * *
IF FORMAT-IS-CUSTOMER
    MOVE INPUT-FIRST-NAME TO FIRST-NAME IN CUSTOMER-LAYOUT
* * *

COBOL术语是“资格”。

在上面的片段中,您可以将FIRST-NAME和STREET-ADDRESS定义放在复制套件中,并将其复制两次到您的程序中。

您还可以使用COPY语句的REPLACING短语为成员生成唯一的名称。 (但我没有经常使用过这种语言功能。)

如果您对此主题的兴趣只是好奇心,那么无论哪种方式都适合您。但是,如果您正在编写生产代码,那么您的经理和编码标准将决定如何处理此问题并建立命名标准。请记住,许多COBOL商店依赖于数据字典工具或与DBMS集成来生成源代码记录布局,因此您根本不必编写自己的DATA DIVISION代码。

通过您的跟进提示,我记得以下方法更像我以前的方式。利用REDEFINES和FILLER:

01  ALL-LAYOUTS.
    03  COMMON-LAYOUT.
        05  HEADER.
            07  ID                   PIC X(02).
            07  NAME                 PIC X(10).
            07  FORMAT-CODE          PIC X(1).
                88  FORMAT-IS-A          VALUE "A".
                88  FORMAT-IS-B          VALUE "B".
        05      FILLER               PIC X(67).
    03  LINE-A-LAYOUT                REDEFINES COMMON-LAYOUT.
        05      FILLER               PIC X(13).
        05  LINE-A-SOME-FIELD-1      PIC X(01).
        05  LINE-A-SOME-FIELD-2      PIC X(01).
        05      FILLER               PIC X(66).
    03  LINE-B-LAYOUT                REDEFINES COMMON-LAYOUT.
        05      FILLER               PIC X(13).
        05  LINE-B-SOMETHING-ELSE    PIC X(40).
        05      FILLER               PIC X(27).

* * *

    MOVE "A" TO FORMAT-CODE
    MOVE INPUT-ID TO ID
    MOVE INPUT-NAME TO NAME
    MOVE INPUT-SOME-FIELD-1 TO LINE-A-SOME-FIELD-1
    MOVE INPUT-SOME-FIELD-2 TO LINE-A-SOME-FIELD-2

您需要某种记录类型指示符(FORMAT-CODE),这样当您从存储中读回记录时,您将知道哪种格式适用。