III.11.7 Nested and Recursive Macro Calls
Macro bodies may also contain macro calls, and so may the bodies of those
called macros, and so forth.
INSIDE MACRO SUBB A,R3 ENDM OUTSIDE MACRO MOV A,#42 INSIDE MOV R7,A ENDM
In the body of the macro OUTSIDE, the macro ISIDE is called. If OUTSIDE is called (and the list mode is set to $GENONLY), one gets something like the following expansion:
Line I Addr Code Source 15+ 1 0000 74 2A MOV A,#42 17+ 2 0002 9B SUBB A,R3 18+ 1 0003 FF MOV R7,A
Since macro calls can be nested to any depth (while there is free memory), the macro expansion level is shown in the I-column of the list file. Since macro and include file levels can be nested in arbitrary sequence and depth, the nesting level is counted through all macro and include file levels regardless. For better distinction, the character following the global line number is ':' for include file levels, and '+' for macro levels.
If macros are calling themselves, one speaks of recursive macro calls. In this case, there must be some stop criterion, to prevent the macro of calling itself over and over until the assembler is running out of memory! Here again, conditional assembly is the solution:
The macro COUNTDOWN is to define 16-bit constants from 1 thru n in descending order in ROM. n can be passed to the macro as a parameter:
COUNTDOWN MACRO DEPTH IF DEPTH GT 0 DW DEPTH COUNTDOWN %DEPTH-1 ENDIF ENDM
If COUNTDOWN is called like this,
something like the following macro expansion results (in list mode $GENONLY/$CONDONLY):
Line I Addr Code Source 16+ 1 0000 00 07 DW 7 19+ 2 0002 00 06 DW 6 22+ 3 0004 00 05 DW 5 25+ 4 0006 00 04 DW 4 28+ 5 0008 00 03 DW 3 31+ 6 000A 00 02 DW 2 34+ 7 000C 00 01 DW 1
After the Dark Ages, when the dust was settling and the sun broke through
the gloom, computer science discovered the method of recursive programming.
There was no doubt that this was the Solution!
The Towers of Hanoi
;The Towers of Hanoi $GENONLY CONDONLY DISCS EQU 3 ;number of discs HANOI MACRO n, SOURCE, DESTINATION, SCRATCH IF n > 0 HANOI %(n-1), SOURCE, SCRATCH, DESTINATION ; move topmost disc from stick &SOURCE to stick &DESTINATION HANOI %(n-1), SCRATCH, DESTINATION, SOURCE ENDIF ENDM HANOI DISCS, 1, 2, 3 END
The recursive macro HANOI generates an instruction manual for the Problem, where the instructions appear as comment lines in the list file. The symbol DISCS must be set to the desired number of discs. If HANOI is called like this,
HANOI 3, 1, 2, 3
the following "instruction manual" is generated:
27+ 3 ; move topmost disc from stick 1 to stick 2 35+ 2 ; move topmost disc from stick 1 to stick 3 44+ 3 ; move topmost disc from stick 2 to stick 3 53+ 1 ; move topmost disc from stick 1 to stick 2 64+ 3 ; move topmost disc from stick 3 to stick 1 72+ 2 ; move topmost disc from stick 3 to stick 2 81+ 3 ; move topmost disc from stick 1 to stick 2
The GENONLY and CONDONLY controls ensure that the table doesn't contain all the macro calls and IF constructions.