2 MACRO PREPROCESSOR

This chapter contains the following sections:

Introduction
mpp51 Invocation
Detailed Description of Macro Preprocessor Options
INCLUDE Files
Creating and Calling Macros
Creating Parameterless Macros
Creating Macros with Parameters
Local Symbols in Macros
The Macro Preprocessor's Built-In Functions
Comment, Escape and Bracket Functions
Comment Function
Escape Function
Bracket Function
METACHAR Function
Numbers and Expressions in mpp51
SET Function
EVAL Function
Logical Expressions and String Comparisons in mpp51
Control Flow Functions and Conditional Assembly
IF Function
IFDEF/IFNDEF Function
WHILE Function
REPEAT Function
EXIT Function
String Manipulation Functions
LEN Function
SUBSTR Function
MATCH Function
Console I/O Functions
Advanced mpp51 Concepts
Macro Delimiters
Implied Blank Delimiters
Identifier Delimiters
Literal Delimiters
Literal vs. Normal Mode
Algorithm for Evaluating Macro Calls

2.1 Introduction

The macro preprocessor, mpp51, is a string manipulation tool which allows you to write repeatedly used sections of code once and then insert that code at several places in your program. mpp51 also handles conditional assembly, assembly-time loops, console I/O and recursion.

The macro preprocessor is implemented as a separate program which saves both time and space in an assembler, particularly for those programs that do not use macros and thus need not run the macro preprocessor. mpp51 is compatible with Intel's syntax for the 8051 macro processing language (MPL). A user of macros must submit his source input to the macro preprocessor. The macro preprocessor produces one output file which can then be used as an input file to the 8051 Cross-assembler.

The macro preprocessor regards its input file as a stream of characters, not as a sequence of statements like the assembler does. The macro preprocessor scans the input (source) file looking for macro calls. A macro-call is a request to the macro preprocessor to replace the call pattern of a built-in or user-defined macro with its return value.

As soon as a macro call is encountered, the macro preprocessor expands the call to its return value. The return value of a macro is the text that replaces the macro call. This value is then placed in a temporary file, and the macro preprocessor continues. The return value of some macros is the null string, i.e., a character string containing no characters. So, when these macros are called, the call is replaced by the null string on the output file, and the assembler will never see any evidence of its presence. This is of course particularly useful for conditional assembly.

This chapter documents mpp51 in several parts. First the invocation of mpp51 is described. The following sections describe how to define and use your own macros, describe the syntax of the macro processing language and describe the macro preprocessor's built-in functions. This chapter also contains a section that is devoted to the advanced concepts of mpp51.

The first five sections give enough information to begin using the macro preprocessor. However, sometimes a more exact understanding of mpp51's operation is needed. The advanced concepts section should fill those needs.

At macro time, symbols, labels, predefined assembler symbols, EQU, and SET symbols, and the location counter are not known. The macro preprocessor does not recognize the assembly language. Similarly, at assembly time, no information about macro symbols is known.

2.2 mpp51 Invocation

The command line invocation line of mpp51 is:

When you use a UNIX shell (C-shell, Bourne shell), arguments containing special characters (such as '( )' ) must be enclosed with " ". The invocations for UNIX and PC are the same, except for the -? option in the C-shell:

The input-file is an assembly source file containing user-defined macros. You must give a complete filename (no default file extension is taken).

The output-file is an assembly source file in which all user-defined macros are replaced. This file is the input file for asm51. If output-file is omitted, the output file has the same basename as the input file but with the file extension .src.

Invocation with -V only displays a version header.

Option Description
-? Display invocation syntax
-Dmacro=def Define preprocessor macro
-f file Read options from file
-Idirectory Look in directory for include files
-V Display version header only
-o filename Specify name of output file

Table 2-1: mpp51 options

2.2.1 Detailed Description of Macro Preprocessor Options

With options that can be set from within EDE, you will find a mouse icon that describes the corresponding action.

-?

Option:

-?

Description:

Display an explanation of options at stdout.

Example:

mpp51  -?

-D

Option:

From the Project menu, select Project Options... Expand the Assembler entry and select Macro Preprocessor. Define a macro (syntax: macro[=def]) in the Define user macros field. You can specify and define more macros by separating them with commas.

-Dmacro=[def]

Arguments:

The macro you want to define and optionally its definition.

Description:

Define macro as in 'define'. Any number of symbols can be defined. If def is not given, the symbol is undefined (empty string).

Example:

The following command defines symbol LEVEL to 3:

The following command undefines symbol LEVEL:

-f

Option:

From the Project menu, select Project Options... Expand the Assembler entry and select Macro Preprocessor. Add the option to the Additional macro preprocessor options field.

-f file

Arguments:

A filename for command line processing. The filename "-" may be used to denote standard input.

Description:

Use file for command line processing. To get around the limits on the size of the command line, it is possible to use command files. These command files contain the options that could not be part of the real command line. Command files can also be generated on the fly, for example by the make utility.

More than one -f option is allowed.

Some simple rules apply to the format of the command file:

1. It is possible to have multiple arguments on the same line in the command file.

2. To include whitespace in the argument, surround the argument with either single or double quotes.

3. If single or double quotes are to be used inside a quoted argument, we have to go by the following rules:

a. If the embedded quotes are only single or double quotes, use the opposite quote around the argument. Thus, if a argument should contain a double quote, surround the argument with single quotes.

b. If both types of quotes are used, we have to split the argument in such a way that each embedded quote is surrounded by the opposite type of quote.

Example:

or

or

4. Some operating systems impose limits on the length of lines within a text file. To circumvent this limitation it is possible to use continuation lines. These lines end with a backslash and newline. In a quoted argument, continuation lines will be appended without stripping any whitespace on the next line. For non-quoted arguments, all whitespace on the next line will be stripped.

Example:

5. It is possible to nest command line files up to 25 levels.

Example:

Suppose the file mycmds contains the following line:

The command line can now be:

-I

Option:

From the Project menu, select Directories... Add one or more directory paths to the Include Files Path field.

-Idirectory

Arguments:

The name of the directory to search for include file(s).

Description:

Change the algorithm for searching $INCLUDE files whose names do not have an absolute pathname to look in directory. Thus, $INCLUDE files are searched for first in the directory of the file containing the $INCLUDE line, then in directories named in -I options in left-to-right order. If the files are still not found mpp51 checks if the environment variable ASMDIR exists. If it does, it searches the directories specified in ASMDIR. More than one directory can be specified to ASMDIR by separating the directories with a semi-colon ';'.

Example:

mpp51 -I/proj/include test.asm

Section Include Files

-o

Option:

EDE determines the name of the output file with the same basename as the input file and extension .src..

-o filename

Arguments:

An output filename.

Default:

Basename of input file with .src suffix.

Description:

Use filename as output filename of the macro preprocessor, instead of the basename of the input file with the .src extension.

Example:

To create the assembly file myfile.src instead of test.src, enter:

-V

Option:

-V

Description:

With this option you can display the version header of the macro preprocessor. This option must be the only argument of mpp51. Other options are ignored. mpp51 exits after displaying the version header.

Example:

mpp51 -V
TASKING 8051 macro preprocessor   vx.yrz Build nnn
Copyright years Altium BV         Serial# 00000000

2.3 INCLUDE Files

If the macro preprocessor encounters a $INCLUDE statement in the input file, preprocessing will continue by scanning the specified file until an end-of-file or another INCLUDE is encountered.

Syntax:

$INCLUDE(file)

Abbreviation:

$IC(file)

Expansion:

$<spaces><eol># 1 "file"

Description:

The '$' must be in column 1 for the macro preprocessor to recognize it for processing at macro time. In the output file the INCLUDE(file) part of the INCLUDE call is replaced by spaces (because the assembler also recognizes the '$' character but does not recognize INCLUDE as a control). Also a line containing # 1 "file" is put in the output file.

As soon as the macro preprocessor encounters an end-of-file in the include file, input is resumed where it left off, namely at the next line after the latest INCLUDE call (which due to nesting does not necessarily mean returning to the original input file). Nesting of include files is allowed up to 32 files.

If the macro preprocessor after recognizing the '$' character does not find an INCLUDE before it encounters an end-of-line, due to misspelling or simple because the '$' is followed by a control only recognized by the assembler, no macro-time error is reported and scanned characters are simply passed to the output file.

mpp51 first searches for $INCLUDE files in the directory of the file containing the $INCLUDE line, then in directories named in -I options in left-to-right order. If the files are still not found mpp51 checks if the environment variable ASMDIR exists. If it does, it searches the directories specified in ASMDIR. More than one directory can be specified to ASMDIR by separating the directories with a semi-colon ';'.

Restriction:

Each control line (i.e. a line starting with '$') may not contain more than one INCLUDE call.

Example:

; source lines
.
$include( mysrc.inc )     ; include the contents of
                          ; file mysrc.inc
.
; other source lines
.

2.4 Creating and Calling Macros

Macro calls differ between user-defined macros and so-called built-in functions. All characters in bold typeface in the syntax descriptions of the following sections are constituents of the macro syntax. Italic tokens represent place holders for user-specific declarations.

The macro preprocessor scans through the input source, one character at a time, looking for a special character called the METACHARACTER, the percent sign '%' initially. This metacharacter must precede a macro-call. Until the macro preprocessor finds a metacharacter, it does not process text. It simply passes the text from the input file to the output file.

Since mpp51 only processes macro calls, it is necessary to call a macro in order to create other macros, the so-called "user-defined macros". The built-in function DEFINE creates macros. Built-in functions are a predefined part of the macro language, so they may be called without prior definition. The general syntax for DEFINE is shown below.

Syntax:

DEFINE is the most important mpp51 built-in function. This section is devoted to describing this built-in function. Each of the symbols in the syntax above (macro-name, parameter-list, local-list and macro-body) are described in detail on the pages that follow. In some cases, we have abbreviated this general syntax to emphasize certain concepts.

2.4.1 Creating Parameterless Macros

When you create a parameterless macro, there are two parts to a DEFINE call: the macro-name and the macro-body. The macro-name defines the name used when the macro is called; the macro-body defines the return value of the call.

Syntax:

The '%' character signals a macro call. The '*' is the optional literal character. When you define a macro using the literal character '*', as shown above, macro calls contained in the body of the macro are not expanded until the macro is called. The exact use of the literal character is discussed in the advanced concept section. When you define a parameterless macro, the macro-name is a macro identifier that follows the '%' character in the source line. The rules for macro identifier are:

- The identifier must begin with an upper or lowercase alphabetic character (A,B,...,Z or a,b,...,z), or a special character ( a question mark '?' or an underscore character '_').

- The remaining characters may be alphabetic, special or decimal digits (0,1,2,...,9).

- Only the first 31 characters of a macro identifier are recognized as the unique identifier name. Upper and lower case characters are not distinguished in a macro identifier.

The macro-body is usually the return value of the macro call. However, the macro-body may contain calls to other macros. If so, the return value is actually the fully expanded macro-body, including the return values of the call to other macros. The macro call is re-expanded each time it is called.

Example 1:

%*DEFINE (String_1)   (An)

%*DEFINE (String_2)   (ele)

%*DEFINE (String_3)   (phant)

%*DEFINE (String_4)   (shopping)

%DEFINE (String_5)    (goes
%String_4)

%DEFINE (Part_1)
     (%String_1 %String_2%String_3)

The macro-body must consist of a balanced-text string, i.e. you must have balanced parentheses within the macro-body. In other words, each left parenthesis must have a succeeding right parenthesis, and each right parenthesis must have a preceding left parenthesis.

The possible placement of the macro-body and the parenthesis are both represented in the above examples. The beginning of the macro-body is determined by the syntactical end of the left parenthesis, where tabs (08H), blanks and the first new line (0AH) are also part of the macro-body.

The macro-body of String_1 starts with the 'A' of "An"
The macro-body of String_3 starts with the 'p' of "phant"
The macro-body of String_4 starts with the '(08H)' of "(08H)shopping".

The end of macro-body is determined by the right parenthesis.

The macro-body of String_4 is "(08H)shopping"
The macro-body of String_5 is "goes (0AH)
(08H)shopping"

The expanded value of DEFINE is the null string, but the macro body is stored internally for later use. User-defined macros may invoke themselves within their bodies. This property is called 'recursion'. Any macro which calls itself must terminate eventually or the macro preprocessor may enter an infinite loop.

Once a macro has been created, it may be redefined by a second call to DEFINE.

To call a macro, you use the '%' character followed by the name of the macro (the literal character '*' is only admissible for defined macros whose call is passed to a macro as a an actual parameter; example: %M1(%*M2)). The macro preprocessor removes the call and inserts the return value of the call. If the macro-body contains any call to other macros, they are replaced with their return values.

Example 2:

%Part_1 %String_5   -->  An elephant goes
                         shopping

Once a macro has been created, it may be redefined by a second call to DEFINE. Note, however that a macro should not redefine itself within its body (see Advanced mpp51 Concepts).

The examples below show several macro definitions. Their return values are also shown.

Example 3:

Macro definition at the top of the program:

%*DEFINE (MOVE)
(    MOV  A, @R1
     MOV  @R2, A
)

The macro call as it appears in the program:

     MOV  R1, #1
----%MOVE

The program as it appears after the macro preprocessor made the following expansion, where the first expanded line is preceded by the four blanks preceding the call (the sign - indicates the preceding blanks):

     MOV  R1, #1
----     MOV  A, @R1
     MOV  @R2, A

Example 4:

Macro definition at the top of the program:

%*DEFINE (ADD5)
(    MOV  R0, #5
     MOV  R5, @R2
     ADD  R5, R0
)

The macro call as it appears in the original program body:

     MOV  R5, #2
%ADD5

The program after the macro expansion:

     MOV  R5, #2
     MOV  R0, #5
     MOV  R5, @R2
     ADD  R5, R0

Example 5:

Macro definition at the top of the program:

%*DEFINE (MOVE_AND_ADD) (
     %MOVE
     %ADD5
)

The macro call as it appears in the body of the program:

     MOV  R1, #1
%MOVE_AND_ADD

The program after the macro expansion:

     MOV  R1, #1

     MOV  A, @R1
     MOV  @R2, A

     MOV  R0, #5
     MOV  R5, @R2
     ADD  R5, R0

2.4.2 Creating Macros with Parameters

If the only function of the macro preprocessor was to perform simple string replacement, then it would not be very useful for most of the programming tasks. Each time we wanted to change even the simplest part of the macro's return value we would have to redefine the macro.

Parameters in macro calls allow more general-purpose macros. Parameters leave holes in a macro-body that are filled in when you call the macro. This permits you to design a single macro that produces code for typical programming operations. The term 'parameters' refers to both the formal parameters that are specified when the macro is defined (the holes, and the actual parameters or arguments that are specified when the macro is called (the fill-ins).

The syntax for defining macros with parameters is very similar to the syntax for macros without parameters.

Syntax:

The macro-name must be a valid identifier.

The parameter-list is a list of macro identifiers separated by macro delimiters. These identifiers comprise the formal parameters used in the macro. The macro identifier for each parameter in the list must be unique, but they may be the same as other formal argument names to other macros since they have no existence outside the macro definition. They may also be the same as the names of other user macros or of macro functions. Note, however that in this case the macro or function cannot be used within the macro-body, since its name would be recognized as a parameter instead. To reference a formal argument within the macro-body, use its name preceded by the metacharacter.

Typically, the macro delimiters are parentheses and commas. When using these delimiters, you would enclose the parameter-list in parentheses and separate each formal parameter with a comma. When you define a macro using parentheses and commas as delimiters, you must use those same delimiters, when you call that macro.

The example below shows the definition of a macro with three parameters: SOURCE, DEST and COUNT. The macro produces code to copy any number of words from one part of memory to another.

Example:

%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT))
(    MOV  R1, #%SOURCE
     MOV  R0, #%DEST
     MOV  R7, #%COUNT
     MOV  A, @R1
     MOV  @R0, A
     INC  R1
     INC  R0
     DJNZ R7, ($-4)
)

To call a macro with parameters, you must use the metacharacter followed by the macro's name as with parameterless macros. However, a list of the actual parameters must follow. These actual parameters have to be enclosed within parentheses and separated from each other by commas. The actual parameters may optionally contain calls to other macros.

A simple call to a macro defined above might be:

%MOVE_ADD_GEN( 10, 24, 8 )

The above macro call produces the following code:

     MOV  R1, #10
     MOV  R0, #24
     MOV  R7, #8
     MOV  A, @R1
     MOV  @R0, A
     INC  R1
     INC  R0
     DJNZ R7, ($-4)

2.4.3 Local Symbols in Macros

If we used a fixed label instead of the offset ($-4) in the previous example, the macro using the fixed label can only be called once, since a second call to the macro causes a conflict in the label definitions at assembly time. The label can be made a parameter and a different symbol name can be specified each time the macro is called.

A preferable way to ensure a unique label for each macro call is to put the label in a local-list. The local-list construct allows you to use macro identifiers to specify assembly-time symbols. Each use of a LOCAL symbol in a macro guarantees that the symbol will be replaced by a unique assembly-time symbol each time the symbol is called.

The macro preprocessor increments a counter once for each symbol used in the list every time your program calls a macro that uses the LOCAL construct. Symbols in the local-list, when used in the macro-body, receive a two to five digit suffix that is the hexadecimal value of the counter. The first time you call a macro that uses the LOCAL construct, the suffix is '00'.

The syntax for the LOCAL construct in the DEFINE function is shown below. (This is the complete syntax for the built-in function DEFINE):

Syntax:

The local-list is a list of valid macro identifiers separated by spaces. Since these macro identifiers are not parameters, the LOCAL construct in a macro has no effect on a macro call.

To reference local symbols in the macro-body, they must be preceded by the metacharacter. The symbol LOCAL is not reserved; a user symbol or macro may have this name.

The next example shows a macro definition that uses a LOCAL list.

Example:

%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) LOCAL LAB
(    MOV  R1, #%SOURCE
     MOV  R0, #%DEST
     MOV  R7, #%COUNT
%LAB:
     MOV  A, @R1
     MOV  @R0, A
     INC  R1
     INC  R0
     DJNZ R7, %LAB
)

A simple call to a macro defined above might be:

%MOVE_ADD_GEN( 50, 100, 24 )

The above macro call might produce the following code (if this is he eleventh call to a macro using a LOCAL list):

     MOV  R1, #50
     MOV  R0, #100
     MOV  R7, #24
LAB0A:
     MOV  A, @R1
     MOV  @R0, A
     INC  R1
     INC  R0
     DJNZ R7, LAB0A

Since macro identifiers follow the same rules as ASM51, any macro identifier can be used in a local-list. However, if long identifier names are used, they should be restricted to 29 characters. Otherwise, the label suffix may cause the identifier to exceed 31 characters and these would be truncated.

2.5 The Macro Preprocessor's Built-In Functions

The macro preprocessor has several built-in or predefined macro functions. These built-in functions perform many useful operations that are difficult or impossible to produce in a user-defined macro.

We have already discussed one of these built-in functions, DEFINE. DEFINE creates user-defined macros. DEFINE does this by adding an entry in the macro preprocessor's tables of macro definitions. Each entry in the tables includes the macro-name of the macro, its parameter-list, its local-list and its macro-body. Entries for the built-in functions are present when the macro preprocessor begins operation.

Other built-in functions perform numerical and logical expression evaluation, affect control flow of the macro preprocessor, manipulate character strings, and perform console I/O.

The following sections deal with the following:

Comment, escape , bracket ('...', '..., n..., (...) )

Metachar function ( METACHAR)

Expressions processed by mpp51

Calculating functions ( SET , EVAL )

Controlling functions ( IF , IFDEF/IFNDEF, WHILE , REPEAT , EXIT )

String-processing functions ( LEN , SUBSTR , MATCH )

String-comparing functions (EQS, NES, LTS, LES, GTS, GES)

Input/Output functions ( IN, OUT)

2.5.1 Comment, Escape and Bracket Functions

2.5.1.1 Comment Function

The macro processing language can be very subtle, and the operation of macros written in a straightforward manner may not be immediately obvious. Therefore, it is often necessary to comment macro definitions.

Syntax:

or

The comment function always evaluates to the null string. Two terminating characters are recognized: the apostrophe ' and the end-of-line (line-feed character, ASCII 0AH). The second form of the call allows macro definitions to be spread over several lines, while avoiding any unwanted end-of-lines in the return value. In either form of the comment function, the text or comment is not evaluated for macro calls.

Example:

%*DEFINE (MOVE_ADD_GEN(SOURCE,DEST,COUNT)) LOCAL LAB
(    MOV  R1, #%SOURCE %'This is the source address'
     MOV  R0, #%DEST %'This is the destination'
     MOV  R7, #%COUNT %'%COUNT must be a constant'
%LAB:     %'This is a local label.
%'End of line is inside the comment!
     MOV  A, @R1
     MOV  @R0, A
     INC  R1
     INC  R0
     DJNZ R7, %LAB
)

Call the above macro:

%MOVE_ADD_GEN( 50, 100, 24 )

Return value from above call:

     MOV  R1, #50
     MOV  R0, #100
     MOV  R7, #24
LAB0A:
     MOV  A, @R1
     MOV  @R0, A
     INC  R1
     INC  R0
     DJNZ R7, LAB0A

Note that the comments that were terminated with the end-of-line removed the end-of-line character along with the rest of the comment.

The metacharacter is not recognized as flagging a call to the macro preprocessor when it appears in the comment function.

2.5.1.2 Escape Function

Sometimes it is necessary to prevent the macro preprocessor from processing text. The escape function and the bracket function perform such tasks.

Syntax:

The escape function prevents the macro preprocessor from processing a text string of n characters long, where n is a decimal digit from 0 to 9. The escape function is useful for inserting a metacharacter as text, adding a comma as part of an argument, or placing a single parenthesis in a character string that requires balanced parentheses.

Example:

Before Macro Expansion  After Macro Expansion

;Average of 20%1%         ->;Average of 20%

%DTCALL(JAN 21%1, 1992,   -> JAN 21, 1992 
       JUN 12%1, 1992)    -> JUN 12, 1992

%MYCALL(1%1) Option 1,    -> 1) Option 1
       2%1) Option 2,     -> 2) Option 2
       3%1) Option 2)     -> 3) Option 3

The first example add a literal '%' in the text. The second example keeps the date as one actual parameter adding a literal ','. The third example adds a literal right parenthesis ')' to each parameter.

2.5.1.3 Bracket Function

The bracket function is the other built-in function that inhibits the macro preprocessor from expanding text.

Syntax:

The bracket function inhibits all macro preprocessor expansion of the text contained within the parentheses. However, the escape function, the comment function, and the parameter substitution are still recognized. Since there is no restriction for the length of the text within the bracket function, it is usually easier to use than the escape function.

The literal character '*' is not accepted in connection with the three functions described in this subsection.

Example:

%*DEFINE (DW(LIST,NAME))
(    %NAME  DW  %LIST)

The macro DW expands DW statements, where the variable NAME represents the first parameter and the expression LIST represents the second parameter.

The following expansion should be obtained by the call:

If the call in the following form:

occurs, the macro preprocessor would interpret the first argument (198H) as NAME and everything after the first comma as the second parameter, since the first comma would be interpreted as the delimiter separating the macro parameters.

In order to change this method of interpretation, all tokens that are to be combined for an individual parameter must be identified as a parameter string and set in a bracket function:

This way the bracket function prevents the string '198H, 3DH, 0F0H' from being evaluated as separate parameters.

2.5.2 METACHAR Function

The METACHAR function can be used to redefine the metacharacter (initially: '%')

Syntax:

Although the balanced-text string may be any number of characters long, only the first character in the string is taken to be the new metacharacter. Macro calls in the balanced-text string are still recognized and corresponding actions that will not lead to any direct expansion on the output file will be performed. So, for example a SET macro call inside the balanced-text string will be performed.

Characters that may not be used as a metacharacter are: a blank, letter, digit, left or right parenthesis, or asterisk.

The following example is catastrophic !!!

This examples defines the space character as the new metacharacter, since it is the first character in the balanced-text strings!

2.5.3 Numbers and Expressions in mpp51

Many built-in functions recognize and evaluate numerical expressions in their arguments. mpp51 uses the same rules for representing numbers as asm51 (see chapter Operands And Expressions for detailed information):

- Numbers may be represented in the formats binary (B suffix), octal (O or Q suffix), decimal (D or no suffix), and hexadecimal (H suffix).

- Internal representation of numbers is 16-bits (00H to 0FFFFH); the processor does not recognize or output real or long integer numbers.

- The following operators are recognized by the macro preprocessor (in descending precedence):

The symbolic forms of the relational operators (i.e., <, >, =, <>, >=, <=) are not recognized by the macro preprocessor.

The macro preprocessor cannot access the assembler's symbol table. The values of labels, location counter, EQU and SET symbols are not known during macro time expression evaluation. Any attempt to use assembly time symbols in a macro time expression generates an error. Macro time symbols can be defined, however, with the predefined macro, SET.

2.5.4 SET Function

SET assigns the value of the numeric expression to the identifier, macro-variable, and stores the macro-variable in the macro time symbol table, macro-variable must follow the same syntax convention used for other macro identifiers. Expansion of a macro-variable always results in hexadecimal format.

Syntax:

The SET macro call affects the macro time symbol table only; when SET is encountered, the macro preprocessor replaces it with the null string. Symbols defined by SET can be redefined by a second SET call, or defined as a macro by a DEFINE call The SET function is thanks to the necessary compatibility with Intel the only predefined macro function which may be redefined. Such a redefinition of the SET function must however be strongly dissuaded, because as a consequence, the original functionality will be lost for the rest of the program, i.e., macro-time symbols can no longer be defined.

Example:

%SET(COUNT,0)                  -> null string
%SET(OFFSET,16)                -> null string
MOV R1, #%COUNT + %OFFSET      -> MOV R1,#0H + 10H
MOV R2, #%COUNT                -> MOV R2,#0H

SET can also be used to redefine symbols in the macro time table:

%SET(COUNT,%COUNT + %OFFSET)   -> null string
%SET(OFFSET,%OFFSET * 2)       -> null string
MOV R1, #%COUNT + %OFFSET      -> MOV R1,#10H + 20H
MOV R2, #%COUNT                -> MOV R2,#10H

2.5.5 EVAL Function

The built-in function EVAL accepts an expression as its argument and returns the expression's value in hexadecimal.

Syntax:

The expression argument must be a legal macro-time expression. The return value from EVAL is built according to asm51's rules for representing hexadecimal numbers. The trailing character is always the hexadecimal suffix (H). The expanded value is at most 16 bits and negative numbers are shown in two's complement form. If the leading digit of the return-value is 'A', 'B', 'C', 'D', 'E' or 'F', it is preceded by a 0.

Example:

COUNT SET %EVAL(33H + 15H + 0f00H)       -> COUNT SET 0f48H

MOV  R1, #%EVAL(10H - ((13+6) *2 ) +7)   -> MOV  R1, #0fff1H

%SET( NUM1, 44)   -> null string
%SET( NUM2, 25)   -> null string

MOV   R1, #%EVAL( %NUM1 LE %NUM2 )       -> MOV  R1, #00H

2.5.6 Logical Expressions and String Comparisons in mpp51

Several built-in functions return a logical value when they are called. Like relational operators that compare numbers and return TRUE or FALSE ('0fffH' or '00H') respectively, these built-in functions compare character strings. If the function evaluates to 'TRUE', then it returns the character string '0ffffH'. If the function evaluates to 'FALSE', then it returns '00H'.

The built-in functions that return a logical value compare two balanced-text arguments and return a logical value based on that comparison. The list of string comparison functions below shows the syntax and describes the type of comparison made for each. Both arguments may contain macro calls.

%EQS(arg1,arg2 ) TRUE if both arguments are identical; equal

%NES(arg1 ,arg2) TRUE if arguments are different in any way; not equal

%LTS(arg1,arg2 ) TRUE if first argument has a lower value than second argument; less than

%LES(arg1,arg2 ) TRUE if first argument has a lower value than second argument or if both arguments are identical; less than or equal

%GTS(arg1,arg2 ) TRUE if first argument has a higher value than second argument; greater than

%GES(arg1,arg2 ) TRUE if first argument has a higher value than second argument, or if both arguments are identical; greater than or equal

Before these functions perform a comparison, both strings are completely expanded. Then the ASCII value of the first character in the first string is compared to the ASCII value of the first character in the second string. If they differ, then the string with the higher ASCII value is to be considered to be greater. If the first characters are the same, the process continues with the second character in each string, and so on. Only two string s of equal length that contain the same characters in the same order are equal.

Example:

Before Macro Expansion After Macro Expansion

%EQS(ABC,ABC) 0ffffH (TRUE).
The character strings are identical.

%EQS(ABC, ABC) 00H (FALSE).
The space after the comma is part of the second argument

%LTS(CBA,cba) 0ffffH (TRUE).
The lower case characters have a higher ASCII value than upper case.

%GES(ABC,ABC) 00H (FALSE).
The space at the end of the second string makes the second string greater than the first one.

%GTS(16,111H) 0ffffH (TRUE).
ASCII '6' is greater than ASCII '1'.

The strings to the string comparison macros have to follow the rules of the balanced-text described earlier.

     %MATCH(NEXT,LIST)(CAT,DOG_MOUSE)

     %EQS(%NEXT,CAT)               -> 0ffffH (TRUE)
     %EQS(DOG,%SUBSTR(%LIST,1,3))  -> 0ffffH (TRUE)

2.5.7 Control Flow Functions and Conditional Assembly

Some built-in functions expect logical expressions in their arguments. Logical expressions follow the same rules as numeric expressions. The difference is in how the macro interprets the 16-bit value that the expression represents. Once the expression has been evaluated to a 16-bit value, mpp51 uses only the low-order bit to determine whether the expression is TRUE or FALSE. If the low-order bit is one, the expression is TRUE. If the low-order bit is zero the expression is FALSE.

Typically, the relational operators (EQ, NE, LE, LT, GE, or GT) or the string comparison functions (EQS, NES, LES LTS, GES, or GTS) are used to specify a logical value. Since these operators and functions always evaluate to 0FFFFH or 00H, internal determination is not necessary.

2.5.7.1 IF Function

The IF built-in function evaluates a logical expression, and based on that expression, expands or withholds its text arguments.

The IF function allows a user to decide at macro time whether to assemble certain code or not (conditional assembly). So, the assembler never has to see any code which is not to be assembled.

Syntax:

The IF function first evaluates the expression. If it is TRUE, then the succeeding balanced-text1 is expanded; if it is FALSE and the optional ELSE clause is included in the call, then the balanced-text2 is expanded. If the expression results to FALSE and the ELSE clause is not included, the IF call returns the null string. The macro call must be terminated by FI.

IF calls can be nested. The ELSE clause refers to the most recent IF call that is still open (not terminated by FI). FI terminates the most recent IF call that is still open. The level of macro nesting is limited to 300.

Example:

This is a simple example of the IF call with no ELSE clause:

%SET( VALUE, 0F0H )
%IF( %VALUE GE 0FFH )
THEN
     (MOV R1, #%VALUE)
FI

Example:

This is a simple form of the IF call with an ELSE clause:

%IF( %EQS(ADD,%OPERATION))
THEN
     (ADD R7, #03H)
ELSE
     (SUB R7, #03H)
FI

Example:

This is an example of three nested IF calls:

%IF( %EQS(%OPER,ADD)) THEN (
     ADD  R1, #03H
)ELSE (%IF( %EQS(%OPER,SUB)) THEN (
     SUB  R1, #03H
     )ELSE (%IF( %EQS(%OPER,MUL)) THEN (
          MOV  R1, #03
          JMP  MUL_LAB
          )ELSE (
               MOV R1, #DATUM
               JMP DIV_LAB
          )FI
     )FI
)FI

Example:

Demonstrating conditional assembly:

%SET(DEBUG,1)
%IF(%DEBUG)
THEN (
     MOV  R1, #%DEBUG
     JMP  DEBUG
)FI

     MOV  R1, R2
      .
      .
      .

This expands to:

     MOV  R1, #%DEBUG
     JMP  DEBUG
     MOV  R1, R2

%SET can be changed to:

     %SET(DEBUG,0)

to turn off the debug code.

2.5.7.2 IFDEF/IFNDEF Function

The IFDEF built-in function tests if a macro is defined and the IFNDEF built-in function tests if a macro is not defined. Based on this test, the function expands or withholds its text arguments.

The IFDEF/IFNDEF function allows a user to decide at macro time whether to assemble certain code or not (conditional assembly). So, the assembler never has to see any code which is not to be assembled.

Syntax:

The IFDEF and IFNDEF functions first test if macro is defined (IFDEF) or not (IFNDEF). If it is TRUE, then the succeeding balanced-text1 is expanded; if it is FALSE and the optional ELSE clause is included in the call, then the balanced-text2 is expanded. If the expression results to FALSE and the ELSE clause is not included, the IF call returns the null string. The macro call must be terminated by FI.

IFDEF/IFNDEF calls can be nested. The ELSE clause refers to the most recent IF call that is still open (not terminated by FI). FI terminates the most recent IF call that is still open. The level of macro nesting is limited to 300.

Example:

This is a simple example of the IFNDEF call with no ELSE clause:

%IFNDEF(MODEL)
THEN (
%DEFINE(MODEL)(SMALL)
) FI

Example:

This is a simple form of the IFDEF call with an ELSE clause:

%IFDEF(DOADD)
THEN
     (ADD R7, #03H)
ELSE
     (SUB R7, #03H)
FI

2.5.7.3 WHILE Function

The IF macro is useful for implementing one kind of conditional assembly including or excluding lines of code in the source file. However, in many cases this is not enough. Often you may wish to perform macro operations until a certain condition is met. The built-in function WHILE provides this facility.

Syntax:

The WHILE function evaluates the expression. If it results to TRUE, the balanced-text is expanded WHILE expands to the null string. Once the balanced-text has been expanded, the logical argument is retested and if it is still TRUE, the balanced-text is expanded again. This continues until the logical argument proves FALSE.

Since the macro continues processing until the expression is FALSE, the balanced-text should modify the expression, or else WHILE may never terminate.

A call to built-in function EXIT always terminates a WHILE macro. EXIT is described below.

The following example shows the common use of the WHILE macro:

Example:

%SET(COUNTER,7)

%WHILE( %COUNTER GT 0 )
(    MOV  R2, #%COUNTER
     MOV  @R1, R2
     ADD  R1, #2
     %SET(COUNTER, %COUNTER - 1)
)

This example uses the SET macro and a macro-time symbol to count the iterations of the WHILE macro.

2.5.7.4 REPEAT Function

mpp51 offers another built-in function that performs the counting loop automatically. The built-in function REPEAT expands its balanced-text a specified number of times.

Syntax:

Unlike the IF and WHILE macros, REPEAT uses the expression for a numerical value that specifies the number of times the balanced-text should be expanded. The expression is evaluated once when the macro is first called, then the specified number of iterations is performed.

A call to built-in function EXIT always terminates a REPEAT macro. EXIT is described in the next section.

Example:

Lab:
     MOV A, #8
     MOV R2, #0FFFFH

     %REPEAT( 8 )
     (  MOV @R2, A
        ADD @R1, A
     )

2.5.7.5 EXIT Function

The built-in function EXIT terminates expansion of the most recently called user defined macro. It is most commonly used to avoid infinite loops (e.g. a recursive user defined macro that never terminates). It allows several exit points in the same macro.

Syntax:

Example:

This use of EXIT terminates a recursive macro when an odd number of bytes have been added.

%*DEFINE (MEM_ADD_MEM(SOURCE,DEST,BYTES))
(     %IF( %BYTES LE 0 )THEN ( %EXIT ) FI
      ADD         A, %SOURCE
      ADDC  A, %DEST
      MOV         %DEST, A
      %IF( %BYTES EQ 1 ) THEN ( %EXIT ) FI
      MOV         A, %SOURCE+1
      ADDC  A, %DEST+1
      MOV         %DEST+1, A
      IF (%BYTES GT 2) THEN (
            %MEM_ADD_MEM(%SOURCE+2,%DEST+2,%BYTES-2)) FI
)

The above example adds two pairs of bytes and stores results in DEST. As long as there is a pair of bytes to be added, the macro MEM_ADD_MEM is expanded. When BYTES reaches a value of 1 or 0, the macro is exited.

Example:

This EXIT is a simple jump out of a recursive loop:

%*DEFINE (BODY)
(     MOV A,%MVAR
      %SET(MVAR, %MVAR + 1 )
)

%*DEFINE (UNTIL(CONDITION,EXE_BODY))
(     %EXE_BODY
      %IF( %CONDITION )
      THEN (
         %EXIT )
      ELSE (
         %UNTIL( %CONDITION, %EXE_BODY )
      )FI
)

%SET(MVAR,0)
%UNTIL( %MVAR GT 3, %*BODY )

2.5.8 String Manipulation Functions

The macro language contains three functions that perform common string manipulation functions, namely, the LEN, SUBSTR and MATCH function.

2.5.8.1 LEN Function

The built-in function LEN takes a character string argument and returns the length of the character string in hexadecimal format (the same format as EVAL).

Syntax:

Before Macro Expansion  After Macro Expansion

%LEN(ABNCDEFGHIJKLMOPQRSTUVWXYZ)    -> 1bH
%LEN(A,B,C)                         -> 05H
%LEN()                              -> 00H

%MATCH(STR1,STR2) (Cheese,Mouse)
%LEN(%STR1)                         -> 06H
%LEN(%SUBSTR(%STR2, 1, 3 ))         -> 03H

2.5.8.2 SUBSTR Function

The built-in function SUBSTR returns a substring of its text argument. The macro takes three arguments: a string from which the substring is to be extracted and two numeric arguments.

Syntax:

balanced-text as described earlier. It may contain a macro call.

expression1 specifies the starting character of the substring.

expression2 specifies the number of characters to be included in the substring.

If expression1 is zero or greater than the length of the argument string, SUBSTR returns the null string.

If expression2 is zero, then SUBSTR returns the null string. If it is greater than the remaining length of the string, then all characters from the start character of the substring to the end of the string are included.

Example:

The examples below several calls to SUBSTR and the value returned:

Before Macro Expansion      After Macro Expansion

%SUBSTR(ABCDEFG, 5, 1 )        -> E
%SUBSTR(ABCDEFG, 5, 100 )      -> EFG
%SUBSTR(123(56)890, 4, 4 )     -> (56)
%SUBSTR(ABCDEFG, 8, 1 )        -> null
%SUBSTR(ABCDEFG, 3, 0 )        -> null

2.5.8.3 MATCH Function

The MATCH function primarily serves to define macro identifiers. The MATCH function searches a character string for a delimiter character and assigns the substrings on either side of the delimiter to the macro identifiers.

Syntax:

balanced-text as described earlier. It may contain a macro call.

macro-id1 and macro-id2 may be any valid mpp51 identifier.

delimiter is the first character to follow macro-id1. You can use a space or a comma or any other delimiter. See the Advanced mpp51 Concepts section for more information on delimiters.

MATCH searches the balanced-text for the first delimiter. When it is found, all characters to the left of it are assigned to macro-id1 and all characters to the right are assigned to macro-id2. If the delimiter is not found, the entire balanced-text is assigned to macro-id1 and the null string is assigned to macro-id2.

Example:

%MATCH(MS1,MS2) (ABC,DEF)      -> MS1=ABC  MS2=DEF
%MATCH(MS3,MS4) (GH,%MS1)      -> MS3=GH   MS4=ABC
%MATCH(MS5,MS6) (%LEN(%MS1))   -> MS5=03H  MS6=null

You can use the MATCH function for processing string lists as shown in the next example.

Example:

%MATCH(NEXT,LIST)(10H,20H,30H)
%WHILE(%LEN(%NEXT))
(    MOV  A, %NEXT
     ADD  A, #2
     MOV  %NEXT, A
     %MATCH(NEXT,LIST)(%LIST)
)

Produces the following code:

First iteration of WHILE:

     MOV  A, 10H
     ADD  A, #2
     MOV  10H, A

Second iteration of WHILE:

     MOV  A, 20H
     ADD  A, #2
     MOV  20H, A

Third iteration of WHILE:

     MOV  A, 30H
     ADD  A, #2
     MOV  30H, A

2.5.9 Console I/O Functions

Two built-in functions, IN and OUT, perform console l/O. They are line-oriented. IN outputs the character '>' as a prompt to the console, and returns the next line typed at the console including the line terminator. OUT outputs a string to the console; the return value of OUT is the null string.

The results of an IN call (of the input) is interpreted as a macro-string. IN can also be used everywhere, where a macro-string is allowed.

Syntax:

Example:

The following lines would be displayed on the console:

2.6 Advanced mpp51 Concepts

For most programming problems, mpp51 as described above, is sufficient. However, in some cases, a more complete description of the macro preprocessor's function is necessary. It is impossible to describe all of the obscurities of the macro preprocessor in a single chapter. Specific questions to mpp51 can easily be answered by simple tests following the given rules.

2.6.1 Macro Delimiters

Delimiters are used in the function DEFINE to separate the macro-name from the optional parameter-list and to separate different parameters in this parameter-list. In the MATCH function a delimiter is used to define a separator, which is used as kind of terminator in the corresponding balanced-text argument. The most commonly used delimiters are characters like parentheses and commas, but the macro language permits almost any character or group of characters to be used as a delimiter.

Regardless of the type of delimiter used to define a macro, once it has been defined, only the delimiters used in the definition can be used in the macro call. Macros defined with parentheses and commas require parentheses and commas in the macro call. Macros defined with spaces (or any other delimiter), require that delimiter when called.

Macro delimiters can be divided into three classes: implied blank delimiters, identifier delimiters, and literal delimiters.

2.6.1.1 Implied Blank Delimiters

Implied blank delimiters are the easist to use and contribute the most readability and flexibility to macro definitions. An implied blank delimiter is one or more spaces, tabs or new lines (a carriage-return/linefeed pair) in any order. To define a macro that uses the implied blank delimiter, simply place one or more spaces, tabs, or new lines surrounding the parameter list and separating the formal parameters.

When you call the macro defined with the implied blank delimiter, each delimiter will match a series of spaces, tabs, or new lines. Each parameter in the call begins with the first non-blank character, and ends when a blank character is found.

Example:

%*DEFINE(WORDS FIRST SECOND)(TEXT: %FIRST %SECOND)

All of the following calls are valid:

Before Macro Expansion  After Macro Expansion

%WORDS hello world        -> TEXT: hello world
%WORDS    one
          two             -> TEXT: one two
%WORDS
          well
done                      -> TEXT: well done

2.6.1.2 Identifier Delimiters

Identifier delimiters are legal macro identifiers designated as delimiters. To define a macro that uses an identifier delimiter in its call pattern, you must prefix the delimiter with the commercial at symbol '@'. You must separate the identifier delimiter from the macro identifiers by a blank character.

When calling a macro defined with identifier delimiters, an implied blank delimiter is required to precede the identifier delimiter, but none is required to follow the identifier delimiter.

Example:

%*DEFINE(ADD M1 @TO M2 @AND M3)(
     MOV A,%M1
     ADD A,%M2
     MOV %M2,A
     MOV A,%M1
     ADD A,%M3
     MOV %M3,A
)

The following call (there is no blank after TO and AND):

%ADD ATOM TOBILL ANDLIST

returns the following code after expansion:

     MOV A,ATOM
     ADD A,BILL
     MOV BILL,A
     MOV A,ATOM
     ADD A,LIST
     MOV LIST,A

2.6.1.3 Literal Delimiters

The delimiters we used with the user-defined macros (parentheses and commas) were literal delimiters. A literal delimiter can be any character except the metacharacter.

When you define a macro using a literal delimiter, you must use exactly that delimiter when you call the macro.

When defining a macro, you must literalize the delimiter string, if the delimiter you wish to use meets any of the following conditions:

You can use the escape function (%n) or the bracket function (%()) to literalize the delimiter string.

Example:

Before Macro Expansion  After Macro Expansion

%*DEFINE(MAC(A,B))(%A  %B)          -> null string
%MAC(2,3)                           -> 2  3

In the following example brackets are used instead of parentheses. The commercial at symbol separates the parameters:

%*DEFINE(OR[A%(@)B])(OR %A,%B)      -> null string
%OR[A1@A2]                          -> OR A1,A2

In the next example, delimiters that could be identifier delimiters have been defined as litteral delimiters:

%*DEFINE(ADD(A%(AND)B))(AND %A,%B)  -> null string
%ADD (A AND #34H)                   -> AND A , #27H

The spaces around AND are considered as part of the argument string.

Next folllows an example to demonstrate the difference between identifier delimiters and literal delimiters.

Example:

%*DEFINE(ADD M1%(TO)M2%(AND)M3)(
     MOV A,%M1
     ADD A,%M2
     MOV %M2,A
     MOV A,%M1
     ADD A,%M3
     MOV %M3,A
)

The following call:

%ADD ATOM TOBILL ANDLIST

returns the following code after expansion (the TO in ATOM is recognized as the delimiter):

     MOV A,A
     ADD A,M TOBILL
     MOV M TOBILL,A
     MOV A,A
     ADD A,LIST
     MOV LIST,A

2.6.2 Literal vs. Normal Mode

In normal mode, the macro preprocessor scans text looking for the metacharacter. When it finds one, it begins expanding the macro call. Parameters and macro calls are expanded. This is the usual operation of the macro preprocessor, but sometimes it is necessary to modify this mode of operation. The most common use of the literal mode is to prevent macro expansion. The literal character in DEFINE prevents the expansion of macros in the macro-body until you call the macro.

When you place the literal character in a DEFINE call, the macro preprocessor shifts to literal mode while expanding the call. The effect is similar to surrounding the entire call with the bracket function. Parameters to the literalized call are expanded, the escape, comment, and bracket functions are also expanded, but no further processing is performed. If there are any calls to other, they are not expanded.

If there are no parameters in the macro being defined, the DEFINE built-in function can be called without the literal character. If the macro uses parameters, the macro will attempt to evaluate the formal parameters in the macro-body as parameterless macro calls.

Example:

The following example illustrates the difference between defining a macro in literal mode and normal mode:

%SET(TOM,1)

%*DEFINE (M1)(
     %EVAL(%TOM)
)

%DEFINE (M2)(
     %EVAL(%TOM)
)

When M1 and M2 are defined, TOM is equal to 1. The macro-body of M1 has not been evaluated due to the literal character, but the macro-body of M2 has been completely evaluated, since the literal character is not used in the definition. Changing the value of TOM has no affect on M2, it changes the return value of M1 as illustrated below:

Before Macro Expansion    After Macro Expansion

%SET(TOM,2)
%M1                       -> 02H
%M2                       -> 01H

The macros themselvescan be called with the literal character. The return value then is the unexpanded body:

%*M2                      -> 01H
%*M1                      -> %EVAL(%TOM)

Sometimes it is necessary to obtain access to parameters by several macro levels. The literal mode is also used for this purpose. The following example assumes that the macro M1 called in the macro-body is predefined.

Example:

@*DEFINE (M2(P1))(
     MOV  A,%P1
     %M1(%P1)
)

In the above example, the formal parameter %P1 is used once as a simple place holder and once as an actual parameter for the macro M1.

Actual parameters in the contents must not be known in literal mode, since they are not expanded. If the definition of M2, however, occurred in normal mode, the macro preprocessor would try to expand the call from M1 and, therefore, the formal parameter %P1 (used as an actual parameter). However, this first receives its value when called from M2. If its contents happen to be undefined, an error message is issued.

Another application possibility for the literal mode exists for macro calls that are used as actual parameters (macro-strings, macro-variables, macro-calls).

Example:

The formal parameter of M1 was assigned the call from M2 ('%M2') by its expansion. M2 is expanded from M1 when the formal parameters are processed.

In normal mode, M2 is expanded in its actual parameter list immediately when called from M1. The formal parameters of M1 in its body are replaced by the prior expanded macro-body from M2.

The following example shows the different use of macros as actual parameters in the literal and normal mode.

Example:

%SET(M2,1)

%*DEFINE (M1(P1))(
     %SET(M2,%M2 + 1)
     %M2, %P1
)

%M1(%*M2)                 -> 02H, 02H
%M1(%M2)                  -> 03H, 02H
%M1(%*M2)                 -> 04H, 04H

2.6.3 Algorithm for Evaluating Macro Calls

The algorithm of the macro preprocessor used for evaluating the source file can be broken down into 6 steps:

1. Scan the input stream until the metacharacter is found.

2. Isolate the macro-name.

3. If macro has parameters, expand each parameter from left to right (initiate step one on actual parameter), before expanding the next parameter.

4. Substitute actual parameters for formal parameters in macro-body.

5. If the literal character is not used, initiate step one on macro-body.

6. Insert the result into output stream.

The terms 'input stream' and 'output stream' are used because the return value of one macro may be a parameter to another. On the first iteration, the input stream is the source line. On the final iteration, the output stream is passed to the assembler.

Example:

The examples below illustrate the macro preprocessor's evaluation algorithm:

%SET(TOM,3)

%*DEFINE (STEVE)(%SET(TOM,%TOM - 1) %TOM)

%DEFINE (ADAM(A,B))(
     DB  %A, %B, %A, %B, %A, %B
)

The call ADAM is presented here in the normal mode with TOM as the first actual parameter and STEVE as the second actual parameter. The first parameter is completely expanded before the second parameter is expanded. After the call to ADAM has been completely expanded, TOM will have the value 02H.

Before Macro Expansion      After Macro Expansion

%ADAM(%TOM,%STEVE)   -> DB 03H, 02H, 03H, 02H, 03H, 02H

Now reverse the order of the two actual parameters. In this call to ADAM, STEVE is expanded first (and TOM is decremented) before the second parameter is evaluated. Both parameters have the same value.

%SET(TOM,3)
%ADAM(%STEVE,%TOM)   -> DB 02H, 02H, 02H, 02H, 02H, 02H

Now we will literalize the call to STEVE when it appears as the first actual parameter. This prevents STEVE from being expanded until it is inserted in the macro-body, then it is expanded for each replacement of the formal parameters. TOM is evaluated before the substitution in the macro-body.

%SET(TOM,3)
%ADAM(%*STEVE,%TOM)  -> DB 02H, 03H, 01H, 03H, 00H, 03H

Copyright © 2002 Altium BV