为什么COBOL同时拥有`SECTION`和`PARAGRAPH`?

24
为什么COBOL中既有SECTION又有PARAGRAPH?
请问为什么COBOL的设计者会同时创建SECTIONS和PARAGRAPHS?它们自COBOL发布以来一直存在,因此我认为它们存在的真正原因早已消失(类似于像NEXT SENTENCE这样的东西,它们仍然在语言规范中用于向后兼容,但自从引入了明确的作用域终止符号后就不再需要了)。
我猜测SECTION可能是为了支持程序覆盖而被引入的。SECTION具有可选的PRIORITY数字与之关联,以标识它所属的程序覆盖。但是,大多数现代的COBOL实现都忽略或已经放弃了PRIORITY数字(和覆盖)。
目前,我发现在PROCEDURE DIVISION的DECLARATIVE部分仍需要使用SECTIONS,但找不到这样做的理由。除了PARAGRAPH是下级的SECTIONS外,我没有看到SECTIONS和PARAGRAPHS之间有任何语义上的区别。
一些COBOL开发团队禁止使用SECTIONS而使用PARAGRAPHS(在北美似乎很常见)。其他人则禁止使用PARAGRAPHS而使用SECTIONS(在欧洲似乎很常见)。还有其他人制定了何时使用每个元素的指南。所有这些对我来说似乎非常随意,这就引出了一个问题:为什么它们最初被放入语言规范中?并且,它们今天是否有任何相关性?
如果您回答这个问题,如果能提供支持您答案的参考资料,那就太好了。
谢谢
9个回答

7

因为这是我从我的店里的老手听到的,所以没有参考资料...

在旧的COBOL编译器中,至少对于IBM和Unisys来说,部分可以逐个加载到内存中。在以前内存不足的好日子里,一个过大无法一次性加载到内存中的程序可以通过使用部分将其模块化以实现内存使用。有了部分和段落,程序员可以决定哪些代码部分应该一起加载到内存中,如果不能一次性加载所有代码 - 你会想要同一执行循环的两个部分一起加载以提高效率。如今这已经不重要了。

我们的商店只使用段落,禁止GOTO并需要退出段落,因此我们所有的PERFORMS都是PERFORM 100-PARAGRAPH THRU 100-EXIT或类似的东西 - 这似乎使段落更像部分。但是我认为现在没有太大的区别。


啊,我看到colemanj和我一样的答案。我只是向下滚动了第一个答案条目。我还不能评论别人的答案,所以我会把这个留下来作为对colemanj所说的稍微扩展的解释。 - Marcus_33
我认为你和colemanj的答案是正确的, 但是你的回答更清晰明了。在小地址空间中,程序分段是管理“大型”程序的“最新技术”。幸运的是,虚拟内存使得这种功能过时了(我经历过编写分段程序的“乐趣”)。现在我只看到可能有一个“命名空间”的用途,以及Declaratives必须引用Sections而不是Paragraphs的未解释要求(正如Tim Sylvester指出的那样)。 - NealB

6

我大约在1978年学习了COBOL,当时是在一台ICL 2903计算机上学习的。我模糊地记得,这些SECTION标头可以被分配一个数字范围,这意味着当程序过大超出内存时,这些SECTION标头可以在内存中进行交换。


1
是的,那些是优先级数字,我敢打赌你一定有很多可怕的故事要讲。如果你让一个独立段(优先级数字>=50)引用另一个独立段,我相信程序会陷入真正的麻烦中。幸运的是,现在这些日子已经基本过去了... - NealB

6
我知道这是一个老问题,但OP要求关于在COBOL中使用SECTION和PARAGRAPH的原始理由的文档。
您可以查看CODASYL杂志的文档,这比“原始”更多。
在该杂志的语言规范的第8节中,"COBOL分段是一种提供通信方式的设施,用户可以通过它来指定目标程序覆盖要求"(第8.1节“分段-概述”,第331页)。
虽然不是必需的,但源程序的Procedure Division通常编写为连续的section组,每个section由一系列密切相关的操作组成,旨在共同执行特定功能。但是,当使用分段时,整个Procedure Division必须位于sections中。此外,每个section必须被归类为属于对象程序的固定部分或独立段之一。分段无论如何都不会影响需要限定过程名称以确保唯一性的需要(第8.1.2.1节“程序段”,第331页)。
在她的比较编程语言的书(“Programming Languages: History and Fundamentals”,1969年)中,Jean Sammet(曾代表Sylvania Electric担任CODASYL委员会成员)表示:“...存储分配由编译器自动处理。分配可执行代码的主要单元是称为段的一组section。程序员通过为每个section的名称指定优先级号码来组合section。编译器必须确保提供正确的控制转移,以便在不同时存储的段之间进行控制转移......”(第369-371页V.3 COBOL)。

2

最简单的原因之一是SECTIONs提供了“模块化”——就像C语言中的函数一样——这在“结构化”程序中是必需的。你会发现使用SECTION编写的代码比仅用段落编写的代码更易读,因为每个SECTION都必须有一个“EXIT”——从SECTION中唯一而明确的退出点(段落的退出点要模糊和隐含得多,即直到找到新的段落声明为止)。考虑下面的示例,你可能会想在你的代码中使用SECTION:

*==================
 MAINLINE SECTION.
*==================
     PERFORM SEC-A
     PERFORM SEC-B
     PERFORM SEC-C
     GOBACK.
*==================
 MAINLINE-EXIT.
*==================
    EXIT.

*==================
 SEC-A SECTION.
*==================

.....
.....
.....
.....

    IF <cond>
       go to A-EXIT
    end-if

..... 
.....
.....
.....

.

*==================
 A-EXIT.
*==================
    EXIT.

在编写代码段落时,不要认为你会得到这种特权。如果某个条件达到时,您可能必须编写一个巨大的ELSE语句来覆盖您不想执行的语句(考虑到这组语句跨越2-3页...再加上一组IF / ELSE将使缩进更加紧凑)。当然,您将不得不使用“GO TO”来实现这一点,但是除了退出时,您可以始终指导您的专业人员不使用GO TOs,这是公平的交易,我认为。

因此,虽然我也同意使用SECTION可以使用少量或不需要调整地使用段落编写的任何内容,但我的个人选择将是选择一种实现,可以使我的开发人员未来的工作更容易!


1
对于有趣的反馈点赞。您描述了一种特定的编码风格,使用SECTION/PARAGRAPH而不是识别导致将SECTION和PARAGRAPH都包含在COBOL语言规范中的语言设计标准。请注意,在您的示例中,如果删除SECTION标题,将它们变成PARAGRAPH,并用PERFORM SEC-A THRU A-EXIT等替换PERFORM SEC-A,则可以使用仅PARAGRAPH的功能等效程序。顺便说一句,在GO TO MAINLINE-EXIT之前放置MAINLINE-EXIT,否则肯定会引起麻烦! - NealB
那些在程序设计中遇到问题时第一反应就是使用“GO TO”的人 :-) 倾向于想象那些不这样做的人必须编写深度嵌套的IF/EVALUATE语句。虽然这种情况确实会发生,但并非必然如此。 - Bill Woodger

2
Cobol是在50年代中期开发的。正如其全名所示,它是为商业编程而开发的,更适合商业目的比现有的“科学”或“技术”语言(当时很少有“语言”,而“机器码”(当然是针对特定的架构(我差点说成了“特定的芯片”,然后想起了真空管)),可能需要在某些机器上通过物理开关/刻度来设置)和如果幸运的话还有一个“汇编器”。Cobol在当时非常先进,适用于其目的。
Cobol的初衷是让使用Cobol编写的程序更像英语而不仅仅是一组对熟悉者有意义的“代码”。
如果您看一下与语言相关的某些命名法,则会发现“段落”、“句子”、“动词”、“从句”等都是有意按照英语语言的模式来命名的。
“SECTION”并不完全符合这个规律,除非你将事物与正式的商业文件联系起来。
“SECTION”和“段落”也出现在“PROCEDURE DIVISION”之外。与书面英语一样,段落可以独立存在,也可以是SECTION的一部分。
“SECTION”可能会有一个与“分段功能”相关的优先级编号。这曾经包括SECTION的“覆盖”,以提供原始的内存管理级别。这是一种“计算功能”,而不是英语语言功能 :-) “分段功能”确实有某种剩余效果,但我从未见过它被真正使用过。
如果不使用DECLARATIVES(我不使用,并且刚刚注意到手册不清楚),那么就可以“选择”使用SECTION或段落来执行PERFORM。
如果使用GO TO,理性地讲,“等价性”可以通过PERFORM ... TRHU ... 来实现。如果没有,而且没有滥用PERFORM ... THRU ...,则已经存在等价性了。
与“结构化”代码和现代语言的比较是“倒推历史”或只是概述特定的“做法”。从“意面条代码”和ALTER ... TO PROCEED TO ...获得的声誉来看,也许20年来PERFORM并没有太多用处,除非你需要“内存管理”,但我没有参考资料或知识来支持这一点。
SECTION允许重复段落名称,否则段落名称必须是唯一的。
我不能总是明确指出哪一个更好。
如果使用GO TO,我会使用SECTION。如果没有,我会使用段落。使用DECLARATIVES时,我会使用SECTION。如果使用SECTION,则我会从SECTION开始PROCEDURE DIVISION,以避免诊断消息。
当地标准可能会规定,但不一定是基于“现代”(甚至“合理”的)基础。在我的经验中,SECTION和段落的很多东西都是“众所周知”,但实际上被误解了。

对于需要处理大量数据的性能问题(我指的是大量数据),使用一个SECTION的PERFORM而不是多个单独的段落会带来改进。使用PERFORM ... THRU ...也会产生同样的效果,但我不建议这样做。 在PERFORM范围之外使用GO TO 1)是不好的2)会损失优化。除非预期没有逻辑返回并且不期望发生异常/异常终止,否则不应该出现问题。如果认为使用这个功能是必要的“立即”操作,那么最好使用PERFORM,即使它具有“违反直觉”的特点(因此需要记录)。


1

首先,段落名称必须是唯一的,除非它们在不同的章节中,因此章节允许对段落进行“命名空间”。

如果我没记错的话,你必须使用SECTION的唯一原因是为了DECLARATIVES。除此之外,它们是可选的,主要用于分组段落。我认为(相对而言),通常要求只有当段落在同一节中时才使用PERFORM


我曾经忘记了“命名空间”功能,即SECTION相对于PARAGRAPH提供的功能,但是这是否是语言设计者在构建这些结构时使用的正当理由呢?J.Sammet曾经在一篇有关COBOL早期历史的有趣文章中提供了一些洞见,解释了为什么某些语言特性是这样的,但没有提供为什么要同时包含SECTIONPARAGRAPH的原因。我就是不明白——但这些人并不是傻瓜,所以我想他们一定有很好的理由来使用它们。谢谢,Neal - NealB

1
一个章节可以有多个段落。当你执行一个章节时,它会执行该章节中所有的段落。在该章节内,你可以使用PERFORM或GOTO来跳转到该章节内的段落。

因此,EXIT语句作为GO TO的目标。今天,EXIT只是一个“挂”段落名称的地方。我认为一些早期编译器要求EXIT是执行范围内SECTIONs / PARAGRAPHs的最后一个段落中唯一的语句。它需要生成实现从PERFORMed范围返回的代码。由于PARAGRAPH是SECTION的下级,可以预期PERFORM SECTION将执行所有包含的段落。可以使用PERFORM para-1 THROUGH para-n执行一系列段落,因此仅使用段落即可实现相同的功能。 - NealB

0

我会尽力回答这个问题。如果你唯一的编程经验是x86或ARM,那么你将会遇到很大的困难。是的,这些芯片销量很大,但这并不意味着它们很好,只是便宜到人们不介意扔掉它们。

许多相关信息可以在“The Minimum You Need to Know to Be an OpenVMS Application Developer”中找到。你会发现这是Dr. Dobb's推荐阅读列表上为数不多的几本书之一。是的,我写了这本书。这也是HP OpenVMS工程组推荐给想要学习该平台的开发者的书籍。

我在那个平台上使用COBOL主要发生在20世纪80年代,当时它是VAX/VMS。然后变成了OpenVMS;Alpha/OpenVMS;Itanium/OpenVMS;很快将成为x86/OpenVMS。在一个真正的计算机和真正的操作系统上,各个部分都有意义。每个部分创建了一个PSECT。在链接器术语中,这是Program SECtion的缩写。根据部分的内容,设置了各种加载属性。每个PSECT将被加载到一个或多个512字节的内存页面中。内存页面的设计大小与磁盘块完全相同。VMS代表虚拟内存系统。IBM有几个自己的操作系统,在底层上是不同的,但它们也是真正的虚拟内存系统。这不是“覆盖链接”。那是一个x86术语,并由于严重的架构缺陷而产生。从286时代开始,阅读关于紧凑型、小型、中型和大型“内存模型”的文章。还要阅读EMS和XMS内存分页。哦,那太有趣了!

这是那本书中发现的众多程序之一。

IDENTIFICATION DIVISION.

程序标识. COB_ZILL_DUE_REPORT_SUB. 作者. Roland Hughes. 编写日期. 2005-02-08. 编译日期. 今天.

环境部分.

输入输出部分.

文件控制.

SELECT DRAW-STATS
    ASSIGN TO 'DRAWING_STATS'
    ORGANIZATION IS INDEXED
    ACCESS MODE IS SEQUENTIAL
    RECORD KEY IS ELM_NO IN DSTATS-REC
    LOCK MODE IS AUTOMATIC
    FILE STATUS IS D-STAT.

SELECT MEGA-STATS
    ASSIGN TO 'MEGA_STATS'
    ORGANIZATION IS INDEXED
    ACCESS MODE IS SEQUENTIAL
    RECORD KEY IS ELM_NO IN MSTATS-REC
    LOCK MODE IS AUTOMATIC
    FILE STATUS IS M-STAT.

SELECT SORT-FILE ASSIGN TO 'TMP.SRT'.

SELECT SORTED-FILE ASSIGN TO DISK.

SELECT RPT-FILE ASSIGN TO 'ZILL_DUE.RPT'.

数据部分。

文件部分。

FD DRAW-STATS 是全局的 标签记录是标准的。

COPY 'CDD_RECORDS.ZILLIONARE_STATS_RECORD' FROM DICTIONARY
    REPLACING ZILLIONARE_STATS_RECORD BY DSTATS-REC.

FD MEGA-STATS 全球覆盖 标签记录是标准的。

COPY 'CDD_RECORDS.ZILLIONARE_STATS_RECORD' FROM DICTIONARY
    REPLACING ZILLIONARE_STATS_RECORD BY MSTATS-REC.

FD RPT-FILE 标签记录被省略。

01 RPT-DTL                         PIC X(80).

SD 排序文件。

COPY 'CDD_RECORDS.ZILLIONARE_STATS_RECORD' FROM DICTIONARY
    REPLACING ZILLIONARE_STATS_RECORD BY SORT-REC.

FD SORTED-FILE
ID 的值是 SORTED-FILE-NAME。

COPY 'CDD_RECORDS.ZILLIONARE_STATS_RECORD' FROM DICTIONARY
    REPLACING ZILLIONARE_STATS_RECORD BY SORTED-REC.

  • 数据声明

工作存储区段。 01 常量。 05 SORT-FILE-NAME PIC X(7) VALUE 'TMP.SRT'. 05 SORTED-FILE-NAME PIC X(8) VALUE 'STAT.SRT'。

01 STATUS-VARIABLES.
   05 M-STAT                PIC X(2).
   05 D-STAT                PIC X(2).
   05 EOF-FLAG              PIC X.
      88 IT-IS-END-OF-FILE VALUE 'Y'.

01 STUFF.
   05 TODAYS-DATE.
      10 TODAY_YYYY         PIC X(4).
      10 TODAY_MM           PIC X(2).
      10 TODAY_DD           PIC X(2).

   05 TODAYS-DATE-FORMATTED.
      10 FMT_MM             PIC Z9.
      10 FILLER             PIC X VALUE '/'.
      10 FMT_DD             PIC 99.
      10 FILLER             PIC X VALUE '/'.
      10 FMT_YYYY           PIC 9(4).

   05 FLT-1                 COMP-2.
   05 WORK-STR              PIC X(65).

01 REPORT-DETAIL.
   05 ELM-NO-DTL            PIC Z9.
   05 FILLER                PIC X(3).
   05 HIT-COUNT-DTL         PIC ZZZ9.
   05 FILLER                PIC X(3).
   05 SINCE-LAST-DTL        PIC ZZZ9.
   05 FILLER                PIC X(5).
   05 PCT-HITS-DTL          PIC Z9.999.
   05 FILLER                PIC X(4).
   05 AVE-BTWN-DTL          PIC ZZ9.999.

01 REPORT-HDR1.
   05 THE-DATE              PIC X(12).
   05 FILLER                PIC X(20).
   05 PAGE-TITLE            PIC X(17).

01 REPORT-HDR2.
   05 FILLER                PIC X(33).
   05 GROUP-TITLE           PIC X(20).

01 REPORT-HDR3.
   05 HDR3-TXT              PIC X(40) VALUE
        'No   Hits   Since   Pct_hits   Ave_btwn'.

01 REPORT-HDR4.
   05 HDR4-TXT              PIC X(40) VALUE
        '--   ----   -----   --------   --------'.

程序部分。

A000-主程序。

PERFORM B000-HSK.

SORT SORT-FILE
    ON DESCENDING KEY SINCE_LAST IN SORT-REC
    INPUT PROCEDURE IS S000-DSTAT-INPUT
    GIVING SORTED-FILE.

PERFORM B010-REPORT-DRAWING-NUMBERS.


STRING SORT-FILE-NAME, ';*' DELIMITED BY SIZE INTO WORK-STR.
CALL 'LIB$DELETE_FILE' USING BY DESCRIPTOR WORK-STR.

STRING SORTED-FILE-NAME, ';*' DELIMITED BY SIZE INTO WORK-STR.
CALL 'LIB$DELETE_FILE' USING BY DESCRIPTOR WORK-STR.

* * 为报告的第二部分进行设置 * 将空格移动到RPT-DTL。 在换页之前写入RPT-DTL。

MOVE SPACES TO EOF-FLAG.
MOVE ' Mega Drawing Numbers' TO GROUP-TITLE.

SORT SORT-FILE
    ON DESCENDING KEY SINCE_LAST IN SORT-REC
    INPUT PROCEDURE IS S001-MSTAT-INPUT
    GIVING SORTED-FILE.


PERFORM B010-REPORT-DRAWING-NUMBERS.


STRING SORT-FILE-NAME, ';*' DELIMITED BY SIZE INTO WORK-STR.
CALL 'LIB$DELETE_FILE' USING BY DESCRIPTOR WORK-STR.

STRING SORTED-FILE-NAME, ';*' DELIMITED BY SIZE INTO WORK-STR.
CALL 'LIB$DELETE_FILE' USING BY DESCRIPTOR WORK-STR.


CLOSE RPT-FILE.

CALL 'LIB$SPAWN' USING BY DESCRIPTOR 'EDIT/READ ZILL_DUE.RPT'.

EXIT PROGRAM.

  • 初始化我们的数据和文件。

B000-HSK。 调用'COB_FILL_IN_LOGICALS'。

MOVE SPACES TO STATUS-VARIABLES.

ACCEPT TODAYS-DATE FROM DATE YYYYMMDD.

MOVE TODAY_YYYY TO FMT_YYYY.
MOVE TODAY_DD   TO FMT_DD.
MOVE TODAY_MM   TO FMT_MM.


OPEN OUTPUT RPT-FILE.


MOVE SPACES TO REPORT-HDR1.
MOVE TODAYS-DATE-FORMATTED TO THE-DATE.
MOVE 'Due Number Report' to PAGE-TITLE.

MOVE SPACES TO REPORT-HDR2.
MOVE 'Drawing Numbers' TO GROUP-TITLE.

  • 处理排序后的选择文件,并创建与绘制数字相关的报告部分。

B010-报告-绘图数字。

MOVE SPACES TO EOF-FLAG.

OPEN INPUT SORTED-FILE.

READ SORTED-FILE
    AT END SET IT-IS-END-OF-FILE TO TRUE.

PERFORM C010-DRAWING-HEADINGS.

PERFORM UNTIL IT-IS-END-OF-FILE
    MOVE SPACES TO REPORT-DETAIL
    MOVE ELM_NO IN SORTED-REC TO ELM-NO-DTL
    MOVE HIT_COUNT IN SORTED-REC TO HIT-COUNT-DTL
    MOVE SINCE_LAST IN SORTED-REC TO SINCE-LAST-DTL
    MOVE PCT_HITS IN SORTED-REC TO PCT-HITS-DTL
    MOVE AVE_BTWN IN SORTED-REC TO AVE-BTWN-DTL
    MOVE REPORT-DETAIL TO RPT-DTL
    WRITE RPT-DTL BEFORE ADVANCING 1 LINE
    READ SORTED-FILE
        AT END SET IT-IS-END-OF-FILE TO TRUE
    END-READ
END-PERFORM.

CLOSE SORTED-FILE.

  • 打印主要图纸编号的标题段落
  • 这些编号是应该完成的。

C010-图纸标题。

MOVE SPACES TO RPT-DTL.


MOVE REPORT-HDR1 TO RPT-DTL.

WRITE RPT-DTL BEFORE ADVANCING 2 LINES.

MOVE SPACES TO RPT-DTL.

MOVE REPORT-HDR2 TO RPT-DTL.

WRITE RPT-DTL BEFORE ADVANCING 1 LINE.

MOVE SPACES TO RPT-DTL.
MOVE REPORT-HDR3 TO RPT-DTL.
WRITE RPT-DTL BEFORE ADVANCING 1 LINE.

MOVE SPACES TO RPT-DTL.
MOVE REPORT-HDR4 TO RPT-DTL.
WRITE RPT-DTL BEFORE ADVANCING 1 LINE.

  • 将段落中的数字过滤到排序文件中。
  • 创建一个浮点临时变量进行比较
  • 与输入文件中的浮点值进行比较。当大于时
  • 记录被释放到排序文件中。

S000-DSTAT-INPUT。

OPEN INPUT DRAW-STATS.

READ DRAW-STATS NEXT
    AT END SET IT-IS-END-OF-FILE TO TRUE.

PERFORM UNTIL IT-IS-END-OF-FILE

    MOVE SINCE_LAST IN DSTATS-REC TO FLT-1

    IF FLT-1 >= AVE_BTWN IN DSTATS-REC
        MOVE DSTATS-REC TO SORT-REC
        RELEASE SORT-REC
    END-IF
    READ DRAW-STATS
        AT END SET IT-IS-END-OF-FILE TO TRUE
    END-READ
END-PERFORM.

CLOSE DRAW-STATS.

  • 将段落中的数字过滤到排序文件中。
  • 创建一个浮点临时变量进行比较
  • 与输入文件中的浮点值进行比较。当大于时
  • 记录被释放到排序文件中。

S001-MSTAT-INPUT。

OPEN INPUT MEGA-STATS.

READ MEGA-STATS NEXT
    AT END SET IT-IS-END-OF-FILE TO TRUE.

PERFORM UNTIL IT-IS-END-OF-FILE

    MOVE SINCE_LAST IN MSTATS-REC TO FLT-1

    IF FLT-1 >= AVE_BTWN IN MSTATS-REC
        MOVE MSTATS-REC TO SORT-REC
        RELEASE SORT-REC
    END-IF
    READ MEGA-STATS
        AT END SET IT-IS-END-OF-FILE TO TRUE
    END-READ
END-PERFORM.

CLOSE MEGA-STATS.

结束程序COB_ZILL_DUE_REPORT_SUB。

对于这个编辑器中“代码”功能的工作方式表示抱歉。

某些部分必须存在。没有输入输出(I-O)段,您的程序无法执行I-O操作。这是您将名称映射到物理存储的位置。

如果您拥有一个I-O段,那么您必须拥有一个文件段。这是您定义每个命名文件的记录布局的位置。在处理磁盘数据文件时,LABEL RECORDS始终为STANDARD,而在编写报表文本文件时则为OMITTED。还有一些其他条款我记不清了。请注意,在所有FD语句中都包含SD。FD是文件定义,SD是排序定义。

如果您要有任何局部变量,则必须拥有一个WORKING-STORAGE SECTION。您不能在运行时声明变量,它们都必须在此处声明。这个PSECT会获得一个数据段属性以及其他一些属性。如果您调用某个服务或其他东西,并且它具有错误的地址,则尝试在此PSECT内执行代码,操作系统将使您的应用程序停止运行。

PROCEDURE DIVISION 后面创建的所有 PSECT 都被标记为 EXEC,是受写保护的。如果您在执行期间尝试覆盖这里的任何内容,操作系统将使您的程序崩溃。任何其他尝试在此处编写的程序也将被彻底清除。

向下滚动到 A000-MAIN 中的 SORT SORT-FILE。COBOL 排序例程非常棒。请注意,我提供了一个输入 PROCEDURE,并且它是一个段落。在那个时代运行 ROSCOE 的 IBM 大型机上,它必须是一个 INPUT SECTION。他们需要在 PSECT 上有不同的属性,以便系统排序例程可以读取/写入。

这是书中另一个程序的片段。

*

* FMS定义 * 将 'MEGA_TEXT_LIB' 库中的 'COBFDVDEF' 复制到当前程序。

LINKAGE部分。

01 FMS-STUFF.
   05 FMSSTATUS                 PIC S9(9) COMP.
   05 RMSSTATUS                 PIC S9(9) COMP.
   05 TCA                       PIC X(12).
   05 WORKSPACE                 PIC X(12).

PROCEDURE DIVISION USING FMS-STUFF.

链接部分创建了一个可共享内存的PSECT。当您调用返回值的外部例程时,它们需要在这里。您还必须授予您的PROCEDURE DIVISION访问链接部分所需的各种内容。

正如您从代码中稍后看到的那样

B010-USER-INPUT.

PERFORM C000-FORWARD-LOAD

CALL 'FDV$PUTAL' USING BY DESCRIPTOR SCREEN-REC.

MOVE SPACES TO WORK-STR.

CALL 'FDV$GETAL' USING BY DESCRIPTOR WORK-STR
                       BY REFERENCE TERMINATOR.


EVALUATE TERMINATOR
    WHEN FDV$K_FK_E6    SET LOAD-FORWARD TO TRUE
    WHEN FDV$K_FK_E5    SET LOAD-REVERSE TO TRUE
    WHEN FDV$K_FK_F10   SET WE-ARE-DONE TO TRUE
END-EVALUATE.

只要正确传递,您可以传递任何本地变量。需要特殊的PSECT属性来编写。

现在已经很晚了,我很累,但我似乎记得在PROCEDURE DIVISION中的SECTION声明上可以有USING子句。至少谷歌索引的COBOL在线文档真的非常没有价值。如果您想要更详细的信息,请搜索大约1980年代的COBOL教科书。它不会有任何新东西,但它会回答许多问题。

这里有一个关于COBOL结构的不太好的教程


-1

我们在所有的37K MVS批处理COBOL程序中使用COBOL SECTION编码技术。我们使用这种技术来获得更快的运行时间和显著降低CPU开销。这种COBOL编码技术与高性能批处理汇编非常相似。

可以称之为高性能功能结构化COBOL编程。

一旦定义了SECTION,所有的PERFORM xxxxx将返回到下一个编码的SECTION而不是SECTION中的下一个段落。如果在第一个SECTION之前编写了段落,则它们可以正常执行。(但我们不允许这样做)

使用SECTION比仅使用段落(PERFORM)的开销要高 - 除非您使用GOTO逻辑来绕过应有条件执行的代码。我们的规则是GOTO只能指向同一SECTION中的Tag-Line(段落)。SECTION中的所有段落必须是SECTION函数的子函数。EXIT指令是汇编NOP指令。它允许在下一个SECTION之前放置一个Tag-Line,以进行快速退出/返回。

执行PERFORM xxxx THRU yyyy比执行没有GOTO标签的SECTION具有更多的CPU开销。

警告:在SECTION中执行PERFORM xxxx Tag-Line 将通过SECTION中的所有代码,直到遇到下一个SECTION。当前 SECTION以外的GOTO将通过新着陆SECTION中的所有代码,直到遇到下一个SECTION(但我们不允许这样做)


有趣的是... 你做过基准测试来展示这些性能差异吗?我原本以为,在 IBM 编译器中使用的控制机制在 PERFORM SECTIONS 和 PARAGRAPHS 时完全相同。IBM COBOL 编译器中用于实现从 PERFORM 返回的控制机制在此文献中描述。我不会期望执行 SECTION 或 PARAGRAPH 有任何区别。 - NealB
1
我知道这已经"老掉牙"了,但是...这里存在许多矛盾和误解。它们可能源于措辞不当,但它们确实存在。"程序员要当心"。特别是“警告”没有意义——第一部分不是真的,第二部分也没有必要是真的。只有一种情况下,使用PERFORM执行一个具有多个段落的SECTION比执行单个段落会更快(如果它们在SECTION之外,则做出这样的操作是荒谬的):PERFORM A-SECTION(包含B-PARA和C-PARA)PERFORM B-PARA PERFORM C-PARA第一个代码较少。 - Bill Woodger
1
作为一名COBOL编译器的作者,我认为这是一派胡言。使用SECTION与使用段落本质上并没有区别。无论你声称它更快还是更慢,都没有理由期望它有所不同。我不知道为什么你使用非COBOL术语“Tag-Line”,而PARAGRAPH已经存在了。你所描述的编码技巧与“高性能批处理汇编程序”毫无关系。使用GOTO绕过条件逻辑不如使用ELSE。EXIT不是汇编NOP:它是一个有条件的返回。在PERFORM xxx THRU yyy中没有GOTO。@BillWoodger++ - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接