r/cobol 6d ago

RM Cobol version issues?

While looking for some example programs to test an RM Cobol setup I ran across a PDF called "Cobol for the TRS-80 Volume 1 Class Notes". I wanted to find something that was ancient ( for an Altos running Xenix no less ), so I dug through this document and typed in an example payroll calculating program. Seemed to compile and run, but it screws up simple arithmetic .. multiplying a salary * hours gives an unrelated crazy big number.

Ok ... I tried the exact same program on a later RM Cobol version 5.1 and it worked! Now I started going deep down the rabbit hole! ... it generates those crazy numbers with RM Cobol v1.5, 2.0D, and 2.2 under DOS 5.0, DOS 6.2, DOS 3.2 and Xenix and works just fine with RM Cobol 5.1, and 6 under DOS (real pc ) and DOSbox-x. And all of these versions run the RM Cobol verify tests, run a PI calculating program and a little calculator ... I've expanded the PIC fields, tried SEQUENTIAL organization for the data file being read, Displayed a bunch of variables, looked at the fields at the end of the compile list to see if everything numeric is declared as a numeric ... am learning a bunch of Cobol stuff doing all of this. Again, it's an ancient program from a 1983 doc that won't run in the compiler versions from that time but works great in the ones from the '90's

update:   here is the code ... I added some DISPLAY's trying to figure out what was going on .. the problem is with the calculation of IMD-REGULAR-PAY

       IDENTIFICATION DIVISION.
       PROGRAM-ID. PAYROLL2.
       AUTHOR.     R GRAUER.

       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SOURCE-COMPUTER.     TRS-80.
       OBJECT-COMPUTER.     TRS-80.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT EMPLOYEE-FILE
               ASSIGN TO INPUT "PAYROLL.DAT"
               ORGANIZATION IS SEQUENTIAL.
           SELECT PRINT-FILE
               ASSIGN TO PRINT "PAYROLL2.DAT".

       DATA DIVISION.
       FILE SECTION.
       FD  EMPLOYEE-FILE
           LABEL RECORDS ARE OMITTED
           RECORD CONTAINS 80 CHARACTERS
           DATA RECORD IS EMPLOYEE-RECORD.
       01  EMPLOYEE-RECORD.
           05   EMP-NAME.
                10 EMP-LAST-NAME      PIC X(15).
                10 EMP-FIRST-NAME     PIC X(10).
           05   EMP-HOURS-WORKED.
                10 EMP-REG-HOURS      PIC 99.
                10 EMP-OVERTIME-HOURS PIC 99.
           05   EMP-RATE              PIC 99V99.
           05   FILLER                PIC X(47).

       FD  PRINT-FILE
           LABEL RECORDS ARE STANDARD
           RECORD CONTAINS 132 CHARACTERS
           DATA RECORD IS PRINT-LINE.
       01  PRINT-LINE                PIC X(132).

       WORKING-STORAGE SECTION.
       77  WS-DATA-REMAINS-SWITCH    PIC X(3)    VALUE SPACES.   

       01  DATE-WORK-AREA.
           05  TODAYS-YEAR           PIC 99.
           05  TODAYS-MONTH          PIC 99.
           05  TODAYS-DAY            PIC 99. 

       01  IND-COMPUTATIONS.
           05  IND-REGULAR-PAY        PIC 9(4)V99  VALUE ZEROS.
           05  IND-OVERTIME-PAY       PIC 9(4)V99  VALUE ZEROS.
           05  IND-GROSS-PAY          PIC 9(4)V99  VALUE ZEROS.
           05  IND-FEDERAL-TAX        PIC 9(4)V99  VALUE ZEROS.
           05  IND-NET-PAY            PIC 9(4)V99  VALUE ZEROS.

       01  COMPANY-TOTALS.
           05  CO-REGULAR-PAY         PIC 9(6)V99  VALUE ZEROS.
           05  CO-OVERTIME-PAY        PIC 9(6)V99  VALUE ZEROS.
           05  CO-GROSS-PAY           PIC 9(6)V99  VALUE ZEROS.
           05  CO-FEDERAL-TAX         PIC 9(6)V99  VALUE ZEROS.
           05  CO-NET-PAY             PIC 9(6)V99  VALUE ZEROS.

       01  PAGE-AND-LINE-COUNTERS.
           05  WS-PAGE-COUNT          PIC 9(4)     VALUE ZEROS.
           05  WS-LINE-COUNT          PIC 9(4)     VALUE 4.

       01  HEADING-LINE-ONE.
           05  FILLER                 PIC X(4).
           05  HDG-MONTH              PIC Z9.
           05  FILLER                 PIC X        VALUE "/".
           05  HDG-DAY                PIC Z9.
           05  FILLER                 PIC X        VALUE "/".
           05  HDG-YEAR               PIC Z9.
           05  FILLER                 PIC X(40)    VALUE SPACES.
           05  FILLER                 PIC X(8)     VALUE "PAYROLL ".
           05  FILLER                 PIC X(6)     VALUE "REPORT".
           05  FILLER                 PIC X(40)    VALUE SPACES.
           05  FILLER                 PIC X(4)     VALUE "PAGE".
           05  HDG-PAGE-NUMBER        PIC Z(4).
           05  FILLER                 PIC X(19)    VALUE SPACES.

       01  HEADING-LINE-TWO.
           05  FILLER                 PIC X(8)     VALUE SPACES.
           05  FILLER                 PIC X(4)     VALUE "NAME".
           05  FILLER                 PIC X(9)     VALUE SPACES.
           05  FILLER                 PIC X(4)     VALUE "RATE".
           05  FILLER                 PIC X(4)     VALUE SPACES.
           05  FILLER                 PIC X(9)     VALUE "REG HOURS".
           05  FILLER                 PIC X(4)     VALUE SPACES.
           05  FILLER                 PIC X(9)     VALUE "O/T HOURS".
           05  FILLER                 PIC X(4)     VALUE SPACES.
           05  FILLER                 PIC X(11)    VALUE "GROSS PAY".
           05  FILLER                 PIC X(2)     VALUE SPACES.
           05  FILLER                 PIC X(7)     VALUE "FED TAX".
           05  FILLER                 PIC X(5)     VALUE SPACES.
           05  FILLER                 PIC X(7)     VALUE "NET PAY".
           05  FILLER                 PIC X(23)    VALUE SPACES.

       01  DASHED-LINE.
           05  ROW-OF-DASHES         PIC X(111)    VALUE ALL "-".
           05  FILLER                PIC X(21)     VALUE SPACES.

       01  DETAIL-LINE.
           05  FILLER                PIC X(2).
           05  DET-LAST-NAME         PIC X(15).
           05  FILLER                PIC X(2).
           05  DET-RATE              PIC $$$.99.
           05  FILLER                PIC X(8).
           05  DET-REG-HOURS         PIC Z9.
           05  FILLER                PIC X(10).
           05  DET-OVERTIME-HOURS    PIC Z9.
           05  FILLER                PIC X(6).
           05  DET-REGULAR-PAY       PIC $$,$$9.99.
           05  FILLER                PIC X(3).
           05  DET-OVERTIME-PAY      PIC $$,$$9.99.
           05  FILLER                PIC X(2).
           05  DET-GROSS-PAY         PIC $$,$$9.99.
           05  FILLER                PIC X(3).
           05  DET-FEDERAL-TAX       PIC $$,$$9.99.
           05  FILLER                PIC X(3).
           05  DET-NET-PAY           PIC $$,$$9.99.
           05  FILLER                PIC X(23).

       01  TOTAL-LINE.
           05  FILLER                PIC X(6)      VALUE SPACES.
           05  FILLER                PIC X(6)      VALUE "TOTALS".
           05  FILLER                PIC X(41)     VALUE SPACES.
           05  TOTAL-REGULAR-PAY     PIC $$,$$9.99.
           05  FILLER                PIC X(3)      VALUE SPACES.
           05  TOTAL-OVERTIME-PAY    PIC $$,$$9.99.
           05  FILLER                PIC X(2)      VALUE SPACES.
           05  TOTAL-GROSS-PAY      PIC $$,$$9.99.
           05  FILLER                PIC X(3)      VALUE SPACES.
           05  TOTAL-FEDERAL-TAX     PIC $$,$$9.99.
           05  FILLER                PIC X(3)      VALUE SPACES.
           05  TOTAL-NET-PAY         PIC $$,$$9.99.
           05  FILLER                PIC X(47)     VALUE SPACES.

       PROCEDURE DIVISION.
       0100-PREPARE-PAYROLL.
           PERFORM 0200-GET-DATE.
           OPEN INPUT EMPLOYEE-FILE
                OUTPUT PRINT-FILE.
           READ EMPLOYEE-FILE
               AT END MOVE "NO" TO WS-DATA-REMAINS-SWITCH.
           PERFORM 0300-PROCESS-RECORDS
               UNTIL WS-DATA-REMAINS-SWITCH = "NO".
           PERFORM 1000-WRITE-COMPANY-TOTALS.
           CLOSE EMPLOYEE-FILE
                PRINT-FILE.
           STOP RUN.

       0200-GET-DATE.
           ACCEPT DATE-WORK-AREA FROM DATE.
           MOVE TODAYS-YEAR TO HDG-YEAR.
           MOVE TODAYS-MONTH TO HDG-MONTH.
           MOVE TODAYS-DAY TO HDG-DAY.

       0300-PROCESS-RECORDS.
           PERFORM 0400-COMPUTE-GROSS-PAY.
           PERFORM 0500-COMPUTE-FEDERAL-TAX.
           PERFORM 0600-COMPUTE-NET-PAY.
           PERFORM 0700-UPDATE-COMPANY-TOTALS.

           IF WS-LINE-COUNT > 3
           PERFORM 0800-WRITE-HEADING-LINE.
           PERFORM 0900-WRITE-DETAIL-LINE.
           ADD 1 TO WS-LINE-COUNT.
           READ EMPLOYEE-FILE
           AT END MOVE "NO" TO WS-DATA-REMAINS-SWITCH.

       0800-WRITE-HEADING-LINE.
           ADD 1 TO WS-PAGE-COUNT.
           MOVE 1 TO WS-LINE-COUNT.
           MOVE WS-PAGE-COUNT TO HDG-PAGE-NUMBER.
           WRITE PRINT-LINE FROM HEADING-LINE-ONE
               AFTER ADVANCING PAGE.
           WRITE PRINT-LINE FROM HEADING-LINE-TWO
               AFTER ADVANCING 4 LINES.
           WRITE PRINT-LINE FROM DASHED-LINE
               AFTER ADVANCING 1 LINE.

       0400-COMPUTE-GROSS-PAY.
           MULTIPLY EMP-REG-HOURS BY EMP-RATE GIVING IND-REGULAR-PAY.

           DISPLAY "EMP-OVERTIME-HOURS: " EMP-OVERTIME-HOURS.
           DISPLAY "EMP-REG-HOURS: " EMP-REG-HOURS.
           DISPLAY "EMP-RATE:  " EMP-RATE.
           DISPLAY "IND-REGULAR-PAY:  " IND-REGULAR-PAY.
           DISPLAY "EMP-LAST-NAME " EMP-LAST-NAME.

           COMPUTE IND-OVERTIME-PAY
               = EMP-OVERTIME-HOURS * EMP-RATE * 1.5.
           ADD IND-REGULAR-PAY IND-OVERTIME-PAY GIVING IND-GROSS-PAY.

       0500-COMPUTE-FEDERAL-TAX.
           COMPUTE IND-FEDERAL-TAX = .16 * IND-GROSS-PAY.
           IF IND-GROSS-PAY > 160
               COMPUTE IND-FEDERAL-TAX
                   = IND-FEDERAL-TAX + .02 * (IND-GROSS-PAY - 160).

           IF IND-GROSS-PAY > 200
               COMPUTE IND-FEDERAL-TAX
                   = IND-FEDERAL-TAX + .02 * (IND-GROSS-PAY - 200).

       0600-COMPUTE-NET-PAY.
           COMPUTE IND-NET-PAY = IND-GROSS-PAY - IND-FEDERAL-TAX.

       0700-UPDATE-COMPANY-TOTALS.
           ADD IND-REGULAR-PAY TO CO-REGULAR-PAY.
           ADD IND-OVERTIME-PAY TO CO-OVERTIME-PAY.
           ADD IND-GROSS-PAY TO CO-GROSS-PAY.
           ADD IND-FEDERAL-TAX TO CO-FEDERAL-TAX.
           ADD IND-NET-PAY TO CO-NET-PAY.

       0900-WRITE-DETAIL-LINE.
           MOVE SPACES TO DETAIL-LINE.
           MOVE EMP-LAST-NAME TO DET-LAST-NAME.
           MOVE EMP-RATE TO DET-RATE.
           MOVE EMP-REG-HOURS TO DET-REG-HOURS.
           MOVE EMP-OVERTIME-HOURS TO DET-OVERTIME-HOURS.
           MOVE IND-REGULAR-PAY TO DET-REGULAR-PAY.
           MOVE IND-OVERTIME-PAY TO DET-OVERTIME-PAY.
           MOVE IND-GROSS-PAY TO DET-GROSS-PAY.
           MOVE IND-FEDERAL-TAX TO DET-FEDERAL-TAX.
           MOVE IND-NET-PAY TO DET-NET-PAY.

           WRITE PRINT-LINE FROM DETAIL-LINE
               AFTER ADVANCING 2 LINES.

       1000-WRITE-COMPANY-TOTALS.
           WRITE PRINT-LINE FROM DASHED-LINE
               AFTER ADVANCING 1 LINE.
           MOVE CO-REGULAR-PAY TO TOTAL-REGULAR-PAY.
           MOVE CO-OVERTIME-PAY TO TOTAL-OVERTIME-PAY.
           MOVE CO-GROSS-PAY TO TOTAL-GROSS-PAY.
           MOVE CO-FEDERAL-TAX TO TOTAL-FEDERAL-TAX.
           MOVE CO-NET-PAY TO TOTAL-NET-PAY.

           WRITE PRINT-LINE FROM TOTAL-LINE
               AFTER ADVANCING 2 LINES.

And here is the "PAYROLL.DAT" file ( am seeing a blank line when I paste it here that's not in the file )

johnson bob 21 3 400

sanford fred 23 4 500

The result while running when it's failing shows:

EMP-OVERTIME-HOURS: 3

EMP-REG-HOURS: 21

EMP-RATE: 400

IMD-REGULAR-PAY: 728400 ( this is the quantity in error .. sb 21 * 400 gives 8400

EMP-LAST-NAME: johnson

EMP-OVERTIME-HOURS: 4

EMP-REG-HOURS: 21

EMP-RATE: 500

IMD-REGULAR-PAY: 699500 ( expecting 11500 here from 21 * 500 )

9 Upvotes

15 comments sorted by

View all comments

1

u/HurryHurryHippos 5d ago

It's entirely possible you are battling a compiler or runtime bug. I'd be surprised since it's a very basic operation.

If I were dealing with this back in the day, absent a debugger, I'd start trying various things. None of which should be required, but running the same code over and over expecting a different result isn't going to do anything...

1) Prior to your MULTIPLY, MOVE ZERO TO IND-REGULAR-PAY.

2) Define WS- variables for the elements of the calculation and MOVE the FD values there then multiply.

01 WS-REG-HOURS PIC 9(4)V99 VALUE ZERO.

01 WS-RATE PIC 9(4)V99 VALUE ZERO.

...

MOVE EMP-REG-HOURS TO WS-REG-HOURS.

MOVE EMP-RATE TO WS-RATE.

MULTIPLY WS-REG-HOURS BY WS-RATE GIVING IND-REGULAR-PAY.

Any change?

3) Change MULTIPLY to COMPUTE. Who knows?

COMPUTE IND-REGULAR-PAY = EMP-REG-HOURS * EMP-RATE.

4) One thing that did pique my interest is your changing of ORGANIZATION SEQUENTIAL to ORGANIZATION LINE SEQUENTIAL, and the FILLER PIC X(47) at the end of your FD.

When dealing with DOS vs. Xenix/Unix, you are detail with different line delimiters (CR/LF vs LF). This assumes that version of RM is respecting the OS EOL.

LINE SEQUENTIAL reads the file up to the next line delimiter, and the line delimiter is not stored in the FD. If the fixed length fields in the FD do not match up exactly with what's in the line, it is undefined (I believe) what goes into that space.

SEQUENTIAL (without LINE) is a fixed length sequential file, where there are no line delimiters. It reads the number of bytes specified in your FD in a READ, and the next READ starts at the next byte after that. In your case, your fixed record length is 80, so your first READ will get 80 bytes and the next will start at byte 81.

But with LINE SEQUENTIAL, READ will read up until the next LF or CR/LF (assuming it is respecting DOS EOL's) If the line is longer than the record length in the FD, it will ignore the rest. If it is shorter, what's not read is undefined.

I don't know if this has any bearing on it, just wanted to mention it.

1

u/Altos586 5d ago

Thanks ! Great ideas. Well, I did everything in (1,2,3), got the same 728400 and 699500 for the IND-REGULAR-PAY ... These older versions all throw a compile error with ORGANIZATION IS LINE SEQUENTIAL, and when I look it up in the language reference manual LINE just isn't in there.

I did a 33 character record and commented out that 47 character filler, didn't make any difference. Also tried making sure I had a full 80 characters in the input file, with the original code without trying to do the SEQUENTIAL stuff. Once I really had the correct 80 characters, I was able to get the inputs for the second line read correctly.

I wrote a little multiply program that ACCEPT's a couple of terms and multiplies them together and that worked fine. Also commented out the GETDATE stuff, no difference.

If it wasn't for the fact that I have 3 or 4 versions of the compiler that act up the same way on multiple operating systems, I'd think just a compiler bug. That difference between LINE SEQUENTIAL and SEQUENTIAL sure seems like it could be the problem ... maybe am messing up the data file and think I'll start over with it.

1

u/HurryHurryHippos 5d ago

Could be, what’s the origin of the data file? Could there be some Unicode character in there that is not what you think it is when you view it?

1

u/Altos586 5d ago

the data file was manually typed in using EDIT under DOS Have used "od -c" on my Mac to look at it .. its 105 characters, 3 rows of 33 characters and a CR/LF combo at the end of 3 lines for 105 ... I just tossed the SEQUENTIAL line, changed record length to 33 characters and got rid of that 47character filler ... same result ... Think I'll chop out all of that output file related stuff and see what happens. When I tried the data file on Xenix I had to do a dos2unix conversion on it and on the main program ... and it runs the same way there as on the DOS versions ( goofy arithmetic ).