【问题标题】:Issues with GO TO statement on execution past the first time第一次执行后 GO TO 语句的问题
【发布时间】:2013-11-18 03:15:50
【问题描述】:

在使用 GO-TO 语句时遇到问题。这假设一直运行到用户键入“END”。如果我在第一次打开程序时输入“END”,它会关闭,但如果我在第一次通过输入有效数据后输入它,它只会继续返回用户输入数据屏幕。

   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.

       SELECT USED-CAR-FILE-OUT
           ASSIGN TO 'USED-CAR.RPT'
           ORGANIZATION IS LINE SEQUENTIAL.

   DATA DIVISION.
   FILE SECTION.

   FD USED-CAR-FILE-OUT.
   01 USED-CAR-RECORD-OUT              PIC X(80).

   WORKING-STORAGE SECTION.
   01  FIRST-RECORD                    PIC X(3)     VALUE 'YES'.
   01  ID-CODE                         PIC X(3).
   01  TOTAL-CASH-PAYMENT              PIC 9(5).
   01  MONTHLY-PAYMENT                 PIC 9(4).
   01  NUMBER-OF-MONTHS                PIC 9(3).
   01  TOTAL-BALANCE                   PIC S9(6)V99 VALUE ZEROS.
   01  INTEREST-COLLECTED              PIC 99V99    VALUE ZEROS.
   01  MONTH-DIFF                      PIC 99       VALUE ZEROS.
   01  MONTH-NUM                       PIC 99       VALUE ZEROS.
   01  YEAR-NUM                        PIC 99       VALUE ZEROS.
   01  ID-HOLD                         PIC X(3)     VALUE SPACES.
   01  PAYMENT-HOLD                    PIC X(3)     VALUE SPACES.






   01  DETAIL-LINE.
       05  ID-CODE-DL                  PIC X(3).
       05                              PIC X(3)    VALUE SPACES.
       05                              PIC X(4)    VALUE 'Yr='.
       05  YEAR-NUMBER-DL              PIC Z9.
       05                              PIC X(4)    VALUE SPACES.
       05                              PIC X(4)    VALUE 'MO='.
       05  MONTH-NUMBER-DL             PIC Z9.
       05                              PIC X(4)    VALUE SPACES.
       05                              PIC X(5)    VALUE 'Pmt='.
       05  PAYMENT-DL                  PIC $$$,$$$.
       05                              PIC X(4)    VALUE SPACES.
       05                              PIC X(5)    VALUE 'Int='.
       05  INTEREST-EARNED-DL          PIC $$$$.99.
       05                              PIC X(3)    VALUE SPACES.
       05                              PIC X(5)    VALUE 'Bal='.
       05  BALANCE-DL                  PIC $$$,$$$.99.


   PROCEDURE DIVISION.
   100-MAIN.

       OPEN OUTPUT USED-CAR-FILE-OUT
           PERFORM 200-USER-INPUT THRU 299-EXIT
       CLOSE USED-CAR-FILE-OUT
       STOP RUN.

   200-USER-INPUT.
       DISPLAY 'Used Car Sales Report'
       DISPLAY 'Enter the ID code (or END) - maxium three char.'
       ACCEPT ID-CODE
       IF ID-CODE = 'END'
           GO TO 299-EXIT
       END-IF
       DISPLAY 'Enter the Total Cash Payment - maximum five digits'
       ACCEPT TOTAL-CASH-PAYMENT
       DISPLAY 'Enter the Monthly Payment - maximum four digits'
       ACCEPT MONTHLY-PAYMENT

       DISPLAY 'Enter the Number of Months - maximum three digits'
       ACCEPT NUMBER-OF-MONTHS
       PERFORM 300-RECORD-PROCESS.

   299-EXIT.
       EXIT.

   300-RECORD-PROCESS.
       IF TOTAL-CASH-PAYMENT > 0
           IF FIRST-RECORD = 'YES'
               MOVE ID-CODE TO ID-CODE-DL
               MOVE 1 TO YEAR-NUMBER-DL
               MOVE 1 TO YEAR-NUM
               move 1 to MONTH-NUMBER-DL
               MOVE TOTAL-CASH-PAYMENT TO PAYMENT-DL
               MOVE PAYMENT-DL TO MONTHLY-PAYMENT
               ADD MONTHLY-PAYMENT TO TOTAL-BALANCE
               MOVE 'NO' TO FIRST-RECORD
            END-IF
           COMPUTE INTEREST-COLLECTED ROUNDED = TOTAL-BALANCE
            * .0175 / 12
           MOVE INTEREST-COLLECTED TO INTEREST-EARNED-DL
           ADD INTEREST-COLLECTED TO TOTAL-BALANCE
           MOVE TOTAL-BALANCE TO BALANCE-DL
           ADD 1 TO MONTH-DIFF
           MOVE MONTH-DIFF TO MONTH-NUMBER-DL
           IF MONTH-NUMBER-DL > 13
               ADD 1 TO MONTH-NUM
               MOVE MONTH-NUM TO MONTH-NUMBER-DL
           END-IF
           IF MONTH-NUMBER-DL = 13
               MOVE 1 TO MONTH-NUM
               MOVE MONTH-NUM TO MONTH-NUMBER-DL
           END-IF
           IF MONTH-NUM = 1
               ADD 1 TO YEAR-NUM
               MOVE YEAR-NUM TO YEAR-NUMBER-DL
           END-IF
           MOVE DETAIL-LINE TO USED-CAR-RECORD-OUT
           WRITE USED-CAR-RECORD-OUT
           AFTER ADVANCING 1 LINE
           MOVE ID-HOLD TO ID-CODE-DL

           IF MONTH-DIFF < NUMBER-OF-MONTHS
               PERFORM 300-RECORD-PROCESS
           END-IF
           PERORM 200-USER-INPUT
       END-IF

       IF MONTHLY-PAYMENT > 0
           IF FIRST-RECORD = 'YES'
               MOVE ID-CODE TO ID-CODE-DL
               MOVE 1 TO YEAR-NUMBER-DL
               MOVE 1 TO YEAR-NUM
               move 1 to MONTH-NUMBER-DL
               MOVE 'NO' TO FIRST-RECORD
           END-IF

           MOVE MONTHLY-PAYMENT TO PAYMENT-DL
           MOVE PAYMENT-DL TO MONTHLY-PAYMENT
           ADD MONTHLY-PAYMENT TO TOTAL-BALANCE
           COMPUTE INTEREST-COLLECTED ROUNDED = TOTAL-BALANCE
            * .0175 / 12
           MOVE INTEREST-COLLECTED TO INTEREST-EARNED-DL
           ADD INTEREST-COLLECTED TO TOTAL-BALANCE
           MOVE TOTAL-BALANCE TO BALANCE-DL
           ADD 1 TO MONTH-DIFF
           MOVE MONTH-DIFF TO MONTH-NUMBER-DL
           IF MONTH-NUMBER-DL > 13
               ADD 1 TO MONTH-NUM
               MOVE MONTH-NUM TO MONTH-NUMBER-DL
           END-IF
           IF MONTH-NUMBER-DL = 13
               MOVE 1 TO MONTH-NUM
               MOVE MONTH-NUM TO MONTH-NUMBER-DL
           END-IF
           IF MONTH-NUM = 1
               ADD 1 TO YEAR-NUM
               MOVE YEAR-NUM TO YEAR-NUMBER-DL
           END-IF
           MOVE DETAIL-LINE TO USED-CAR-RECORD-OUT
           WRITE USED-CAR-RECORD-OUT
           AFTER ADVANCING 1 LINE
           MOVE ID-HOLD TO ID-CODE-DL
           IF TOTAL-CASH-PAYMENT > 0
               MOVE 0 TO TOTAL-CASH-PaYMENT
               MOVE 0 TO PAYMENT-DL
           END-IF
           IF MONTH-DIFF < NUMBER-OF-MONTHS
           PERFORM 300-RECORD-PROCESS
           END-IF
       PERFORM 200-USER-INPUT
       END-IF.

EDIT 解决了以下问题 如果几个月 > 24,我也会遇到问题。我逐步执行该程序,它显示我的最后一个详细信息行是正确的结果,但我的输出在 24 个月时停止。提前致谢。

【问题讨论】:

  • 如果您之前没有答案的问题不再需要,您可以将其删除。
  • 我认为您必须对当前代码提出一个新问题。请保持原样,我们可以回滚您的最新编辑。请每个问题一个问题。如果您进行编辑,未来的搜索者将很难跟上正在发生的事情。我们现在的日子不好过。谢谢。
  • 我要感谢大家对此主题的投入。这门课对我来说非常难掌握,你所有的答案都极大地帮助我完成了这个程序。我没有用 goto 语句掌握全局,并且在执行完段落后它又返回了。我在第 100-MAIN 段中遗漏了。 UNTIL ID-CODE ='END'

标签: cobol goto


【解决方案1】:

啊啊啊啊!

对任何提到的人进行严厉打击
使用重物
直到承诺-再也不做。

PERFORM THOUGH 是 邪恶。它会导致依赖于布局的代码。

在顶层控制层,使用

PERFORM 200-USER-INPUT
  UNTIL ID-CODE = 'END'.

(或者可能在 ID-CODE 上使用 88 USER-INPUT-ENDED - 风格问题)

然后,您如何确定是否继续输入 200-... 也是您的选择

IF NOT USER-INPUT-ENDED
   DISPLAY 'Enter the Total Cash Payment - maximum five digits'
   ACCEPT TOTAL-CASH-PAYMENT
   ...
   ACCEPT NUMBER-OF-MONTHS
   PERFORM 300-RECORD-PROCESS.

  IF NOT USER-INPUT-ENDED
     PERFORM 210-ACCEPT-DETAILS.

210-ACCEPT-DETAILS.

   DISPLAY 'Enter the Total Cash Payment - maximum five digits'.
   ACCEPT TOTAL-CASH-PAYMENT.
   ...
   ACCEPT NUMBER-OF-MONTHS.
   PERFORM 300-RECORD-PROCESS.

既然你 PERFORMED 200-... 那么只有 200-... 会被执行; 210-... 是一个新段落,只能从 200-... IF END 没有输入。

下一步是稍微修改300-...
将初始化(FIRST-RECORD = 'YES' 代码)移到 PERFORM 300-... 之前的 200-... 中,然后将 PERFORM 300-RECORD-PROCESS. 修改为

  PERFORM 300-RECORD-PROCESS
    UNTIL TOTAL-BALANCE = 0.

(我在这里假设这是报告终止条件;如果不是,请替换您的报告终止条件)

您现在可以重组 300-... 来计算应付利息,修改年份和月份数字并显示结果。 所有 300-...中的PERFORMs 将消失。

所以,本质上你有

MAIN:perform user-input until end-detected.  
user-input: get user data; perform calculations until balance is zero.
calculations: one month's calculations at a time. 

这还有一个好处,如果你选择,你可以插入

IF MONTHLY-PAYMENT IS LESS THAN INTEREST-COLLECTED
   MOVE 'ERR' TO ID-CODE.

并使用 ID-CODE 中的“ERR”在 300-... 中生成适当的错误消息,而不是渐进式报告行,同时将 0 分配给 TOTAL-BALANCE,从而终止 PERFORM 300-... UNTIL ... .

【讨论】:

    【解决方案2】:

    您对 GO TO 和 PERFORM THROUGH 段落范围的使用破坏了 COBOL 的过程返回机制 用于维护适当的程序控制流。本质上,您有一个无效的程序 - 它可能会编译 没有错误,但根据 COBOL 规则仍然是无效程序。

    以下是您的程序从控制流的角度所做的概述。这 主线程序本质上是:

    100-MAIN.
       PERFORM 200-USER-INPUT THRU 299-EXIT
    

    这是要求 COBOL 执行从开头找到的所有代码 200-USER-INPUT 到 299-EXIT 结束。这些的大纲 程序是:

    200-USER-INPUT.
        IF some condition GO TO 299-EXIT
        ...
        PERFORM 300-RECORD-PROCESS
        .
    
    299-EXIT.
    

    请注意,如果some condition 为真,程序流将跳过结尾 200-USER-INPUT 并跳转到 299-EXIT。 299-EXIT 不执行任何操作 很有趣,它只是一个空的段落作为一个结尾 PERFORMed 范围的段落。

    在第 300-RECORD-PROCESS 段中,您有相当多的代码。有趣的 位是:

     300-RECORD-PROCESS.
        ...
        PERFORM 200-USER-INPUT
    

    请注意PERFORM 200-USER-INPUT 这不是 PERFORM THRU,因为您在 100-MAIN 中进行了编码。 问题是当你回到 200-USER-INPUT 并且 some codition 变成 true (就像你输入“EXIT”时一样),控制流 跳转到段落末尾的 299-EXIT 你目前正在表演。从此 转发 COBOL 用于管理从 PERFORM 动词返回的控制机制的流程 被破坏。不再有正常的流程控制机制返回到 200-USER-INPUT 是在 300-RECORD-PROCESS 中执行的。

    接下来发生的事情不是大多数程序员所期望的。大多数程序员似乎期望 当 299-EXIT 结束时,程序流应该返回到最后一个 PERFORM 的地方 已完成。在这种情况下,就在 PERFORM 200-USER-INPUT 之后。不,COBOL 不能那样工作,控制流 将继续执行 299-EXIT 之后的下一个可执行语句。这让你 回到 300-RECORD-PROCESS 中的第一个可执行语句!这就是为什么你 没有从该程序中获得预期的行为。

    COBOL 程序中的逻辑流必须确保执行过程的结束是 总是以它们制作的相反顺序到达。这对应于调用/返回 堆栈语义 大多数程序员都熟悉。

    我的建议是避免使用PERFORM THRUGO TO。这是两个最大的 今天在 COBOL 编程语言中留下的罪恶。这些结构是来自 过去的编程时代,今天没有建设性的好处。

    【讨论】:

      【解决方案3】:

      您的问题是您为自己创建了一个无限循环。您的 200 段执行 300 段,您的 300 段执行您的 200 段。

      你需要重组你的程序。

      一个名为 200-USER-INPUT 的段落应该只关注它。

      repeat until end of input
           get some input
           if there is input to process 
               process the input
      

      呸!我刚刚注意到你也在 300 以内 PERFORM 300-!

      【讨论】:

        猜你喜欢
        • 2017-02-02
        • 2012-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-02
        • 1970-01-01
        • 2017-09-15
        相关资源
        最近更新 更多