Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Common COBOL Errors 1

Status
Not open for further replies.

3gm

Programmer
Mar 7, 2001
437
US
All -

I've recently been "dumpster diving" in some old, production code and turned up a number of common errors that persist in the code to this day. That set me thinking about common traps that COBOL programmers, especially beginners, fall into. I figured that topic might be worthy of a FAQ. Some of my nominees include:

1. A general failure to initialize variables before use.

2. Failing to zero the counter before an INSPECT . . . TALLYING.

3. Failing to initialize the receiving item to spaces before a STRING statement.

4. Moving a group item to an alphanumeric edited item.

5. Failing to set the index appropriately before a SEARCH verb.

6. Failing to use parentheses where needed in logical expressions containing a mixture of logical operators.

7. Failing to check FILE-STATUS after every I/O operation.

Are there other common pitfalls you think I might include?

(Obviously, a well-done FAQ will include examples and additional narrative. I'm simply looking for more problems to include.)

Regards.

Glenn
 
Some other errors (usually from "beginning" programmers)

A) Failure to provide logic for empty input files (coding for "AT END" on first read)

B) Problems with handling of last input record (processed twice or not at all). Reading "buffers" after a file is closed.

C) testing a numeric field agains (> or <) than a value BEFORE checking that it is numeric, e.g.

If (Num-Field < 5) or (Num-Field not Numeric)

D) Failure to check "validity" of fields used as arguments to intrinsic functions, e.g.
20041332
as a date field.

E) Inserting a NEW paragraph name in the middle of a paragraph names that are referenced in a single PERFORM THRU

F) Not knowing (or thinking about) performance:
- high-level for application design
- micro-level for "tight loops" where lots of processing is done

Instead, worrying about performance of routines (or statements) that are only performed once or trice per program execution.

Bill Klein
 
I differentiate between:

[A] Syntactical (or grammatical) errors.
All syntactical errors are detected by the compiler.

Semantical (or logical) errors.
Almost all semantical errors are language independent logic errors.

[C] Usability errors.
All 'things' grammatically and syntactical correct but practically unusable (such as excessive storage requirements, excessive I/O, excessive processor requirements, etc...).



[semantical]
Not knowing (or realising) the rounding or truncation rules of the intermediate results in the COMPUTE statement.

[semantical]
(Similar) Not knowing the move rules between fields of unequal type or size.

[grammatical/semantical]
(N.B. should be intercepted by the compiler but isn't!)
Table index addressing beyound the table size.

[semantical]
When divide is used; not testing on division by zero (both in the code as well as in the test phase).

[semantical]
(N.B. some incorrect variants may be detected by the compiler)
- formally - Missing or incorrect termination condition of the loop invariant.
- informally - infinite loops.

[sematical]
Number, type or size of parameters passed to a subroutine does not stroke with the number, type or size of parameters addressed by, and used in, the called subroutine.



...those are the once I can think of for the moment.
Note: that none of the above are really grammatical errors.
That is, any grammatical error is 'stopped' by the compiler. As a result most grammatical errors are not worth mentioning (in my opinion).


Regards, Wim Ahlers.
 
Not coding for overloading a table.

Not signing fields that will be used in monetary calcualtions.
 
Hmmmm ...

How about :

Failure to use a PERFORM instead of a GOTO?

[smile]

.DaviD.
 
Failure to recompile the Run unit after a bug correction...
 
I've encountered just about all of the previously-mentioned "gotchas" in my 25 years of programming, but I'd like to add a couple more:

#1) Always provide an "else" fall-through condition when processing multiple record types.
(See #1 Detail below.)

#2) Prioritize the sequence of processing record types, putting the most common first, ending with the least common.
(See #2 Detail below.)


#1 Detail) Your input data may include 4 record types, so you code:

IF REC-TYPE = 'A'
PERFORM 1100-PROCESS-REC-A
ELSE
IF REC-TYPE = 'B'
PERFORM 1200-PROCESS-REC-B
ELSE
IF REC-TYPE = 'C'
PERFORM 1300-PROCESS-REC-C
ELSE
PERFORM 1400-PROCESS-REC-D.

What happens if the source process of your data changes and an 'E' record mysteriously appears? Using the above code, it would be processed as a 'D' record. If you had been a little more explicit and coded:

IF REC-TYPE = 'A'
PERFORM 1100-PROCESS-REC-A
ELSE
IF REC-TYPE = 'B'
PERFORM 1200-PROCESS-REC-B
ELSE
IF REC-TYPE = 'C'
PERFORM 1300-PROCESS-REC-C
ELSE
IF REC-TYPE = 'D'
PERFORM 1400-PROCESS-REC-D.

the 'E' record wouldn't get processed at all.

You ALWAYS need to provide a "fall-through" check, to trap something that you're not expecting, like this:

IF REC-TYPE = 'A'
PERFORM 1100-PROCESS-REC-A
ELSE
IF REC-TYPE = 'B'
PERFORM 1200-PROCESS-REC-B
ELSE
IF REC-TYPE = 'C'
PERFORM 1300-PROCESS-REC-C
ELSE
IF REC-TYPE = 'D'
PERFORM 1400-PROCESS-REC-D
ELSE
DISPLAY ' UNKNOWN RECORD TYPE: '
REC-TYPE
MOVE 'Y' TO REC-TYP-ERR-FLAG
... followed by code to do whatever
it is that you want to do when you
find an error, be it simply count
the number of unexpected records
or abend the program, or whatever...

This holds true whether you use a nested IF statement, as shown above, or an EVALUATE statement.

EVALUATE REC-TYPE
WHEN 'A'
PERFORM 1100-PROCESS-REC-A
WHEN 'B'
PERFORM 1200-PROCESS-REC-B
WHEN 'C'
PERFORM 1300-PROCESS-REC-C
WHEN 'D'
PERFORM 1400-PROCESS-REC-D
WHEN OTHER
PERFORM 1500-PROCESS-UNKNOWN-REC.


#2 Detail) When processing data with multiple record types or some similar distinction between "records", prioritize the processing of those data types. A number of years ago I took a program that had been in production for several years and did a little analysis and found that, of the 100 different record types that were being processed (record types '00' through '99'), over half of the data was record type '90', with '95' the second most common record type. The program was using a large nested IF statement like this:

IF REC-TYPE = '00'
PERFORM 100-PROCESS-REC-00
ELSE
IF REC-TYPE = '01'
PERFORM 101-PROCESS-REC-01
ELSE
IF REC-TYPE = '02'
PERFORM 102-PROCESS-REC-02
IF REC-TYPE = '03'
PERFORM 103-PROCESS-REC-03
ELSE
....
ELSE
IF REC-TYPE = '99'
PERFORM 199-PROCESS-REC-99.

(There was also no trapping of record types other than '00' through '99'.)

The data file being processed contained millions of records, so the time wasted in wading through all of the IFs was very significant. I changed the code to:

IF REC-TYPE = '90'
PERFORM 190-PROCESS-REC-90
ELSE
IF REC-TYPE = '95'
PERFORM 195-PROCESS-REC-95
ELSE
IF REC-TYPE = '37' (the 3rd most common record type)
PERFORM 137-PROCESS-REC-37
ELSE
IF REC-TYPE = '20' (the 4th most common record type)
PERFORM 120-PROCESS-REC-20
ELSE
.....
ELSE
IF REC-TYPE = '43' (the least common record type)
PERFORM 143-PROCESS-REC-43
ELSE
PERFORM 200-UNKNOWN-RECORD-TYPE.

After I made these simple changes to the program, the run time dropped from over 2 hours per day, on average, to 5-10 minutes. I got a big thank-you from my manager, and a nice bonus. :>)

Rich (in Minn.)
 
One more, that actually came to mind when I saw the above example :

Never use a period in the middle of a paragraph. There should only ever be one period in a paragraph, and that's at the end of it. Scope delimiters were invented for a reason. Use them :)

It's incredibly frustrating to try and find out what's wrong when a period was inadvertently removed, and since it terminated (for example) a group of six nested IFs, all the logic after that nest is affected. Proper use of END-IFs solves this.

.DaviD.
 
To continue on richinmin's discussion...

Use else even when you don't use it (yet!!!).
(example).

IF condition
, PERFORM doStuff
ELSE
, CONTINUE
END-IF

To: richinmin

Using your particular example:
Maybe you can nock off another minute or so by using the depending on ... go to instruction.
Given certain requirements of course...the record type should be numeric only now and in the future.
Plus you need to code a fall through instruction.
Assuming these conditions are met then you can keep the normal numeric order and when record type 50 is the favorite next year it will still be as fast.

Note:
depending on ... go to - is limited in usage.
Given certain conditions I have an alternative that does not need the condition to be numeric and is only limited by the number of nested programs that are allowed within one program.
 
Wahlers,

depending on ... go to - is limited in usage.
Depends.

I have written a program in COBOL-74 that heavly relied on this associated with a "perform ... varying".
Doing otherwyse would have required over 200 IF's in several programs.


Using depending on on the case RICHINMINN mentioned would work, but would it have the same impact on speed? if the highest performers took 90% of more of the occurrences maybe not.


davidk13

Using or not periods on the middle of paragraphs is style related issue only, not really a "Common COBOL Errors".



Regards

Frederico Fonseca
SysSoft Integrated Ltd
 
Davidk13

The using of points means end of and instruction, I strongly recommend to used

IF REC-TYPE = '90'
PERFORM 190-PROCESS-REC-90
ELSE
IF REC-TYPE = '95'
PERFORM 195-PROCESS-REC-95
ELSE
IF REC-TYPE = '37' (the 3rd most common record type)
PERFORM 137-PROCESS-REC-37
ELSE
IF REC-TYPE = '20' (the 4th most common record type)
PERFORM 120-PROCESS-REC-20
ELSE
IF REC-TYPE = '43' (the least common record type)
PERFORM 143-PROCESS-REC-43
ELSE
PERFORM 200-UNKNOWN-RECORD-TYPE
END-IF <----Insert this instead
.
and used the point "." as you last line or paragraph ending, this will save you a lot of headached you you placed a "." point in the wrong place, if you are refering to this point ".", and when you consolidate you IF when you reach the condition you the PERFORM is executed and you don't have to go thru another IF, imagine doing and extra instruction when you have couple of million of records, you are doing an extra innecesary operation.

Also try to use structured programming, avoiding the use of "GO TO" or "GO", and use PERFORM instead this way it's better to follow the program logic instead using COBOL-SPAGHETTI




Regards

Vinicio Aizpurua
25 Years Programming in Cobol
 
Sorry, versys. I disagree completely. Allowing the use of a period anywhere other than at the end of a paragraph was a bad idea on the part of the ANSI standards people, which is only slightly worse than the #1 mistake - the GOTO.

First of all, the IF statement you show above should be indented as follows:

Code:
IF REC-TYPE = '90'
  PERFORM 190-PROCESS-REC-90
ELSE
  IF REC-TYPE = '95'
    PERFORM 195-PROCESS-REC-95
  ELSE
    IF REC-TYPE = '37' (the 3rd most common record type)
      PERFORM 137-PROCESS-REC-37
    ELSE
      IF REC-TYPE = '20' (the 4th most common record type)
        PERFORM 120-PROCESS-REC-20
      ELSE
        IF REC-TYPE = '43' (the least common record type)
          PERFORM 143-PROCESS-REC-43
        ELSE
          PERFORM 200-UNKNOWN-RECORD-TYPE
        END-IF
      END-IF
    END-IF
  END-IF
END-IF

This code is way more readable (and easier to debug) than one that does not use indentation and lacks the necessary scope delimiters.

Any good programmer's next comment would now obviously be regarding the limit of nested IF's. Namely, how many do you put before your code becomes ugly? Do you nest 10 IFs? 15? 20?

In my experience, I've always tried to limit it to 3 or 4 levels max. If I need more than that, then I automatically switch to an EVALUATE, which makes things a lot clearer. The above code would then look like this:

Code:
EVALUATE REC-TYPE
WHEN'90'
  PERFORM 190-PROCESS-REC-90
WHEN '95'
  PERFORM 195-PROCESS-REC-95
WHEN '37'
  PERFORM 137-PROCESS-REC-37
WHEN '20'
  PERFORM 120-PROCESS-REC-20
WHEN '43' 
  PERFORM 143-PROCESS-REC-43
WHEN OTHER
  PERFORM 200-UNKNOWN-RECORD-TYPE
END-EVALUATE

What do you think?

.DaviD.
 
David,

What I meant is, do not or try not to end an if by period "." use if-then-else-end-if, and OF COURSE, I agree with you in not to use that many level of nested IF, and totally agree with you in the use of EVALUATE when you have more than 4 levels, and I just COPIED and PASTED the instructions, and also agree with use INDENTATION.
I was not talking about beutifying the way of coding, the use of INDENTATION and comments in your programs, represent the respect that you have for others when thry have to check or mantain your programs, so you are right about INDENTATION and use of EVALUATE instead nested IF for more than 4 or 5 levels.

About the period do not misunderstand me, at the end of paragraph or whole set of instructions or routine, before the next level, a period "." in the wrong place is a headache.

Good point..... yours.....

Regards


Vinnie

 
Versys

Glad to see there are other pgmrs out there that appreciatre a good and clean set of code [smile].

One last thing - how about the case people code in? I realise that it was pretty much an unspoken rule way back when that COBOL programs were always written in uppercase. But ever since I started coding in the language professionaly, I found I prefered coding in lowercase, which made the code much more readable and clear. It also opened up the opportunity for using mixed cases when declaring variable and paragraph names.

Sorry 3GM - I know this isn't exactly a coding error, so it doesn't exactly follow your initial train of thought, but these postings always have a way of digresing and taking on a life of their own ...

.DaviD.
 
To: Frederico Fonseca

With limited usage I mean the goto...depending on is limited to numbers only (which makes sense because internally it is resolved with an offset instruction).
You can bypass this logic using a nested program approach. This is far more flexible but was not possible before COBOL-85.
There might even be a nicer way in COBOLO 2002, I don't know. But then you would probably not need it anyway because then you will work with objects and use the object identity.


Regards, Wim Ahlers.
 
If you are using "free format" source code, having a stray character "off screen" to the right. It produces a syntax error, but does not show on the listing.
 
To: webrabbit

Free format...???? :) :) :)

I am forced to admit that I am from the 'old' school.
I still stick to the old fashioned number-A-B-comment region.
First, because the compiler did not support free format, and later because I cannot easily read left right zapped text (dislexic).
 
That's a real shame, wahlers. There's nothing nicer than being able to code in TERMINAL mode (which is what I think webrabbit is referring to). The ability to code beyond col 72 and not have to worry about your code being cut off is a huge relief [smile]

The only bummer I'm facing on my end (I'm using Acu Cobol v6.1 on windows) is that although the compiler supports TERMINAL format, their debugger doesn't (at least not fully). Go figure. When I'm debugging a pgm in this format, I can't see the code byond col 72, can't double click on a variable to query it's value, etc. Very annoying.

.DaviD.
 
SOURCEFORMAT"FREE" is the Micro Focus compiler directive. I don't know what it is called in other dialects. As david says it is TERMINAL mode for Acu COBOL.

Mico Focus' debugger (called Animator) has the same problem, except it is limited to column 80. It hasn't been too much of a problem, however, because my procedure code rarely extends past column 80. What's usually out there is non-numeric literals.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top