Introduction to Macros in GHS

(Applies to GHS/BHS)

"Macros" are found in various kinds computer programs. The "mainline application" programs such as word processors, spread sheets and data-base programs often provide something called a "macro" facility. "Macro" literally means "large", and in computer jargon it generally refers to a command which may be made up of a large number of other commands.

Most of the macro facilities found in application programs are built-in versions of what was a common utility a few years ago: the "keyboard macro" program. They function basically by recording keystrokes, allowing you to collect the keystrokes as a named "macro" and "play them back" at a later time by invoking the macro name.

However such "macro" facilities are awkward and of limited use compared to an older tradition in which the macro is an extension of a programming language. Most assembly languages have macros of this type as do a few higher- level languages. Even DOS, which is itself a rudimentary language, has a macro facility known as the "batch file". It is this type of "language-based macro" which BHS implements; and in the following discussion, the term "macro" will be used to mean this kind of macro.

The concept of the macro is very simple: a macro is a collection of commands which, when the macro name is invoked, causes those commands to be executed. This alone is a powerful thing; but its power is vastly increased when "parameter substitution" is performed.

If you know a programming language such as FORTRAN, C, Pascal or a modern version of BASIC, you are familiar with the concept of the "subroutine" (or "subprogram" or "procedure", depending on the terminology of the particular language). These all have the ability to "pass parameters" which are referenced as symbols (usually variable names) within the subroutine. Although you can also "pass parameters" when invoking a macro, the interpretation of the parameters in macros is a little different.

When you define a macro, you are simply storing a collection of text. The system does not require that it make sense at the time it is defined. Therefore, your parameter substitution may take place anywhere within the macro. You can even supply whole commands as parameters. This leads to an extremely broad range of possibilities and is what makes the macro so powerful. However, one of the liabilities of the macro, compared with the subroutine, is that the system cannot warn you of syntax errors within the macro until it is actually executed.

In GHS, the form of a macro definition is
    MACRO name
where "name" is an arbitrary name by which the macro is thereafter referenced and "body" is one or more lines of text. The single slash on a line by itself marks the end of the macro definition. If a macro by the same name already exists, it is replaced by the new definition. If "body" is missing, it is a "null" macro and the definition has no effect except that if a macro by the same name does exist, that macro is "erased" -- this is how you delete a macro.

Other than storing a series of text lines, the MACRO command does nothing. Therefore it may appear anywhere in a command stream. It is usually placed in a Run File.

Making use of a previously-defined macro simply requires the name of the macro preceded by a "dot" or period. Thus, if a macro named XYZ has been defined,
will cause the text in its "body" to executed as a series of commands.

If parameters are involved in a macro definition, they are represented by the appearance, in the macro body, of the 2-character string "%n" where "n" is a single digit 1 through 9. This is the same convention which is used by DOS in batch files. For example,
     DRAFT = %1 @ MS
defines a macro named MSDRAFT which contains one line of text. The "%1" is interpreted as "parameter #1 goes here". It's sometimes called a "dummy" parameter. If you execute this macro by saying
    .MSDRAFT 12
    DRAFT = 12 @ MS
is the actual command which the system will receive.

Consider another example:
This might be executed by
     .LOAD FO1.P, .95, SW
yielding the command sequence
Note that even though the macro is named LOAD, the same as the name of an intrinsic command, there is no confusion since a macro invocation is distinguished by the leading "dot".

Also note that the dummy parameters can occur in any order within the body of the macro definition. At execution time, the order in which the actual parameters are given determines their identification with the %1, %2, etc. within the macro body.

If there are more dummy parameters in the body than there are actual parameters given at the execution, the missing parameters will be considered to be empty, and the result of the substitution is that the extra dummy parameters are removed. For example,
     TANK= WINGTK%1%2
   .WT 3, .S  yields  TANK= WINGTK3.S
   .WT 3    yields  TANK= WINGTK3
A very important ability of GHS macros is that they can invoke other macros. For example,
     .WT %1, *
     LOAD= %2
    .LDWT 1, %1
    .LDWT 2, %1
    .LDWT 3, %1
and the execution,
    .LDWT1-3 .98
would put 98% fuel oil in three (pairs of) tanks.

As another example, consider the following macro:
       \****** Condition: %1 ******\
This would work fine if you passed it a single word, such as
but what if you wanted to use two or more words? If you threw some extra dummy parameters into the definition (eg. "*** Condition: %1%2%3 ***"), there would be no spaces between the words; and "*** Condition: %1 %2 %3 ***" would give you an extra space or two if you happened to use less than three words.

The better solution is to enclose a multi-word parameter in quotation marks. For example,
    .HEADING "Wing Tanks Damaged"
would take all three words, strip off the quotation marks and then substitute them all for %1.

Using the IF control command, you can make a macro do different things depending on some variable or parameter. For example, you can check that the proper number of parameters is supplied at execution time:
       IF "%3"="" THEN MESSAGE "Parameter missing! | EXIT
       TANK= %1
       CONTENTS= %3
       LOAD= %2

Another powerful feature of macros is their ability to create or "spawn" other macros. This is often used when implementing menus in GHS. For example,
       MACRO ESC
        EXIT MAIN
       MENU " Weight setup " %1
       \A\.ADD\Add a weight item
       \D\.DEL\Delete a weight item
spawns a little macro named ESC prior te executing the MENU command. Notice that MACRO ESC is treated as ordinary text when WSET is defined, with the exception that one of the slashes is removed from its terminating line. Thus, when WSET is executed, it right away presents the system with a macro definition.

Incidentally, when a GHS process is aborted by your pressing the Escape key, it looks for the presence of a macro named ESC, and if it finds one it executes ESC instead of returning to the normal input stream.

When a macro is defined within a macro as in the example above, you must be careful to avoid unintended parameter substitution in the inner macro. Actually, you cannot avoid parameter substitution because every %n within the macro is replaced when the macro is used. However you can use a little trick to get what you want anyway. For example, If the inner macro needs one parameter, you would like it to retain a %1 after parameter substitution has taken place. This can be done by putting %%91 in place of the %1, assuming that the parent macro will always have less than 9 parameters. The %9 is replaced by nothing, leaving the %1 you wanted.

Although these brief examples were selected to demonstrate various features of GHS macros, the primary, overriding purpose in applying macros is to reduce repetition. Whenever you find that you have to repeat a certain sequence of commands several times, it is almost always better to construct a macro which contains the sequence and then execute the macro. This reduces the repetition within the text of the Run File and thereby reduces the chance of making an input error.

While macros can be placed in any Run File (and you will find that most Run Files are more compact and easier to check when they use macros) it is sometimes convenient to organize general-purpose macros into separate "Library Files" so that they may be more conveniently used in any job. In other respects, a Library File is no different from any other Run File. When executing the GHS program from DOS, you can indicate that you want to have it read a given Library File by including the file name after the "/L" parameter.

For some people, the best way to learn about using macros is to simply experiment with using them. Others learn better by studying examples. Examples of macro Library Files can be found in the GHS distribution files which have the file name extension ".LIB".

If you would like to see another bulletin created regarding a specific topic, please email Creative Systems, Inc. at

Copyright (C) 2011 Creative Systems, Inc.