.NH 1
TEMPLATE PROCESSING
.LP
In some code generation applications, pieces of the target
numerical program are known in advance.  A "template" file
containing a program outline is supplied by the user, and
formulas are derived in VAXIMA, converted to numerical code,
and inserted in the corresponding places in the program outline
to form a complete numerical program.  A template processor is
provided by GENTRAN for use in these applications.
.NH 2
The Template Processing Command
.SH
User Level Syntax:
.RS
.DS L
.ft CR
\fIgentranin(\fRf1,f2,...,fn {,[f1,f2,...,fm]});
.ft
.DE
.RE
where f1,f2,...,fn is an argument list containing one or more
f's, each of which is one of the following:
.RS
.DS L
.ft CR
a string  =  a template (input) file
\fItrue\fR      =  the terminal
.ft
.DE
.RE
and [f1,f2,...,fm] is an optional argument list which, if
supplied, contains one or more f's, each of which is one
of the following:
.RS
.DS L
.ft CR
a string  =  an output file
\fItrue\fR      =  the terminal
\fIfalse\fR     =  the current output file(s)
\fIall\fR       =  all files currently open for output by GENTRAN
             (see section 4)
.ft
.DE
.RE
.SH
LISP Level Syntax:
.RS
.DS L
.ft CR
\fI(gentranin '(\fRf1 f2 ... fn) '(f1 f2 ... fm))
.ft
.DE
.RE
where f1 f2 ... fn is an argument list containing one or
more f's, each of which is one of the following:
.RS
.DS L
.ft CR
a string  =  a template (input) file
\fIt\fR         =  the terminal
.ft
.DE
.RE
and (f1 f2 ... fm) is an argument list which
contains zero or more f's, each of which is one of the
following:
.RS
.DS L
.ft CR
a string  =  an output file
\fIt\fR         =  the terminal
\fInil\fR       =  the current output file(s)
\fI$all\fR      =  all files currently open for output by GENTRAN
             (see section 4)
.ft
.DE
.RE
.SH
Side Effects:
.LP
\fIgentranin\fR processes each template file f1,f2,...,fn
sequentially.
.LP
A template file may contain any number of parts, each of which
is either an "active" or an "inactive" part.  Each active
part starts with the delimiter << and ends with >>.
.LP
Inactive parts of template files are assumed to
contain code in the target language, FORTRAN, RATFOR, or C, depending on the
value of the global variable \fI*gentranlang\fR.  Each inactive
part is copied to the output.  Each comment delimited by the
appropriate characters,
.RS
.DS L
.ft CR
C  ... <cr>    for FORTRAN (beginning in column 1) or
*  ... <cr>    for FORTRAN (beginning in column 1),
#  ... <cr>    for RATFOR, and
/* ...  */     for C
.ft
.DE
.RE
is also copied in its entirety to the output.  Thus the character
sequences << and >> have no special meanings within
comments.
.LP
Active parts may contain any number of VAXIMA expressions and
statements.  They are not copied directly to the output.  Instead,
they are given to VAXIMA for evaluation \fIat the user level\fR.  All
output generated by each evaluation is sent to the output
file(s).  Returned values are only printed on the terminal.
.LP
Active parts will most likely contain calls to \fIgentran\fR
to generate code.  This means that the result of processing a template
file will be the original template file with all active
parts replaced by generated code.
.LP
If [f1,f2,...,fm] ((f1 f2 ... fn)) is empty, then
generated code is simply written to the current output file(s).
.LP
However, if it is given, then the current output file is
temporarily overridden.  Generated code is written to each file
represented by f1,f2,...,fn for this command
only.  Files which were open prior to the call to \fIgentranin\fR
will remain open after the call, and files which did not exist
prior to the call will be created, opened, written to, and
closed.  The output file stack will be exactly the same both
before and after the call.
.SH
Return Value:
.LP
\fIgentranin\fR returns the names of all files written to by this
command.
.SH
Diagnostic Messages:
.LP
Nonexistent Input File
.sp
Template File Already Open for Input
.sp
Wrong Type of Arg
.SH
Example:
.LP
Suppose we wish to generate a FORTRAN subprogram to compute the determinant
of a 3 x 3 matrix.  We can construct a template file with an outline of the
FORTRAN subprogram and VAXIMA and GENTRAN commands to fill it in:
.DS L
.ft CR
Contents of file det.tem:
+----------------------------------------------+
|      real*8 function det(m)                  |
|      real*8 m(3,3)                           |
|<<                                            |
|      m : genmatrix(m, 3,3, 1,1)$             |
|      gentran( rsetq( det, determinant(m) ) )$|
|>>                                            |
|      return                                  |
|      end                                     |
+----------------------------------------------+
.ft
.DE
.LP
Now we can generate a FORTRAN subprogram with the following VAXIMA session:
.DS L
.ft CR
(c1) gentranlang(fortran)$
.ft
.DE
.DS L
.ft CR
(c2) gentranin("det.tem", ["det.f"]);

(d2)                       det.f
.ft
.DE
.DS L
.ft CR
Contents of file det.f:
+------------------------------------------------------------------------+
|      real*8 function det(m)                                            |
|      real*8 m(3,3)                                                     |
|      det=m(1,3)*(-m(2,2)*m(3,1)+m(2,1)*m(3,2))-m(1,2)*(-m(2,3)*m(3,1)+m|
|     . (2,1)*m(3,3))+m(1,1)*(-m(2,3)*m(3,2)+m(2,2)*m(3,3))              |
|      return                                                            |
|      end                                                               |
+------------------------------------------------------------------------+
.ft
.DE
.NH 3
Copying Files into Template Files
.LP
Template files can be copied into other template files with recursive
calls to \fIgentranin\fR; i.e., by calling \fIgentranin\fR from the
active part of a template file.
.LP
For example, suppose we wish to copy the contents of the file det.f,
generated in the previous section, into a file containing a main
program.  The template file for the main program, main.tem, will
contain an active part to copy the contents of det.f:
.DS L
.ft CR
Contents of file main.tem:
+----------------------------------------+
|c                                       |
|c --- Main Program ---                  |
|c                                       |
|      real*8 m(3,3),det                 |
|      write(6,*) 'Enter 3 x 3 Matrix:'  |
|      do 100 i=1,3                      |
|          read(5,*) (m(i,j),j=1,3)      |
|100   continue                          |
|      write(6,*) 'Determinant = ',det(m)|
|      stop                              |
|      end                               |
|c                                       |
|c --- Determinant Calculation ---       |
|c                                       |
|<<                                      |
|      gentranin("det.f")$               |
|>>                                      |
+----------------------------------------+
.ft
.DE
.LP
The following VAXIMA session will create the file main.f:
.DS L
.ft CR
(c1) gentranin("main.tem", ["main.f"]);

(d1)                       main.f
.ft
.DE
.DS L
.ft CR
Contents of file main.f:
+------------------------------------------------------------------------+
|c                                                                       |
|c --- Main Program ---                                                  |
|c                                                                       |
|      real*8 m(3,3),det                                                 |
|      write(6,*) 'Enter 3 x 3 Matrix:'                                  |
|      do 100 i=1,3                                                      |
|          read(5,*) (m(i,j),j=1,3)                                      |
|100   continue                                                          |
|      write(6,*) 'Determinant = ',det(m)                                |
|      stop                                                              |
|      end                                                               |
.ft
.DE
.DS L
.ft CR
|c                                                                       |
|c --- Determinant Calculation ---                                       |
|c                                                                       |
|      real*8 function det(m)                                            |
|      real*8 m(3,3)                                                     |
|      det=m(1,3)*(-m(2,2)*m(3,1)+m(2,1)*m(3,2))-m(1,2)*(-m(2,3)*m(3,1)+m|
|     . (2,1)*m(3,3))+m(1,1)*(-m(2,3)*m(3,2)+m(2,2)*m(3,3))              |
|      return                                                            |
|      end                                                               |
+------------------------------------------------------------------------+
.ft
.DE
.NH 3
The Template File Stack
.LP
The VAXIMA \fIbatch\fR command takes one file name as its argument.  VAXIMA
reads in the file and executes all statements and commands, any of which
may be another \fIbatch\fR command.  A stack of input file names is
maintained by VAXIMA to allow recursive invocation of the \fIbatch\fR
command.  Similarly, a stack of template file names is maintained by
GENTRAN to facilitate recursive invocation of the template
processor.  Section 3.2 showed that the \fIgentranin\fR command can be
called recursively to copy files into other files.  This section shows that
template files which are copied into other template files can also contain
active parts, and thus, the whole code generation process can be
invoked recursively.
.LP
We can generalize the example of section 3.2 by generating code
recursively.  We can extend it to generate code which will compute
entries of the inverse matrix, also.  Suppose we have created the
file init.in, which contains a VAXIMA command to create an
n x n matrix, m, and initialize its entries to
m(1,1), m(1,2), ..., m(n,n), for some user-entered value
n:
.DS L
.ft CR
Contents of file init.in:
+---------------------------+
|m : genmatrix(m, n,n, 1,1)$|
+---------------------------+
.ft
.DE
.LP
We have also created template files det.tem and inv.tem
which contain outlines of FORTRAN subprograms to compute the
determinant and inverse of an n x n matrix, m,
respectively:
.DS L
.ft CR
Contents of file det.tem:
+-------------------------------------------------------+
|      real*8 function det(m)                           |
|<<                                                     |
|      gentran( type("real*8", m(eval(n),eval(n)) ),    |
|               rsetq( det, determinant(m) )        )$  |
|>>                                                     |
|      return                                           |
|      end                                              |
+-------------------------------------------------------+
.ft
.DE
.DS L
.ft CR
Contents of file inv.tem:
+-------------------------------------------------------+
|      subroutine inv(m,minv)                           |
|<<                                                     |
|      gentran( type("real*8", m(eval(n),eval(n)),      |
|                              minv(eval(n),eval(n))),  |
|               rsetq( minv, m^^(-1) )                )$|
|>>                                                     |
|      return                                           |
|      end                                              |
+-------------------------------------------------------+
.ft
.DE
.LP
Now we can construct a template file with a generalized version of
the main program given in section 3.2 and can place \fIgentranin\fR
commands in this file to generate code recursively from the template
files det.tem and inv.tem:
.DS L
.ft CR
Contents of file main.tem:
+-------------------------------------------------------------------+
|c                                                                  |
|c  Main Program                                                    |
|c                                                                  |
|<<                                                                 |
|      gentran( type("real*8", m(eval(n),eval(n)),                  |
|                              det,                                 |
|                              minv(eval(n),eval(n)) ),             |
|               type("integer", n),                                 |
|               literal(tab, "data n/", eval(n), "/", cr) )$        |
|>>                                                                 |
|      write(6,*) 'Enter ',n,' x ',n,' Matrix:'                     |
|      do 100 i=1,n                                                 |
|          read(5,*) (m(i,j),j=1,n)                                 |
|100   continue                                                     |
|      write(6,*) 'Determinant = ',det(m)                           |
|      write(6,*) 'Inverse Matrix:'                                 |
|      call inv(m,minv)                                             |
|      do 200 i=1,n                                                 |
|          write(6,*) (minv(i,j),j=1,n)                             |
|200   continue                                                     |
|      stop                                                         |
|      end                                                          |
.ft
.DE
.DS L
.ft CR
|c                                                                  |
|c  Determinant Calculation                                         |
|c                                                                  |
|<<                                                                 |
|      gentranin("det.tem")$                                        |
|>>                                                                 |
|c                                                                  |
|c  Inverse Calculation                                             |
|c                                                                  |
|<<                                                                 |
|      gentranin("inv.tem")$                                        |
|>>                                                                 |
+-------------------------------------------------------------------+
.ft
.DE
.LP
The following VAXIMA session will create the file main.f:
.DS L
.ft CR
(c1) n : 3$
.ft
.DE
.DS L
.ft CR
(c2) batch("init.in");

(c3) m : genmatrix(m, n,n, 1,1)$

(d4)                       BATCH DONE
.ft
.DE
.DS L
.ft CR
(c5) gentranlang(fortran)$
.ft
.DE
.DS L
.ft CR
(c6) gentranin("main.tem", ["main.f"]);

(d6)                       main.f
.ft
.DE
.DS L
.ft CR
Contents of file main.f:
+------------------------------------------------------------------------+
|c                                                                       |
|c  Main Program                                                         |
|c                                                                       |
.ft
.DE
.DS L
.ft CR
|      real*8 m(3,3),det,minv(3,3)                                       |
|      integer n                                                         |
|      data n/3/                                                         |
|      write(6,*) 'Enter ',n,' x ',n,' Matrix:'                          |
|      do 100 i=1,n                                                      |
|          read(5,*) (m(i,j),j=1,n)                                      |
|100   continue                                                          |
|      write(6,*) 'Determinant = ',det(m)                                |
|      write(6,*) 'Inverse Matrix:'                                      |
|      call inv(m,minv)                                                  |
|      do 200 i=1,n                                                      |
|          write(6,*) (minv(i,j),j=1,n)                                  |
|200   continue                                                          |
|      stop                                                              |
|      end                                                               |
|c                                                                       |
|c  Determinant Calculation                                              |
|c                                                                       |
|      real*8 function det(m)                                            |
|      real*8 m(3,3)                                                     |
|      det=m(1,3)*(-m(2,2)*m(3,1)+m(2,1)*m(3,2))-m(1,2)*(-m(2,3)*m(3,1)+m|
|     . (2,1)*m(3,3))+m(1,1)*(-m(2,3)*m(3,2)+m(2,2)*m(3,3))              |
|      return                                                            |
|      end                                                               |
|c                                                                       |
|c  Inverse Calculation                                                  |
|c                                                                       |
|      subroutine inv(m,minv)                                            |
|      real*8 m(3,3),minv(3,3)                                           |
|      minv(1,1)=(-m(2,3)*m(3,2)+m(2,2)*m(3,3))/((-m(1,3)*m(2,2)+m(1,2)*m|
|     . (2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,1|
|     . )+m(1,1)*m(2,2))*m(3,3))                                         |
|      minv(1,2)=-(-m(1,3)*m(3,2)+m(1,2)*m(3,3))/((-m(1,3)*m(2,2)+m(1,2)*|
|     . m(2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,|
|     . 1)+m(1,1)*m(2,2))*m(3,3))                                        |
|      minv(1,3)=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))/((-m(1,3)*m(2,2)+m(1,2)*m|
|     . (2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,1|
|     . )+m(1,1)*m(2,2))*m(3,3))                                         |
|      minv(2,1)=-(-m(2,3)*m(3,1)+m(2,1)*m(3,3))/((-m(1,3)*m(2,2)+m(1,2)*|
|     . m(2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,|
|     . 1)+m(1,1)*m(2,2))*m(3,3))                                        |
|      minv(2,2)=(-m(1,3)*m(3,1)+m(1,1)*m(3,3))/((-m(1,3)*m(2,2)+m(1,2)*m|
|     . (2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,1|
|     . )+m(1,1)*m(2,2))*m(3,3))                                         |
|      minv(2,3)=-(-m(1,3)*m(2,1)+m(1,1)*m(2,3))/((-m(1,3)*m(2,2)+m(1,2)*|
|     . m(2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,|
|     . 1)+m(1,1)*m(2,2))*m(3,3))                                        |
|      minv(3,1)=(-m(2,2)*m(3,1)+m(2,1)*m(3,2))/((-m(1,3)*m(2,2)+m(1,2)*m|
|     . (2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,1|
|     . )+m(1,1)*m(2,2))*m(3,3))                                         |
|      minv(3,2)=-(-m(1,2)*m(3,1)+m(1,1)*m(3,2))/((-m(1,3)*m(2,2)+m(1,2)*|
|     . m(2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,|
|     . 1)+m(1,1)*m(2,2))*m(3,3))                                        |
|      minv(3,3)=(-m(1,2)*m(2,1)+m(1,1)*m(2,2))/((-m(1,3)*m(2,2)+m(1,2)*m|
|     . (2,3))*m(3,1)+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)+(-m(1,2)*m(2,1|
|     . )+m(1,1)*m(2,2))*m(3,3))                                         |
|      return                                                            |
|      end                                                               |
+------------------------------------------------------------------------+
.ft
.DE
.LP
This is an example of a modular approach to code generation;
separate subprogram templates are given in separate
files.  Furthermore, the template files are general; they can be
used for matrices of any predetermined size.  Therefore, we
can easily generate different subprograms to handle matrices
of different sizes from the same template files simply by
assigning different values to n, and reloading the file
init.in.
.NH 2
Insertion of Generated Type Declarations
.LP
The \fIgendecs\fR flag makes it possible to generate declarations
for variables generated from within active parts of template files.
.SH
Example:
.LP
Suppose we wish to process a template file which will cause GENTRAN
to generate one or more temporary variables in an active part.  We can
tell GENTRAN to generate declarations in the correct location by
processing the template file twice as follows:
.LP
Construct the template file as usual, but with two additions:
.IP 1)
Insert an active part at the beginning of the file to turn the
\fIgendecs\fR flag off:
.DS L
.ft CR
<<  off(gendecs)$  >>
.ft
.DE
.IP 2)
Insert an active part immediately after the subprogram heading to write
an active part to the output file.  This active part will cause the
\fIgendecs\fR flag to be switched back on during the second pass over
the template file:
.DS L
.ft CR
<<  gentran( literal("<<  on(gendecs)\e$  \e>\e>", cr) )$  >>
.ft
.DE
.LP
For example, suppose the original template file contains the following:
.DS L
.ft CR
Contents of file detinv.tem:
+------------------------------------------------------------+
|      subroutine detinv(m,det,inv)                          |
|<<                                                          |
|      off(gendecs)$                                         |
|      gentran( literal("<<    on(gendecs)\e$    \e>\e>", cr) )$|
|>>                                                          |
|<<                                                          |
|      m : genmatrix(m, n,n, 1,1)$                           |
|      gentran( type("real*8", m(eval(n),eval(n))) )$        |
|>>                                                          |
|<<                                                          |
|      gentran( type("real*8", det),                         |
|               rsetq( det, determinant(m) ) )$              |
|>>                                                          |
|<<                                                          |
|      gentran( type("real*8", inv(eval(n),eval(n))),        |
|               rsetq( inv, m^^(-1) ) )$                     |
|>>                                                          |
|      return                                                |
|      end                                                   |
+------------------------------------------------------------+
.ft
.DE
Now we are ready to invoke the template processor.  Since it must make
two passes over the template file, we will invoke it twice and have it
write to a temporary file as follows:
.DS L
.ft CR
(c1) n : 3$
.ft
.DE
.DS L
.ft CR
(c2) ?maxexpprintlen\* : 60$
.ft
.DE
.DS L
.ft CR
(c3) gentranin("detinv.tem", ["##detinv"]);

(d3)                       ##detinv
.ft
.DE
.DS L
.ft CR
(c4) gentranin("##detinv", ["detinv.f"]);

(d4)                       detinv.f
.ft
.DE
.LP
After the first template processing command has been executed, ##detinv
contains the following:
.DS L
.ft CR
Contents of file ##detinv:
+------------------------------------------------------------+
|      subroutine detinv(m,det,inv)                          |
|<<    on(gendecs)$    >>                                    |
|      t0=m(1,3)*(-m(2,2)*m(3,1)+m(2,1)*m(3,2))              |
|      t0=t0-m(1,2)*(-m(2,3)*m(3,1)+m(2,1)*m(3,3))           |
|      det=t0+m(1,1)*(-m(2,3)*m(3,2)+m(2,2)*m(3,3))          |
|      t1=-m(2,3)*m(3,2)+m(2,2)*m(3,3)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(1,1)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(1,3)*m(3,2)+m(1,2)*m(3,3))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(1,2)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(1,3)*m(2,2)+m(1,2)*m(2,3)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(1,3)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(2,3)*m(3,1)+m(2,1)*m(3,3))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(2,1)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(1,3)*m(3,1)+m(1,1)*m(3,3)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(2,2)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(1,3)*m(2,1)+m(1,1)*m(2,3))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(2,3)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(2,2)*m(3,1)+m(2,1)*m(3,2)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(3,1)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(1,2)*m(3,1)+m(1,1)*m(3,2))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(3,2)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(1,2)*m(2,1)+m(1,1)*m(2,2)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(3,3)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      return                                                |
|      end                                                   |
+------------------------------------------------------------+
.ft
.DE
This is a temporary file.  It can be removed after the second \fIgentranin\fR
command has been executed.
.LP
The final output file will contain the following:
.DS L
.ft CR
Contents of file detinv.f:
+------------------------------------------------------------+
|      subroutine detinv(m,det,inv)                          |
|      real*8 m(3,3),det,inv(3,3),t0,t1                      |
|      t0=m(1,3)*(-m(2,2)*m(3,1)+m(2,1)*m(3,2))              |
|      t0=t0-m(1,2)*(-m(2,3)*m(3,1)+m(2,1)*m(3,3))           |
|      det=t0+m(1,1)*(-m(2,3)*m(3,2)+m(2,2)*m(3,3))          |
|      t1=-m(2,3)*m(3,2)+m(2,2)*m(3,3)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(1,1)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(1,3)*m(3,2)+m(1,2)*m(3,3))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(1,2)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(1,3)*m(2,2)+m(1,2)*m(2,3)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(1,3)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(2,3)*m(3,1)+m(2,1)*m(3,3))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(2,1)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(1,3)*m(3,1)+m(1,1)*m(3,3)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(2,2)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(1,3)*m(2,1)+m(1,1)*m(2,3))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(2,3)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(2,2)*m(3,1)+m(2,1)*m(3,2)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(3,1)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-(-m(1,2)*m(3,1)+m(1,1)*m(3,2))                    |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(3,2)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      t1=-m(1,2)*m(2,1)+m(1,1)*m(2,2)                       |
|      t0=(-m(1,3)*m(2,2)+m(1,2)*m(2,3))*m(3,1)              |
|      t0=t0+(m(1,3)*m(2,1)-m(1,1)*m(2,3))*m(3,2)            |
|      inv(3,3)=t1/(t0+(-m(1,2)*m(2,1)+m(1,1)*m(2,2))*m(3,3))|
|      return                                                |
|      end                                                   |
+------------------------------------------------------------+
.ft
.DE
.NH 2
Special Template Variables
.LP

    ** Not Implemented Yet **
