Defining and Using Macros [ HP COBOL II/XL Reference Manual ] MPE/iX 5.0 Documentation
HP COBOL II/XL Reference Manual
Defining and Using Macros
One of the most powerful facilities of the preprocessor is the macro
processor. This processor associates a macro name with a string of text.
When the macro name is used by itself in a COBOL sentence, the
preprocessor sends the definition of the macro to the compiler. See also
the COPY and REPLACE statements.
Macros can have up to nine formal parameters. If formal parameters are
used in the definition, actual parameters are supplied to replace them
when the macro is called in the source program.
$DEFINE Command
Use the $DEFINE command to define a macro. When you define a macro, you
associate a macro name with a string of text.
The $DEFINE command can redefine a previously defined macro. However,
all macro definitions are global. If you use the $DEFINE command to
redefine a macro, the old definition is lost, and can only be recovered
by issuing another $DEFINE command that repeats the old definition.
Syntax.
$DEFINE macro-name=[string-text]#
Parameters.
macro-name the name of the macro being defined, and consists of an
initial non-alphanumeric character (default is the percent
sign, %), followed by an alphabetic character, followed by
zero or more alphanumeric characters.
The length of the macro name may be any number of
characters, but only the first fifteen are recognized by
the preprocessor. Note that care must be taken to assure
uniqueness of such names.
string-text can be any text you choose. However, because this text is
sent to the compiler, it must be a valid COBOL statement or
sentence, with one exception. This exception is the use of
formal parameters in the string-text. Formal parameters
are described later in this section.
Description.
Note that string-text is delimited by an equal sign and a pound sign.
The pound sign is the delimiter of the entire definition. This is a
default delimiter, and can be changed by the $PREPROCESSOR command.
Nested $DEFINE commands and recursive macros can be used; however, you
must take care in using recursive macros, as there is no specific method
for terminating the macro call sequence when used in this manner.
If a continuation character is used in a macro definition, it is assumed
to be a part of the macro definition, and not a continuation character.
The following illustrates the use of a continuation character in defining
a macro.
Example.
000100 $DEFINE %INCA=ADD 1 TO ALPHA-COUNTER.
000200 ADD ALPHA-COUNTER TO BETA-COUNTER.
000300* INCREMENT THE VALUES OF COUNTERS ALPHA-COUNTER &
000400* BETA-COUNTER.#
In the above example, the entire definition of the macro, %INCA, is the
following set of sentences:
000100 ADD 1 TO ALPHA-COUNTER.
000200 ADD ALPHA-COUNTER TO BETA-COUNTER.
000300* INCREMENT THE VALUES OF COUNTERS ALPHA-COUNTER &
000400* BETA-COUNTER.#
The dollar symbol is not needed in continuation lines of a macro
definition. The only time that a dollar sign would appear in the first
column after the sequence number field is when the macro definition
contains preprocessor commands.
When the $DEFINE command is processed, the string-text that makes up the
definition of the macro is stored exactly as it appears in the command.
All end-of-line markers and sequence numbers are saved. The only
exception to this rule is that if all characters between the equal sign
in the macro definition and the end of the text line in which the
definition begins are blank, then only the end-of-line marker is saved,
and the macro definition begins in the first column of the next line.
This allows you to control the initial column of the macro definition
without worrying about the column position of the macro name when it is
called. Below is an illustration:
Macro definition:
000300$DEFINE %ADDIT=MOVE SPACES TO DISPLY-ITM.#
000400
:
Macro call:
001200 DISPLAY DISPLY-ITM. %ADDIT
:
Expanded source code:
001200 DISPLAY DISPLY-ITM. MOVE SPACES TO DISPLY-ITM.
:
Because the macro definition starts on the same line as the macro name,
the definition of the macro replaces the macro call starting in exactly
the same column as the macro call.
000100$DEFINE %CHECKIF=
000200 IF STAT-ITEM EQUAL "10"
000300 THEN PERFORM STATUS-REPORT
000400 ELSE NEXT SENTENCE.#
In this case, because the characters between the equal sign and the end
of line 000100 are blanks, the macro definition begins on line 000200.
Thus, when the macro call to %CHECKIF is made, the expanded source
appears as shown below.
Macro call:
002400 WRITE FILE-OUT. %CHECKIF
002500 :
Replacement:
002400 WRITE FILE-OUT.
000200 IF STAT-ITEM EQUAL "10"
000300 THEN PERFORM STATUS-REPORT
000400 ELSE NEXT SENTENCE.
Formal Parameters.
A macro definition may contain up to nine formal parameters. A formal
parameter is designated by an exclamation point followed immediately by
an integer from the range 1 to 9.
Formal parameters in a macro definition are replaced by values you assign
when you call the macro in your source program, as illustrated below.
Source program:
000100$DEFINE %PERFORM=
000200 PERFORM !1
000300 VARYING !2 FROM !3 BY !4
000400 UNTIL !5.#
:
001200 %PERFORM(CHEK-PARA#,CTROL#,INIT#,OFFSET#,A = B#)
:
Expanded source program:
:
000200 PERFORM CHEK-PARA
000300 VARYING CTROL FROM INIT BY OFFSET
000400 UNTIL A = B.
:
Macro Calls.
There are two different forms of a macro call:
macro-name
and
macro-name(p1#,p2#,p3#,...,pn#)
Parameters.
macro-name the name of a macro which has been previously defined in
the source program, using a $DEFINE command.
p1,p2,...,pn the actual parameters. Each of p1, p2,[REV BEG] and so
on may be either a null string or any combination of
characters and[REV END] numerals, including spaces.
Each actual parameter begins with the first character
after a preceding comma (except p1, which begins after
the left parenthesis), and ends with the pound sign.
If no characters are specified for an actual parameter
(that is, if an actual parameter is specified by "#"),
then a null string replaces its corresponding formal
parameter in the macro definition.
Note from the above format that there can be no intervening spaces
between the end of the macro name and the left parenthesis of the actual
parameter list.
Continuation of lengthy parameters in a macro call is established by
starting the continued line with a comma. The following illustrates
this:
macro-name(p1#,p2#,p3#,p4#
,p5#,p6#,pn#)
The first method of calling a macro is used when the macro definition has
no formal parameters.
The second method must be used when formal parameters are specified in
the definition of the macro.
When a macro name is encountered in a source program, it is deleted, and
the associated macro definition is sent to the compiler in place of the
name. Any formal parameters are replaced by actual parameters listed in
the macro call.
With two exceptions, macro names are replaced wherever they occur in the
source program, including quoted strings. Macro names are not expanded
1) in a comment, unless the comment itself is found in a macro, and 2) in
list and compilation preprocessor commands (such as $CONTROL), where they
are not recognized.
Relationship of Formal Parameters to Actual Parameters.
The numeric value of a formal parameter determines which actual parameter
in the macro call is to replace it.
That is, for a formal parameter, !n (where n is 1 through 9), the nth
actual parameter from the left in the macro call replaces !n, as
illustrated below.
Examples.
Macro definition:
$DEFINE %OPENSTATE=
OPEN INPUT !1.
DISPLAY !2,!3.#
Macro call:
%OPENSTATE(FILE-IN#,"FILE STATISTICS"#, OPEN-STATS#)
Result of macro call:
OPEN INPUT FILE-IN.
DISPLAY "FILE STATISTICS", OPEN-STATS.
Macro definition:
090000$DEFINE %COMPUTESUM= COMPUTE !1 = !2 + !3.#
Macro call:
091000 %COMPUTESUM(INCREMEN#,OFFSETTER#,7#)
Result of macro call:
091000 COMPUTE INCREMEN=OFFSETTER + 7.
In the second example above, !3 is replaced by the third parameter in the
macro call, which is 7; !2 is replaced by the second parameter,
OFFSETTER, and !1 is replaced by the first parameter in the call,
INCREMEN.
For a given macro definition, if there is a formal parameter, !n, and if
there are less than n actual parameters in the macro call, then any
formal parameter whose numeric value is greater than the number of
parameters in the macro call is ignored. This is illustrated in the
following example.
Macro definition:
001100$DEFINE %SHOWIT= DISPLAY !1,!2,!3,!5.#
Macro call:
002500 %SHOWIT("A"#," WORD "#,"IS "#,"MISSING"#)
Result of macro call:
002500 DISPLAY "A"," WORD ","IS ", .
When you specify a formal parameter in a macro definition, you can choose
not to use it in the macro call by entering only a comma and a pound sign
in the appropriate position within the macro call. This is shown in the
next example:
Macro definition:
000100$DEFINE %INITSTUFF=
000200 IDENTIFICATION DIVISION.
000300 PROGRAM-ID. !1
000400 AUTHOR. !2
000500 DATE-COMPILED. !3#
Macro call:
001000 %INITSTUFF(MACRO-TEST.#,#,#)
Result of macro call:
000200 IDENTIFICATION DIVISION.
000300 PROGRAM-ID. MACRO-TEST.
000400 AUTHOR.
000500 DATE-COMPILED.
The last two actual parameters were specified by ",#". When the
replacement code compiled, no author name or compile date was supplied.
The format for a macro definition assures that the initial column of each
line in the macro definition maps onto the same column when the macro
definition is inserted into the source program at macro call time. This
could cause a wraparound of the replacement text when actual parameters
are substituted in the definition. However, to ensure that this does not
happen, blanks are removed from the executable text field to make it the
correct size. If there are no trailing blanks to remove, the overflow
portion of the executable text field is used to create a new record on
the next line. The sequence number field is left blank for this new
record.
[REV BEG]
Nested Macro Calls.
You can pass the result of one macro call as an actual parameter to
another macro by using the $PREPROCESSOR command discussed in the next
section. By redefining the macro delimiter for the nested macro, you can
use a call to that macro as a parameter to another macro. The following
examples illustrate two slightly different ways of nesting macro calls.
Example 1.
This example defines two macros, %M1 and %M2. The macro %M2 is passed as
a parameter to %M1.
Macro definition:
$PREPROCESSOR DELIMITER=? Change the delimiter to define M1.
$DEFINE %M1= Start the definition of M1.
$PREPROCESSOR DELIMITER=~ Change the delimiter within M1.
DISPLAY "!1" Body of macro M1.
$PREPROCESSOR DELIMITER=# Restore the delimiter to # within M1.
? End of definition of M1.
$PREPROCESSOR DELIMITER=# Restore the delimiter to #.
$DEFINE %M2=ADD !1 TO !2 GIVING !3# Define macro M2.
In the following macro call, macro %M2 is passed as a parameter to macro
%M1. Notice that the "~" character is the delimiter for the parameters
to %M2:
%M1(%M2(A~,B~,C~)#)
Result of macro call:
DISPLAY "ADD A TO B GIVING C"
Example 2.
This example also defines two macros, %M1 and %M2. The macro %M2 is
again passed as a parameter to %M1. In this case, however, a third
macro, %NESTEDM2, is created that consists of the call to %M2. This
third macro is passed to %M1 instead of passing %M2 directly.
Macro definition:
$DEFINE %M1=DISPLAY "!1"# Define macro M1.
$DEFINE %M2=ADD !1 TO !2 GIVING !3# Define macro M2.
In the following nested macro call, the delimiter is changed to create
the third macro, %NESTEDM2. This third macro is passed to macro %M1:
$PREPROCESSOR DELIMITER=~ Change the delimiter.
$DEFINE %NESTEDM2=%M2(A#,B#,C#)~ Define macro NESTEDM2.
$PREPROCESSOR DELIMITER=# Restore the delimiter to #.
%M1(%NESTEDM2#) Call M1, passing NESTEDM2.
Result of macro call:
DISPLAY "ADD A TO B GIVING C"
[REV END]
$PREPROCESSOR Command
The $PREPROCESSOR command allows you to change the default characters
used in macro definitions and names. The default characters are:
% used as the initial character in a macro name.
! used as the first character of a formal parameter in macro
definitions.
# used to delimit string-text in a macro definition, and actual
parameters.
To specify a different character to be used in place of one of these, use
the $PREPROCESSOR command in the following format:
$PREPROCESSOR parameter=subparameter [, parameter=subparameter ]
Parameters.
parameter one of the keywords shown below. Each may be used only
once in a given $PREPROCESSOR command.
KEYCHAR specifies that the initial character of all
macro names is to be subparameter.
PARMCHAR specifies that the initial character of all
formal parameters in macro definitions is to be
subparameter.
DELIMITER specifies that the delimiting character in a
macro string-text is to be subparameter.
subparameter the character to be used in replacing the currently used
initial character or delimiter.
Example.
000100$PREPROCESSOR KEYCHAR= ,PARMCHAR=?,DELIMITER=^
000200$DEFINE MOVEIT=
000300 MOVE ?1 TO ?2.^
Note that care must be taken when you redefine the initial characters and
the string-text delimiter, because there may be cases when you use one of
the newly defined characters in your string-text as part of the
string-text itself, and not as a delimiter or an initial character.
MPE/iX 5.0 Documentation