Shawn M. Gordon
I want to open this month with a caution about a couple of the tips I gave a while back. I showed how you could strip leading spaces by doing an INSPECT with REPLACING the spaces to a NULL value. This works fine, but it does put a NULL in the place of the space. This could cause you problems occasionally depending on what you are doing with the data.
The other trick was using page layout descriptions in your FD statement for formatting reports. I failed to mention that the HP LaserJet hooked up as a spooled device is only guaranteed to work if you use PCL code. Under most simple carriage control directives it will work fine and you won’t notice, but using the FD directives as I showed you can cause misalignment on the page.
I always recommend that you try these examples before you commit to them. No one has reported any problems, but I was re-reading the columns, and I noticed that I didn’t give strong enough warnings.
With that said I want to thank everyone for all of the positive feedback that I have been getting. As a matter of fact, this issue is going to be pretty much dedicated to Rick Gilligan at Computer and Software Enterprises Inc. up in San Luis Obispo and some code that he sent me. After my first column on some basic macro usage, I got a call from Rick and he wanted to show me some of the stuff he had been doing with macros. I was totally blown away, I had no idea you could go that far with macros and I felt it was worth revisiting the topic so I could show you these new samples. Thanks again Rick for taking the time.
I also want to make a note about the HP Cobol Macro facility. As far as I have been able to determine, HP is the ONLY Cobol out there that has this facility. As a matter of fact, many people that have switched to HP-UX and MicroFocus Cobol have been very disappointed by the lack of a Macro facility. So all you code jockeys that are ready to jump on UNIX with another Cobol compilier better think twice if you like using macros. There has been enough said about it now, that the next standard of Cobol which I think comes out in 1996 or 1997, has a good
chance of containing a Macro facility. I sure hope so, it makes the language so much more powerful.
Ok, the intro is done, now I am going to start on the code;
The first thing I want to touch on that Rick showed me was the ability to call Macros recursively, this ties in with another comment that I made about being able to change the character that is used as a delimited inside of a macro.
$DEFINE %DBCHECK= IF (DB-CONDITION-CODE <> 17) AND (DB-CONDITION-CODE <> 0) CALL "DBEXPLAIN" USING DB-STATUS-AREA CALL INTRINSIC "QUIT" USING \!1\ END-IF# $PREPROCESSOR KEYCHAR=\,DELIMITER=~ $DEFINE \DBGET= CALL "DBGET" USING !1, !2, !3, DB-STATUS-AREA, DB-LIST-ALL, !4, !5 %DBCHECK(!6)~ $PREPROCESSOR KEYCHAR=%,DELIMITER=#
Although this is far from an elegant example it does demonstrate both points. First we are defining the macro DBCHECK, we then use the $PREPROCESSOR command to redefine the two key characters that are used in a macro. This allows us to call another macro without the characters being defined as key characters. So now we define a DBGET macro loosely based on the example in my previous column. The end of the macro makes a call to the DBCHECK macro which will test the condition code and call DBEXPLAIN if necessary. We then use the $PREPROCESSOR command to set the key characters back to the default values.
Now I am going to cover what was the big revelation for me in terms of macros. Turns out you can use them pretty much anywhere in your program, this means that you can use them in the Working-Storage section of your program. For those of you who use COPY..REPLACING, this could be used as an alternative way of using replacement values. This also gives you something similar to the C ‘struct’ verb. You can essentially create templates for record structure layouts, and not have to retype all that stuff in. Here is a small example of how you could use it.
$CONTROL USLINIT IDENTIFICATION DIVISION. PROGRAM-ID. MACTEST. AUTHOR. SHAWN GORDON. DATE-WRITTEN. WED, MAY 11, 1994. DATE-COMPILED. ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. $DEFINE %CUSTMAST= 01 !1-RECORD. 03 !1-CUST-NUM PIC X(10). 03 !1-CUST-NAME PIC X(30). 03 !1-ADDRESS PIC X(30). 03 !1-CITY PIC X(20). 03 !1-STATE PIC X(02). 03 !1-ZIP PIC X(10).# %CUSTMAST(WS#) %CUSTMAST(CM#) PROCEDURE DIVISION. A1000-INIT. DISPLAY 'HELLO WORLD'. STOP RUN. Now here is what the code looks like when you compile it. PAGE 0001 HP32233A.02.05 <[>85] Copyright Hewlett-Packard CO. 1989 000100* The following are defaults for Compatibility mode compiler. *CONTROL LIST,SOURCE,NOCODE,NOCROSSREF,ERRORS=100,NOVERBS,WARN *CONTROL LINES=60,NOMAP,MIXED,QUOTE=",NOSTDWARN,SYNC16,INDEX16 000400* 000500* The following are defaults for Native compiler. 000600* *CONTROL LIST,SOURCE,NOCODE,NOCROSSREF,ERRORS=100,NOVERBS,WARN *CONTROL LINES=60,NOMAP,MIXED,QUOTE=",NOSTDWARN,SYNC32,INDEX32 000900*CONTROL NOVALIDATE,OPTIMIZE=0 001000* 001100* For any other options, redirect COBCNTL.PUB.SYS by using 001200* a file equation. 001300* 001000$CONTROL USLINIT 001100 IDENTIFICATION DIVISION. 001200 PROGRAM-ID. MACTEST. 001300 AUTHOR. SHAWN GORDON. 001400 DATE-WRITTEN. WED, MAY 11, 1994. 01500 DATE-COMPILED. WED, MAY 11, 1994, 10:59 AM 001600 ENVIRONMENT DIVISION. 001700 DATA DIVISION. 001800 WORKING-STORAGE SECTION. 001900 002000$DEFINE %CUSTMAST= 002100 01 !1-RECORD. 002200 03 !1-CUST-NUM PIC X(10). 002300 03 !1-CUST-NAME PIC X(30). 002400 03 !1-ADDRESS PIC X(30). 002500 03 !1-CITY PIC X(20). 002600 03 !1-STATE PIC X(02). 002700 03 !1-ZIP PIC X(10).# 002800 002900%CUSTMAST(WS#) 002100 01 WS-RECORD. 002200 03 WS-CUST-NUM PIC X(10). 002300 03 WS-CUST-NAME PIC X(30). 002400 03 WS-ADDRESS PIC X(30). 002500 03 WS-CITY PIC X(20). 002600 03 WS-STATE PIC X(02). 002700 03 WS-ZIP PIC X(10). 003000 003100%CUSTMAST(CM#) 002100 01 CM-RECORD. 002200 03 CM-CUST-NUM PIC X(10). 002300 03 CM-CUST-NAME PIC X(30). 002400 03 CM-ADDRESS PIC X(30). 002500 03 CM-CITY PIC X(20). 002600 03 CM-STATE PIC X(02). 002700 03 CM-ZIP PIC X(10). 003200 003300 PROCEDURE DIVISION. 003400 A1000-INIT. 003500 DISPLAY 'HELLO WORLD'. 003600 STOP RUN. 0 ERROR(s), 0 QUESTIONABLE, 0 WARNING(s) DATA AREA IS %000345 WORDS. CPU TIME = 0:00:00. WALL TIME = 0:00:02. END OF COMPILE
This is also a very simplistic example, but I hope it sparks your imagination of what might be possible and how you might streamline
your coding process.
There is one last point with macros I want to cover, and this is also a feature I didn’t realize was available. This is the ability to define constants, this is a very popular and powerful feature in the C language, and it turns out we have it available to us in Cobol. I am going to quote directly from Rick’s example that he sent me where they use this, it is a variation on the previous example.
WORKING-STORAGE SECTION. $DEFINE %CurMo =1# $DEFINE %M1Mo =2# $DEFINE %M12Mo =3# $DEFINE %M2Mo =4# $DEFINE %M3Mo =5# $DEFINE %M13Mo =6# $DEFINE %M14Mo =7# $DEFINE %LastMo =7# $DEFINE %MCABOMDef = 10 MCA-BOM-!1. 15 MCA-BOM-!1-YRMO PIC X(06). 15 MCA-BOM-!1-DAY PIC X(02).# $DEFINE %MCAEOMDef = 10 MCA-EOM-!1. 15 MCA-EOM-!1-YRMO PIC X(06). 15 MCA-EOM-!1-DAY PIC X(02).# $DEFINE %MCARgnSrcDef = 10 MCA-RGN-SRC-!1 PIC S9(09) COMP SYNC. 88 MCA-RGN-SRC-!1-NA VALUE 0. 88 MCA-RGN-SRC-!2-DTD VALUE 1. 88 MCA-RGN-SRC-!3-MSD VALUE 2.# $DEFINE %MCALnSrcDef = 10 MCA-LN-SRC-!1 PIC S9(09) COMP SYNC. 88 MCA-LN-SRC-!1-NA VALUE 0. 88 MCA-LN-SRC-!2-DTD VALUE 1. 88 MCA-LN-SRC-!3-MSD VALUE 2.# * * order of items by month must match definitions of pointer * macros. * 01 MONTH-CTL-AREA. 05 MCA-BOMS. 10 MCA-BOM OCCURS %LastMo. 15 MCA-BOM-YRMO PIC X(06). 15 MCA-BOM-DAY PIC X(02). 05 FILLER REDEFINES MCA-BOMS. %MCABOMDef(CURMO#) %MCABOMDef(1MO#) %MCABOMDef(12MO#) %MCABOMDef(2MO#) %MCABOMDef(3MO#) %MCABOMDef(13MO#) %MCABOMDef(14MO#) 05 MCA-EOMS. 10 MCA-EOM OCCURS %LastMo. 15 MCA-EOM-YRMO PIC X(06). 15 MCA-EOM-DAY PIC X(02). 05 FILLER REDEFINES MCA-EOMS. %MCAEOMDef(CURMO#) %MCAEOMDef(1MO#) %MCAEOMDef(12MO#) %MCAEOMDef(2MO#) %MCAEOMDef(3MO#) %MCAEOMDef(13MO#) %MCAEOMDef(14MO#) 05 MCA-RGN-SRCS. 10 MCA-RGN-SRC PIC S9(09) COMP SYNC OCCURS %LastMo. 88 MCA-RGN-SRC-NA VALUE 0. 88 MCA-RGN-SRC-DTD VALUE 1. 88 MCA-RGN-SRC-MSD VALUE 2. 05 FILLER REDEFINES MCA-RGN-SRCS. %MCARgnSrcDef(CURMO#) %MCARgnSrcDef(1MO#) %MCARgnSrcDef(12MO#) %MCARgnSrcDef(2MO#) %MCARgnSrcDef(3MO#) %MCARgnSrcDef(13MO#) %MCARgnSrcDef(14MO#) 05 MCA-LN-SRCS. 10 MCA-LN-SRC PIC S9(09) COMP SYNC OCCURS %LastMo. 88 MCA-LN-SRC-NA VALUE 0. 88 MCA-LN-SRC-DTD VALUE 1. 88 MCA-LN-SRC-MSD VALUE 2. 05 FILLER REDEFINES MCA-LN-SRCS. %MCALnSrcDef(CURMO#) %MCALnSrcDef(1MO#) %MCALnSrcDef(12MO#) %MCALnSrcDef(2MO#) %MCALnSrcDef(3MO#) %MCALnSrcDef(13MO#) %MCALnSrcDef(14MO#)
I am really excited about the possibilities that this example opens up for us Cobol folks. The first series of $DEFINE statements create a set of constants, so any reference to say ‘CurMo’ will resolve to the value ‘1’. If you change the $DEFINE statement for CurMo, then everything in the program will change automatically. It is important
to note that placement of constants is critical in this context, the value MUST be the next character after the equal ‘=’ sign.
Now combining the constants and some generic working-storage macro
definitions, we can then make totally dynamic record structure declarations. Stop, look, and think about this for a minute, it
might take a little longer thinking up how your are going to set up your program the first time, but used correctly you can get to a point
where the bulk of your program can be defined with a handful of macros. Data set definitions, data base access, V/Plus routines, KSAM and MPE file access, virtually anything you want. Makes the mind spin a bit, but wouldn’t you rather learn some new concepts in a language you are familiar with than learn a whole new language?
To wrap up this month I want to point out a couple of things. Some of what I have shown you this month are ways to simulate features found in languages such as C and C++, but in a much easier fashion, and in a language you already know. You don’t have wait for COOL (Cobol Object Oriented Language) to take advantage of some it’s concepts such as code re usability. I just finished up a class on C++, and there are some really great conceptual features that I would love to see in Cobol. I have to say though that C++ is the most cludged language I have ever seen. I hope the Cobol ANSI committee do a better job putting Object Oriented extensions into Cobol (there is no ANSI standard for C++).
I am hoping to show some more user examples of neat tricks in the
next issue, I am just waiting for the stuff (Bob and Bruce). Thanks
again to Rick Gilligan for his input and ideas for this months column.