7

The MAP and FAP assemblers for the IBM 709/7090/7094 had a nice macro facility. I was surprised by its power. (Actually, I guess it is possible that most macro processors at the time were as sophisticated, but I haven't seen any. Strachey's “General-purpose macro-generator”, from a year later, was incredibly limited by comparison) Here are some of its capabilities:

  • Macros could have an arbitrary number of parameters.
  • Macro expansions could nest.
  • Macro definitions could nest (macro-defining macros were possible).
  • With the IFF and IFT pseudo-instructions (only IFF in FAP) text could be substituted conditionally.
  • The IRP pseudo-instruction allowed iterating over a comma-separated list.
  • The SET pseudo-instruction changed the value of a symbol. By combining SET with the macro-related pseudo-instructions, you can implement arbitrary loops; SET also makes recursive macro expansion more useful.
  • The GOTO pseudo-instruction (only in MAP) made it possible to instruct the assembler not to include a certain number of instructions in the expansion.
  • Concatenation of arguments and other text could be done, with the ' character.

Here is all the relevant documentation I have been able to locate:

There is earlier information about FAP, but from before it had support for macros.


The general form of a macro definition in FAP was this:

NAME   MACRO   P1,P2,P3
       ...
NAME   END

Here NAME is the name of the macro, P1, P2, and P3 are parameters, and the text elided with “...” is the macro's body. After such a definition, you can use NAME as if it were any other instruction, as in

       NAME    X,Y,Z

In the body, occurrences of P1, P2, P3 would be replaced with the corresponding arguments (in the example, X, Y, and Z).

If a macro-instruction includes a symbol in its location/name field, as in

ABCDEF NAME    X,Y,Z

then the effect would be as if the symbol had been given with the first instruction of the macro expansion. For example, if the macro's body began like this:

NAME   MACRO   P1,P2,P3
       CLA     LOCAT,4
       ...
NAME   END

then the expansion of

ABCDEF NAME    X,Y,Z

would begin

ABCDEF CLA     LOCAT,4

An alternative form of macro definition could change this behavior. If you wrote

        MACRO
SYMPAR  NAME   P1,P2,P3
        ...
NAME    END

then the macro would essentially gain a new parameter, here named SYMPAR, which would be matched to a symbol given in the location field of a use of the macro. Thus in the expansion of

ABCDEF NAME    X,Y,Z

any occurrences of SYMPAR would be replaced by ABCDEF. (This alternative form works in MAP, but it is not documented in any of the MAP manuals listed above.)


The IBM 709/7090/7094 support indirect addressing, indicated in assembly code by placing an asterisk after the operation mnemonic. So the instruction

       STA*    LOC

Replaces the address part of the accumulator with the value stored at the address stored in LOC. What happens if a macro-instruction includes the indirection tag? For instance, what would happen if I said

       NAME*   X,Y,Z

For an incredible demonstration of the assembler's abilities, see this code from 1966, which expresses preloaded list structure in a Lisp interpreter by using macros: https://github.com/rcornwell/ctss/blob/master/extra/lisp/atoms.fap.

1
  • 1
    You may want to have a look at the /360 ASSEMBF as that macro language is a follow up with a more regular structure, dropping all machine specific parts in favour for a more regular structure. – Raffzahn Apr 17 at 1:32
8

This is not documented anywhere, as far as I can tell. But the source code of a few versions of the assemblers is available, so we can look there.

It turns out that there is a third form of macro definition. If you say MACRO* instead of MACRO, then the contents of the first parameter of your macro will be * if the macro was invoked with an asterisk, and empty otherwise. So

DOIT   MACRO* I,D,S,IR
       SXA    S,IR
       TSX'I  D,IR
DOIT   END

would define a (useless) macro that carried an indirection flag to the TSX. When invoked as

       DOIT   PLACE1,PLACE2,4

the expansion is

       SXA    PLACE2,4
       TSX    PLACE1,4

but if invoked as

       DOIT*  PLACE1,PLACE2,4

the expansion is

       SXA    PLACE2,4
       TSX*   PLACE1,4

Here is an excerpt from MAP's source code. (You can find it as 7090-SP-804 IBMAP here; append .gz to the printable ASCII tape links to get them to work.)

* THE INTERNAL DICTIONARY ENTRY FOR A MACRO-INSTRUCTION HAS THE FORM (6)4J161702
*                                                                    (6)4J161704
*              O6/62,12/N,3/SC,15/SKEL                               (6)4J161706
*                                                                    (6)4J161708
*      WHERE                                                         (6)4J161710
*                                                                    (6)4J161712
*              N IS THE NUMBER OF ARGUMENTS                          (6)4J161714
*                                                                    (6)4J161715
*              SC IS 2 TO SUPPRESS CREATED SYMBOLS FOR MISSING ARGS  (6)4J161716
*                    6 TO FORCE CREATION OF MISSING ARG SYMBOLS      (6)4J161718
*                    0 FOR SYMBOL CREATION UNDER NOCRS CONTROL       (6)4J161720
*                                                                    (6)4J161722
*              SKEL IS THE ADDRESS OF THE CHAIN WORD PRECEDING THE   (6)4J161724
*                   SKELETON FOR THE CORRESPONDING MACRO DEFINITION  (6)4J161726
*                                                                    (6)4J161728
* EACH SKELETON IS PRECEDED BY A CHAIN WORD WHOSE                    (6)4J161730
*                                                                    (6)4J161732
*              ADDRESS IS A POINTER TO THE CHAIN WORD FOR THE NEXT   (6)4J161734
*                   SKELETON (OR END OF DEFINITION STORAGE IF LAST)  (6)4J161736
*                                                                    (6)4J161738
*              DECREMENT IS A POINTER TO THE DICTIONARY ENTRY        (6)4J161740
*                                                                    (6)4J161742
*              PREFIX HAS FLAGS FOR PURGE AS FOLLOWS..               (6)4J161744
*                                                                    (6)4J161746
*                   S - SKELETON IS TO BE PURGED FROM TABLE          (6)4J161748
*                   1 - CANNOT BE PURGED BECAUSE OTHER DEFINITIONS   (6)4J161750
*                       REFER TO THIS ONE VIA OPSYN                  (6)4J161752
*                   2 - CONTAINS ADDRESS POINTERS FOR OPSYN          (6)4J161754
*                                                                    (6)4J161756
* THE TAG FIELD OF THE CHAIN WORD SUPPLEMENTS THE DICTIONARY ENTRY   (6)4J161758
*      WITH FLAGS FOR                                                (6)4J161759
*                                                                    (6)4J161760
*              LOCATION FIELD OF MACRO IS A PARAMETER (BIT 18).      (6)4J161762
*                                                                    (6)4J161763
*              NAME OF MACRO-INSTRUCTION IS A PARAMETER (BIT 19).    (6)4J161764
*                                                                    (6)4J161765
*              THE USE OF INDIRECT ADDRESSING OF THIS MACRO IS A     (6)4J161766
*                   PARAMETER (BIT 20 OF CHAIN WORD).  THE ARGUMENT  (6)4J161768
*                   WHICH WAS FIRST IN THE VARIABLE FIELD OF THE     (6)4J161770
*                   MACRO HEADER WILL BE REPLACED IN THE EXPANSION   (6)4J161772
*                   BY THE NULL STRING OR BY AN * ACCORDING TO THE   (6)4J161774
*                   ABSENCE OR PRESENCE OF AN ASTERISK TERMINATING   (6)4J161776
*                   THE OPERATION CODE IN THE CALL.  THE FIRST FIELD (6)4J161778
*                   OF THE VARIABLE FIELD OF THE CALL CORRESPONDS TO (6)4J161780
*                   THE SECOND PARAMETER IN THE VARIABLE FIELD OF    (6)4J161782
*                   THE MACRO HEADER CARD, ETC.                      (6)4J161784

The last point, about bit 20, is the relevant portion. Here “skeleton” is referring to the macro's replacement text.

I haven't yet found any code that actually uses this feature, except for some built-in internal macros to the MAP assembler (see, e.g., card 4J198700).

(I'm not sure whether the feature was implemented in FAP or not. A location MCDIND is reserved for a “FLAG FOR INDIRECTLY ADDRESSED MACRO”, but the code doesn't seem to do anything with it besides stack and unstack it as macro depth changes. I could certainly be wrong.)


What happens if you use the asterisk on a macro not defined with MACRO*? It's an error.

MCC.22 RNT     100000              IS INDIRECT ADDRESS AN ARGUMENT   (6)4J119300
       TRA     MCC.23              NO, CHECK FOR MISUSED *           (6)4J119400
       CLA     INDPAR              YES, PREPARE TO STUFF *           (6)4J119410
       ZET     SWIND               WAS OP CODE STARRED               (6)4J119420
       ACL     1DECR               YES, ARG HAS LENGTH ONE           (6)4J119430
       TSX     XPLCE,4             PLACE PARAMETER                   (6)4J119440
       TXL     MCC.24,2,0          CHECK FOR MORE ARGUMENTS          (6)4J119450
       TXI     MCC.24,2,-1                                           (6)4J119460
       SPACE                                                         (6)4J119470
MCC.23 ZET     SWIND               WAS OP CODE STARRED               (6)4J119480
       TSX     INDXB,4             YES, FILE ERROR MESSAGE           (6)4J119490
       SPACE   1                                                        4J119500

The transfer to INDXB causes the message INDIRECT ADDRESS NOT ALLOWED ON THIS INSTRUCTION to be printed (eventually).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.