STRUCTURED ASSEMBLER 102: Part II - A TUTORIAL IN MACRO AND ASSEMBLER CODING TECHNIQUES By Dave Clark This is the second in a three-part series on structured assembler. The first part presented the `WHILE-WEND' construct and the four macros used to implement it. This second part presents the `IF-ELSE-ENDIF' construct and its four associated macros. The third part will give a practical example using the macros shown while also presenting a very useful assembler subroutine. The implementation of the `WHILE-WEND' construct showed an example of a macro (the `WHILE' macro) that supported a single invocation format. This implementation of the `IF-ELSE-ENDIF' construct is a bit more complex in that the `IF' macro accepts a dual format. The alternative format allows the frugal programmer to reduce the number of resulting instructions for certain situations. IF-ELSE-ENDIF Construct My implementation of the `IF-ELSE-ENDIF' construct uses four macros named `IF', `AND', `ELSE' and `ENDIF' (Figures 1 to 4). Each invokes the expected function suggested by their names. The addition of the `AND' macro was a logical extension of the `IF' macro in order to provide nearly unlimited condition testing potential. `Nearly unlimited' because only the `IF' macro supports the `OR' condition and may cause unexpected results if combined with the use of the `AND' macro. The `AND' condition of the `IF' macro does, however, combine well with the `AND' macro and its `AND' condition. Additionally, the `IF-ELSE-ENDIF' construct will accept up to five (arbitrary) levels of nesting. Optionally, the programmer may modify the normal function of the `IF' macro, if the situation warrants it, by using an alternative invocation format. The use of this alternative format is mutually exclusive with the use of the `ELSE' macro. One situation that can use this format is if a single condition test, when `true', would result in an unconditional branch instruction. The other situation is if multiple condition testing must be done on a single comparison. Examples are given later of these two situations. IF Macro The `IF' macro (Figure 1), for the most part, functions (and is coded) like the `WHILE' macro presented in part one of this series. Hence, I will only discuss the new or changed portions of the `IF' macro (indicated in Figure 1 with an asterisk after the line number). First, the names of the global variables (03-04 and wherever referenced) have changed. This is not only good practice but it also allows both constructs to be programmatically nested within each other. Likewise, the generated assembler labels (18, 36, 61, 90 and 93) have changed. This time, however, it is only for good practice as the macro index number `&SYSNDX' ensures uniqueness. Beyond those pseudo-cosmetic differences, lines 31, 38-54, 60 and 63-69 are new lines with 59 being a change to an old line. These additions and changes are all in support of the alternative macro invocation format. The alternative format substitutes support for a second conditional expression with support for altering the processing flow of the first conditional statement. The standard format allows a `true' condition to fall through to `THEN' processing and a `false' condition to branch to `ELSE' or `ENDIF' processing. The alternative format causes a `true' condition to branch to a user-specified label and a `false' condition to fall through to `THEN' or `ENDIF' processing. So that means the `&CONN', `&C', `&S', and `&D' variables (from the macro invocation format line) serve double duty. The first new line (31) reflects this by testing for two new `connectors', `BC' or `BCR'. Although these coincide with two standard assembler mnemonics, the macro uses them here for convenience as they do not directly relate to any assembler statement generated. Here "BRANCH ON `TRUE' CONDITION to label `&C'" or ". . . to register `&C'" is what they, respectively, stand for. If the macro finds either of these two new `connectors' then the new code to process them (and a little old code) executes (38-69). First the macro determines if an additional flow modification is present in the `&S' (and by association `&D') variable (38). If not, the macro skips validation of it. Otherwise, the macro validates the `&S' variable against all possible assembler extended-mnemonic branch instructions (39-53). If validation fails, a severity eight message prints (54) but processing continues. Then actual processing commences by using four lines of old code (55-58) to extract the desired condition from the expression. The macro accesses the remaining new code by retesting the `connector' used (59-60). At this point in the old code the `connector' would be an `OR'. If the `connector' is `BCR' (60), then the macro appends the letter `R' to the extracted condition (64) in order to use the `register' form of the condition. In either case, processing continues with the generation of the selected extended-mnemonic branch instruction (66). Note that this single assembler model statement handles both the `label' and `register' forms of the branch instruction. To finish up processing, the macro now re-determines if a second flow modification is present (67). If so, the macro generates it (68) exactly as specified by the user. In either case, macro processing completes by branching to normal exit processing. AND Macro The `AND' macro (Figure 2) is, for the most part, a stripped down version of the `IF' macro. Hence, I will only note that the deleted lines (from the `IF' macro) were 13-16, 31, and 38-69 and Figure 2 shows changed lines with an asterisk after the line number. ELSE Macro The `ELSE' macro (Figure 3) prototype statement (02) says that the macro invocation ignores an assembler label and any parameters that may be coded. The same global variables defined here (03-04) allow the receipt of information passed from the `IF' macro. As with the `IF' macro, a local character variable definition (05) contains, for esthetic purposes, the value stored in the `&IFNDX' array for the current nesting level. Validation assures that, at the current nesting level, processing of the `IF' macro has taken place but processing of the `ELSE' and `ENDIF' macros have not. If the validation sequence number is one (06) then that condition exists and processing continues. Otherwise, a severity twelve message prints (07) and macro processing ends (08). Next, the macro sets the local character variable (10) to the value stored in the `&IFNDX' array. As I said, this is for esthetic purposes only and provides a shorter variable name that allows me to maintain normal assembler column alignment. The first thing this macro needs to do is the generation of a branch instruction to end `THEN' processing and, thereby, skip `ELSE' processing. Hence, the macro generates the branch instruction (11) with the appropriate label for the current level of nesting. Next, the macro marks the start of `ELSE' processing with an appropriate label (12) for use by both the `IF' and `AND' macros. Lastly the macro increments the validation sequence number (13), for the current nesting level, to show that the `ELSE' macro has been processed. This has specific bearing on processing for the `ENDIF' macro as you will see. ENDIF Macro The `ENDIF' macro (Figure 4) prototype statement (02) also says that the macro invocation ignores an assembler label and any parameters that may be coded. The same global variables defined here (03-04) allow the receipt of information passed from the `IF' macro. As with the `ELSE' macro, a local character variable definition (05) contains, for esthetic purposes, the value stored in the `&IFNDX' array for the current nesting level (11). Validation assures that, at the current nesting level, processing of the `IF' macro (and, optionally, the `ELSE' macro) has taken place but processing of the `ENDIF' macro has not. If the validation sequence number is one (06) or two (07) then those conditions exist and processing continues. Otherwise, a severity twelve message prints (08) and macro processing ends (09). Since the use of the `ELSE' macro is optional, the first thing this macro needs to do is to determine if the user has coded the `ELSE' macro. If the validation sequence number is two (12) then `ELSE' macro processing has taken place and the `ENDIF' macro may skip special handling. Otherwise, the macro generates the needed `ELSE' label (13) and increments the validation sequence number (14). The next thing this macro needs to do is mark the end if `IF' processing. Hence, the macro generates an appropriate label (16) for use by the `ELSE' macro. Now the macro increments the validation sequence number (17), for the current nesting level, to show that the `ENDIF' macro has been processed. Lastly, as this ends the current level of nesting, the macro decrements the nesting level (18) completing `IF' construct processing for this level. Example and Comparison Figure 5 shows three examples of `IF' statements showing the different ways it can be coded. A fourth way of coding the `IF' statement is like the third example but omitting the optional `ELSE' processing section. Now compare Figure 5 with Figure 6 showing the same three examples coded in standard assembler. Which would you prefer? Keep in mind that they both generate the same machine code. Conclusion Maybe my `IF-ELSE-ENDIF' construct implementation is missing the ability to combine `OR' and `AND' processing. Maybe it is limiting in the number of conditions it can handle. Maybe you prefer standard assembler. I know I'm repeating myself, but if you want more features, that is the beauty of macros. Each programmer can get what they want and how they want it. You don't have to take the supplied assembler language as is. Change it! Enhance it! But most of all, "Have it YOUR way!" Next time I will present a complete (and very useful) assembler subroutine containing many examples of the `IF-ELSE-ENDIF' and `WHILE-WEND' constructs. This subroutine may be used by any program in all online and batch environments. In the meantime, get into some macro coding of your own. Have fun! /* 1681 Was this article of value to you? If so, please let us know by circling Reader Service No. 00. Figure 1: MACRO (01) &LBLNAME IF &A,&T,&B,&CONN,&C,&S,&D,&BAD (02)* GBLA &IFLVL,&IFSEQ(5) (03)* GBLC &IFNDX(5) (04)* LCLC &LVL,&X (05) AIF (T'&BAD EQ 'O').GOOD (06) MNOTE 12,'TOO MANY OPERANDS IN ''IF'' STATEMENT' (07)* MEXIT (08) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The "IF" macro accepts the following two formats (format 2 may be * * combined with one or more "AND" macros for extended testing): * * * *