2

I am currently studying for a week an old programming language COBOL but had encounter a problem. this is the sample of a Cobol program.

   IDENTIFICATION DIVISION.
   PROGRAM-ID. MONTHLY.
   ENVIRONMENT DIVISION.
   INPUT-OUTPUT SECTION.
   FILE-CONTROL.
       SELECT IN-FILE ASSIGN TO "USERINPUT.DAT".
       SELECT OUT-FILE ASSIGN TO "USEROUTPUT.DAT".
   DATA DIVISION.
   FILE SECTION.
   FD IN-FILE
       LABEL RECORDS ARE STANDARD
       DATA RECORD IS IN-REC.
   01 IN-REC.
       02 C-NAME PIC X(25).
       02 STREET PIC X(20).
       02 ZIP-CODE PIC X(15).
       02 CREDIT PIC 9(6)V99.
       02 MONTH PIC 99.
       02 FILLER PIC XX VALUE "\n".
   FD OUT-FILE
       LABEL RECORDS ARE STANDARD
       DATA RECORD IS OUT-REC.
   01 OUT-REC PIC X(80).
  *-----------------------
   WORKING-STORAGE SECTION.
  *-----------------------
   01 HDG-01.
       02 FILLER PIC X(27) VALUE SPACES.
       02 FILLER PIC X(27) VALUE "ABC Loans & Savings Company".
   01 HDG-02.
       02 FILLER PIC X(28) VALUE SPACES.
       02 FILLER PIC X(25) VALUE "Ayala Avenue, Makati City".
   01 HDG-03.
       02 FILLER PIC X(30) VALUE SPACES.
       02 FILLER PIC X(20) VALUE "SCHEDULE OF PAYMENTS".
   01 HDG-04.
       02 FILLER PIC X(28) VALUE SPACES.
       02 FILLER PIC X(15) VALUE "ORIGINAL AMOUNT".
       02 REC-CREDIT PIC Z(5)9.99.
   01 HDG-05.
       02 FILLER PIC X(14) VALUE SPACES.
       02 FILLER PIC X(9) VALUE "MONTH".
       02 FILLER PIC X(11) VALUE "INTEREST".
       02 FILLER PIC X(17) VALUE "TOTAL-PAYMENT".
       02 FILLER PIC X(14) VALUE "UNPAID-BALANCE".
   01 TRANSFER-LINE.
       02 FILLER PIC X(16) VALUE SPACES.
       02 REC-MONTH PIC 99.
       02 FILLER PIC X(6) VALUE SPACES.
       02 INTEREST PIC 9(3)V99.
       02 FILLER PIC X(7) VALUE SPACES.
       02 TOTAL-PAY PIC 9(6)v99.
       02 FILLER PIC X(10) VALUE SPACES.
       02 UNPAID-BAL PIC 9(6)v99.
   01 PRINT-LINE.
       02 FILLER PIC X(16) VALUE SPACES.
       02 FILLER PIC 99.
       02 FILLER PIC X(6) VALUE SPACES.
       02 FILLER PIC ZZ9.99.
       02 FILLER PIC X(7) VALUE SPACES.
       02 FILLER PIC Z(5)9.99.
       02 FILLER PIC X(10) VALUE SPACES.
       02 FILLER PIC Z(5)9.99.
   01 PRINT-NULL.
       02 FILLER PIC X(16) VALUE SPACES.
       02 FILLER PIC XX VALUE "--".
       02 FILLER PIC X(6) VALUE SPACES.
       02 FILLER PIC XXXXX VALUE "-----".
       02 FILLER PIC X(7) VALUE SPACES.
       02 FILLER PIC X(9) VALUE "---------".
       02 FILLER PIC X(9) VALUE SPACES.
       02 FILLER PIC X(9) VALUE "---------".
   01 X PIC 99.
   01 REM PIC 999.
   01 CHECK-MONTH PIC 99.
   01 CLIENT-NO PIC 9.
   01 PRINT-ASTERISK.
       02 FILLER PIC X(30) VALUES ALL "*" .
       02 FILLER PIC X(18) VALUES "-END OF CLIENT NO ".
       02 CLIENT PIC 9.
       02 FILLER PIC X VALUE "-".
       02 FILLER PIC X(30) VALUES ALL "*" .
   PROCEDURE DIVISION.

   OPEN INPUT IN-FILE
        OUTPUT OUT-FILE.

   REPEAT-RTN.
       ADD 1 TO CLIENT-NO.
       MOVE CLIENT-NO TO CLIENT.
       READ IN-FILE AT END PERFORM CLOSE-RTN.
       MOVE CREDIT TO UNPAID-BAL.
       MOVE MONTH TO CHECK-MONTH.
       PERFORM WITH TEST BEFORE UNTIL CHECK-MONTH < 13
           COMPUTE CHECK-MONTH = CHECK-MONTH - 12
       END-PERFORM.
       COMPUTE CHECK-MONTH = MONTH + (12 - CHECK-MONTH).
       MOVE ZEROES TO X.
       PERFORM PROCESS-RTN CHECK-MONTH TIMES.
       WRITE OUT-REC FROM PRINT-ASTERISK AFTER 1 LINE.
       PERFORM REPEAT-RTN.

   PROCESS-RTN.
       ADD 1 TO X.
       MOVE X TO REM.

       PERFORM WITH TEST BEFORE UNTIL REM <= 13
           COMPUTE REM = REM - 12
       END-PERFORM.

       IF REM=13 OR REM = 1 THEN
           PERFORM HDG-RTN
       END-IF.
       IF REM=13 THEN
           MOVE SPACES TO OUT-REC
           WRITE OUT-REC.
       MOVE X TO REC-MONTH.
       COMPUTE INTEREST = UNPAID-BAL * 0.015.
       COMPUTE TOTAL-PAY ROUNDED= CREDIT / MONTH + INTEREST.
       COMPUTE UNPAID-BAL = UNPAID-BAL - TOTAL-PAY + INTEREST.

       IF UNPAID-BAL < 1 THEN
           MOVE ZEROES TO UNPAID-BAL
       END-IF.

       IF X > MONTH THEN
           WRITE OUT-REC FROM PRINT-NULL AFTER 1 LINE
       ELSE
           MOVE TRANSFER-LINE TO PRINT-LINE
           WRITE OUT-REC FROM PRINT-LINE AFTER 1 LINE
       END-IF.

   HDG-RTN.
       IF X > 1 THEN
           WRITE OUT-REC FROM HDG-01 AFTER 2 LINE
           WRITE OUT-REC FROM HDG-02 AFTER 1 LINE
           WRITE OUT-REC FROM C-NAME AFTER 2 LINE
       ELSE IF CLIENT-NO > 1 THEN
           WRITE OUT-REC FROM HDG-01 AFTER 1 LINE
           WRITE OUT-REC FROM HDG-02 AFTER 1 LINE
           WRITE OUT-REC FROM C-NAME AFTER 2 LINE
       ELSE
           WRITE OUT-REC FROM HDG-01 BEFORE 1 LINE
           WRITE OUT-REC FROM HDG-02 BEFORE 1 LINE
           WRITE OUT-REC FROM C-NAME AFTER 1 LINE
       END-IF.
       WRITE OUT-REC FROM STREET AFTER 1 LINE.
       WRITE OUT-REC FROM ZIP-CODE AFTER 1 LINES.
       WRITE OUT-REC FROM HDG-03 AFTER 2 LINE.
       MOVE CREDIT TO REC-CREDIT.
       WRITE OUT-REC FROM HDG-04 AFTER 1 LINE.
       WRITE OUT-REC FROM HDG-05 AFTER 2 LINE.

   CLOSE-RTN.
       CLOSE IN-FILE , OUT-FILE.
       STOP RUN.

   END PROGRAM MONTHLY.  

The program suppose to produce an output like these:

                      ABC Loans & Savings Company                          
                        Ayala Avenue, Makati City                           

The Client Name is Here:                                                        
The Client Address:                                                             
The ZiP/CITY:                                                                   

                          SCHEDULE OF PAYMENTS                              
                        ORIGINAL AMOUNT  4291.50                            

          MONTH    INTEREST   TOTAL-PAYMENT    UNPAID-BALANCE               
            01      64.37        422.00           3933.87                  
            02      05900        416.63           3576.24                  
            03      05364        411.27           3218.61                  
            04      04827        405.90           2860.98                  
            05      04291        400.54           2503.35                  
            06      03755        395.18           2145.72                  
            07      03218        389.81           1788.09                  
            08      02682        384.45           1430.46                  
            09      02145        379.08           1072.83                  
            10      01609        373.72            715.20                  
            11      01072        368.35            357.57                  
            12      00536        362.99              0.00                  
******************************-END OF CLIENT NO 1-******************************

But the program output when I run the program is different. It looks like this:

                      ABC Loans & Savings Company                          
                        Ayala Avenue, Makati City                           

The Client Name is Here:                                                        
The Client Address:                                                             
The ZiP/CITY:                                                                   

                          SCHEDULE OF PAYMENTS                              
                        ORIGINAL AMOUNT  4291.50                            

          MONTH    INTEREST   TOTAL-PAYMENT    UNPAID-BALANCE               
            01      06437       00042200          00393387                  
            02      05900       00041663          00357624                  
            03      05364       00041127          00321861                  
            04      04827       00040590          00286098                  
            05      04291       00040054          00250335                  
            06      03755       00039518          00214572                  
            07      03218       00038981          00178809                  
            08      02682       00038445          00143046                  
            09      02145       00037908          00107283                  
            10      01609       00037372          00071520                  
            11      01072       00036835          00035757                  
            12      00536       00036299          00000000                  
******************************-END OF CLIENT NO 1-******************************

I've got a problem regarding the decimal formatting and zero suppression .any advice? by the way i just used a DAT file for my input so I don't use any ACCEPT or input functions and it contains an exact character needed for a record like the text below:

The Client Name is Here: The Client Address: The ZiP/CITY: 0042915012

I believe the problem lies in the working storage print-line and transfer line.

piet.t
  • 11,718
  • 21
  • 43
  • 52

2 Answers2

4

At a first glance I notice two problems with your code:

  1. The length of your PRINT-LINE and TRANSFER-LINE are different because of the difference in the PICTURE-clauses of the numeric items. For example PRINT-LINE uses PIC ZZ9.99 while TRANSFER-LINE uses PIC 9(3)V99. Note that the decimal-point . in the PICTURE-clause requires one byte of storage while the V does not take any storage at all, so the field in PRINT-LINE is one byte larger than that in TRANSFER-LINE.
  2. When you do MOVE TRANSFER-LINE TO PRINT-LINE you don't do a field-by-field transfer but instead move the entire block of data as one, so the PICTURE-clauses in PRINT-LINE are completely ignored. You don't run into greater trouble since PRINT-LINE takes more storage than TRANSFER-LINE (see 1.) - if it was the other way round you might even have problems with storage-overwrites (but should at least get a compiler-warning).

To get this right you could

  • Name the level-02-items of PRINT-LINE like those of TRANSFER-LINE and do a MOVE CORRESPONDING TRANSFER-LINE TO PRINT-LINE - but then you will have to address your field with a qualified name (INTEREST OF TRANSFER-LINE)

or

  • Get rid of TRANSFER-LINE and put your data directly into PRINT-LINE
piet.t
  • 11,718
  • 21
  • 43
  • 52
3

@piet.t has pointed out the problem in generating your output. Only when an individual field is the "target" field for something will any data-conversion of any type take place. For a MOVEing a group to a group, all subordinate definitions are ignored.

Further:

You have a "recursive" use of a PERFORM. What this does is undefined, and can differ from compiler to compiler. Never use that.

You have a VALUE clause on a non-88-level item in the FILE SECTION. That does nothing - and if it did, what were you attempting?

Your naming is poor. COBOL programs often exist for many, many, years. There are for certain programs written in the 1970s still running with their 100 accuracy today. A program will be written once, but will need to be understood many times - so write for people to understand. Don't use single-word names, use descriptive names (there's always a chance that a new COBOL Standard will "reserve" your single-word name, and that will cause confusion next time the program changes). X, REM and CHECK-MONTH mean what? What does MONTH mean (not what people would expect)?

What is this, and it's cousin, supposed to do?

   PERFORM WITH TEST BEFORE UNTIL CHECK-MONTH < 13
       COMPUTE CHECK-MONTH = CHECK-MONTH - 12
   END-PERFORM.

For someone concerned about "ancient" languages, why are you typing all those full-stops/periods? They've not been needed in such a broad (and error-prone) use since 1985.

Use END-IF. Always, not just when you feel like it, to end each IF.

Use EVALUATE. Available since 1985, and replacing your END-IF-deficient nested-IF.

WITH TEST BEFORE is the default. No need to specify it.

Consider that fields which may become negative are not going to do so if they are not signed.

Design your program before you write it. If it turns out the design doesn't work, re-design, rather than just "patching up" the existing program so that it looks like it "works".

For instance you know that you need a heading for each record, don't you? Why test for that inside a loop?

Bill Woodger
  • 12,968
  • 4
  • 38
  • 47
  • 1
    I guess the VALUE is here for informations purposes(seems a carriage returne, btw). But I agree with you : while recursion in some languages is sexy, it is not a good idea in COBOL. At all. And it's done with an exit that breaks the flow of execution, so it's not even proper recursion. Even proper recursion, though, shall not be used, as you said. And this variable named "X". Aaaaargh. – gazzz0x2z Aug 25 '16 at 12:37
  • 2
    @gazzz0x2z I know what the /n is intended to be, but COBOL is a compiled language, "text" of /n at run-time is just that. Text :-) – Bill Woodger Aug 25 '16 at 13:39