Conditional Assembly Language…
If you’ve ever read or written a macro you have no doubt at least seen conditional assembly language. It’s all that AIF and AGO stuff that forms a sort of ‘program’ within the macro so that it can generate code or whatever depending on whatever the input parameters are.
What’s really cool though is that it is not just limited to macros, you can use it within open code as well. So you might ask ‘why would you need to do that?’ but even if you don’t ask, here’s one interesting situation that came up recently.
I had some code that used a macro to generate a DSECT to map a control block. However we were switching version of the product that supplied the macro and a field within the macro had changed names even though it’s content had not. The result was that my code would only assemble with one version of the macro since with the other one it would get a not found error for the changed label. Since I did not want to have to co-ordinate my source code change with a build tool change the problem I had was how to make my source code support both versions of the macro and DSECT that it generated?
In case you have not guessed, the answer is conditional assembly language.
Here’s an example.
The old macro/DSECT:
MYMACRO SOMENAME DSECT MYFIELD DS CL8
The new version of the macro/DSECT
MYMACRO SOMENAME DSECT NEWNAME DS CL8
So my code originally looked something like this:
USING SOMENAME,R2 CLC MYFIELD,=CL8'AAAAAAAA'
Obviously if I switch to the new macro library, my assembly will fail since the field ‘MYFIELD’ is no longer defined within the DSECT.
However, what you can do is to test to see if the variable ‘MYFIELD’ is defined and if not then conditionally change the code that gets assembled. Thus:
USING SOMENAME,R2 AIF (T'MYFIELD EQ 'U').NEWMAC CLC MYFIELD,=CL8'AAAAAAAA' AGO .CONT .NEWMAC ANOP CLC NEWNAME,=CL8'AAAAAAAA' .CONT ANOP
The AIF tests to see if the ‘type’ specification for the field MYFIELD is ‘U’, that is undefined. If it is undefined that means it has not been seen by the assembler (yet) so jump to the label .NEWMAC and continue to generate the code from there, which of course generates the code using the new field label of NEWNAME.
If the field MYFIELD is not ‘undefined’ then the assembler generates the code using the old field name, MYFIELD and then jumps (AGO) to the label .CONT to continue the assembly.
As a result, no matter which version of the macro library I am using, my code still assembles and works correctly.
There are other ways of achieving the same effect; For example by using the conditional assembly language to control the redefining of the old or renamed symbol to a common name and using that common name in the open code.
One gotcha though to be aware of. The macro/DSECT has to be defined in the source code BEFORE the conditional assembly code. If it is defined after the conditional code then, since the assembler has not seen either field at the time it encounters the test for the field being defined, it will always treat it as being undefined which would cause an assembly error when using the old macro/DSECT library because it would generate the code to use the new field name.