Click here for RAC Consulting sponsor message

 

Using COBOL Macros

By Shawn M. Gordon

By Shawn Gordon

For those of you who were waiting and waiting for this issue, your patience is finally rewarded. I am at long last going to uncover the mystery of COBOL macros for you. I personally found out about macros by reading a column in a magazine around 10 years ago, and have been in love with them ever since.

There are still a huge number of people that don’t know what they are, let alone how to use them. I recently had to fill about 10 contract programmer slots for a client, and in the process of interviewing about 40 people only found three that had ever heard of or used COBOL macros. So if this topic is new to you, don’t feel bad — you’re in good company.

What are COBOL macros? Well, they are an HP extension to the ANSI COBOL standard. Since they are an HP extension, it means that you won’t see them in any other COBOL out there. On the upside, our very own SIGCOBOL special interest group has gotten pretty involved with the COBOL ANSI committee, and are pushing very hard to get the macros put into the COBOL standard. So hopefully in the next couple of years you will see this wonderful extension added to the standard.

Basically, a COBOL macro is a way to predefine code that can accept replacement parameters. This code is then resolved inline at compile time. The upside to this versus using a paragraph is that the code is inline and no branching takes place to execute it — so you get slightly lower overhead and faster execution speeds. The downside is that your compiled listing can bloat up enormously over your source listing.

I will typically have a 1,500 line program easily double in size in the compile listing — but then I use macros for everything: from database calls, to terminal IO to system intrinsic usage. Basically I put all of my reusable routines inside macros instead of in paragraphs. Here is a simple example of using a macro to display information:


$DEFINE %MYDISPLAY=
DISPLAY !1 NO ADVANCING#

%MYDISPLAY(“This is some text”#).

The major thing to get out of this example is the $DEFINE must take place in column 7. The compiler sees a $ in column 7 as a compile time directive. The name of your macro can be anything, but must start with a %, unless you have redefined it, which I will get into in a moment. The macro definition can be as many lines as you want — all you need to do is use a # at the end of the last line to terminate it.

Now the period terminator creates an interesting problem for us. Keeping in mind that the text is literally replaced, if you use a period inside the macro then you probably won’t be able to use the macro in an IF statement. However, if you leave the period out of the macro you will need to put a period at the end of the use of the macro, as I did in the above example.

Now in the use of the macro, we use the same %MYDISPLAY, and then in parenthesis we put in our replacement parameters. Each replacement parameter is delimited by a # sign and is positional, so the first parameter will replace !1 in the macro, the second parameter will replace !2, and so on.

The above example doesn’t illustrate this very well — so how about we define a DBGET and DBEXPLAIN to illustrate two points? The first point is using multiple replacement parameters, the second point will be how to call one macro from inside another macro.

$DEFINE %DBEXPLAIN=
DISPLAY `Error location: !1’
CALL “DBEXPLAIN” USING !2#

$PREPROCESSOR PARMCHAR=^, DELIMITER=@

$DEFINE %DBGET=
CALL “DBGET” USING ^1,
^2,
^3,
^4,
ALL-LIST,
^5,
^6@
IF NOT DB-CALL-OK
%DBEXPLAIN(!7#,!4#)
END-IF#

$PREPROCESSOR PARMCHAR=!, DELIMITER=#

%DBGET(MYBASE#,MYSET#,MODE7#,DB-STATUS-AREA#,MYBUFF#,MYARGUE#
,”B1000: Getting MYSET”#).


Take note of one thing in the use of the DBGET macro: When we have to continue on another line, the comma must precede the argument on the next line — it can’t be left trailing on the previous line. I never found out why this was true, and have ceased to care.

Now take a look at the $PREPROCESSOR statement. This allows us to redefine what characters are used inside of a macro to indicate the various delimiters. This is important if you want to call one macro from within another macro that takes parameters. If it doesn’t take parameters then it doesn’t matter.

One last item on macros to keep in mind is that they can be defined anywhere you want. That means that you could put your DBGET macro definition in the WORKING STORAGE section, or IDENTIFICATION DIVISION, or even before the $CONTROL line. I personally define them at the top of the PROCEDURE DIVISION. Also remember that you can use them for anything, this means you can also do something like;


$DEFINE %MAXCHAR=50#

01 FIRST-NAME PIC X(%MAXCHAR#) VALUE SPACES.

I haven’t personally found this useful, but I have seen other people do it.

Well, that’s it for this month — I hope it was worth the wait. Keep those cards and letters coming, and earn yourself a free 3000 Always Online hat for tips you submit, either to the NewsWire or to me at smga@compuserve.com.

Shawn Gordon, whose S.M. Gordon & Associates firm supplies HP 3000 utilities, has worked with 3000s since 1983.Shawn M. Gordon, whose S.M. Gordon & Associates firm supplies HP 3000 utilities, has worked with 3000s since 1983.


Copyright 1998, The 3000 NewsWire. All rights reserved.