通过变化执行:确切的行为?

PERFORM THRU VARYING : exact behavior?

我试图了解 COBOL 程序的行为,但我遇到了以下几行:

PERFORM  525-NUMERIC    THRU  525-EXIT                       
    VARYING K FROM 1  BY 1   UNTIL  K > CAR-L.         

我理解它是某种基于 K 值的循环的全局概念,但我无法理解 THRU 525-EXIT 单词的影响?

PERFORM 可以连续执行一系列段落或SECTIONS。这是通过使用 THRU/THROUGH 命名系列的最后一个 paragraph/SECTION 来完成的,PERFORM 已经命名了起点。

段落的简单 PERFORM:

       PERFORM                      10-OPEN-INPUT-FILES

这为从 10-OPEN-INPUT-FILES 开始并以该段的最后一条语句结束的 PERFORM 建立了一个 "range"。

多个段落的PERFORM,一个接一个:

       PERFORM                      10-OPEN-INPUT-FILES
         THRU                       10-OPEN-INPUT-FILES-EXIT

这为 PERFORM 建立了更宽的范围,从 10-OPEN-INPUT-FILES 开始到 10-OPEN-INPUT-FILES-EXIT 的最后一条语句结束。

这并不是一件好事或有用的东西,但它以特定的方式被广泛使用,这也许就是你所拥有的。这是为了让 "exit paragraph" 与执行的每个段落相关联。一个原始段落,后跟一个与该原始段落相关联的唯一退出段落(通过第二段的位置,没有别的)。

这从来都不是必需的,没有它们程序也能正常工作。然而,由于有一个 "exit-paragraph" 当然现在有一个标签可以作为 GO TO 的目标。编写一些愚蠢的代码,或者遇到一些已经用这种方式编写的代码,然后插入一个 GO TO 来让你(但也许不是下一个人)摆脱困境。 这不是一件好事,尽管它通常会被视为"expedient"。下一次在相同的代码中将采取权宜之计,下一次,然后应该总是简单的东西变得......复杂。

令人惊讶的是(我认为,对于许多人来说这是正常做法),不少网站在其本地标准中规定每个 PERFORMed 段落和 PERFORM ... THRU ...必须打码

除了邀请使用 GO TO 自找麻烦外,另一个问题是 代码的物理位置现在是相关的。如果你在 exit-paragraph 之前放置一个新段落,那么它就会成为 PERFORM 范围的一部分,无论是否有意。有些人甚至打算将几个段落编码到 PERFORM 的范围内,并使用方便的 GO TO 作为他们的 "get out of mess" 工具。

另一个问题是,当您遇到 PERFORM ... with THRU ... 您不知道 PERFORM 中包含多少段落(或 SECTIONS)无需查看段落(或章节)本身。

您还可以执行一个部分。这是一个过程标签,后跟单词 SECTION 并以 full-stop/period.

结束

SECTION 可以包含段落。当你 PERFORM 一个 SECTION 时,SECTION 中的所有段落都在 PERFORM 范围内,直到该 SECTION 的最后一个语句。它就像一个 PERFORM ... THRU ... 没有 THRU ... 位。它具有与 PERFORM ... THRU ... 相同的问题,另外还有一个问题,即如果将唯一段落用作 GO TO 的目标,则在复制 SECTION 以创建新段落时必须格外小心。 GO TO 跳出一个 SECTION(或段落)是完全合法的,但这通常是无意的,并且会导致混乱,因为程序控制在其他地方徘徊。如果使用 GO TO 跳转至 SECTION 中的退出段落,最好的做法是 对退出段落使用相同的名称。 SECTION 中的任何 GO TO 将由编译器自动 "qualified" 到该 SECTION 中的段落(如果 SECTION 中引用了非唯一的段落名称,但 SECTION 本身没有该名称的段落,则编译器会发现错误)。

使用您的代码,找到正在执行的段落,然后按顺序搜索在 THRU 上命名的段落。它可能只是一个愚蠢的退出(一个只有 EXIT 语句和 full-stop/period 的段落)。如果你运气不好的话,这两段之间可能还有其他段落。任何此类段落都包含在 PERFOR 的范围内,而无需在 PERFORM 语句 中明确说明。

值得注意的是,EXIT 语句本身什么都不做。它是 "No Operation" 或 NOP(或 NOOP)。在 PERFORMed 段落的末尾,将生成一些指令来执行退出处理,这是自动的,并且不(而且从来没有)依赖于 EXIT 语句的存在。

在 1985 年标准之前,EXIT 必须单独编码在一个段落中。这已不再是这种情况。您可以用 EXIT 语句(例如 20)填充一个段落,然后用一个 DISPLAY 结束该段落。执行段落,您将看到 DISPLAY 输出。

没有 THRU 的 PERFORMed 段落不应 包含 GO TO。如果 包含 GO TO,则不是编译错误。这是一场等待发生的事故。

觉得需要使用 GO TO 的人必须使用 PERFORM ... THRU ... 或使用 SECTION 的 PERFORM。不幸的是,即使原始编码器不使用 GO TO,使用 PERFORM ... THRU ... 或 PERFORM 的 SECTION 确实让将来的人很容易使用 GO TO。如果某个地方有一个 GO TO 可以去,那么 GO TO 很可能会在某个时候出现。如果没有现有的 GO TO 目标,则下一个编码员将不得不进行其他更改,从而无法使用 GO TO。

在目前的标准中,从2014年开始,有一些新版本的EXIT。 (EXIT 的 EXIT PROGRAM 版本已经存在很长时间了,尽管最近受 IBM 启发的 GOBACK 更可能用于 return 调用程序)。

新的可能性包括 EXIT PARAGRAPHEXIT SECTION。检查您的编译器的文档以查看可用的 EXIT 变体。 EXIT 的所有变体都生成可执行代码,只是普通的 EXIT 不会。

如果您的编译器确实允许 EXIT PARAGRAPH 和 EXIT SECTION,这意味着您不再需要标签来允许使用(现在 "secret")GO TO,它只是不会被称为 GO TO,它将被称为 EXIT somevariant。请记住,所有这些(EXIT PROGRAM 除外)都是经过伪装的 GO TO,并且代码总是可以重新排列(并且经常被简化)以避免 GO TO 的需要。

构建 no-GO TO 代码确实需要经验,所以暂时不要太在意。如果您的站点使用 GO TO(通过使用 THRU 暗示),那么了解使用 GO TO 的后果将非常重要,因为现有代码将使用它。

然后从小处着手,避免 GO TO 自己,随着您熟悉这样做的技巧,扩大您的努力范围。请记住,目的是简化代码,或者至少不要让它变得更糟,而不仅仅是不要死记硬背地编写 GO TO 代码。如果您只是为了避免 GO TO 而使代码复杂化,请使用 GO TO 直到您知道如何做得更好。

许多优秀且经验丰富的 COBOL 程序员使用 GO TO 编写易于理解的程序。不幸的是,大多数程序员都不是 "good and experienced",所以很乐意使用 GO TO 将某些东西短路并继续前进。

PERFORM 上的 VARYING 是一种重复执行的方法,具有起点、增量和终止条件。这个不管THRU有没有编码都是一样的。


可以在此处找到有关超出 PERFORM 范围的错误 GO TO 可能发生的情况的示例:https://codegolf.stackexchange.com/a/20889/16411。这是用 SECTION 编码的,但同样可以用 PERFORM ... TRHU ...


结合 Bruce Martin 的回答阅读这篇文章非常好。

继 Bill 的回答之后,我将尝试添加一个更直观的答案。

         Perform Proc-A thru Proc-D.
         ...

     Proc-A. 
        ....

     Proc-B.
        ....

     Proc-C.
        ....

     Proc-D.
        ....

在上面,Perform Proc-A thru Proc-D 执行过程的Proc-A, Proc-B, Proc-CProc-D。 shorthand

     Perform Proc-A
     Perform Proc-B
     Perform Proc-C
     Perform Proc-D

Perform Thru 语法有几个问题:

  • 并不总是清楚正在执行的是什么。

     Perform B100-Load-From-DB thru B500-Save-To-Db
    

    我想下面的内容告诉你更多

     Perform B100-Load-From-DB
     Perform B200-Adjust-Stock-for-Purchases
     Perform B300-Adjust-Stock-for-Sales
     Perform B400-Calculate-Markdowns
     Perform B500-Save-To-Db
    
  • 很容易引入问题,即如果你在错误的位置添加了一个过程,你将在不知不觉中引入代码

     Proc-B.
        ....
    
     Proc-in-wrong-position.
        ....
    
     Proc-C.
        ....
    

像上面这样的错误很容易犯但很难发现

这是 Cobol 的一项功能,在当时看来是个好主意;但应该避免 !!!

阐述 Bill 和 Bruce 的出色回答。

从 Bruce 示例中的代码开始。

    Perform B100-Load-From-DB thru B500-Save-To-Db
...
B100-Load-From-DB
...
B200-Adjust-Stock-for-Purchases
...
B300-Adjust-Stock-for-Sales
...
Some-Danged-Ol-Thing
...
B400-Calculate-Markdowns
...
B500-Save-To-Db

这看起来还是相当简单的。每个段落中的代码将按自上而下的顺序处理:B100-Load-From-DB、B200-Adjust-Stock-for-Purchases、B300-Adjust-Stock-for-Sales、Some-Danged-Ol-Thing、B400-计算降价,B500-Save-To-Db

正如 Bill 所指出的,将 GO TO 语句添加到 PERFORM ... THRU 块会将所述代码的作者引入地狱第九圈的特殊象限。

    Perform B100-Load-From-DB thru B500-Save-To-Db
...
B100-Load-From-DB
...
    GO TO B400-Calculate-Markdowns
...
B200-Adjust-Stock-for-Purchases
...
B300-Adjust-Stock-for-Sales
...
    GO TO B200-Adjust-Stock-for-Purchases
...
Some-Danged-Ol-Thing
...
B400-Calculate-Markdowns
...
B500-Save-To-Db

当有人决定 运行 部分 PERFORM ... THRU 块时,更多 "clever thinking" 会加剧地狱。

    Perform B200-Adjust-Stock-for-Purchases thru B300-Adjust-Stock-for-Sales
...
    Perform B100-Load-From-DB thru B200-Adjust-Stock-for-Purchases
...
    Perform B100-Load-From-DB thru Some-Danged-Ol-Thing

有无数机会从窥镜中掉落并继续进入几个替代现实。我不只是在谈论理论上的可能性。我说的是我多年来在代码方面的实际经验。

在我成长的过程中,呃,我的意思是学习使用 COBOL 编写代码,我几乎被威胁说如果我越界就会被一个拿着藤条的大个子殴打。因此,我知道如何走在悬崖的边缘,并使用 PERFORM ... THRU 和 GO TO 穿插在整个过程中,而不是从世界的边缘掉下来。然而,它会产生非常危险的代码,可以杀死,所以更重要的是我知道如何去除这样的代码并将其变成文明的东西。