h3 macro, .macro, endm and .endm macro, endm p '.macro' starts a macro definition and '.endm' ends it. Macros are assigned a name by which they can later be used at the place of an ordinary instruction to insert the macro body. p There are quite numerous formats used by different assemblers and zasm tries to support at least some of them out of the box. In the following code examples the instruction names with or without a dot can be used interchangeably. h5 Define a simple macro without arguments pre .macro ... .endm p Alternate syntax: pre .macro ... .endm p.b Example: pre counter = 0 .macro COUNT counter = counter + 1 .endm   ... COUNT ...   final_count equ counter p This defines a counter for something, e.g. Forth words if your source happens to be a Forth interpreter. It uses a redefinable label which is redefined every time the macro is used in the source. The final value of the redefinable label is only really the final value at the end of your source. In order to use it before the last occurance of the macro, it is finally copied into another label named 'final_count' which can be used everywhere in the source. h5 Define a macro with arguments pre .macro [ , … ] ... .endm p Alternate syntax: pre .macro [ , … ] ... .endm p Invocation: pre [ , … ] p This defines a macro with some arguments. Either of both definition styles are possible. Additionally there are different methods for defining and referencing the symbol arguments: pre foo: .macro A, B ; 1) ld &A, &B .endm   .macro foo, A, B ; 2) ld \A, \B .endm   foo: .macro &A, &B ; 3) ld &A, &B .endm   .macro foo, %A, %B ; 4) ld %A, %B .endm h5 Argument processing in the macro definition p A special character, a 'tag', should be preprended to the argument names in the head and body. This 'tag' varies from assembler to assembler. zasm treats any non-letter character at start of the argument names as this 'tag'. Most commonly used is '&'. p Some assemblers required the tag only in the macro body, not in the head, see version 1) and 2) in the above example. zasm supports this "as seen in source examples" in the following way: ul li If the macro is defined as macro then the tag is '&'. li If the macro is defined as macro then the tag is '\'. p Also, the tag is not required in the body if it was not written in the argument list. Then argument references must be full words, whereas with tag they are also detected as part of a words. p.i The use of '&' is recommended. All other tags are to support various sources out of the box only! p.b Example: pre foo: macro &A ld b,&A foo&A: ld a,' ' ; <-- simple unique label name rst 8 djnz foo&A endm   ... foo 20 ... foo 8 p In this example the argument is used as the second argument for 'ld b,N' and to construct a unique label name for each invocation. Another solution would have been to use a counter and a redefinable label. pre .macro foo_define &NAME, &rr ld_&NAME_&rr = ld_int_&rr .endm p In this example '&NAME' in 'ld_&NAME_&rr' is also replaced, though 'NAME' is only the first 4 characters of the potential 5-letter name 'NAME_'. p An example without tag character: pre DWA: MACRO WHERE DB (WHERE >> 8) + 128 DB WHERE & 0FFH ENDM h5 Argument processing in the macro invocation p There are two methods for argument parsing, the standard 'clean & simple' one, and one for complex arguments. p.b Standard arguments p Arguments must follow the basic syntax rules: strings or character literals must be closed (balanced delimiters) and arguments end at the next comma, semicolon or line end. Brackets are not required to match. pre foo a, 1+2, a*(1+2) foo (, "hi, i'm Kio!", ) ; 3 arguments p.b Complex arguments p Complex arguments start with an opening '<' and run up to the next '>' which is followed by a comma, a semicolon or the line end. With the help of the angle brackets you can pass unbalanced ''' and '"' or a comma or a semicolon as one argument to a macro. It is also helpful if you need to pass spaces at the start or end of an argument, or even just a space. pre foo <,>, <;>, <"> ; 3 arguments: , ; and " foo <<>, < >, ; 3 arguments: < space and ld a,b foo >, ><, ; 3 arguments: > >< and nothing p There are still some impossible combinations, e.g. it is not possible to pass <>, (3 characters) as an argument. p.b '{...}' replacement p Since version 4.4.6 numeric expressions between '{' and '}' are evaluated and immediately replaced with the resulting text. This also happens for macro arguments. If you mix this with the complex argument style then you can probably run into interesting problems. B-) h5 Labels in macros p Frequently you need some program labels in a macro, but if you use a macro more than once then you'll have multiple definitions of this label name and assembly fails. ul li Use redefinable labels instead which are defined with 'defl', '=' or 'set' li or use a local context between '.local' and '.endlocal' (since version 4.4.6) li or construct unique label names using a redefinable counter and text replacement with '{…}'. h5 Literal text replacement of expressions between '{' and '}' p Expressions between '{' and '}' are evaluated and immediately replaced with the result ul li Since version 4.2.6 in macros li Since version 4.4.6 everywhere p.b Example: pre cnt: .equ 0 ; initialize redefinable label 'cnt'   ; calculate unsigned max ; &A = umax(&A,&B) ; usable for a and hl.   umax: .macro &A, &B and a sbc &A,&B jr nc,L{cnt} ld &A,&B jr L{cnt+1} L{cnt}: add &A,&B L{cnt+1}: cnt .equ cnt+2 ; next macro call will use L2 and L3 and so on .endm p.b Difference between version 4.2.6 and 4.4.6: p Since version 4.2.6 the text replacement was done at the point of the macro replacement. This had a subtle side effect: All expressions between '{' and '}' were already evaluated before the lines from the macro were assembled. Therefore redefinitions of labels performed inside the macro had no effect on '{…}' expressions until the end of the macro. So in the above example the line cnt .equ cnt+2 had no effect on the expressions between '{' and '}' even if this line was the very first in the macro; but it would have effected all other normal expressions in the macro as expected. (in the above example there is none except in the cnt incrementing expression itself.) pre cnt = 0 .macro Foo cnt = cnt+1 L{cnt}: .dw cnt ; 1) cnt = cnt+1 L{cnt}: .dw cnt ; 2) .macro p In this example the label in line 1) would still be 'L0' while the value stored with '.dw' would be 1. In line 2) the label again would still be 'L0' (and assembly fails) while the value stored with '.dw' would be 2. This was irritating and is no longer the case since version 4.4.6. p Since version 4.4.6 text replacements between '{' and '}' are now possible everywhere in the source and they are done when the lines are actually assembled. Now in the above example the label names are 'L1' and 'L2' as expected. h5 conditional assembly with '.if' in macros p It is possible to conditionally exclude portions of the macro by use of the pseudo instructions '.if', '.else' and '.endif'. (do not use '#if' and '#endif'!) h5 Assembler directives in macros p.red Assembler directives (starting with '#') inside macros are possible but deprecated. p Also, you should not use '#' for your argument tag. h5 Nested macro definitions p Since version 4.4.6 macro dfinitions inside macro definitions are possible and may make some sense with text replacement between '{' and '}'. But you really should know what you are doing! h5 Not implemented: ul li Reference to arguments without a tag character li Keyword 'local' before a to define a single local label: try to use 'defl'. since version 4.4.6: use a local context: '.local' … '.endlocal'