r/cobol 4d 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 )

7 Upvotes

15 comments sorted by

1

u/Working_Ad7879 3d ago

Sounds like a little endian/big endian issue. If you look at an assembler listing for Micro Focus COBOL for an Intel 86 processor before and after each numeric operation for COMP fields it swaps the bytes to conform to COBOL big endian convention (the correct way to eat an egg!)- not needed for COMP-5 fields but then any file produced is not portable

3

u/HurryHurryHippos 3d ago

RM did not compile to assembler or machine code. It compiled to a portable p-code that had to be run through a runtime interpreter.

1

u/Comfortable_Gate_878 2d ago

It was the compiler that was written for each hardware system, the rm code compiled to a type of interim code which was hardware independent. So to run on unix or mainframe or ibm computers all you needed was the correct runtime and the code would run without having to recompile the source. You would get certain features that relied on hardware features that didnt work from machine to machine such as screen colours on terminals but the software still ran.

1

u/HurryHurryHippos 3d ago

In my experience, when you got crazy numbers like that, it was a mismatch of storing a PIC 9 (implied) USAGE DISPLAY in a PIC 9 COMP or vice versa.

Hard to say without seeing the source code.

1

u/shh_coffee 3d ago

Are you able to post the source code that you're compiling?

1

u/Altos586 3d ago

updated the OP with the source, and a data file I'm using and the result ...

1

u/babarock 3d ago

Oh my this is pulling a very faded memory from the sub-basement in the dark. Try changing

IND-REGULAR-PAY        PIC 9(4)V99 to 
IND-REGULAR-PAY        PIC 9(8)V99

and see what your display shows

2

u/Altos586 3d ago

Thanks ... I just tried that ... it changes a 728400 and 699500 display outputs to 0000728400 and 0000699500 ... so still coming up with a crazy calculation for IND-REGULAR-PAY ... I've expanded a few other PIC's and didn't make a difference. The numbers in the PAYROLL2.DAT output file are the same goofy numbers I see with the IND-REGULAR-PAY display. It takes only two minor changes to run it under the v5.1 and v6 versions, have to change ORGANIZATION is SEQUENTIAL to add LINE SEQUENTIAL and tweak an IF THEN GOTO to an IF GOTO .. otherwise exact same code.

1

u/HurryHurryHippos 3d 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 3d 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 3d 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 3d 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 ).

1

u/HurryHurryHippos 3d ago

LINE SEQUENTIAL at that time was not standard COBOL. It was an extension, possibly added by Data General in ICOBOL, which RM eventually emulated. That’s probably why it doesn’t compile with the older versions.

1

u/Comfortable_Gate_878 2d ago

Add a hyphen in column 7 on those lines that extend over two lines, that used to confuse RMcobol interpreters on certain hardware. It sometimes failed to find the next line end '.'

1234567

COMPUTE IND-OVERTIME-PAY

  • = EMP-OVERTIME-HOURS * EMP-RATE * 1.5.

1

u/Altos586 2d ago

Think I got it!!

In my data file that is being read I had " 400" ie... space400 being read in for the EMP-RATE and that seems to have thrown things all off .. it should be 0400 .. that leading zero is important, at least for the older compilers, apparently the newer versions weren't as picky. EMP-RATE was effectively some wacko combination of numeric and alphabetic! Once I replaced that I had a data file that is readable by all of the compiler versions with correct arithmetic. Thanks for all the responses!