Cobol 使用不同的编译器会产生不同的结果

Cobol 使用不同的编译器会产生不同的结果,cobol,zos,microfocus,Cobol,Zos,Microfocus,我正在尝试使用DISPLAY输出以下行,并在Visual Studio中的Micro Focus COBOL和TutorialPoint COBOL编译器中获得正确的结果,但在使用IBM的Enterprise COBOL在z/OS大型机上运行时出现了一些奇怪的情况: 01 W05-OUTPUT-ROW. 05 W05-OFFICE-NAME PIC X(13). 05 W05-BENEFIT-ROW OCCURS 5 TIMES. 10 PIC X(2) VALUE S

我正在尝试使用DISPLAY输出以下行,并在Visual Studio中的Micro Focus COBOL和TutorialPoint COBOL编译器中获得正确的结果,但在使用IBM的Enterprise COBOL在z/OS大型机上运行时出现了一些奇怪的情况:

01 W05-OUTPUT-ROW.
   05 W05-OFFICE-NAME PIC X(13).
   05 W05-BENEFIT-ROW OCCURS 5 TIMES.
       10 PIC X(2) VALUE SPACES.
       10 W05-B-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
   05 PIC X(2) VALUE SPACES.
   05 W05-OFFICE-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
在Enterprise COBOL中,空格似乎被忽略,并添加了一个额外的零填充列,尽管两个版本中的执行代码和显示代码完全相同:

PERFORM VARYING W02-O-IDX FROM 1 BY 1
   UNTIL W02-O-IDX > W12-OFFICE-COUNT

   MOVE W02-OFFICE-NAME(W02-O-IDX) TO W05-OFFICE-NAME

   PERFORM 310-CALC-TOTALS VARYING W02-B-IDX FROM 1 BY 1
       UNTIL W02-B-IDX > W13-BENEFIT-COUNT

   MOVE W02-O-TOTAL(W02-O-IDX) TO W05-OFFICE-TOTAL
   DISPLAY W05-OUTPUT-ROW
END-PERFORM
W13-BENEFIT-COUNT是5,并且在程序中从不更改,所以第6列对我来说是个谜

正确输出:

奇怪的输出:

编辑:根据要求,这里是W02-OFFICE-TABLE:

01 W02-OFFICE-TABLE.
    05 W02-OFFICE-ROW OCCURS 11 TIMES
    ASCENDING KEY IS W02-OFFICE-NAME
    INDEXED BY W02-O-IDX.
        10 W02-OFFICE-CODE PIC X(6).
        10 W02-OFFICE-NAME PIC X(13).
        10 W02-BENEFIT-ROW OCCURS 5 TIMES
        INDEXED BY W02-B-IDX.
            15 W02-B-CODE PIC 9(1).
            15 W02-B-TOTAL PIC 9(5)V99 VALUE ZERO.
        10 W02-O-TOTAL PIC 9(5)V99 VALUE ZERO.
W12-OFFICE-COUNT始终为11,永不更改:

01 W12-OFFICE-COUNT PIC 99 VALUE 11.

如果将
发生
混合,并将WS重新编码为

01 W05-OUTPUT-ROW.
   05 W05-OFFICE-NAME  PIC X(13).
   05 W05-BENEFITS     PIC X(55) VALUE SPACES.
   05 FILLER REDEFINES W05-BENEFITS.
     07 W05-BENEFIT-ROW OCCURS 5 TIMES.
       10 FILLER       PIC X(02).
       10 W05-B-TOTAL  PIC ZZ,ZZ9.99.
   05 FILLER           PIC X(02) VALUE SPACES.
   05 W05-OFFICE-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
也许这与缺少的字段名有关


啊!!邪恶的
索引
。我会将***-IDX变量都简化为99。

我会非常犹豫是否将
发生
混合,并将WS重新编码为

01 W05-OUTPUT-ROW.
   05 W05-OFFICE-NAME  PIC X(13).
   05 W05-BENEFITS     PIC X(55) VALUE SPACES.
   05 FILLER REDEFINES W05-BENEFITS.
     07 W05-BENEFIT-ROW OCCURS 5 TIMES.
       10 FILLER       PIC X(02).
       10 W05-B-TOTAL  PIC ZZ,ZZ9.99.
   05 FILLER           PIC X(02) VALUE SPACES.
   05 W05-OFFICE-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
也许这与缺少的字段名有关


啊!!邪恶的
索引
。我想把***-IDX变量都简化为99s。

问题不在于“为什么企业COBOL会这样做?”,因为它是有文档记录的,而在于“为什么其他两个编译器会生成我想要的程序?”,这可能也是有文档记录的

这里引用了2014年COBOL标准草案(实际标准需要花费金钱):

C.3.4.1使用索引名进行订阅

为了方便查找表和 通过操纵特定项目,可以使用一种称为索引的技术。 为了使用这种技术,程序员分配一个或多个索引名 指向其数据描述条目包含OCCURS子句的项。一 与索引名关联的索引充当下标,其值 对应于所选项目的事件编号 索引名是关联的

按短语编制索引,通过该短语标识索引名,并 与表关联的是OCCURS子句的可选部分。 没有单独的条目来描述与关联的索引 索引名称,因为其定义完全面向硬件。在 运行时索引的内容对应于一个事件编号 用于创建索引的表的特定维度 相关;然而,通信方式取决于 实施者。运行时索引的初始值未定义, 索引应在使用前初始化。初始值 索引与带有不同短语的PERFORM语句一起分配, 包含ALL短语的搜索语句或SET语句

[……]

索引名只能用于引用它所指向的表 通过“按词组索引”关联

从第二段可以清楚地看出,如何实现索引取决于编译器的实现者。这意味着,只要结果相同,索引实际包含的内容和内部操作方式可能会因编译器而异

引用的最后一段指出,根据标准,特定索引只能用于定义该特定索引的表格

310-CALC-TOTALS
中,您有一些代码与此等效:使用表中的索引获取源数据项,并使用“错误”表中的该索引将从该索引派生的值存储到另一个表中

这打破了“索引名只能用于引用通过“索引依据”短语与之关联的表”

因此,您将310-CALC-TOTALS中的代码更改为:使用表中的索引获取源数据项,并使用目标表中定义的数据名或索引将从该数据项派生的值存储到另一个表中

因此,您的代码现在可以工作了,并且每个编译器都会给您相同的结果

如果标准(之前的标准也是如此)禁止使用,为什么要编译企业COBOL代码

IBM有一个语言扩展。事实上,两个扩展适用于您的案例(引自附录A中的企业COBOL语言参考):

索引和订阅。。。引用具有索引名的表 为不同的表定义

发生。。。当没有索引时,通过索引引用表 短语是指定的

因此,您不会得到编译错误,因为使用来自不同表的索引和在表上未定义索引时使用索引都是可以的

那么,当你使用另一个索引时,它会做什么呢?同样来自语言参考,这次是关于使用索引名订阅(索引)

索引名可用于引用任何表。然而,元素 被引用的表的长度以及 与关联的索引名称应匹配。否则,参考 将不会添加到每个表中的同一个表元素,您可能会 运行时错误

这正是发生在你身上的事。发生中项目长度的差异取决于图片中显示的表格的“插入编辑”符号。如果两个表中的项目长度相同,您就不会注意到问题

您为表项提供了一个VALUE子句(不必要,因为您总是在输出之前在表项中放入一些内容),这就留下了“第六”列,前面的五列被写为较短的项。请注意,当对一个长度进行编辑并使用不同的隐式长度进行存储时,会造成混乱,甚至会覆盖第二个小数位

IBM的索引实现方式是