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.