如何获取当前段落名称?

How to get the current paragraph name?

我想知道如何在 COBOL 中获取当前段落名称(这里使用 MVS Enterprise COBOL V4.2)。

假设我在 PROCEDURE DIVISION 中有这段代码:

   MAIN-LOGIC.
       MOVE SPACE TO ABT-MSG
       PERFORM PARAGRAPH-1
       PERFORM PARAGRAPH-2
       GO TO CLOSE-PROGRAM.
  *
  * SEARCH FOR A VALUE IN AN ARRAY AND GET THE RELATED INDEX
  *
   PARAGRAPH-1.
       MOVE 42 TO SEARCH-VALUE
       PERFORM VARYING I-SEARCH FROM 1 BY 1
           UNTIL SOME-ARRAY(I-SEARCH) = SEARCH-VALUE
         IF (I-SEARCH = MAX-ARRAY-POSITION)
           MOVE SEARCH-ABORT TO ABT-MSG
           MOVE 'PARAGRAPH-1' TO ABT-LOC
           GO TO CLOSE-PROGRAM
         END-IF
       END-PERFORM
       DISPLAY 'VALUE WAS FOUND AT POSITION ' I-SEARCH '.'.
  *
  * STORE A NEW VALUE AT THE END OF AN ARRAY
  *
   PARAGRAPH-2.
       MOVE 42 TO STORAGE-VALUE
       ADD 1 TO I-STORAGE
       IF (I-STORAGE > MAX-ARRAY-POSITION)
         MOVE STORAGE-ABORT TO ABT-MSG
         MOVE 'PARAGRAPH-2' TO ABT-LOC
         GO TO CLOSE-PROGRAM
       END-IF
       MOVE STORAGE-VALUE TO SOME-ARRAY(I-STORAGE).
  *
  * CLOSE THE PROGRAM
  *
   CLOSE-PROGRAM.
       IF ABT-MSG > SPACE
         DISPLAY ABT-MSG
         DISPLAY '(FOUND IN ' ABT-LOC ')'
         MOVE 20 TO RETURN-CODE
       ELSE
         DISPLAY SUCCESS-MESSAGE
       END-IF
       STOP RUN.

我希望能够访问当前段落名称(并将其存储在 ABT-LOC 中)而不必编写它。 是否有 COBOL 系统变量可以执行此操作,例如 'CURR-PARA-NAME' 或其他?

谢谢。

------ 更新 1 ------

我更新了我的代码示例以使其更具体。 知道,在我真正的 COBOL 程序中,有各种 SEARCH-ABORT 和 STORAGE-ABORT 的可能性(我正在处理许多数组)。

我想让我的代码尽可能好,因此我愿意访问当前段落名称而不是必须编写它。

再次感谢。

-------- 更新 2 ------

那好吧。看来我做不到(我的程序的用户可能会拒绝他们不习惯获得的任何调试消息 - 供您参考,我正在重写一个 50 年前的程序,其中包含非常非常糟糕的编程实践,例如向上 GO TO, fall-through 逻辑和 godforsaken ALTER,我想在最后得到相同的输出。

放心,今晚我不会哭的。这只是对我的代码的美学改进,没有它我也可以生活(我的代码已经比我自己基于的代码漂亮很多)。

感谢大家的宝贵时间,祝你们一切顺利... Stack Overday!

因为你有伪代码 "something bad happened here" 我假设有一个例外。在这种情况下,标准(COBOL 2002、COBOL 2014)函数 EXCEPTION-LOCATION 可能会有所帮助(尽管实际字符串是实现者定义的,但我认为该段落可能在其中 [例如 GnuCOBOL 的格式为:program-id; paragraph [或部分或部分的段落,取决于您的程序];源代码行])。

如果您的 COBOL 编译器在此函数中提供此信息,并且违规部分已经没有异常:通过 subtract 1 from unsigned-var 或类似方式创建一个。

正如 Bill 已经说过(或暗示)的那样:这是一个问题,如果您必须将名称作为标识符和标签,那么实际使用的 COBOL 编译器将是最重要的部分。

编辑(实际COBOL编译器知道后):

IBM MVS Enterprise COBOL 没有 EXCEPTION-LOCATION 函数。因此我只看到一个内置解决方案:

DECLARATIVES.
debug-declaratives SECTION.
   USE FOR DEBUGGING ON ALL PROCEDURES.
debug-par.
    MOVE debug-name  TO current-procedure.
END DECLARATIVES.

但是因为这只有在你的程序 运行 处于调试模式时才有效(这可能会导致出现很多调试消息)我不建议实际使用它.

尝试使用提供宏的编辑器(或 运行 实际源上的 shell 脚本)来创建随后传递给编译器的源。

正如 Simon Sobisch 在他的回答中正确指出的那样,完全按照您的意愿行事的唯一方法是使用 "debugging declaratives"。请参阅后面的答案以了解如何进行这项工作,但没有人会允许您对生产程序执行此操作。

COBOL 是一种编译语言,因此除非编译器提供某些内容,否则不会自动访问任何数据名称或过程名称(段落或部分)。其中,除了上述情况,它没有。

剩下三种方法:手动执行(您正确地希望避免这种情况,就像桃子一样肯定有人会在不更改文字的情况下复制或重新定位代码);预处理(使用程序或编辑器)以使用正确的标签自动填充您的字段;做点别的。

既然你隐含地低估了第一个,我再次相信是正确的,让我们考虑第二个。如果你在同一个paragraph/SECTION中有两个,三个或八个东西都是"business errors"怎么办(虽然通常这些类型的东西更多"integrity errors",这是不应该存在的状态,所以不要继续)?

因为你会得到这些,"pre-processing" 解决方案开始变得更难看。

还能做什么?

好吧,这是我们多年来一直面临的问题。答案是唯一的(在程序内)错误号。各个错误都可以命名,嗯,并给一个数字。命名错误参考很难使用 "incorrectly"。添加新错误时,很难复制现有数字。或者,换句话说,它很容易复制,但在测试中却非常容易被发现 - "hey, that's produced 1234, that's wrong".

它绝不是万无一失的,但数据名称(和任何相关的文本)比段落名称(除非人为地,否则不会是什么的任何指示)更能说明问题错误是,只是它的位置)。在程序中很容易找到错误引用,并且很容易找到过程名称,除非您实际上不再需要它。

错误编号的程序是否超过手动维护的 MOVE 'literal' TO 一些标准名称程序的渣滓未知。但是你可以猜到我喜欢和推荐哪一个。

现在,如何使用 DECLARATIVES 为企业 COBOL 做到这一点。

   IDENTIFICATION DIVISION. 
   PROGRAM-ID. STAB39. 
   ENVIRONMENT DIVISION. 
   CONFIGURATION SECTION. 
   SOURCE-COMPUTER. FRED DEBUGGING MODE. 

   DATA DIVISION. 
   WORKING-STORAGE SECTION. 
   01  W-WHEN-COMPILED                     PIC X(8)BX(8).
   01  ABT-LOC                             PIC X(30). 


   PROCEDURE DIVISION. 
  DDECLARATIVES. 
  DSOME-SECTION SECTION. 
  D    USE FOR DEBUGGING ON ALL PROCEDURES 
  D    . 
  DSOME-PARA. 
  D    MOVE DEBUG-NAME TO ABT-LOC 
  D    . 
  DEND DECLARATIVES. 
   STARTING-UP SECTION. 
       DISPLAY 
               ABT-LOC 
  D    DISPLAY 
  D            "IT IS STARTING UP" 
       MOVE WHEN-COMPILED           TO W-WHEN-COMPILED 
       DISPLAY 
               "STAB39 " 
               W-WHEN-COMPILED 
       . 
   A-PARA. 
       DISPLAY 
               ABT-LOC 
       PERFORM 
         10 TIMES 
  D        DISPLAY 
                   "ITERATING" 
       END-PERFORM 
       . 
   ANOTHER-PARA. 
       DISPLAY 
               ABT-LOC 
       PERFORM                      THE-PARA 
                                     10 TIMES 
       PERFORM                      THE-SECOND-PARA 
       GOBACK 
       . 
   THE-PARA. 
       DISPLAY 
               ABT-LOC 
       . 
   THE-SECOND-PARA. 
       DISPLAY 
               ABT-LOC
       . 

一些注意事项:

要使用 COBOL 的内置调试功能,需要 SOURCE-COMPUTER 段落才能打开它们。因此,还需要 ENVIRONMENT DIVISION 和 CONFIGURATION SECTION。 "computer name",示例中的 FRED 是必需的,但它是无关紧要的。如果你愿意,你可以 "name" 你的电脑跟在你最喜欢的宠物或亲戚之后,或者把任何东西放在那里,必须有东西。

DECLARATIVES 只能在 PROCEDURE DIVISION 的开头指定。它们必须在一个 SECTION 中,并且所有操作都必须在属于一个 SECTION 的段落中。 SECTION 和段落的名称无关紧要,但无论如何都使它们有意义。

因为 DECLARATIVES 必须包含一个 SECTION,如果您的第一个程序标签不是一个 SECTION,您将收到一条信息性诊断消息。这不需要在您的程序中的段落上使用 SECTIONS,它没有进一步的影响。

第 7 列中的 D 表示 "debugging line"。这些行仅在您使用 SOURCE-COMPUTER 段落打开调试时生成代码。

该程序练习段落的所有用法(对于此示例,SECTION 的用法没有什么不同)除了 GO TO。转到的段落将产生与任何其他参考相同的结果,但您不会在我的程序中看到转到:-)

可以使用 DECLARATIVES 来命名您想要 "trap" 的过程,而不是使用 "ALL PROCEDURES"。

您可能有多个 DEBUGGING 过程,如果您愿意,可以在其中包含大量代码(例如,设置测试条件)。

虽然此功能在 COBOL 中存在了很长时间,但可以说它没有被广泛使用,尤其是在特定 "debugging products" 可用时。

仅仅有这个程序是不够的,"run time"需要打开DEBUG,如果它不是默认的。 z/OS 上的 运行 时间称为语言环境,由多种语言共享(允许轻松进行语言间交流)。语言包括 C/C++、PL/I 和 Java 以及 COBOL。有语言环境例程和宏可用于制作 HLASM/Assembler 程序 "LE Compliant" 以提供现成的接口。

要查看您的站点默认有哪些 运行 时间选项,最简单的方法是在您的 运行 JCL 中包含 CEEOPTS DD 语句。

//CEEOPTS  DD  *
   RPTOPTS(ON) 

这将列出用于您的 "Enclave"(您的 运行 环境)的所有选项,并指出每个选项的来源。

如果您在 OPTION 列中看到 NODEBUG,则默认情况下 COBOL 调试处于关闭状态。要为特定的 运行 打开它:

//CEEOPTS  DD  *
   DEBUG 

这将允许执行所有 D 标记的调试行和调试声明。

这会做你想做的事,但没有人会允许调试的程序进入生产环境,所以你不能用它做你想做的事。

按照优先顺序,我建议错误编号(和测试)、自动化、手工编码的过程名称文字。

IBM 完整地记录了它的所有产品,您可以找到 Enterprise COBOL V4.2 的文档(语言参考和编程指南等)以及您发布的 z/OS 的语言环境(多个)。

最后一点。不要使用 GO TO 到 "break out" 的正常处理流程。使用执行。即使从逻辑上讲,PERFORM 不能 return。使用 GO TO 将关闭包含 GO TO 的 paragraphs/SECTIONs 的编译器优化,这很容易对执行产生明显影响。这与 IBM COBOL 确保 PERFORMed paragraphs/SECTIONs 的状态不会在 CALL 之间保留之前的建议相反。当时正确的建议是使用 GO TO。这不再是正确的建议。