Inside COBOL
by
Shawn M. Gordon
President S.M.Gordon & Associates
I am going to touch on some various general tips this month. Some of
this will be obvious to a lot of you, but for those of you who don’t
know it, it will be a real treat. I was recently talking with a friend
of mine who is also a COBOL programmer, and the subject of stripping
leading spaces, or all spaces in a string came up. It turns out he
had tried to do this many times over the years but never could make
it work. He had been trying syntax such as.
01 IN-BUFF PIC X(40) VALUE SPACES. DISPLAY 'Enter a string: ' NO ADVANCING. ACCEPT IN-BUFF FREE. INSPECT IN-BUFF CONVERTING ' ' TO ''. DISPLAY IN-BUFF. STOP RUN. If you try to compile this however, you will get the following message from the compiler; /COBOLIIX(ALL),,$NULL PAGE 0001 HP32233A.02.03 <[>85] Copyright Hewlett-Packard CO. 1989 LINE SEQ COL ERROR SEV TEXT ------------------------------------------------------------------------------ 00030 002600 53 104 Q NULL LITERAL NOT ALLOWED; REPLACED BY SPACE. 0 ERROR(s), 1 QUESTIONABLE, 0 WARNING(s) DATA AREA IS %000237 WORDS. CPU TIME = 0:00:00. WALL TIME = 0:00:00. END OF COMPILE
Now this seemed like a fairly logical syntax since most editors will
let you do something like that. The COBOL compiler doesn’t like it
when you try to replace values of different lengths with the INSPECT
statement. So what is the answer here?
01 IN-BUFF PIC X(40) VALUE SPACES. DISPLAY 'Enter a string: ' NO ADVANCING. ACCEPT IN-BUFF FREE. * * The next statement will remove all spaces from the string INSPECT IN-BUFF CONVERTING ' ' TO LOW-VALUES. DISPLAY 'No spaces ' IN-BUFF. DISPLAY 'Enter a string: ' NO ADVANCING. ACCEPT IN-BUFF FREE. * * The next statement will strip leading spaces from the string INSPECT IN-BUFF REPLACING LEADING ' ' BY LOW-VALUES. DISPLAY 'No leading spaces ' IN-BUFF. STOP RUN.
The reserved word ‘LOW-VALUES’ will put a NULL character in the area where the space was. You could also specify %0 (octal zero) and get the same affect.
Under some situations you may not want to have the NULL’s in your data stream, so make sure you test any results and make sure you are getting what you want.
There are two other things in the above code sample that may require explanation. The first is the DISPLAY statement with the ‘NO ADVANCING’ directive at the end. What this will do is leave the cursor at the end of the string that you just displayed (not do a carriage return/line feed). What’s funny is in some of other popular languages you had to explicitly tell the display string to do a carriage return,
but in COBOL we had to jump through hoops to make it work. This is the equivalent of a carriage control code of %320 on a PRINT or FWRITE intrinsic.
The other verb that may require explanation is the ‘FREE’ directive at the end of the ‘ACCEPT’ statement. What many people would do before an ACCEPT statement is MOVE SPACES to the variable they were about to ACCEPT. If the user typed in the number of characters that was equivalent to the length of the variable you would get an automatic carriage return/line feed. The user would not be able to type any more characters than the variable allowed.
By specifying FREE on the ACCEPT verb, this causes the compiler to initialize the variable for you that you are about to ACCEPT. It has the side effect of not doing the carriage return/line feed when it is full. So you could be accepting a 10 character description field, and the user could type 50 characters, thinking the whole thing would take, but only the first 10 would end up in your program.
How many times have you had to read some small data set or file that has a series of codes in it and needed to sort it. It seems like a lot of work and overhead to set up an FD and SD and write them out to a file and then sort and then read them back in, wouldn’t it be nice if you could just read them into a table and then sort the table in memory? Well you can, and here is a simple way to do it.
What we are going to do is use a small bubble sort, it only requires that we have two counters, one save buffer, and one table max variable, on top of the table data.
WORKING-STORAGE SECTION. 01 SAVE-CODE PIC X(04) VALUE SPACES. 01 S1 PIC S9(4) COMP VALUE 0. 01 S2 PIC S9(4) COMP VALUE 0. 01 TABLE-MAX PIC S9(4) COMP VALUE 0. 01 CODE-TABLE. 03 CODE-DATA PIC X(04) OCCURS 100 TIMES. PROCEDURE DIVISION. A1000-INIT. * * Do whatever steps are necessary to fill CODE-TABLE with the values * you are going to use in your program. Make sure to increment * TABLE-MAX for each entry you put in the table. * * Now we are going to perform a bubble sort of the table. * PERFORM VARYING S1 FROM 1 BY 1 UNTIL S1 = TABLE-MAX PERFORM VARYING S2 FROM S1 BY 1 UNTIL S2 <;> TABLE-MAX IF CODE-DATA(S2) << CODE-DATA(S1) MOVE CODE-DATA(S1) TO SAVE-CODE MOVE CODE-DATA(S2) TO CODE-DATA(S1) MOVE SAVE-CODE TO CODE-DATA(S2) END-IF END-PERFORM END-PERFORM.
As you can see, we have taken advantage of some of the features of COBOL85 by using the in-line PERFORM statement, and the END-IF statement.
That's it for this month, next month I am going to try to find out how to redefine the terminator character (#) in macros, and explain why you may need to do it.