Macros, Part 2

Before looking at this, you should first read "Macros-1".


Other system variables

Aside from &SYSNDX, there are several other system variables. Here are a few (not all) of them:


Positional and keyword parameters

Thus far we have been using "positional" parameters. They are listed in order on the prototype statement for the macro, and when it is used, the values listed are assigned to the parameters in order, left to right. Positional parameters do not have default values other than an empty string.

We can also have "keyword" parameters. When we use the macro, we use the keyword in assigning a value to the parameter, and for this reason, the order is much less important.

Examples:

Here are prototype statements for three macros:

     &LABEL   MAX    &A,&B,&C
     &LABEL   ENTER  &BR=12,&SA=YES
     &LABEL   FILL   &DEST,&LEN,&CHAR=C' '

The macro called MAX has three positional parameters. It presumably does something like setting &C = the larger of &A and &B, so the order is important.

The macro called ENTER has two keyword parameters. When we use it, we can accept the existing default values:

     ENTER

or we can change one or both of them, in either order:

     ENTER   BR=11

where &SA still has the value "YES".

     ENTER   SA=NO,BR=10

Notice that when we use the keyword, we do not include the ampersand.

The macro called FILL has two positional parameters and one keyword parameter. The positional parameters are at the left and the keyword parameter is at the right.

(End of example)

Some high-level languages support keyword parameters (Ada, Python, FORTRAN, LISP, etc) and some do not (C, C++, etc).


Sublists and &SYSLIST

Sometimes it is desirable to have a parameter which is a list. This is called a "sublist".

For instance, we could have

     &LABEL   ADD  &SUM,&LIST

where &SUM is the label or D(B) address of a fullword and &LIST is a list of such. We could call it:

     ADD  TOTAL,(A,B,C)

When we want to refer to the individual items in &LIST, we can use &LIST(1), &LIST(2) or LIST(3).

More generally, we could use a tool called &SYSLIST:

&SYSLIST(K) = Kth positional parameter (or null = an empty string if K is too large)

&SYSLIST(K,N) = Nth item on a sublist which is the Kth positional parameter (or null if N is too large)

Example (adapted from an IBM manual):

MYLABEL MACALL ONE,TWO,(3,(4,5,6),,8),,TEN

We can use &SYSLIST to get hold of all of this:

If the Kth parameter is not a sublist, then &SYSLIST(K,1) is the same as &SYSLIST(K).

(As we are using ASSIST, it is possible some of the more advanced features here are not implemented, such as 2-level sublists.)


Local variables in a macro

We can have local variables in a macro.

We can have a "Local Arithmetic Variable":

     LCLA  &N

Here &N is an integer, initially 0. We can change its value:

&N       SETA  expression

For instance:

     &N       SETA  &N+1

We can have a "Local Boolean Variable":

     LCLB  &F

Here &F is a boolean variable, initially 0 (or False). We can change its value:

     &F       SETB  expression

where the expression is a logical condition as in an AIF.

(It is possible to use various operators such as AND and OR in an expression, but it is not clear that ASSIST supports this.)

We can have a "Local Character Variable":

     LCLC  &S

Here &S is a character string, initially empty. We can change its value:

     &S       SETC  expression

where the expression may be:

We can also have global variables in a macro.

These are very similar to local variables, but they retain their values from one call to the macro to the next. We could, for instance, have a counter for how many times we call the macro.

We define these using GBLA, GBLB and GBLC, and modify their values using SETA, SETB and SETC.

Local and global variables in a macro are sometimes called "SET" variables because of the use of "SET".


Attributes

Often it is useful to have some access to various properties of arguments. This is provided by "attributes".

Number attribute: If &Q is a sublist, then

     N'&Q

is the number of items on the sublist (including empty strings).

Thus:

Count attribute: The value of any symbolic parameter &B is a character string. The number of characters in the string is

     K'&B

Thus if &B = 'Hello', we have K'&B = 5.

Length and Type attributes: Suppose the value of &P is the actual label of a variable, not a D(B) address. Then:

     L'&P

is the number of bytes of whatever was defined at that label. This is the length attribute. If we have

     PQRS     DS   F

and the value of &P is 'PQRS', then L'&P = 4.

We also have the type attribute:

     T'&P

is one letter which indicates the type of data. Possible values are

and there are some others.

In theory, we could use the attributes to create macros that could adapt to the types of data we provided. For instance, we could have an Add macro which could accept values of various types (binary, zoned decimal, packed decimal) and generate the code needed to add them. (This would be "polymorphic" behavior.)