Unit 10.4 - Assembly Time Variables and If Statements
SCHAUM 14.6 and 14.7
ALR Chapter 9
SILVER Section 14.2
PROG
Improvement to previous program
PED
Introduction to the full power of the Macro Language
How to avoid duplicate copies of Control Blocks in macros.
CONCEPTS
IF assembly-time-condition
generate some code
ENDIF
translated to
AIF (not assembly-time-condition).SEQnn
code to be generated when assembly-time-conditon
true
.SEQnn ANOP
IF assembly-time-condition
code1
ELSE
code 2
ENDIF
AIF (not assembly-time-condition).SEQnn
code 1
AGO .SEQnn+1
.SEQnn ANOP
code 2
.SEQnn+1 ANOP
New and Improved Template for Subroutine Call Macros
MACRO
name &arg1,&arg2,...,&argn
GBLB &cbnameDEF
L regA,&arg1 if first
argument value argument
or
LA regA,&arg1 if it's "by var" argument
ST regA,cbname
L rega,&arg2 if second argument value
argument
or
LA regA,&arg2 if it's
"by var" argument
ST regA,cbname+4
.
.
.
L regA,argn if nth argument value
argument
or
LA regA,argn if it's "by var" argument
ST regA,cbname+(n-1)*4
BAL regB,name
AIF (&ccbnameDEF).SEQ01
B cbnameA
DS 0f
cbname&sysndx EQU *
DS nF
cbnameA&SYSNDX EQU *
.SEQ01 ANOP
&ccbnameDEF SETB 1
MEND
regA - register subroutines expects used to pass control
block,
also used for temp storage
regB - register subroutine expects return address
cbname - name for control block <= 3 letters long
SF
Macro Time Variable Types
Boolean
GBLB &name
LCLB &name
&name SETB (logical expression)
either zero or one, intially zero
can be used in logical expresions
arithmetic
GBLA &name
LCLA &name
&name SETA expression
character
GBLC &name
LCLC &name
&name SETC expression
&C SETC 'string0'
AIF ('&C' EQ 'string1').b
Note quotes around &C and space before and after EQ
74.ASS
74.LIS
Unit 10.4 - Assembly Time Variables and If Statements
Our last example showed how to create macros that call
subroutines and set up the Control Block containing the
parameters. Each invocation of the macro, corresponding to
a call of a subroutine, allocated a new control block. This
works. Because we used the &SYSNDX mechanism, each control
block, and the label to branch around same, gets unique
names.
However, it wastes space. We learn how to deal with this
problem in this lecture. The mechanism used are the Macro-
time variables and the conditional assembly features of the
ASSEMBLER.
A conditional-assembly statement will cause some code to be
generated, or some assembly-time action to be taken, if the
conditions are specified. Assembly-time or macro-time
variables are variables that can be set or changed as
ASSEMBLY is occuring. They don't correspond to memory
locations when the program is running. They corresponding
to variables maintained by the ASSEMBLER in the process of
generating the code. The macro-time variables are used in
(a more elaborated version of) the pseudocode in Unit 41.
Logical expressions involving the ASSEMBLY time variables
determine what actions are taken by the conditional-assembly
features. The ASSEMBLY time variables can be changed by SETx
statements.
Macro-time variables can be either GLOBAL or LOCAL. LOCAL
variables are LOCAL to a specific MACRO. Thus if &A is
defined as a local variable in MACRO X, it can also be
defined as a local variable in MACRO Y. They would be two
different variables.
GLOBAL variables are the same in each macro. They can also
be used in the main program. If there is a GBL definition
for &A in macro X and another one in macro Y, they both
refer to the same thing.
Macro variables, whether global or local, come in three
flavors. They are arithmetic which contain integer,
booleans which contain either 0 or 1 and character string
variables.
In the GBL statement that defines a GLOBAL macro-time
variable, the LCL statement that defines a LOCAL macro-time
variable and the SET statements that use them, we suffix the
appropriate command by A,B or C for arithmetic, boolean or
character. We thus speak of a LCLx, a GBLx and a SETx
statement.
Thus, we write
LCLA - to define and create a local arithmetic macro-time
variable
LCLB - to define and create a local boolean macro-time
variable
LCLC - to define and create a local character macro-time
variable
GBLA - to define and create a global arithmetic macro-
time variable
GBLB - to define and create a global boolean macro-time
variable
GBLC - to define and create a global character macro-time
variable
SETA - to assign a new or different value to an
arithmetic macro-time variable
SETB - to assign a new or different value to a boolean
macro-time variable
SETC - to assign a new or different value to a character
macro-time variable
The GBLx or LCLx statement appears right after the macro
prototype line in each macro. (The macro prototype line is
the second line of the macro, where the names of the dummy
arguments and the name of the macro are specified.) There
must be a GBLx or LCLx statement for each macro-time
variable used in a macro. If a global variable is used by
multiple macros, there must be a GBLx statement for it in
each macro.
Each global or local macro-time variable is assigned a
default initial value. We will see these are very useful to
find out if something has happened yet--we just check to see
if a particular global variable still has its initial value.
Arithmetic macro-time variables are initialized to zero.
Boolean macro-time variables are initialized to zero for
false. And character-string macro-time variables are
initialized to the null string ("").
The assembly-time if statement (AIF) will branch to a given
location if a logical expression is true, usually involving
macro-time variables. Locations for assembly-time variables
are proceeded with a period and are sometimes referred to as
sequence symbols.
To define the location, we put the sequence symbol (don't
forget the period) in the label field (column 1) and the
word "ANOP" in the operation field. Like,
.SEQ01 ANOP
Thus, we set up an assembly time if-then-end or if-then-else-
end, analagous to the template we use with converting if-
then-end or if-then-else-end in PASCAL to a sequence of
branches in regular ASSEMBLER. If we want to do something
when the condition is true, we branch around that code when
the condition is false. This is illustrated by the
templates below.
AIF (not assembly-time-condition).SEQnn
code to be generated when assembly-time-conditon
true
.SEQnn ANOP
is how we translate a simple-if. Remember that the
evaluation of the condition occurs at ASSEMBLY-time and
cannot be affected by the values in memory locations, only
in macro-time variables.
We can translate an if-then-else as follows.
IF assembly-time-condition
code1
ELSE
code 2
ENDIF
AIF (not assembly-time-condition).SEQnn
code 1
AGO .SEQnn+1
.SEQnn ANOP
code 2
.SEQnn+1 ANOP
A classic thing we want to do with macro-time variables is
to ensure that something is only generated once. The
"something" is either going to be some data definitions (DCs
or DSs) or some EQUATES. The ASSEMBLER gets very upset when
you have two "DC" statements, both with the same name. It
also gets upset if there are two "EQU", both of which define
the same value. This is true, even if the definitions both
assign the same address to the same variable.
The technique is to have a global boolean macro-time
variable associated with the stuff that is only supposed to
be executed once. There is a macro that is called many
times, e.g., the macro-call routine, and the macro is
responsible for generating the DCs, DS's or EQU's. The
macro sets the global macro-time variable at the end. In
the interior of the macro, it checks this variable. If it's
one, then the macro must have already been run before, and
nothing is done. The DC's, DS's or EQU's were generated in
the previous call. If it's zero, the default value for
boolean variables, this is the first call for the particular
macro. We thus generate the needed DC's, DS's or EQU's.
We see this type of code in the template for a subroutine-
calling macro. A global boolean variable whose beginning is
the same as the Control Block but which has a "DEF" suffix
is created. If it's on, then we branch around the creation
of the control block. Otherwise, we go ahead and create the
control block.
Let's look at our example. In this case we use "CCB" as the
name of the control block on line 16. Note that have a
global definition in line 4. It's for &CCBDEF. In line 13,
if it's set we do an ASSEMBLY-time branch to line 18 where
the ".SEQ01" is. Otherwise, we generate the control block
as well as the needed branch around it. Note also that we
set &CCBDEF to one at the end of the macro in line 19.
This macro is called twice. In the first time on line 26,
we copy A to B with a length of =A(ALEN). Note in this
case, we define "CCB" and "CCBA." (This call also sets the
macro time variable &CCBDEF.) The next time we call the
macro, we find this is now on and we don't generate any
"CCB." The CCB that is generated in the previous call is
reused again.