

   Mp                         16-August-1980                            Mp
















                   MP     -      Macro Processor



                   1.      Introduction
                   2.      What Mp does
                   2.1         The pass
                   2.2         The macros
                   2.3         Treatment of non macros
                   2.4         Conditionals
                   2.5         Other internal statements
                   2.6         Switches
                   2.7         Macro definitions and arguments
                   2.8         The string stack
                   2.9         Macro argument operators
                   3.      Operating instructions
                   4.      Built in default macros
                   5.      Macro summary
                   6.      Alternate default macro librarys
                   7.      Examples
























                                    -1-




   Mp                         16-August-1980                            Mp
















   1.  Introduction

   Mp is a macro expander. It came into existance  after  experience  with
   macro-11  macro  libraries  failed to produce an efficient higher order
   (higher than assembler, not `high order') language compatible with  the
   supported  systems  programming  language  of Rsx11 (which is regetably
   macro-11). This, along  with  an  interest  in  macro  processors,  has
   resulted  in a flexible medium level language translator. It is missing
   many of the niceties  of  true  high  order  languages  (such  as  true
   expressions,  free format input, and high level data structures) but it
   does allow the construction of efficient `structured  macro  languages'
   without   giving  up  intimate  processor  contact  and  full  macro-11
   compatibility. It is an order of magnitude faster than  macro-11  alone
   (E.g. Dec's supermac) although it is not as fast as I might like. While
   its not Bliss or C, it is convenient and simple to use.

   The  format of input is the compatible with the assembler on the PdP-11
   (Macro-11). However, the arguments  inside  of  macro  definitions  are
   referenced  by number rather than symbolically. Labels and comments are
   compatible (i.e. the `:' and `;'  delimeters  for  labels  and  comment
   fields).  Parameters passed to macros have the same nesting rules (i.e.
   <>'s etc.) but there are  no  Keyword  macros.  The  ^z...z  syntax  is
   supported  and  the  form  "..." is additionally allowed (although this
   means that "xx must be specified as  <"xx>).  Arguments  have  selector
   operators  which  permit  extracting  portions  of a single argument or
   referencing multiple arguments (e.g. arguments 2 thru arg n, where n is
   the number of arguments passed to the macro).

   In  addition,  there  is  a string stack which may be accessed globally
   with operators for referencing absolute elements and elements  relative
   to  the top of the stack. The stack may be divided into two stacks with
   two stack pointers if  desired.  The  elements  on  the  stack  may  be
   assigned  to  the  local parameters of the macro. A method is available
   for generating labels of the form xxxnnn where nnn is a decimal  number
   and xxx is user definable (0-3 chars).

   Various  statements  exist for the conditional expansion of code either
   from  within  macros  or  at  the  statement  level.  Target  assembler
   directives may be placed in line and will be output unmodified.


   Macro  construction is very convenient. One can simply edit a file with
   the macro definitions, envoke the processor with both input and  output

                                    -2-                                1.0




 Mp                            12-October-80                            Mp
                                                                       1.0


   directed  to  the  terminal  and  proceed  to  test various expansions.
   Various dump  options  exist  to  interactively  see  all  intermediate
   results.  If  a  good text editor exists, one can spawn Mp without ever
   leaving the editor, test a macro, exit Mp, continue editing the macros,
   etc. In this  way,  one  has  almost  all  the  capability  of  a  good
   interpreter.

   Many  of  the  routines  I  have  used were originally written by David
   Conroy (of C compiler fame). Reading David's code is in many ways  more
   enjoyable than a novel. I found many great ideas there and recomend his
   work to anyone with an interest in good technique.







   2.  What Mp does









   2.1  The pass

   Mp reads the entire source file one time and acts as a  filter  copying
   from  its input to its output without modification unless it detects an
   opcode that is either an internal code or a user defined macro.  Macros
   are  recursively expanded until a non macro and non internal opcode are
   detected, at which time the statement is output unmodified.

   Having been designed primarily for Macro-11 preprocessing,  the  method
   of  handling  listings is tied to the Macro-11 .print statement and how
   it works in conjunction with a list suppress option.  Each  input  line
   is immediatly copyied to the output  after being modified as follows:

                   ".print ;statement"

   When the Mp output is run through  Macro-11  with  listing  suppressed,
   only  the  .print  statements  are output. The assembler address of the
   beginning of the statement is output with the .print statement  thereby
   allowing  easy  use  of  the assembler debuggers, while suppressing the
   actual expansion of the code generated by the  macros  themselves.   If
   the input is a ".MACRO" (upper case) directive, then the macro-11 macro
   definition is simply copied from input to the output until a subsequent
   ".ENDM" is encountered. No .print statements are added here.






                                    -3-                                2.1




 Mp                            12-October-80                            Mp
                                                                       2.1








   2.2  The macros

   Mp  accepts  macros  from  various  places. The order in which they are
   entered into the macro name table  determines  which  definition  takes
   precedence  when the macro is multiply defined. The following lists the
   the search order for opcodes.


   a.   The first set of names  are  the  conditionals  (these  are  hard-
        coded).

   b.   The file which contains the source to be processed, may have macro
        definitions  (if  the  /lm  switch is specified - see later). They
        must precede all other source  code  and  be  separated  from  the
        source by a line with a slash `/' alone in column 1.

   c.   One macro library may be specified and is a file of  macros  whose
        file-name  is  determined  by Mp according the following rule. The
        default file-name is "[1,1]mplib.mac". The /ml switch changes  the
        default  name  to  "[your,uic]mplib.mac".  A  command-line  option
        allows the setting of any file name in place of the defaults.  The
        /ml switch then is meaningless.

   d.   Built into Mp is a default set of macro definitions  (loaded  from
        an  overlay  makes processing faster). The loading of these may be
        suppressed by the /ni switch.







   2.3  Treatment of non macros

   Any statement not recognized by Mp is copied directly  to  the  output.
   These  statements  may be any Target assembler directives  provided the
   label: and ;comment syntax  aggrees.  Note  that  the  opcode  is  what
   determines if the statement is a macro and that opcodes are not limited
   to the rad50 subset. Also, string matching is case  sensitive;  so  all
   macro definitions and later invocation must agree totally in case.










                                    -4-                                2.3




 Mp                            12-October-80                            Mp
                                                                       2.3








   2.4  Conditionals

        A variety of conditional statements exist, they are:


   a.   I%B <string> <statement>

            This expands statement if string is blank.

   b.   I%NB <string> <statement>

            Expands statement if string is nonblank.

   c.   I%IDN <string1> <string2> <statement>

            Expands statement if both strings are identical.

   d.   I%DF  <string1> <string2> <statement>

            Expands statement if strings are different.

   e.   I%IN <key> <S1,S2,...,Sn> <E1,E2,...,En> <else>

            Compares  key  to  each  of Sn until a match is found,
            then En is expanded. If no match is  found,  then  the
            else  statement is expanded. Else may be omitted. Null
            strings may be present where desirable.


   f.   I%SW switch# <statement1> <else-statement>

            Expands statement1 or the else statement depending  on
            whether  the  switch is set. See below for explanation
            of switches.

















                                    -5-                                2.4




 Mp                            12-October-80                            Mp
                                                                       2.5








   2.5  Other internal statements

   The following lists the rest of the internal statements.



   g.   I%DOUT <statement>

            This will output statement  directly  without  further
            recursive  expansion.  This is useful when one desires
            to supplement code to  an  existing  target  assembler
            directive.  One  example  might be to output something
            additional to the .END statement by defining  a  macro
            called  ".END"  and having it output some code and end
            up with  an  output  of  the  actual  .END  directive.
            Comments may be output in this fassion as well.

   h.   I%ERR <message>

            This  outputs  a .error statement to the ti: device as
            well as to the file. The format is:

                .error ;message


   i.   S%SW switch#

            This sets the switch specified. The switch  is  turned
            on  if  switch# is positive and off if preceded with a
            minus sign.


   j.   E%S <symbol> n

            Enters symbol into a symbol  table  with  the  integer
            value  of  n  associated  with  it.  The symbol may be
            subsequently looked up, see below.

   k.   T%YP function symbol index

            This directive requires that function  be  `T'.  Later
            enhancements may add additional function codes here.

            The  `T' functions causes a search of the symbol table
            for the specified symbol. If it is found, the  numeric
            value  assigned is placed into the global string stack
            at location index. If  it  is  not  found,  the  value
            placed is 0.



                                    -6-                                2.5




 Mp                            12-October-80                            Mp
                                                                       2.5


   l.   D%SYM

            This  directive  dumps the symbol table as a series of
            macro calls. The format is as follows:

                                $$$$$$4 n
                                $$$$$$5 sym val
                                $$$$$$6 n

            where n is the number of symbols  and  the  $$$$$5  is
            expanded once for each symbol in the symbol table. The
            user  may  wish  to define these macros as there is no
            default definition.


   m.   **  macro  parm1 parm2 ...

            This opcode expands `macro' once  for  each  non-blank
            parameters.  Note  that `macro' may be null to execute
            multiple commands on a single line.







   2.6  Switches

        Mp reads the command line and extracts switches without  using
        the  CSI  modules.  Thus  switches  can appear anywhere on the
        line. They are always  2  letters  and  have  no  negation  or
        optional  data  capablilies.  Each switch is assigned a number
        (from 1 to 31) and it is this number which may  be  referenced
        in  the I%SW and S%SW statements described above. There are 16
        switches which are reserved for Mp and the rest can be used by
        the user. The switches are:


   1.   /nl

            No .print statements generated.

   2.   /da

            Not implemented.

   3.   /is

            This will print on ti: internal macros as they are read.
            This  aids  in  locating  a  faulty macro that bombs the
            preprocessor.

   4.   /me

            Expands  macros  one  level  deep  only  (for  debugging

                                    -7-                                2.6




 Mp                            12-October-80                            Mp
                                                                       2.6


            macros).

   5.   /ml

            Use local uic for standard macro library name, not [1,1]

   6.   /op

            Allows opcodes that are hardcoded to not take precedence
            over macros with the same name. (Not supported).

   7.   /tr

            Implements the trace feature.

            This causes Mp to internally invoke two macro calls  for
            every  statement  input.  The two macro calls are passed
            the entire input line as  parameters.  One  call  occurs
            before expansion of the statement and one after.

            Example:
                   input line:   LET a = b

                   affect:       $$$$$$1 LET a = b
                                 (expansion of LET a = b)
                                 $$$$$$2 LET a = b

            The two macros $$$$$$1 and $$$$$$2 must be user defined.

   8.   /ni

            No internal macro definitions.

   9.   /md

            Expands   macros   and   outputs   (as  a  comment)  all
            intermediate steps during expansion of the macro.

   10.  /pp

            Not implemented.

   11.  /un

            Outputs to the ti: device, amounts of storage used after
            macro libraries are read  in  (to  determine  how  large
            table sizes should be in the task image).

   12.  /x2

            Turns  on unary operator recognition for first operator.
            It is not recomended that this switch be  applied  until
            all  macros  are  read  in,  or  any  detection  of  the
            operators during macro load time  will  cause  expansion
            which  is  not  usually desirable. Rather they should be
            turned on by program control as needed. See see  section

                                    -8-                                2.6




 Mp                            12-October-80                            Mp
                                                                       2.6


            on Macros for further information.

   13.  /x3

            Turns on unary operator recognition for second operator.

   14.  /x4

            Turns on unary operator recognition for third operator.

   15.  /x5

            Turns on unary operator recognition for quote operator.

   31.  /lm

            Used  to  signal  that  local macros are included in the
            source file.

            The  remaining  switches  are  unassigned  and  are   as
            follows:


                   switch 16 as /x6
                   switch 17 as /x7
                   switch 18 as /x8
                   switch 19 as /x9
                   switch 20 as /x0
                   switch 21 as /y1
                   switch 22 as /y2
                   switch 23 as /y3
                   switch 24 as /y4
                   switch 25 as /y5
                   switch 26 as /y6
                   switch 27 as /y7
                   switch 28 as /y8
                   switch 30 as /y0




















                                    -9-                                2.6




 Mp                            12-October-80                            Mp
                                                                       2.7








   2.7  Macro definitions and arguments

        Macros have the form:

                          $MACRO name

                           macro text

                          $ENDM

   Additional information on the $MACRO and $ENDM lines is optional and is
   treated as comments.

   Arguments are referenced as #@n where n is a hexidecimal  (upper  case)
   digit. For example, the following is a definition of a push macro.

                           $MACRO push
                            mov #@1,-(sp)
                           $ENDM

   This macro would be called (for example):

                           push this

   And it would generate the following code:

                           mov this,-(sp)

   Note that if the definition is in lower case then the call must also be
   lower case (resp. for upper case).

   One additional syntax item (not found in macro-11) is the following: An
   argument of the form A[B] is translated into <A,B>.

   Macro  arguments  are substituted into macro text as follows: A left to
   right scan is performed copying text into a secondary buffer  character
   for  character  until  an  argument reference occurs. Then the argument
   text from the command line is copied replacing the argument  reference.
   When  copying  the  argument text itself, no interpretation of argument
   references is made and no  second  pass  on  the  line  is  made.  Thus
   recursion within macro argument replacement is disallowed.










                                   -10-                                2.7




 Mp                            12-October-80                            Mp
                                                                       2.8








   2.8  The string stack


   Mp has a string stack which is accessable to macros only.  When a macro
   is  expanded,  the  expander  only  has  access  to the current macro's
   argument strings. Because of this, a special macro  construct  for  use
   only  inside  macros  is  used  to transmit strings between this string
   stack and the parameters of the macro.

   The stack appears to be a 60 element (assembly parameter) string  array
   (like those found in basic-11).

   The  first  24 are generally used for stack 1, 25-30 as a scratch area,
   and 31-60 for stack 2. Item 29 contains the  string  used  to  generate
   labels. Stack operations are coded as statements which begin with a `?'
   character and start in column 1. There are 2 forms of this construct as
   follows:


   1.                        ??  p1,p2,...,pn

        This format does not  reference  the  string  stack  directly  but
        generates  automatic  symbols  of  the form $$$nnn and places them
        into the list of parameters specified. Example:

                                  ?? 1,2

        would generate (assuming no other labels have yet been gen'd)  two
        symbols

                      $$$1 which would replace argument 1

                      $$$2 which would replace argument 2

        If the arguments  had  been  defined  (i.e.  not  null)  then  the
        previous  contents are lost.  The `$$$' is the default and by user
        control can be changed to some  other  string.  See  the  absolute
        string placement below.





   2.                 ?- <string> relative absolute switch

                                      and

                      ?+ argument relative absolute switch

        The  above  are  pushes  (-) and pops (+) of the string stack. The

                                   -11-                                2.8




 Mp                            12-October-80                            Mp
                                                                       2.8


        `?-' expects a literal string to be supplied as <string>. This  is
        usually done via some reference to an argument.

        Example:

                                  ?- #@1

        This will push argument 1 onto the stack.

        The second parameter (if supplied) specifies a  position  relative
        to  the  stack  pointer and ALSO denotes that the operation is NOT
        actually a push, rather it is a move.

        Stack relative placement does not modify the stack pointer.

        Example:

                                 ?- #@1,2

        This will place argument 1 into the stack at position 2.  The  top
        grows downward and begins at location 1 of the string stack.

        The  third  parameter  (if  not  null)  specifies  that  the  push
        (actually move) is not relative to anything but is absolute.

        Example:

                                ?- abc,,29

        This will place the string `abc' into absolute position 29 of  the
        string   stack,   thereby  setting  the  label  generation  string
        described above.



        The fourth argument is to conditionalize the entire  operation  on
        the  status  of  a  particular  switch.  Note  that these  special
        directives  cannot be the expansion  clause  of  other  directives
        (E.g.  I%B).   For  this  reason  the  user   needs to make a test
        somewhere else and set a switch.

        Example:

                                ?- #@5,,,20

        This specifies that if switch 20 is set then push argument 5  onto
        the stack.

        To specify that the condition is based on the switch NOT being set
        then supply the switch number as negative.

        The ?+ operation is analgous to the ?- operation with  respect  to
        the relative, absolute, and switch parameters. The first parameter
        is however the argument number in which to move to. This number is
        a decimal number.


                                   -12-                                2.8




 Mp                            12-October-80                            Mp
                                                                       2.8


        Example:

        Suppose we redefine the push  macro  such  that  if  the  argument
        supplied is reg0 then we will change it to R0.

          $MACRO push parm1
          ?- R0,,25                     ;put an R0 into string element 25
          S%SW -26                      ;clear switch 26
          I%IDN reg0,<#@1> <S%SW 26>    ;set switch 26 if arg1 = `reg0'
          ?+ 1,,25,26                   ;if sw 26 set, move str 25 to arg1
          mov #@1,-(sp)                 ;now do the actual push
          $ENDM

        The above example demonstrates some of  the  stack  options  in  a
        macro  but  is  not  very  efficient  in  terms of statements (the
        overiding concern for speed). The following shows how  to  do  the
        same  thing  in one statement. Note the use of the I%IN to specify
        an else clause.

           $MACRO push
           I%IN <#@1> reg0 <<mov r0,-(sp)>> <mov #@1,-(sp)>
           $ENDM

        The second stack pointer is referenced as ++ or --.

        Example:

                ?-- abc         ;pushes "abc" onto stack 2.
                ?++ 3,2         ;pops next to top of stack 2 into parm 3

        Macros may also be expanded by the use of certain unary operators.
        When the tokenizer encounters a token (each parameter of  a  macro
        and  the opcode itself) it checks to see if the first character is
        one of 3 operators (defined in the tkb file for mp). If it is  and
        switches  12,  13, or 14 respectively for operators 1, 2, and 3 is
        also set, then an expansion of the macro $x is performed (x is the
        unary operator). The token is stripped of the operator and  passed
        onto  the $x macro as parameters. The $x macro is user defined. It
        may generate code or just fiddle with the stack and switches  etc.
        On  exit  however, it MUST push onto stack one a string which will
        replace the token which caused the expansion.

        Example:

                          LET a = _function[a,b]

        where  `_'  is  the  unary  operator  would  cause  the  following
        expansion to be invoked (before the LET is invoked):

                          $_ function,a,b

        IF $_ returns (via a push on stack one) the  string  `replacement'
        then the let statement would be expanded as:

                           LET a = replacement


                                   -13-                                2.8




 Mp                            12-October-80                            Mp
                                                                       2.8


        A suitable macro definition for `$_' could be:

                           $MACRO $_
                           ?- replacement
                           $ENDM







        The  quote character (usually " but definable at mp build time) is
        a special case  unary  operator.  Its  interpretation  depends  on
        switch 15. If switch 15 is off, then a quoted string is treated as
        a macro argument in <>'s. For example:

                           "Quoted string"

        is the same as:

                           <Quoted string>

        However,  if  switch  15 is on, then it is also treated as a unary
        operator but the entire argument is passed to the $" macro in  one
        piece.

        For example:

                           LET a = "Quoted string"

        would cause "Quoted string" to be passed to $" as:

                           $" <Quoted string>

        This  allows an implementation of the $" macro to output a labeled
        ascii statement (possibly in  a  data  psect)  and  replacing  the
        "Quoted  string"  (in  the  LET statement) with the address of the
        ascii string. This is basically what the default  macros  do.  See
        the file mcmd.mac.

















                                   -14-                                2.8




 Mp                            12-October-80                            Mp
                                                                       2.9








   2.9   Macro argument operators

    Macro arguments may be either simple argument references or  they  may
    select  portions  of the argument. An argument reference which has the
    following format selects a portion of the argument selected.

                   #@=n(f:l)

    In this format `n' is the argument number, `f' is the first  character
    in  the argument and `l' is the last. The `n', `f', and `l' parameters
    are all single hexidecimal (upper case) digits. However digits  beyond
    15  (`E') are permitted as no range check is performed upto the letter
    `Y'. Anything not a number or letter (or  `Z')  (or  larger  than  the
    argument  for  the  `l'  parameter)  is  converted  to  the  number of
    characters in the argument.

    For example:


                   #@=1(2:Z)       ;extracts chars 2-end of arg 1
                   #@=A(B:D)       ;extracts chars 11-13 of arg 10

    To reference multiple arguments the following form is used:

                   #@*(f:l)

    which  concatonates  arguments `f' thru `l'. The same rules for digits
    as above apply here as well except a value larger than the  number  of
    arguments  is  converted  to  the  number  of arguments (not including
    locally defined labels).

    For example:

                   #@*(2:Z)                ;selects args 2 thru n-args
                   #@*(3:B)                ;selects args 3 thru 12

    The `:' is actually a special case for the `separator' character which
    is output between each character  (in  extraction  of  characters)  or
    argument  (multiple argument selection). The following table describes
    the `separator' characters currently in use.


     -------------------------------------------------------------------
     |     "       double quote            separates with ><            |
     |     :       colon                   no separation (null)         |
     |     _       underline character     separates with a space       |
     |     x       any other char          separates with x             |
     --------------------------------------------------------------------



                                   -15-                                2.9




 Mp                            12-October-80                            Mp
                                                                       2.9


   For example, the macro call:    TEST arg1 arg2 arg3


   The following argument references:



           #@=1(1,Z)       --->    a,r,g,1
           #@=1(1:Z)               arg1
           #@=1(1"Z)               a><r><g><1
           <#@=1(1"Z)>             <a><r><g><1>


           #@*(1,Z)                arg1,arg2,arg3
           #@*(1_Z)                arg1 arg2 arg3
           <#@*(1"2)>              <arg1><arg2>

    Note  that  arguments separated by <><> type pairs do not need a comma
    or space  between  them.  The  ><  characters  are  the  corresponding
    characters  defined in the Mp task build file for left and right angle
    brackets. If these values are  changed,  the  characters  used  as  ><
    separators in the argument selector also are changed.

    One special case argument reference exists which permits conditionally
    appending  (r5)  to  argument  (the  string  appended  is  defined  in
    stak.mac). An argument reference of the form:

                           #@{n}

    where  n  is  of  the form used above to reference an argument number,
    causes the symbol table to be  searched  for  the  string  defined  by
    argument  n.  If  it  is  present, then the string (r5) is appended to
    argument n and is output as the replacement. This was added  to  allow
    variables  in  a  C-like  macro  language  be declared and substituted
    efficiently.

    One useful technique to determine if a variable is in the symbol table
    is:

               I%IDN <#@n> <#@{n}> <a match means in symbol table>

















                                   -16-                                2.9




 Mp                            12-October-80                            Mp
                                                                       2.9








   3.  Operating instructions

        Mp uses the get-command-line routine with 1 level of  indirection.
        It does not make direct use of the CSI parsing routines; rather it
        parses the command line itself. The format is:

        mp>OUT=IN[+MACROLIB][/sw's]

                or

        mp>file[+macrolib][/sw's]

        IN is the input file (def ext=.mac)

        OUT is the output file (def ext = .mpp)

        MACROLIB is an optional library of MP macros (def ext = .mac)

        If there is  no  `='  present,   then  "file"  is  converted  into
        "file=file".  In  this case the extensions must be defaulted.  The
        choice of .mpp for the intermediate file  extension  is  to  allow
        easy deletion of temporary files.

        If no command line is entered, repetitive mode is enabled. In this
        mode a file is translated until an eof on input. Then command mode
        is re-entered (like pip or tkb etc.). Thus  multiple  translations
        are permitted (usually from an indirect file). However, macros are
        only defined for the first command entered.  This allows a set  of
        modules to be translated with out the reloading of macro libraries
        (and the internal macro definitions). If new  macros  need  to  be
        defined the processor must be reloaded via a new invocation.

        One useful technique for debugging macros is the following:

            mcr>mp
                mp>ti:+lib/sw's          -input and output to tty
                    interactively test macros
                    control-z
                mp>ti:/sw's
                    more interactive tests with different switch settings
                    control-z
                mp>control-z             -to exit mp.

        This  technique allows one to test a macro and switch on the macro
        expansion if a problem results. It is also a good way to see how a
        macro expands before actually writing code that uses a  particular
        construct.




                                   -17-                                3.0




 Mp                            12-October-80                            Mp
                                                                       3.0



        Error reporting is poor in the expander. If messages come out  out
        on  the  terminal  that  say things like string buffer overflow or
        string index out of range, you have exceeded some internal  limit.
        Check  the  last  thing  you wrote. Usually the error is caused by
        some butchered statement or one with unterminated  <>  pairs.  The
        expander  will  write  the offending line on the terminal. In some
        cases, a .error statement is generated.


        Some times it may be necessary to rebuild the task with  a  larger
        stack and if many local symbols are generated there is a parameter
        which can be increased in the tkb file.  Stak.mac  also  has  some
        values which can be increased if you run out of space for macros.











































                                   -18-                                3.0




 Mp                            12-October-80                            Mp
                                                                       3.0








   4.  Built in default macros

        The  following  is  a  description  of  a  macro  language  easily
        constructed using Mp. It is supplied with Mp as the default  macro
        library,  that  is,  the one built into the Mp task. The library's
        control structures were  loosely  copied  from  the  C  and  Basic
        languages.  The  few  statements  that deal with data are meant to
        provide C compatibility (a far  better  choice  than  the  ancient
        fortran)   which   provides  reentrancy  with  a  simpler  calling
        sequence. C routines can use registers  r0-r4  since  only  r5  is
        needed  to  point  to  both  the  local  variables  as well as the
        parameters.  Passing  of  register  contents  and  immediate  mode
        constants are also much simpler as no temporaries are required.

        Even  though two processors must run, it is 7-10 times faster than
        supermac because of the ease with which it can deal  with  stacks.
        It  also  need  only  expand macros once whereas macro-11 does the
        expansion twice. A short  description  will  be  given  here  with
        comments on how to set up an alternate built in set.

        In the following description:

                <repeat>*           repeated 0 or more times
                <repeat>+           repeated 1 or more times
                [optional]          0 or 1 time
                <thing>             a syntactic item i.e. not literal
                OTHER STUFF         litteral string if upper case
                other stuff         example of thing if lower case
                `thing'             denotes thing is not a meta-character

        Macro description:



   o    PROGRAM <string>

             Initializes macro library and sets <string>  to  be  the
             prefix  for label generation. It should be <= 3 chars in
             length. This macro must be specified  and  should  occur
             before  all other macro usage. It enables lower case and
             sets switch 15 (for strings).

   o    AUTO  <label>+

             Sets its arguments to  offsets  which  are  computed  in
             macro-11.   These  offsets correspond to local variables
             defined in a C function.   All  autos  are  allocated  2
             bytes by default. To allocate a different amount use the
             form:


                                   -19-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


                     AUTO var[amount] ...

             Auto's  are  implemented  as  var(r5).  The  macros will
             append the (r5) but a mov statement  would  require  the
             auto to be explicitly referenced as var(r5).

   o    FUNCTION name`['<parameter label>*`]' [TRACE] [ODT]

             Specifies  a  C  compatible function with arguments. The
             arguments are labels  which  the  assembler  equates  to
             offsets  on r5. This permits C calls and simulation of a
             C function. The stack is decremented  according  to  how
             many  auto  variables  are  defined. Some extra stack is
             also allocated, see the comment at the end  of  the  LET
             macro description.

             The TRACE option generates a call  to  printf  with  the
             name  of the function and the value of the arguments. It
             will also print the address  of  the  top  of  the  file
             (relative  0 on the listing) which is usually the offset
             desired for odt usage. The  ODT  option  specifies  that
             after  the  print, enter odt by an iot trap instruction.
             The TRACE option also sets a  switch  so  that  all  RET
             statements print the value of the return.

             Parameters  are  implemented as var(r5). The macros will
             append the (r5) but a mov statement  would  require  the
             parameter to be explicitly referenced as var(r5).

   o    RET [<Expression>]

             returns via a call  thru  the  C  return  mechanism  and
             optionally  returns a value.  Stack storage for autos is
             deallocated.  <expression>  is  passed  on  to  the  LET
             statement as

                     LET R0 = ...

       Thus  caution  must  be  excercised if the expression contains R0.
       Also do not specify r0 (lower case) as this would defeat all error
       detection.  Also,  the  expression  can   not   include   function
       references   yet.  A  bad  operator  message  occurs  if  this  is
       attempted.














                                   -20-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


   The following diagram shows the overall structure of a program:

      |------------------------------------------------------------|
      |                                                            |
      |       Usage of C function compatible routines              |
      |                                                            |
      |                                     |------------          |
      |    PROGRAM lab                      |used once             |
      |                                     |------------          |
      |    AUTO l1 l2 l3 ...                |                      |
      |    FUNCTION name1[p1 p2 p3 ...]     | Function 1           |
      |    ...                              |                      |
      |    RET [value]                      |                      |
      |                                     |                      |
      |                                     |-------------         |
      |    AUTO l1 l2 l3 ...                |                      |
      |    FUNCTION name2[p1 p2 p3 ...]     | Function 2           |
      |    ...                              |                      |
      |    RET [value]                      |                      |
      |                                     |-------------         |
      |                                                            |
      |------------------------------------------------------------|

                All  variables  are  referenced as xxx(r5)
                and are call by value as in C.

                If  one is very careful, all labels may be
                redefined  in  several  functions  as  the
                assembler will determine the current value
                of the label by the most recent definition
                (which is declared before usage).


   o    LET <dest> = <source> {<operator> <source>}*

            <dest>     ::= <lvalue>
            <source>   ::= <rvalue> | <c-func> | <array-ref>
            <c-func>   ::= <function>`['<parm>+`]'
            <array-ref>::= .<variable>`['<variable>`]'
            <parm>     ::= <rvalue>
            <rvalue>   ::= <variable> | <constant> | <register> | <string>
            <lvalue>   ::= <variable> | <register>

             Variables  are  anything  that  can appear in the source
             field of a pdp-11 mov instruction. The unary operator  &
             may  be  applied  to auto variables. See the note below.
             Operators are the standard four: + - / *.

             <Dest>  may  not appear on the right side unless its the
             first term after the `='. Only 6 terms are allowed. When
             referencing  functions  and  using  the  `*'   and   `/'
             operators,  r0  and r1 are usually destroyed. Evaluation
             is strictly left to right. The & unary operator  is  not
             separated  from the symbol but other operators must have
             blanks around them.


                                   -21-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


             A <c-func> generates a call to a C compatible  function.
             The  calling sequence is to push all parameters onto the
             stack and  jsr  pc,<function>.  After  the  return,  the
             caller cleans up the stack. The return from the function
             leaves  a  return  value in r0 which is then used in the
             LET statement. R1 is also not restored  across  function
             calls.  Thus  references to R0 and R1 in the rest of the
             let statement will generate incorrect code.

             Array references may only appear on the right side also.
             However, they always return  to  r0  the  value  of  the
             location  and r1 gets the address of the array ref. Thus
             the array location may be found in one LET statement and
             used indirectly in another.

             The LET statement is the only statement  which  provides
             some  of these capabilitys. It is also somewhat slow and
             thus should not be used where  a  simple  mov  statement
             works just as well.

             Examples:

                    LET a = b - c / d
                    LET a = b - fun[a,#1,&c] * fun2[loc(r5),par(r5)]
                    LET s = "s gets address of this asciz string"
                    LET r = val[.argv[#1],#10.] + #5.

             Note  that  all the macros ignore the possiblity of side
             affects  occuring  when   referencing   operands.   They
             therefore take the liberty of making multiple references
             to  any opperand specified. This usually causes incorect
             code to be generated if auto increment or  decrement  is
             used.  Always  expand  the  code first before using such
             operands; better still, only use them in simple macro-11
             machine instructions.

             The   current   state  of  implementation  permits  some
             recursiveness  in  the  LET  statement.  (See  the  last
             example  above).  This  means that under some conditions
             the arguments to a function may be an  expression  or  a
             function. However, a method for generating temps has not
             been  totally  implemented  yet and thus it is advisable
             not to use this capability. Note that  the  program  and
             func  statments initialize various counters and allocate
             some extra stack frame storage which  will  in  time  be
             used to implement recursive expressions. This means that
             when  no  recursive  expressions  are used, one need not
             have the func statement, but the  program  statement  is
             allways  necessary since it enables switch 15 for quoted
             strings.


   o    IF(B) <condition> [OR|AND <condition> [OR|AND <condition>]]

                or


                                   -22-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


   o    IF <condition-code>



       <relation> ::= NE | EQ | LT | HI | LO | LOS | HIS | GT | GE | LE | =
       <condition-code> ::= <relation>  | CC | CS  | ON  | OFF
       <condition> ::= <value> <relation> <value>
       <value>     ::= <variable> | <constant> | <register>



             This  sets  up an if-block. Condition is evaluated right
             to left with respect to OR/AND (because of the recursive
             expansion technique used).  Only  three  conditions  may
             appear  on one line. Note that only simple variables may
             be tested (for efficiency of expansion).


             Example:

                           IF a = b   AND  c = d   OR   e = f

             is equivalent to a ()'ed boolean

                              IF (a=b AND (c=d   OR (e=f)))


             The on/off are used for bit testing.

             Example:

                                     bit #4,variable
                                     IF ON
                                     ...
                                     FI



   o    ELSEIF(B) condition ...


             alternate if block, conditions as in an IF


   o    ELSE

             default selection within an IF block (must follow all
             elseif's)

   o    FI

             terminate an if block





                                   -23-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


             Example:

                          IF this = r0    OR   foo NE #5
                             ...
                             ...
                          ELSEIF autovar(r5) HIS parameter(r5)
                             ...
                          ELSE
                             ...
                          FI

   o    SELECT case <variable> of


             introduce a case construct


   o    CASE(B) <operand> [OR]

             One or more case statements follow the select statement.
             Each  selects a block of code conditionally by comparing
             the  SELECT  variable  with  <operand>.  Multiple   case
             statements  may  be  OR'd with a single block of code by
             using the OR keyword. The last case in  the  group  does
             not  have  the   OR.  Note  that  a  BREAK or some other
             transfer of control must follow the block of code (as in
             C) since `drop-thru' is undefined.



   o    DEFAULT


             executes the default code for a case statemtment.   This
             must be the last selector in the SELECT group.






















                                   -24-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


   o    ESAC


             terminates a case construct.


             Example:


                            SELECT case (r0) of

                              CASE #'a
                                 ...
                                 BREAK

                              CASE #'b OR
                              CASE #'c
                                 ...
                                 BREAK

                              DEFAULT
                            ESAC

             The  select/case  group  is  a  more  compact  form of a
             multiway IF block. However,  the  individual  selections
             must  be  terminated  by an explicit transfer of control
             (usually via a BREAK).


   o    LOOP for <indx> = <ini> TO|DOWNTO|THRU|DOWNTHRU <end> [STEP <amt>]

                 <indx> ::= index variable
                 <ini>  ::= initial value set into <indx>
                 <amt>  ::= step amount

             (THRU and DOWNTHRU generate unsigned branches)



             Negative going loops must supply  the  step  amount.  It
             defaults  to #1 (regardless of the existance of a DOWNTO
             or DOWNTHRU keyword). Loop is top tested; hence, a  loop
             may be iterated zero or more times.


   o    NEXT <indx>


             At  the  end of a loop body, this adds the step value to
             the <indx> and returns to the top of the loop. <indx> is
             checked for proper nesting.






                                   -25-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0




             Example:


                LOOP for i = #alpha  THRU  #beta  STEP   #2   ;step by words

                ...
                    IF ...
                       BREAK                                  ;terminates loop
                    FI
                NEXT i







   o    DO WHILE(B) <if-condition>


             Loop  as  long as condition is met. <if-condition> is an
             IF statement type condition. Loop is top tested.


   o    DO FOREVER

             sets up an infinite loop which is only ended via  a  jmp
             or BREAK.


   o    OD


             end of the do loop.


             Example:

                DO FOREVER                      DO WHILE a = b
                  ...                              ...
                  BREAK IF a NE b               OD
                OD


   o    BREAK [IF(B) ...]


             This causes a controled  jump  to  the  first  statement
             following  a  DO WHILE, DO FOREVER, LOOP, or SELECT CASE
             construct.  It leaves only the innermost  loop  or  case
             construct  currently  active.   If  an  IF  statement is
             supplied then it is equivalent to the form:

                     IF(B) ...

                                   -26-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


                        BREAK
                     FI


   o    PUSH|POP  <variable>

             These  are  simple  stack  push  and pop macros. They do
             however check for the `&' operator (see below).





        Note that various commands have a (B) appended to the command or a
        keyword  within the command. This causes a byte test as apposed to
        a word test.  The litteral #0 is tested for and will cause  a  TST
        or  TSTB to be used rather than a cmp or cmpb.  If branches do not
        reach, then the code must be  split  out  into  subroutines.   One
        exception  is  that  just  after  the  IF  statement,  a BEGIN-END
        construct is allowed which will force jmp instructions to be used.

        Example:

                IF condition
                  BEGIN
                  ...
                  END
                ELSE
                  ...
                FI

        Note that all keywords  must  be  in  upper  case.  This  includes
        relationals (such as LE HIS etc.).

        The  current  version  of  the  macro  library  supports one unary
        operator macro. It defines the `&' operator to be the  address  of
        an  Auto variable. Internally it sets switch 14 on and off when it
        gets to a place where it is ready to access a  variable.  It  only
        does  this for a few macros however, since there is extra overhead
        which would slow  down  the  processor.  The  currently  supported
        macros  that  permit  the  `&'  operator  are:  LET (including the
        parameters of a function call), C, and PUSH/POP. The If macros  do
        not support this.














                                   -27-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0


        Example:

             LET a = &b

        This will generate code which puts the address of b(r5) into a.

             LET a = function.of[c,d,&e]

        This invokes `function.of' passing c, d, and the address of e. The
        function returns a value in r0 which is stored in a.

        A version of sprintf  is  found  in  the  Main  library  which  is
        interfaced  via  printf  and  type.  These  along  with the `main'
        interceptor permit one to create very small  programs  that  enjoy
        many  of  the  nice  features of the C language i/o mechanism. See
        macros for description.


        Some stack dump macros exist as well: Dump,  dmpstr,  dmpsw,  peek
        and   poke.  These  are  usually  used  to  test  out  new  macros
        interactively but poke is sometimes used elsewhere. Setlab  allows
        one  to  set the string used to make labels. A macro `.' exists to
        execute a function without a LET statement.

        The macros make use of the two stacks  internally.  Stack  one  is
        used  for  all "IF" constructs and all others use stack 2. This is
        so that a BREAK can be nested inside an  IF  block  and  find  the
        innermost LOOP or CASE branch-to label.





























                                   -28-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0



        Stack usage is as follows:




                 If (stack 1)
                        tos     branch to on false
                        nos     go here on done (after elseif's etc)

                 case (stack 2)
                        tos     break to label
                        nos     variable to test
                        3os     skip over to next case test label
                        4os     Case true (the Or label)

                 Do while/forever (stack 2)
                        tos     break to
                        nos     jmp back to test or continue in loop label

                 loop (stack 2)
                        tos     break to
                        nos     jmp back to test for more looping label
                        3os     loop index
                        4os     step parameter
































                                   -29-                                4.0




 Mp                            12-October-80                            Mp
                                                                       4.0









   5.   Macro Summary


              PROGRAM <string>
              AUTO  <label>+
        name: FUNC  <parameter label>*
              RET [<Expression>]

              LET <destination> = <source> {<operator> <source>}*

              IF|IFB <condition> [OR|AND <condition> [OR|AND <condition>]]
              IF <condition-code>
              ELSEIF(B) condition ...
              ELSE
              FI

              SELECT case <variable> of
              CASE(B) <operand> [OR]
              DEFAULT
              ESAC

              LOOP for <indx> = <ini> TO|DOWNTO|THRU|DOWNTHRU <end> [STEP <amt>]
              NEXT <index>

              DO WHILE(B) <IF-condition>
              DO FOREVER
              OD

              BREAK [IF(B) ...]

              PUSH|POP  <variable>



















                                   -30-                                5.0




 Mp                            12-October-80                            Mp
                                                                       5.0








   6.  Alternate default macro librarys

        The  default  library  is  built in at task build time. The module
        mcmd.mac contains a macro called "mc". This  module  is  assembled
        with  all text for a macro library as calls to the "mc" macro (one
        per line of macros in the library). The  "mc"  macro  simply  puts
        some  pointers  around  the  text  which  is  assembled  as .ascii
        statements. Then at run time, these are loaded from an overlay and
        scanned (as if they came from a file). The main  reason  for  this
        method  of  loading  is speed. Note that the /NI switch suppresses
        this loading. Useful when testing out a new  library.  The  module
        mcmd.mac is assembled as:

                             >mac  mcmd=mcmd.

        Then the MP task is rebuilt:

                             >tkb @mp.bld.

        The mcmd.obj module is NOT put in a library.

        One other source module is available which has  some  labels  that
        allocate  more  or  less  storage for various mp internals and the
        area for storage of macro text. Use the /un switch to measure  the
        remaining  storage  available  after  a library is loaded. If many
        levels  of  recursive  macro  expansion  are  required,  bump  the
        stack=xxx  in  the  build file. The amount of storage used is kept
        track of and the lowest sp value detected is output at the end  of
        each  run.  Running out of space may cause program failures, so be
        generous. The module stak.mac contains the storage  which  can  be
        increased.  It  is  assembled thus:

                            >mac stak=ml/ml,stak.

        It  also is not put into a library. If the processor blows up when
        trying to initialize itself (loading default macros) use  the  /is
        switch  to  have  the  lines echoed on the tty so one may see what
        line in the mcmd.mac file caused the problem. If the program  runs
        out  of space for macro library text it usually just crashes. Bump
        the amount of text (in bytes) and the number of lines allowed  for
        macros.










                                   -31-                                6.0




 Mp                            12-October-80                            Mp
                                                                       6.0


        The  task  build  file for Mp also contains global definitions for
        the various characters used to delimit parameters. If  one  wishes
        to  have  >  and >= etc. as operators instead of GT or GE then the
        enclosing brackets would need to be changed from <>'s to something
        else, say for example {}'s. Any macro library used would of course
        have to  conform  to  these  characters  as  well.  The  character
        definitions for the unary operators also are found there.

        Note  that  any  change in the delimiter characters would probably
        result in some Macro-11 incompatibility.















































                                   -32-                                6.0




 Mp                            12-October-80                            Mp
                                                                       6.0








   7. Examples

        The following is an example program written using mp  macros.  The
        program  supplies a system "kill" command which will get all tasks
        active on the current terminal (except ...mcr, prt... and the kill
        program itself) and issue aborts for them.


                       .title kill             ;kill all tasks on ti:
                       .psect kill
                       .ident /v1/

          ;------------------------------------------------------------------;
                  PROGRAM KIL
          ;------------------------------------------------------------------;
                  .mcall abrt$,exit$s,dir$

          abort:  abrt$   AAABBB  ;to be stuffed later

          max     =       25.     ;max tasks to buffer
          first:  .blkw max
          last:   .blkw max

          nfirst: .rad50 /.../ /PRT/
          nlast:  .rad50/MCR/ /.../       ;non-abortables (prt... and ...mcr)
          nabo    =      <.-nlast>/2


          tasks:  .word   ;# tasks found
          j:      .word
          k:      .word
     ;-----------------------------------------------------------------------;
     ; Main program just invokes start function. Does not use Standard Main. ;
     ;-----------------------------------------------------------------------;

          go:     call start           ;this is ok if function has no parms
                  exit$s

     ;------------------------------------------;
     ; All work is done in function  start      ;
     ;------------------------------------------;
                  FUNCTION start       ;this is required since it alloc's stack

                  mov $tskhd,r5        ;get the task list header
                  mov $tktcb,r4        ;our tcb address (for KNOWING ourselves)
                  mov t.ucb(r4),r0     ;get our ucb address (for matching ti's)
                  mov #first,r1
                  mov #last,r2         ;first and last addrs in regs for speed

                  call $lockl

                                   -33-                                7.0




 Mp                            12-October-80                            Mp
                                                                       7.0



                  clr tasks
          ;------------------------------------------------------------------;
          ; check for ucb match (our ti:), not us (tktcb not the tcb we are  ;
          ; looking at) and task active, (negative status)                   ;
          ;------------------------------------------------------------------;
                  DO FOREVER
                  |
                  |   IF t.ucb(r5) = r0  AND  r5 NE r4  AND  t.stat(r5) GE #0
                  |   |   mov t.nam(r5),(r1)+
                  |   |   mov t.nam+2(r5),(r2)+   ;store 2 word rad50 task name
                  |   |   inc tasks
                  |   |   BREAK IF tasks GE #max
                  |   |...FI
                  |   mov t.tcbl(r5),r5   ;next tcb
                  |   BREAK IF t.tcbl(r5) = #0        ;null task, quit
                  |...OD

                  call $unlkl     ;unlock lists

          ;---------------------------------------;
          ; now abort all tasks we found except   ;
          ; for those nonabortables above.        ;
          ;---------------------------------------;
                  mov #first,r0
                  mov #last,r1

                  LOOP for j = #1 to tasks
                  |   mov (r0)+,r2        ;first 1/2 of tsk name
                  |   mov (r1)+,r3        ;second 1/2
                  |   mov #nfirst,r4      ;first 1/2 of non abort tsk name
                  |   mov #nlast,r5       ;2nd 1/2
                  |   LOOP for k = #1 to #nabo
                  |   |   IF (r4) = r2  AND  (r5) = r3    ;task namme match
                  |   |   |   jmp nokill
                  |   |   |...FI
                  |   |   tst (r4)+
                  |   |   tst (r5)+
                  |   |...NEXT k
                  |
                  |   mov r2,abort+a.bttn
                  |   mov r3,abort+a.bttn+2
                  |   dir$ #abort
                  |
          nokill: |
                  |...NEXT j
              RET

             .end go








                                   -34-                                7.0




 Mp                            12-October-80                            Mp
                                                                       7.0



       The following is an example program  which  uses  some  of  the  C
       compatible  features  though  not  using much of the C runtime. It
       references a library (at tkb time) which contains a  MAIN  program
       like  the  one  found  in  the C runtime. (It does not support the
       Standard i/o features  and  only  talks  with  the  terminal  thru
       qio's).  Its  purpose  is  to simulate some of what a C program on
       Unix would inherit  with  as  small  a  runtime  as  possible.  It
       provides a standard program interface which sees each user program
       being  called  at  its main function with two parameters: argv and
       argc; the function returns to  the  main  program  with  the  exit
       status.  Argv  is  a  vector of addresses which point into the mcr
       command line buffer which has been broken into argc asciz strings.
       Note that any JPL rsx program can be run by simply typing the file
       name following by arguments exactly the same  as  if  it  were  an
       installed task. Other instalations may not support this capability
       and  many restrict a terminal to invoking only one such program at
       a time.

       The printf macro formats an asciz string  into  a  scratch  buffer
       allocated from the main library and outputs the string to ti: thru
       lun  5.  The  format codes are a subset of the Conroy C system and
       the portable i/o library  on  unix.  Supported  are  at  least  %s
       (string),  %d  (decimal)  %o (octal) and %c (character). The field
       width and leading zero suppression codes should all also  work  as
       the formating routine was taken directly for the printf routine in
       Conroy's C runtime.

       The LEN macro is a 4 line code sequence to compute the  length  of
       an asciz string into r0.



        ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        ;
        ; The following is just to demonstrate how to place local
        ; macros into a program.
        ;
        $MACRO NOPP
           I%DOUT <;This macro does nothing useful - but it puts this out>
        $ENDM
        /















                                   -35-                                7.0




 Mp                            12-October-80                            Mp
                                                                       7.0



        ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        PROGRAM tst

        AUTO a b c int

        FUNCTION main[argc,argv]

            IF argc   LE   #0
              PRINTF  "Usage: Factorial N"
              RET #4                                   ;severe error
            FI

            LET argv = argv  +  #2                     ;bump past arg 1
            mov @argv(r5),c(r5)                        ;get addr of 2nd argument
            LEN c                                      ;Get len of c in r0
            mov r0,r2                                  ;don't use r0/r1 in LET
            LET  b = btoi[c,r2,&int,#10.]              ;ascii `c' to int `int'

            LET  a = fact[int]                         ;all work done here

            PRINTF  "Factorial of %d = %d" int  a

            RET #1                                     ;successful exit status

        ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        AUTO a

        FUNCTION fact[i]

            PRINTF  "Fact recursively called with %d" i


            IF i  LE   #1
                RET #1
            ELSE
                LET a = i * fact[<i - #1>] ;see note on expression usage above
            FI

            RET a
        ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -














                                   -36-                                7.0




 Mp                            12-October-80                            Mp
                                                                       7.0


        The  following  is  an  example  of  a  Macro  created to supply a
        construct similar to the C and Ratfor FOR loop. Recall the  syntax
        of the FOR is:

           For (initialize ; test ; reinitialize)
              statement

        The  easiest  way  to  implement  this statement, is to modify the
        syntax to keep within the allowable constructs  of  MP.  Thus  our
        version will be:



           FOR <initialize> <WHILE(B) test> <reinitialize>

           ROF

        Any of the three parts of a FOR loop  may  be  null  and  will  be
        interpreted as in C and RATFOR.

        Note  the requirement that the keyword WHILE(B) be explicit in the
        test part of the macro call. This  is  to  avoid  needing  a  FORB
        macro.  The  following  macro definitions supply such a statement,
        using the allready existing macros in the default  macro  library.

        The initialize part is simply expanded on a line by itself.

        The  test  part  is converted into a DO WHILE(B) loop. If the test
        part  is  null,  then  it  is  converted  into  FOREVER  which  is
        consistant  with  the  definition of the FOR loop. This is done by
        placing either parameter 2 into string element 25  or  if  it  was
        null,  FOREVER  is  put  there.  Then  element  25  is placed into
        parameter 2 replacing any previous contents.

        The reinitialize part of the call is pushed in its  entirety  onto
        the  string  stack.  The  ROF  macro simply pops the statement and
        expands it. All the leg work for label generation  is  handled  by
        the DO and OD macros.



                      $MACRO FOR <init-1> <condition-2> <reinit-3>
                      #@1
                      I%IN <#@2> <> <<POKE 25 FOREVER>> <POKE 25 <#@2>>
                      ?+ 2,,25
                      DO  #@2
                      ?- <#@3>
                      $ENDM



                      $MACRO ROF
                      ?+ 1
                      #@1
                      OD
                      $ENDM

                                   -37-                                7.0




 Mp                            12-October-80                            Mp
                                                                       7.0



        A valid macro call using this construct could be:


                       FOR <clr i> <WHILE i LT #10.> <inc i>
                       ...
                       ROF


                                 the end















































                                   -38-                                7.0


