\documentstyle[11pt,reduce]{article}
\title{GENTRAN User's Manual \\ REDUCE Version}
\date{}
\author{Barbara L. Gates \\ RAND \\
Santa Monica CA 90407-2138 USA \\[0.05in]
{\em Updated for {\REDUCE} 3.4 by} \\[0.05in]
Michael C. Dewar \\
The University of Bath \\
Email: miked@nag.co.uk}
\begin{document}
\maketitle

\index{GENTRAN ! package} \index{GENTRAN package !}

\begin{center} February 1991 \end{center}

GENTRAN is an automatic code GENerator and TRANslator which runs under
REDUCE and VAXIMA\index{VAXIMA}.  It constructs complete numerical
programs based on sets of algorithmic specifications and symbolic
expressions.  Formatted FORTRAN, RATFOR or C code can be generated
through a series of interactive commands or under the control of a
template processing routine.  Large expressions can be automatically
segmented into subexpressions of manageable size, and a special
file-handling mechanism maintains stacks of open I/O channels to allow
output to be sent to any number of files simultaneously and to
facilitate recursive invocation of the whole code generation process.
GENTRAN provides the flexibility necessary to handle most code
generation applications.  This manual describes usage of the GENTRAN
package for REDUCE.

\subsection*{Acknowledgements}

The GENTRAN package was created at Kent State University to generate
numerical code for computations in finite element analysis.  I would
like to thank Prof. Paul Wang for his guidance and many suggestions
used in designing the original package for VAXIMA.

The second version of GENTRAN was implemented at Twente University of
Technology to run under REDUCE.  It was designed to be interfaced with
a code optimization facility created by Dr. J. A. van Hulzen.  I would
like to thank Dr. van Hulzen for all of his help in the implementation
of GENTRAN in RLISP during a stay at his university in The
Netherlands.

Finally, I would like to thank Dr. Anthony Hearn of the RAND
Corporation for his help in better integrating GENTRAN into the REDUCE
environment.

\section{INTRODUCTION}

Solving a problem in science or engineering is often a two-step
process.  First the problem is modeled mathematically and derived
symbolically to provide a set of formulas which describe how to solve
the problem numerically.  Next numerical programs are written based on
this set of formulas to efficiently compute specific values for given
sets of input.  Computer algebra systems such as REDUCE
provide powerful tools for use in the formula-derivation phase but
only provide primitive program-coding tools.  The GENTRAN 
package~\cite{Gates:85,Gates:85a,Gates:85b,Gates:86}
has been constructed to automate the tedious,
time consuming and error-prone task of writing numerical programs
based on a set of symbolic expressions.

\subsection{The GENTRAN Code Generator and Translator}
The GENTRAN code GENeration and TRANslation package, originally
implemented in Franz LISP to run under VAXIMA~\cite{Gates:84}, is now also
implemented in RLISP to run under REDUCE.  Although GENTRAN
was originally created specifically to generate numerical
code for use with an existing FORTRAN-based finite element analysis
package~\cite{Wang:86,Wang:84}, it was designed
to provide the flexibility required to handle most code generation
applications.  GENTRAN contains code generation commands, file-handling
commands, mode switches, and global variables, all of which are
accessible from both the algebraic and symbolic modes of REDUCE to
give the user maximal control over the code generation process.  Formatted
\index{FORTRAN} \index{RATFOR} \index{C}
FORTRAN~\cite{FORTRAN}, RATFOR~\cite{Kernighan:79}, C~\cite{Kernighan:78},
or PASCAL code can be generated from algorithmic specifications,
i.e., descriptions of the behaviour of the target numerical program expressed
in the REDUCE programming language, and from symbolically derived expressions
and formulas.

In addition to arithmetic expressions and assignment statements,
GENTRAN can also generate type declarations and control-flow
structures.  Code generation can be guided by user-supplied
template file(s) to insert generated code into pre-existing program
skeletons, or it can be accomplished interactively through a series
of translation commands without the use of template files.  Special
mode switches enable the user to turn on or off specific features such as
automatic segmentation of large expressions, and global variables
allow the user to modify the code formatting process.  Generated
code can be sent to one or more files and, optionally, to
the user's terminal.  Stacks of open I/O channels facilitate temporary
output redirection and recursive invocation of the code generation process.

\subsection{Code Optimization}
\index{optimization, code}
A code optimizer~\cite{vanHulzen:89}, which runs under REDUCE, has
been constructed to reduce the arithmetic complexity of a set of
symbolic expressions (see the SCOPE package on
page~\pageref{SCOPE:intro}).  It optimizes them by extracting common
subexpressions and assigning them to temporary variables which are
inserted in their places.  The optimization technique is based on
mapping the expressions onto a matrix of coefficients and exponents
which are searched for patterns corresponding to the common
subexpressions.  Due to this process the size of the expressions is
often considerably reduced.

GENTRAN and the Code Optimizer have been interfaced to make it
possible to generate optimized numerical programs directly
\index{GENTRANOPT switch} from REDUCE.  Setting the switch {\tt
GENTRANOPT} {\bf ON} specifies that all sequences of assignment
statements are to be optimized before being converted to numerical
code.

\subsection{Organization of the Manual}
The remainder of this manual is divided into five sections.  Sections
\ref{GENTRAN:inter} and \ref{GENTRAN:template} describe code
generation.  Section \ref{GENTRAN:inter} explains interactive code
generation, the expression segmentation facility, and how temporary
variables can be generated; then section \ref{GENTRAN:template}
explains how code generation can be guided by a user-supplied template
file.  Section \ref{GENTRAN:output} describes methods of output
redirection, and section \ref{GENTRAN:mod} describes user-accessible
global variables and mode switches which alter the code generation
process.  Finally section \ref{GENTRAN:examples} presents three
complete examples.

\subsubsection{Typographic Conventions}
The following conventions are used in the syntactic definitions of
commands in this manual:
\begin{itemize}
\item[{-}]
Command parts which must be typed exactly as shown are given in 
{\bf BOLD PRINT}.
\item[{-}]
User-supplied arguments are {\it emphasized}.
\item[{-}]
[ ... ] indicate optional command parts.
\end{itemize}
The syntax of each GENTRAN command is shown terminated with a {\bf ;}.
However, either {\bf ;} or {\bf \$} can be used to terminate any
command with the usual REDUCE meaning:  {\bf ;} indicates that the
returned value is to be printed, while {\bf \$} indicates that printing
of the returned value is to be suppressed.

Throughout this manual it is stated that file name arguments must be
atoms.  The exact type of atom (e.g., identifier or string) is
system and/or site dependent.  The instructions for the implementation
being used should therefore be consulted.

\section{Interactive Code Generation}\label{GENTRAN:inter}
GENTRAN generates numerical programs based on algorithmic specifications
in the REDUCE programming language and derived symbolic expressions
\index{FORTRAN} \index{RATFOR} \index{PASCAL} \index{C}
produced by REDUCE evaluations.  FORTRAN, RATFOR, PASCAL or C code can
be produced.  Type declarations can be generated, and comments and
other literal strings can be inserted into the generated code.  In
addition, large arithmetic expressions can be automatically segmented
into a sequence of subexpressions of manageable size.

This section explains how to select the target language, generate
code, control expression segmentation, and how to generate temporary
variable names.

\subsection{Target Language Selection}
\label{gentranlang}
Before generating code, the target numerical language must be
selected.  GENTRAN is currently able to generate FORTRAN, RATFOR,
PASCAL and C \ttindex{GENTRANLANG"!*} code.  The global variable {\bf
GENTRANLANG!*} determines which type of code is produced.  {\bf
GENTRANLANG!*} can be set in algebraic or symbolic mode.  It can be
set to any value, but only four atoms have special meaning: {\bf
FORTRAN}, {\bf RATFOR}, {\bf PASCAL} and {\bf C}.  Any other value is
assumed to mean {\bf FORTRAN}.  {\bf GENTRANLANG!*} is always
initialized to {\bf FORTRAN}.


\subsection{Translation}
\label{translation}
\index{GENTRAN ! command}
The {\bf GENTRAN} (GENerate/TRANslate) command is used to generate
numerical code and also to translate code from algorithmic
specifications in the REDUCE programming language to code in the
target numerical language.  Section~\ref{generation} explains code
{\em generation}.  This section explains code {\em translation}.

A substantial subset of all expressions and statements in the REDUCE
programming language can be translated directly into numerical code.
The {\bf GENTRAN} command takes a REDUCE expression, statement, or
procedure definition, and translates it into code in the target
language.

\begin{describe}{Syntax:}
{\bf GENTRAN} {\it stmt} [ {\bf OUT} {\it f1,f2,\dots\  ,fn} ]{\it ;}
\end{describe}

\begin{describe}{Arguments:}
{\it stmt} is any REDUCE expression, statement (simple, compound, or
group), or procedure definition that can be translated by GENTRAN into the
target language\footnote{See~\ref{appa} for a complete listing of REDUCE
expressions and statements that can be translated.}
{\it stmt} may contain any number of calls
to the special functions {\bf EVAL}, {\bf DECLARE}, and {\bf LITERAL}
(see sections~\ref{translation}~--~\ref{comments}).

{\it f1,f2,\dots\  ,fn } is an optional argument list containing one or more
{\it f}'s, where each {\it f} is one of:
\par
\begin{tabular}{lll}
{\it an atom} &= &an output file\\
{\bf T} &= &the terminal\\
{\bf NIL} &= &the current output file(s)\\
\ttindex{ALL"!*} {\bf ALL!*} &= &all files currently open for output \\
& & by GENTRAN (see section~\ref{GENTRAN:output})\\
\end{tabular}
\end{describe}
\index{side effects}
\begin{describe}{Side Effects:}
{\bf GENTRAN} translates {\it stmt} into formatted code in the target language.

If the optional part of the command is not given, generated code is simply
written to the current output file.  However, if it is
given, then the current output file is temporarily overridden.  Generated
code is written to each file represented by 
{\it f1,f2,\dots\  ,fn} for this command only.  Files which were open prior
to the call to {\bf GENTRAN} 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 stack will be exactly the same both before and
after the call.
\end{describe}
\begin{describe}{Returned Value:}
{\bf GENTRAN}  returns the name(s) of the file(s) to which code was written.
\end{describe}
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** OUTPUT FILE ALREADY EXISTS
    OVERWRITE FILE? (Y/N)
\end{verbatim}
\begin{verbatim}
***** WRONG TYPE OF ARG
\end{verbatim}
exp
\begin{verbatim}
***** CANNOT BE TRANSLATED
\end{verbatim}
\end{describe}
\begin{describe}{\example\footnote{When the {\bf PERIOD} flag (default
setting: ON) is turned on, all \ttindex{PERIOD}
integers are automatically printed as real numbers except exponents,
subscripts in subscripted variables, and index values in DO-type loops.}}
\index{GENTRAN package ! example}
\begin{verbatim}
1: GENTRANLANG!* := 'FORTRAN$

2: GENTRAN
2:     FOR I:=1:N DO
2:         V(I) := 0$

      DO 25001 I=1,N
          V(I)=0.0
25001 CONTINUE

3: GENTRANLANG!* := 'RATFOR$ 

4: GENTRAN 
4:      FOR I:=1:N DO 
4:          FOR J:=I+1:N DO 
4:          << 
4:              X(J,I) := X(I,J); 
4:              Y(J,I) := Y(I,J) 
4:          >>$ 

DO I=1,N
    DO J=I+1,N
    {
        X(J,I)=X(I,J)
        Y(J,I)=Y(I,J)
    }

5: GENTRANLANG!* := 'C$ 

6: GENTRAN 
6:      P := FOR I:=1:N PRODUCT I$ 

{
    P=1;
    for (I=1;I<=N;++I)
        P*=I;
}

7: GENTRANLANG!* := 'PASCAL$

8: GENTRAN
8:     S := FOR I := 1:10 SUM V(I)$
BEGIN
    S:=0;
    FOR I:=1 TO 10 DO
        S:=S+V(I)
END;
\end{verbatim}
\end{describe}


\index{numeric code} Translation is a convenient method of producing
numerical code when the exact behaviour of the resultant code is
known.  It gives the REDUCE user who is familiar with the syntax of
statements in the REDUCE programming language the ability to write
code in a numerical programming language without knowing the exact
syntactical requirements of the language.  However the {\em real}
power of the {\bf GENTRAN} command lies in its ability to generate
code: it can produce numerical code from symbolic expressions derived
in REDUCE in addition to translating statements directly.  This aspect
is described in section~\ref{generation}.

\subsection{Precision}
\label{precision}
\index{precision} \index{DOUBLE switch}
By default {\bf GENTRAN} generates constants and type declarations in
single precision form.  If the user requires double precision output
then the switch {\bf DOUBLE} must be set {\bf ON}.  This does the
following:

\begin{itemize}
\item Declarations of appropriate type are converted to their double
precision counterparts.  In FORTRAN and RATFOR this means that objects of type
{\it REAL\/} are converted to objects of type {\it DOUBLE PRECISION\/}
and objects of type {\it COMPLEX\/} are converted to {\it COMPLEX*16\/}
\footnote{This is not part of the ANSI FORTRAN standard.  Some compilers
accept {\it DOUBLE COMPLEX\/} as well as, or instead of, {\it COMPLEX*16\/},
and some accept neither.}. \index{DOUBLE PRECISION} \index{COMPLEX}
\index{COMPLEX*16}
In C the counterpart of {\it float\/} is {\it double\/}, and of {\it int\/}
is {\it long\/}.  There is no complex data type and trying to translate complex
objects causes an error.
\item Similarly subprograms are given their correct type where appropriate.
\item In FORTRAN and RATFOR {\it REAL\/} and {\it COMPLEX\/} numbers are
printed with the correct double precision format.
\item Intrinsic functions are converted to their double precision counterparts
(e.g. in FORTRAN $SIN \rightarrow DSIN$ etc.).
\end{itemize}

\subsubsection{Intrinsic FORTRAN and RATFOR functions.}
An attempt is made to convert the arguments of intrinsic functions to
the correct type.  For example:
\begin{verbatim}
5: GENTRAN f:=sin(1)$
      F=SIN(1.0)

6: GENTRAN f:=sin(x)$
      F=SIN(REAL(X))

7: GENTRAN DECLARE <<x:real>>$

8: GENTRAN f:=sin(x)$
      F=SIN(X)
\end{verbatim}
Which function is used to coerce the argument may, of course, depend on the
setting of the switch {\bf DOUBLE}.

\subsubsection{Number of printed floating point digits.}
\index{PRECISION command} \index{PRINT"!-PRECISION command}
To ensure the correct number of floating point digits are
generated it may be necessary to use either the {\bf PRECISION} or
{\bf PRINT!-PRECISION} commands.  The former alters the number of
digits REDUCE calculates, the latter only the number of digits REDUCE
prints.  Each takes an integer argument.  It is not possible to set
the printed precision higher than the actual precision.  Calling {\bf
PRINT!-PRECISION} with a negative argument causes the printed
precision to revert to the actual precision.

\begin{verbatim}
1: on rounded$

2: precision 16$

3: 1/3;

0.333 33333 33333 333

4: print!-precision 6$

5: 1/3;

0.333333

6: print!-precision(-1)$

7: 1/3;

0.333 33333 33333 333
\end{verbatim}

\subsection{Code Generation:  Evaluation Prior to Translation}
\label{generation}
Section~\ref{translation} showed how REDUCE statements and expressions
can be translated directly into the target language.  This section
shows how to indicate that parts of those statements and expressions
are to be handed to REDUCE to be evaluated before being translated.
In other words, this section explains how to generate numerical code
from algorithmic specifications (in the REDUCE programming language)
and symbolic expressions.  Each of the following four subsections
describes a special function or operator that can be used to request
partial or full evaluation of expressions prior to translation.  Note
that these functions and operators have the described effects {\it
only} when applied to arguments to the {\bf GENTRAN} function and that
evaluation is done in algebraic or symbolic mode, depending on the
value of the REDUCE variable {\bf !*MODE}.\ttindex{"!*MODE}

\subsubsection{The EVAL Function}
\label{eval}
\begin{describe}{Syntax:} 
{\bf EVAL} {\it exp}
\end{describe} \ttindex{EVAL}
\begin{describe}{Argument:}
{\it exp} is any REDUCE expression or statement which, after evaluation
by REDUCE, results in an expression that can be translated by
GENTRAN into the target language.
\end{describe}
\begin{describe}{Side Effect:}
When {\bf EVAL} is called on an expression which is to be translated, it
tells {\bf GENTRAN} to give the expression to REDUCE
for evaluation first, and then to translate the result of that evaluation.
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
The following formula, F, has been derived symbolically:
\begin{verbatim}
   2
2*X  - 5*X + 6
\end{verbatim}
We wish to generate an assignment statement for the quotient
of F and its derivative.
\begin{verbatim}
1: GENTRAN 
1:      Q := EVAL(F)/EVAL(DF(F,X))$ 

      Q=(2.0*X**2-(5.0*X)+6.0)/(4.0*X-5.0)
\end{verbatim}
\end{describe}

\subsubsection{The :=: Operator}
\index{:=:}
\label{rsetq} \index{GENTRAN ! preevaluation} \index{rsetq operator}
In many applications, assignments must be generated in which the
left-hand side is some known variable name, but the
right-hand side is an expression that must be evaluated.  For
this reason, a special operator is provided to indicate that the expression
on the right-hand side is to be evaluated prior to translation.  This
special operator is {\bf :=:} (i.e., the usual REDUCE assignment operator
with an extra ``:'' on the right).
\begin{describe}{\example} \index{GENTRAN package ! example}
\begin{verbatim}
1: GENTRAN 
1:  DERIV :=: DF(X^4-X^3+2*x^2+1,X)$ 

      DERIV=4.0*X**3-(3.0*X**2)+4.0*X
\end{verbatim}
\end{describe}
Each built-in operator in REDUCE has an alternative alphanumeric identifier
associated with it.  Similarly, the GENTRAN {\bf :=:} operator has a
special identifier associated with it: {\bf RSETQ} may be used \ttindex{RSETQ}
interchangeably with {\bf :=:} on input.
\subsubsection{The ::= Operator}
\label{lsetq}
\index{matrices ! in GENTRAN}
When assignments to matrix or array elements must be generated, many
times the indices of the element must be evaluated first.  The special operator
\index{::=} \index{lsetq operator}
{\bf ::=} can be used within a call to {\bf GENTRAN}
to indicate that the indices of the matrix or
array element on the left-hand side of the assignment are to
be evaluated prior to translation.  (This is the usual REDUCE
assignment operator with an extra ``:'' on the left.)
\begin{describe}{\example}\index{GENTRAN package ! example}
We wish to generate assignments which assign zeros to all elements
on the main diagonal of M, an n x n matrix.
\begin{verbatim}
10: FOR j := 1 : 8 DO 
10:      GENTRAN 
10:          M(j,j) ::= 0$

      M(1,1)=0.0
      M(2,2)=0.0
      :
      :
      M(8,8)=0.0
\end{verbatim}
\end{describe}

{\bf LSETQ} may be used interchangeably with {\bf ::=} on input.\ttindex{LSETQ}
\subsubsection{The ::=: Operator}
\label{lrsetq}
\index{::=:}  \index{lrsetq operator}
In applications in which evaluated expressions are to be assigned to
array elements with evaluated subscripts, the {\bf ::=:} operator can be
used.  It is a combination of the {\bf ::=} and {\bf :=:} operators described
in sections~\ref{rsetq} and ~\ref{lsetq}.
\index{matrices ! in GENTRAN}

\newpage
\begin{describe}{\example}\index{GENTRAN package ! example}
The following matrix, M, has been derived symbolically:
\begin{verbatim}
(  A   0  -1   1)
(               )
(  0   B   0   0)
(               )
( -1   0   C  -1)
(               )
(  1   0  -1   D)
\end{verbatim}
We wish to generate assignment statements for those elements
on the main diagonal of the matrix.
\begin{verbatim}
10: FOR j := 1 : 4 DO 
10:      GENTRAN 
10:          M(j,j) ::=: M(j,j)$

      M(1,1)=A
      M(2,2)=B
      M(3,3)=C
      M(4,4)=D
\end{verbatim}
\end{describe}
The alternative alphanumeric identifier associated with {\bf ::=:} is 
{\bf LRSETQ}.\ttindex{LRSETQ}

\subsection{Explicit Type Declarations}
\label{explicit:type}
Type declarations are automatically generated each time a subprogram
heading is generated.  Type declarations are constructed
from information stored in the GENTRAN symbol table.  The user
can place entries into the symbol table explicitly through calls
to the special GENTRAN function {\bf DECLARE}. \index{DECLARE function}
\begin{describe}{Syntax:}
{\bf \ \ DECLARE} {\it v1,v2,\dots\  ,vn} {\bf :} {\it type;}

    or

\begin{tabular}{ll}
{\bf DECLARE}\\
{\bf $<$$<$}\\ 
&{\it v11,v12,\dots\  ,v1n} {\bf :} {\it type1;}\\
&{\it v21,v22,\dots\  ,v2n} {\bf :} {\it type2;}\\
& :\\
& :\\
&{\it vn1,vnn,\dots\  ,vnn} {\bf :} {\it typen;}\\ 
{\bf $>$$>$}{\it ;}
\end{tabular}
\end{describe}
\begin{describe}{Arguments:}
Each {\it v1,v2,\dots\  ,vn} is a list of one or more variables
(optionally subscripted to indicate array dimensions), or
variable ranges (two letters separated by a ``-'').  {\it v}'s are
not evaluated unless given as arguments to {\bf EVAL}.

Each {\it type} is a variable type in the target language.  Each
must be an atom, optionally preceded by the atom {\bf IMPLICIT}.
\index{IMPLICIT option}
{\it type}'s are not evaluated unless given as arguments to {\bf EVAL}.
\end{describe}
\begin{describe}{Side Effect:}
Entries are placed in the symbol table for each variable or
variable range declared in the call to this function.  The function
call itself is removed from the statement group being
translated.  Then after translation, type declarations are
generated from these symbol table entries before the resulting
executable statements are printed.
\end{describe}
\begin{describe}{Diagnostic Message:}
\begin{verbatim}
***** INVALID SYNTAX
\end{verbatim}
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: GENTRAN 
1: <<
1:      DECLARE 
1:      << 
1:          A-H, O-Z : IMPLICIT REAL; 
1:          M(4,4)   : INTEGER 
1:      >>; 
1:      FOR I:=1:4 DO 
1:          FOR J:=1:4 DO 
1:              IF I=J 
1:                  THEN M(I,J):=1 
1:                  ELSE M(I,J):=0; 
1:      DECLARE I, J : INTEGER; 
1: >>$ 

      IMPLICIT REAL (A-H,O-Z)
      INTEGER M(4,4),I,J
      DO 25001 I=1,4
          DO 25002 J=1,4
              IF (I.EQ.J) THEN
                  M(I,J)=1.0
              ELSE
                  M(I,J)=0.0
              ENDIF
25002     CONTINUE
25001 CONTINUE
\end{verbatim}
\end{describe}
The {\bf DECLARE} statement can also be used to declare subprogram types (i.e.
{\bf SUBROUTINE} or {\bf FUNCTION}) for \index{SUBROUTINE} \index{FUNCTION}
FORTRAN and RATFOR code, and function types for all four languages.
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: GENTRANLANG!* := 'RATFOR$ 

2: GENTRAN 
2:      PROCEDURE FAC N; 
2:      BEGIN 
2:      DECLARE 
2:      << 
2:          FAC : FUNCTION; 
2:          FAC, N : INTEGER 
2:      >>; 
2:      F := FOR I:=1:N PRODUCT I; 
2:      DECLARE F, I : INTEGER; 
2:      RETURN F 
2:      END$

INTEGER FUNCTION FAC(N)
INTEGER N,F,I
{
    F=1
    DO I=1,N
        F=F*I
}
RETURN(F)
END

3: GENTRANLANG!* := 'C$
4: GENTRAN 
4:      PROCEDURE FAC N; 
4:      BEGIN 
4:      DECLARE FAC, N, I, F : INTEGER; 
4:      F := FOR I:=1:N PRODUCT I; 
4:      RETURN F 
4:      END$ 

int FAC(N)
int N;
{
    int I,F;
    {
        F=1;
        for (I=1;I<=N;++I)
            F*=I;
    }
    return(F);
}
\end{verbatim}
\end{describe}

When generating code for subscripted variables (i.e., matrix and
array elements), it is important to keep several things in mind.  First
of all, when a REDUCE array is declared with a declaration such as
\index{ARRAY}
\begin{center}
{\bf ARRAY A(}{\it n}{\bf )\$} 
\end{center}
where {\it n} is a positive integer, {\bf A} is actually being declared
to be of size {\bf n}+1.  Each of the elements {\bf A(0), A(1), \dots\  , A(n)}
can be used.  However, a FORTRAN or RATFOR declaration such as
\begin{center}
{\bf DIMENSION A(}{\it n}{\bf )}
\end{center}
declares {\bf A} only to be of size {\bf n}.  Only the elements
{\bf A(1), A(2), \dots\  , A(n)} can be used.  Furthermore, a C declaration
such as
\begin{center}
{\bf float A[}{\it n}{\bf ];}
\end{center}
declares {\bf A} to be of size {\bf n} with elements referred to as
{\bf A[0], A[1], \dots\  , A[}{\it n-1}{\bf ]}.

To resolve these array size and subscripting conflicts, the user should
remember the following:
\index{subscripts ! in GENTRAN}
\begin{itemize}
\item {\it All REDUCE array subscripts are translated literally.}
Therefore it is the user's responsibility to be sure that array elements with
subscript 0 are not translated into FORTRAN or RATFOR.
\item Since C and PASCAL
arrays allow elements with a subscript of 0, when an array is
declared to be of size {\it n} by the user, {\it the actual generated type
declaration will be of size n+1} so that the user can translate
elements with subscripts from 0, and up to and including {\it n}.
\end{itemize}

If the user is generating C code, it is possible to produce declarations 
for arrays with unknown bounds:
\begin{verbatim}
5: gentran declare <<x(*,*):real;y(*):integer>>$

6: gendecs nil;
float X[ ][ ];
int Y[ ];
\end{verbatim}


\subsection{Implicit Type Declarations}
\label{implicit:type} \index{GETDECS switch}
Some type  declarations can be made automatically if the switch {\bf GETDECS}
is {\bf ON}.  In this case:
\begin{enumerate}
\item The indices of loops are automatically declared to be integers.
\index{loop indices ! in GENTRAN}
\item There is a global variable {\bf DEFTYPE!*}, which is the default
type given to objects.  Subprograms, their parameters, and local scalar
objects are automatically assigned this type. \ttindex{DEFTYPE"!*}
\index{REAL*8} \index{DOUBLE PRECISION}
Note that types such as REAL*8 or DOUBLE PRECISION should not
be used as, if {\bf DOUBLE} is on, then a default type of REAL
will in fact be DOUBLE PRECISION anyway.
\item  If GENTRAN is used to translate a REDUCE procedure, then it assigns
objects declared {\bf SCALAR} the type given by {\bf DEFTYPE!*}.  Note that
\index{INTEGER declaration} \index{REAL declaration}
it is legal to use the commands {\bf INTEGER} and {\bf REAL} in the place
of {\bf SCALAR}, which allows the user to specify an actual type.  The
procedure may also be given a return type, in which case that is used as
the default.  For example:
\begin{verbatim}

2: on getdecs,gendecs$

3: GENTRAN
3: real procedure f(x);
3: begin integer n;real y;
3:     n := 4;
3:     y := n/(1+x)^2;
3:     return y;
3: end;
      REAL FUNCTION F(X)
      INTEGER N
      REAL X,Y
      N=4
      Y=N/(1.0+X)**2
      F=Y
      RETURN
      END

\end{verbatim}
\end{enumerate}

\subsection{More about Type Declarations}
\label{more:type}
A check is made on output to ensure that all types generated are legal ones.
This is necessary since {\bf DEFTYPE!*} can be set to anything.
Note that {\bf DEFTYPE!*} ought normally to be given a simple 
type as its \ttindex{DEFTYPE"!*}
value, such as REAL, INTEGER, or COMPLEX,
since this will always be translated into the corresponding type in the
target language on output.

An entry is removed from the symbol table once a declaration has been
generated for it.  The {\bf KEEPDECS} switch (by default {\bf OFF})
disables this, allowing a user to check the types of objects
\index{KEEPDECS switch} which GENTRAN has generated (useful if they
are being generated automatically)

\subsection{Comments and Literal Strings}
\label{comments} \index{comments ! in GENTRAN}
Comments and other strings of characters can be inserted directly into
the stream of generated code through a call to the special function
{\bf LITERAL}.
\begin{describe}{Syntax:}
{\bf LITERAL} {\it  arg1,arg2,\dots\  ,argn;}
\end{describe}
\begin{describe}{Arguments:}
{\it arg1,arg2,\dots\  ,argn} is an argument list containing one or more
{\it arg}'s, where each {\it arg} either is, or evaluates to, an atom.  The
\ttindex{TAB"!*} \ttindex{CR"!*} 
atoms {\bf TAB!*} and {\bf CR!*} have special meanings.  {\it arg}'s are
not evaluated unless given as arguments to {\bf EVAL}.
\end{describe}
\begin{describe}{Side Effect:}
This statement is replaced by the character sequence resulting from
concatenation of the given atoms.  Double quotes are stripped from
all string type {\it arg}'s, and the reserved atoms {\bf TAB!*} and
{\bf CR!*} are replaced by a tab to the current level of indentation, and
an end-of-line character, respectively.
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
Suppose N has value 10.
\begin{verbatim}
1: GENTRANLANG!* := 'FORTRAN$ 

2: GENTRAN 
2: << 
2:      LITERAL 
2:        "C",TAB!*,"--THIS IS A FORTRAN COMMENT--",CR!*, 
2:        "C",CR!*; 
2:      LITERAL 
2:        TAB!*,"DATA N/",EVAL(N),"/",CR!* 
2: >>$ 

C     --THIS IS A FORTRAN COMMENT--
C
      DATA N/10/

3: GENTRANLANG!* := 'RATFOR$ 
4: GENTRAN 
4:     FOR I:=1:N DO 
4:     << 
4:         LITERAL 
4:            TAB!*,"# THIS IS A RATFOR COMMENT",CR!*; 
4:         LITERAL 
4:            TAB!*,"WRITE(6,10) (M(I,J),J=1,N)",CR!*, 
4:            10,TAB!*,"FORMAT(1X,10(I5,3X))",CR!* 
4:     >>$ 

DO I=1,N
    {
        # THIS IS A RATFOR COMMENT
        WRITE(6,10) (M(I,J),J=1,N)
10      FORMAT(1X,10(I5,3X))
    }

5: GENTRANLANG!* := 'C$ 
6: GENTRAN 
6: << 
6:      X:=0; 
6:      LITERAL "/* THIS IS A",CR!*, 
6:              "   C COMMENT */",CR!* 
6: >>$ 

{
    X=0.0;
/* THIS IS A
   C COMMENT */
}

7:  GENTRANLANG!* := 'PASCAL$

8: GENTRAN
8: <<
8:     X := SIN(Y);
8:     LITERAL "{ THIS IS A PASCAL COMMENT }", CR!*
8: >>$
BEGIN
    X:=SIN(Y)
{ THIS IS A PASCAL COMMENT }
END;

\end{verbatim}
\end{describe}
\subsection{Expression Segmentation}
\label{segmentation} \index{segmenting expressions}
Symbolic derivations can easily produce formulas that can be anywhere
from a few lines to several pages in length.  Such formulas
can be translated into numerical assignment statements, but unless they
are broken into smaller pieces they may be too long for a compiler
to handle.  (The maximum number of continuation lines for one statement
allowed by most FORTRAN compilers is only 19.)  Therefore GENTRAN
\index{continuation lines}
contains a segmentation facility which automatically {\it segments},
or breaks down unreasonably large expressions.

The segmentation facility generates a sequence of assignment
statements, each of which assigns a subexpression to an automatically
generated temporary variable.  This sequence is generated in such a
way that temporary variables are re-used as soon as possible, thereby
keeping the number of automatically generated variables to a minimum.
The facility can be turned on or off by setting the mode
\index{GENTRANSEG switch} switch {\bf GENTRANSEG} accordingly (i.e.,
by calling the REDUCE function {\bf ON} or {\bf OFF} on it).  The user
can control the maximum allowable expression size by setting the
\ttindex{MAXEXPPRINTLEN"!*}
variable {\bf MAXEXPPRINTLEN!*} to the maximum number of characters
allowed in an expression printed in the target language (excluding
spaces automatically printed by the formatter).  The {\bf GENTRANSEG}
switch is on initially, and {\bf MAXEXPPRINTLEN!*} is initialized to
800.
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: ON EXP$ 

2: JUNK1 := (A+B+C+D)^2$ 

3: MAXEXPPRINTLEN!* := 24$ 

4: GENTRAN VAL :=: JUNK1$ 

      T0=A**2+2.0*A*B
      T0=T0+2.0*A*C+2.0*A*D
      T0=T0+B**2+2.0*B*C
      T0=T0+2.0*B*D+C**2
      VAL=T0+2.0*C*D+D**2

5: JUNK2 := JUNK1/(E+F+G)$ 

6: MAXEXPPRINTLEN!* := 23$ 

7: GENTRANLANG!* := 'C$ 

8: GENTRAN VAL :=: JUNK2$ 

{
    T0=power(A,2)+2.0*A*B;
    T0+=2.0*A*C;
    T0=T0+2.0*A*D+power(B,2);
    T0+=2.0*B*C;
    T0=T0+2.0*B*D+power(C,2);
    T0=T0+2.0*C*D+power(D,2);
    VAL=T0/(exp(1.0)+F+G);
}
\end{verbatim}
\end{describe}
\subsubsection{Implicit Type Declarations}\label{GENTRAN:itd}
When the segmentation routine generates temporary variables, it places
type declarations in the symbol table for those variables if
possible.  It uses the following rules to determine their type:
\index{implicit type declarations} \index{temporary variables ! type}
\begin{itemize}
\item[{(1)}]
If the type of the variable to which the large expression is being
assigned is already known (i.e., has been declared by the user),
then the temporary variables will be declared to be of that same type.
\item[{(2)}] \ttindex{TEMPVARTYPE"!*}
If the global variable {\bf TEMPVARTYPE!*} has a non-NIL value, then the
temporary variables are declared to be of that type.
\item[{(3)}]
Otherwise, the variables are not declared.
\end{itemize}

\newpage
\begin{describe}{\example} \index{GENTRAN package ! example}

\begin{verbatim}
1: MAXEXPPRINTLEN!* := 20$

2: TEMPVARTYPE!* := 'REAL$ 

3: GENTRAN 
3: << 
3:      DECLARE ISUM : INTEGER; 
3:      ISUM := II+JJ+2*KK+LL+10*MM+NN; 
3:      PROD := V(X,Y)*SIN(X)*COS(Y^2)*(X+Y+Z^2) 
3: >>$ 

      INTEGER ISUM,T0
      REAL T1
      T0=II+JJ+2.0*KK+LL
      ISUM=T0+10.0*MM+NN
      T1=V(X,Y)*SIN(X)*COS(Y**2)
      PROD=T1*(X+Y+Z**2)
\end{verbatim}
\end{describe}
\subsection{Generation of Temporary Variable Names}
\label{tempvars} \index{temporary variables ! names}
As we have just seen, GENTRAN's segmentation module generates
temporary variables and places type declarations in the symbol table
for them whenever possible.  Various other modules also generate
variables and corresponding declarations.  All of these modules call
one special GENTRAN function each time they need a temporary
variable name.  This function is {\bf TEMPVAR}.  There are situations
in which it may be convenient for the user to be able to generate
temporary variable names directly.\footnote{One such example is suppression
of the simplification process to generate numerical code which is more
efficient.  See the example in section~\ref{tempvar:example} on
page~\pageref{tempvar:example}.}
Therefore {\bf TEMPVAR} \ttindex{TEMPVAR}
is a user-accessible function which may be called from both
the algebraic and symbolic modes of REDUCE.
\begin{describe}{Syntax:}
{\bf TEMPVAR} {\it type}
\end{describe}
\begin{describe}{Argument:}
{\it type} is an atom which either indicates the variable type in the
target language (INTEGER, REAL, etc.), or is {\bf NIL} if the variable
type is unknown.
\end{describe}
\begin{describe}{Side Effects:}
{\bf TEMPVAR} creates temporary variable names by repeatedly concatenating
the values of the global variables {\bf TEMPVARNAME!*} (which has a
\ttindex{TEMPVARNUM"!*}
default value of {\bf T}) and {\bf TEMPVARNUM!*} (which is initially set
to 0) and incrementing {\bf TEMPVARNUM!*} until a variable name is created
which satisfies one of the following conditions:
\begin{itemize}
\item[{(1)}]
It was not generated previously, and it has not been declared by the user.
\item[{(2)}]
It was previously generated to hold the same type of value that it
must hold this time (e.g. INTEGER, REAL, etc.), and the value assigned
to it previously is no longer needed.
\end{itemize}
If {\it type} is a non-NIL argument, or if {\it type} is {\bf NIL}
and the global variable {\bf TEMPVARTYPE!*} (initially NIL) has been
\ttindex{TEMPVARTYPE"!*}
set to a non-NIL value, then a type entry for the generated variable name
is placed in the symbol table.
\end{describe}
\begin{describe}{Returned Value:}
{\bf TEMPVAR} returns an atom which can be used as a variable.
\end{describe}
Note:  It is the user's responsibility to set {\bf TEMPVARNAME!*} and 
{\bf TEMPVARNUM!*} to values such that generated variable
names will not clash with variables used elsewhere in the
program unless those variables have been declared.

\subsubsection{Marking Temporary Variables}
In section~\ref{tempvars} we saw that a temporary variable name (of a certain
type) can be regenerated when the value previously assigned to it
is no longer needed.  This section describes a function which {\it marks}
a variable to indicate that it currently holds a
significant value, and the next section describes functions which
{\it unmark} variables to indicate that the values they hold are no
\index{temporary variables ! marking}
\index{marking temporary variables}
longer significant.\ttindex{MARKVAR}
\begin{describe}{Syntax:}
{\bf MARKVAR} {\it  var}
\end{describe}
\begin{describe}{Argument:}
{\it var} is an atom.
\end{describe}
\begin{describe}{Side Effects:}
{\bf MARKVAR} sets a flag on {\it var}'s property list to indicate that
{\it var} currently holds a significant value.
\end{describe}
\begin{describe}{Returned Value:}
{\bf MARKVAR} returns {\it var}.
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
The following matrix, M has been derived symbolically:
\begin{verbatim}
(X*(Y+Z)       0     X*Z)
(                       )
(     -X     X+Y       0)
(                       )
(    X*Z       0    Z**2)
\end{verbatim}
We wish to replace each non-zero element by a generated variable name
to prevent these expressions from being resubstituted into further
calculations.  (We will also record these substitutions in the
numerical program we are constructing by generating assignment
statements.)\footnote{ Note: {\bf MARKVAR} is a symbolic mode
procedure.  Therefore, the name of each variable whose value is to be
passed to it from algebraic mode must appear in a {\bf SHARE}
\index{SHARE command} declaration.  This tells REDUCE to share the
variable's value between algebraic and symbolic modes.}
\begin{verbatim}
9: SHARE var$ 

10: FOR j := 1 : 3 DO 
10:      FOR k := 1 : 3 DO 
10:          IF M(j,k) NEQ 0 THEN 
10:          << 
10:              var := TEMPVAR(NIL); 
10:              MARKVAR var;
10:              GENTRAN
10:                  EVAL(var) :=: M(j,k);
10:              M(j,k) := var
10:          >>$ 

      T0=X*(Y+Z)
      T1=X*Z
      T2=-X
      T3=X+Y
      T4=X*Z
      T5=Z**2
\end{verbatim}
Now matrix M contains the following entries:
\begin{verbatim}
(T0   0  T1)
(          )
(T2  T3   0)
(          )
(T4   0  T5)
\end{verbatim}
\end{describe}

\subsubsection{Unmarking Temporary Variables}
\index{unmarking temporary variables} \index{temporary variables ! unmarking}
After the value assigned to a temporary variable has been used
in the numerical program and is no longer needed, the variable name can be \
\ttindex{UNMARKVAR}
{\it unmarked} with the {\bf UNMARKVAR} function.
\begin{describe}{Syntax:}
{\bf UNMARKVAR} {\it  var;}
\end{describe}
\begin{describe}{Argument:}
{\it var} is an atom (variable name) or an expression containing one or more
variable names.
\end{describe}
\begin{describe}{Side Effect:}
{\bf UNMARKVAR} resets flags on the property lists of all variable names in 
{\it var} to indicate that they do not hold significant values any longer.
\end{describe}

\subsection{Enabling and Disabling Generation of Type Declarations}
\label{control:type}
GENTRAN maintains a symbol table of variable type and dimension
information.  It adds information to the symbol table by processing
user-supplied calls to the {\bf DECLARE} function (see
Section~\ref{explicit:type}) and as a
side effect of generating temporary variable names 
(see Sections~\ref{segmentation} and \ref{tempvars}).
All information is stored in the symbol table until GENTRAN is ready
to print formatted numerical code.  Since programming languages such as
FORTRAN require that type declarations appear before executable statements,
GENTRAN automatically extracts all relevant type information and prints it
in the form of type declarations before printing executable
statements.  This feature is useful when the entire body of a (sub)program is
generated at one time:  in this case, type declarations are printed
before any executable code.  However, if the user chooses to generate code
in pieces, the resulting code may have type declarations interleaved
\index{GENDECS switch}
with executable code.  For this reason, the user may turn the {\bf GENDECS}
mode switch on or off, depending on whether or not s/he chooses to use
this feature.

In the following we re-examine the example of Section~\ref{GENTRAN:itd}.
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: MAXEXPPRINTLEN!* := 20$ 

2: TEMPVARTYPE!* := 'REAL!*8$

3: GENTRAN 
3: << 
3:      DECLARE ISUM : INTEGER; 
3:      ISUM := II+JJ+2*KK+LL+10*MM+NN 
3: >>$ 

      INTEGER ISUM,T0
      T0=II+JJ+2*KK+LL
      ISUM=T0+10*MM+NN

4: GENTRAN PROD := V(X,Y)*SIN(X)*COS(Y^2)*(X+Y+Z^2)$ 

      REAL*8 T2
      T2=V(X,Y)*SIN(REAL(X))*COS(REAL(Y**2))
      PROD=T2*(X+Y+Z**2)

5: OFF GENDECS$ 

6: GENTRAN 
6: <<
6:      DECLARE ISUM : INTEGER; 
6:      ISUM := II+JJ+2*KK+LL+10*MM+NN 
6: >>$ 

      T0=II+JJ+2*KK+LL
      ISUM=T0+10*MM+NN

7: GENTRAN PROD := V(X,Y)*SIN(X)*COS(Y^2)*(X+Y+Z^2)$ 

      T2=V(X,Y)*SIN(REAL(X))*COS(REAL(Y**2))
      PROD=T2*(X+Y+Z**2)
\end{verbatim}
\end{describe}

In Section~\ref{template:type} we will explain how to further control
the generation of type declarations.

\subsection{Complex Numbers}
\label{complex} \index{complex numbers} \index{COMPLEX}
With the switch {\bf COMPLEX} set {\bf ON}, GENTRAN will generate the
correct representation for a complex number in the given precision
provided that:

\begin{enumerate}
\item The current language supports a complex data type (if it doesn't then
an error results);
\item The complex quantity is evaluated by REDUCE
to give an object of the correct
domain; i.e.
\begin{verbatim}
        GENTRAN x:=: 1+i;

        GENTRAN x:= eval 1+i;

        z := 1+i;
        GENTRAN x:=: z;
\end{verbatim}
will all generate the correct result, as will their Symbolic mode equivalents,
while:
\begin{verbatim}
        GENTRAN x := 1+i;
\end{verbatim}
will not.
\end{enumerate}

\subsection{Intrinsic Functions}
\label{intrinsic} \index{intrinsic functions}
A warning is issued if a standard REDUCE function is encountered which
does not have an intrinsic counterpart in the target language (e.g.
 {\it cot\/},
{\it sec\/} etc.).
Output is not halted in case this is a user--supplied function, either via
a REDUCE definition or within a GENTRAN template.

The types of intrinsic FORTRAN functions are coerced to reals (in the correct
precision) as the following examples demonstrate:
\begin{verbatim}
19: GENTRAN x:=sin(0)$
      X=SIN(0.0)

20: GENTRAN x:=cos(A)$
      X=COS(REAL(A))

21: ON DOUBLE$

22: GENTRAN x := log(1)$
      X=DLOG(1.0D0)

23: GENTRAN x := exp(B)$
      X=DEXP(DBLE(B))

24: GENTRAN DECLARE <<b:real>>$

25: GENTRAN x := exp(B)$
      X=DEXP(B)

\end{verbatim}

\subsection{Miscellaneous}

\subsubsection{MAKECALLS}
A statement like:
\begin{verbatim}
        GENTRAN x^2+1$
\end{verbatim}
will yield the result:
\begin{verbatim}
        X**2+1
\end{verbatim}
but, under normal circumstances, a statement like:
\begin{verbatim}
        GENTRAN sin(x)$
\end{verbatim}
will yield the result:
\begin{verbatim}
              CALL SIN(X)
\end{verbatim}
\index{MAKECALLS switch}
The switch {\bf MAKECALLS} (OFF by default) will make GENTRAN yield
\begin{verbatim}
       SIN(X)
\end{verbatim}
This is useful if you don't know in advance what the form of the expression
which you are translating is going to be.

\subsubsection{E}
\index{e} \index{EXP}
When GENTRAN encounters $e$ it translates it into EXP(1), and when GENTRAN
encounters
$e^x$ it is translated to EXP(X).  This is then translated
into the correct statement in the given language and precision.  Note that
it is still possible to do something like:
\begin{verbatim}
                GENTRAN e:=:e;
\end{verbatim}
and get the correct result.

\subsection{Booleans}
\index{booleans} \index{true} \index{false}
Some languages, like Fortran-77, have a boolean data type.  Others, like
C, do not.  When translating Reduce code into a language with a boolean
data type, GENTRAN will recognise the special identifiers $true$ and
$false$.  For example:
\begin{verbatim}
3: gentran <<declare t:logical ;t:=true>>;
      LOGICAL T
      T=.TRUE.
\end{verbatim}


\section{Template Processing}\label{GENTRAN:template}

\index{GENTRAN ! templates} \index{templates !} \index{code templates}
In some code generation applications pieces of the target numerical
program are known in advance.  A {\it template} file containing a
program outline is supplied by the user, and formulas are derived in
REDUCE, 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.

\subsection{The Template Processing Command}
\label{templates} \index{GENTRANIN command}
\begin{describe}{Syntax:}
{\bf GENTRANIN} {\it f1,f2,\dots\ ,fm} [{\bf OUT} {\it f1,f2,\dots\
 ,fn\/}]{\it ;}
\end{describe}
\begin{describe}{Arguments:}
{\it f1,f2,\dots\ ,fm\/} is an argument list containing one or more
{\it f\/}'s,
where each {\it f\/} is one of:
\begin{center}
\begin{tabular}{lll}
{\it an atom}& = &a template (input) file\\
{\bf T}& = &the terminal\\
\end{tabular}
\end{center}
{\it f1,f2,\dots\ ,fn\/} is an optional argument list containing one or more
{\it f\/}'s, where each {\it f\/} is one of:
\begin{center}
\begin{tabular}{lll}
{\it an atom}& = &an output file\\
{\bf T}& = &the terminal\\
{\bf NIL}& = &the current output file(s)\\
{\bf ALL!*}& = &all files currently open for output \\
& &  by GENTRAN (see section~\ref{GENTRAN:output}) \\
\end{tabular}
\end{center}
\end{describe}
\begin{describe}{Side Effects:}
{\bf GENTRANIN} processes each template file {\it f1,f2,\dots\ ,fm}
sequentially.

A template file may contain any number of parts, each of which
is either an active or an inactive part.  All active parts start with
the character sequence {\bf ;BEGIN;} and end with {\bf ;END;}.  The end
of the template file is indicated by an extra {\bf ;END;} character
sequence. \index{;BEGIN; marker}  \index{;END; marker}

Inactive parts of template files are assumed to contain code in the
target language (FORTRAN, RATFOR, PASCAL or C, depending on the value
\ttindex{GENTRANLANG"!*}
of the global variable {\bf GENTRANLANG!*}).  All inactive parts are
copied to the output.  Comments delimited by the appropriate characters,
\index{comments ! in GENTRAN}
\begin{center}
\begin{tabular}{lll}
&{\bf C} \dots\  $<$cr$>$ & FORTRAN (beginning in column 1)\\
&{\bf \#} \dots\  $<$cr$>$ & RATFOR \\
&{\bf /*} \dots\  {\bf */} & C \\
&{\bf \{} \dots\ {\bf \}} or {\bf *(} \dots\  {\bf )*} & PASCAL\\
\end{tabular}
\end{center}
are also copied in their entirety to the output.  Thus the character
sequences {\bf ;BEGIN;} and {\bf ;END;} have no special meanings
within comments.

Active parts may contain any number of REDUCE expressions, statements,
and commands.  They are not copied directly to the output.  Instead,
they are given to REDUCE for evaluation in algebraic mode\footnote{
Active parts are evaluated in algebraic mode unless the mode is
explicitly changed to symbolic from within the active part itself.
This is true no matter which mode the system was in when the template
processor was called.}.  All output generated by each evaluation is
sent to the output file(s).  Returned values are only printed on the
terminal.\index{GENTRAN ! preevaluation}

Active parts will most likely contain calls to {\bf GENTRAN} 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.

If {\bf OUT} {\it f1,f2,\dots\ ,fn} is not given, generated code is simply
written to the current-output file.

However, if {\bf OUT} {\it  f1,f2,\dots\ ,fn}
is given, then the current-output file
is temporarily overridden.  Generated code is written to each file represented
by {\it f1,f2,\dots\ ,fn} for this command only.  Files which were
open prior to the call to {\bf GENTRANIN} 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-stack will be
exactly the same both before and after the call.
\end{describe}
\begin{describe}{Returned Value:}
{\bf GENTRANIN} returns the names of all files written to by this
command.
\end{describe}
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** OUTPUT FILE ALREADY EXISTS
    OVERWRITE FILE? (Y/N)

***** NONEXISTENT INPUT FILE

***** TEMPLATE FILE ALREADY OPEN FOR INPUT

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
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 REDUCE and
GENTRAN commands to fill it in:
\index{matrices ! in GENTRAN}

Contents of file {\tt det.tem}:
\end{describe}
\begin{framedverbatim}
      REAL FUNCTION DET(M)                         
      REAL M(3,3)                                  
;BEGIN;                                              
      OPERATOR M$                                    
      MATRIX MM(3,3)$                                
      MM := MAT( (M(1,1),M(1,2),M(1,3)),             
                 (M(2,1),M(2,2),M(2,3)),             
                 (M(3,1),M(3,2),M(3,3)) )$           
      GENTRAN DET :=: DET(MM)$                       
;END;                                                
      RETURN                                         
      END                                            
;END;                                                
\end{framedverbatim}

\begin{describe}{}
Now we can generate a FORTRAN subprogram with the following
REDUCE session:
\begin{verbatim}
1: GENTRANLANG!* := 'FORTRAN$ 

2: GENTRANIN 
2:      "det.tem" 
2: OUT "det.f"$ 
\end{verbatim}
Contents of file det.f:
\end{describe}
\begin{framedverbatim}
      REAL FUNCTION DET(M)
      REAL M(3,3)
      DET=M(3,3)*M(2,2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)
     . *M(2,3)*M(1,1))+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1
     . ,2)-(M(3,1)*M(2,2)*M(1,3))
      RETURN
      END
\end{framedverbatim}

\subsection{Copying Files into Template Files}
\label{copy:template}

\index{GENTRANIN command} \index{files ! in GENTRAN}
Template files can be copied into other template files with recursive
calls to {\bf GENTRANIN} ; i.e., by calling {\bf GENTRANIN} from the
active part of a template file.

For example, suppose we wish to copy the contents of a file containing
a subprogram into a file containing a main program.  We will call 
{\bf GENTRANIN} to do the copying, so the subprogram file must
have {\bf ;END;} on its last line:

Contents of file {\tt det.tem}:
\begin{framedverbatim}
      REAL FUNCTION DET(M)                              
      REAL M(3,3)                                       
      DET=M(3,3)*M(2,2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)
     . *M(2,3)*M(1,1))+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1
     . ,2)-(M(3,1)*M(2,2)*M(1,3))
      RETURN                                              
      END                                                 
;END;                                                     
\end{framedverbatim} 

Now the template file for the main program can be constructed
with an active part which will include file det.tem:

Contents of file {\tt main.tem}:
\begin{framedverbatim} 
C                                                         
C  MAIN PROGRAM                                           
C                                                         
      REAL 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,*) ' DET = ', DET(M)                        
      STOP                                                
      END                                                 
C                                                         
C  DETERMINANT CALCULATION                                
C                                                         
;BEGIN;                                                   
      GENTRANIN "det.tem"$                                
;END;                                                     
;END;                                                     
\end{framedverbatim} 

The following REDUCE session will create the file {\tt main.f}:
\begin{verbatim}
1: GENTRANIN 
1:      "main.tem" 
1: OUT "main.f"$
\end{verbatim}

Contents of file {\tt main.f}:
\begin{framedverbatim}
C                                                         
C  MAIN PROGRAM                                           
C                                                         
      REAL 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,*) ' DET = ', DET(M)                        
      STOP                                                
      END                                                 
C                                                         
C  DETERMINANT CALCULATION                                
C                                                         
      REAL FUNCTION DET(M)                              
      REAL M(3,3)                                       
      DET=M(3,3)*M(2,2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)
     . *M(2,3)*M(1,1))+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*
     . M(1,2)-(M(3,1)*M(2,2)*M(1,3))
      RETURN                                              
      END                                                 
\end{framedverbatim} 

\subsection{The Template File Stack}
\label{template:stack}

\index{templates ! file stack}
The REDUCE {\bf IN} command takes one or more file names as
arguments.  REDUCE reads each of the given files and executes all
statements and commands, any of which may be another {\bf IN}
command.  A stack of input file names is maintained by
REDUCE to allow recursive invocation of the {\bf IN} command.  Similarly,
a stack of template file names is maintained by GENTRAN to facilitate
recursive invocation of the template processor.  Section~\ref{copy:template}
showed that the {\bf GENTRANIN} command can be
\index{GENTRANIN command}
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.

We can generalize the example of section~\ref{copy:template} 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.red, which contains REDUCE commands to
create an {\it n}x{\it n} matrix MM and initialize its entries
to M(1,1), M(1,2),~\dots~, M({\it n}, {\it n}), for some user-entered
value of {\it n}:

Contents of file {\tt init.red}:
\begin{framedverbatim}
OPERATOR M$                                               
MATRIX MM(n,n)$                                           
FOR J := 1 : n DO                                         
    FOR K := 1 : n DO                                     
        MM(J,K) := M(J,K)$                                
END$                                                      
\end{framedverbatim} 

We have also created template files {\tt det.tem} and {\tt inv.tem} which
contain outlines of FORTRAN subprograms to compute the
determinant and inverse of an {\it n}x{\it n} matrix, respectively:

Contents of file {\tt det.tem}:
\begin{framedverbatim}
      REAL FUNCTION DET(M)                              
;BEGIN;                                                   
      GENTRAN                                             
      <<                                                  
          DECLARE M(EVAL(n),EVAL(n)) : REAL;            
          DET :=: DET(MM)                                 
      >>$                                                 
;END;                                                     
      RETURN                                              
      END                                                 
;END;                                                     
\end{framedverbatim} 
Contents of file {\tt inv.tem}:
\begin{framedverbatim}
      SUBROUTINE INV(M,MINV)                              
;BEGIN;                                                   
      GENTRAN                                             
      <<                                                  
          DECLARE M(EVAL(n),EVAL(n)),                     
          MINV(EVAL(n),EVAL(n)) : REAL;                 
          MINV :=: MM^(-1)                                
      >>$                                                 
;END;                                                     
      RETURN                                              
      END                                                 
;END;                                                     
\end{framedverbatim} 

Now we can construct a template file with a generalized version of the main
program given in section~\ref{copy:template}
and can place {\bf GENTRANIN} commands
in this file to generate code recursively from the template files det.tem
and inv.tem:

Contents of file {\tt main.tem}:
\begin{framedverbatim}
C                                                         
C  MAIN PROGRAM                                           
C                                                         
;BEGIN;                                                   
      GENTRAN                                             
      <<                                                  
          DECLARE                                         
          <<                                              
              M(EVAL(n),EVAL(n)),                         
              DET,                                        
              MINV(EVAL(n),EVAL(n)) : REAL;             
              N                     : INTEGER             
          >>;                                             
          LITERAL TAB!*, "DATA N/", EVAL(n), "/", CR!*    
      >>$                                                 
;END;                                                     
      WRITE(6,*) 'ENTER ', N, 'x', N, ' MATRIX'           
      DO 100 I=1,N                                        
          READ(5,*) (M(I,J),J=1,N)                        
100   CONTINUE                                            
      WRITE(6,*) ' DET = ', 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                                                         
;BEGIN;                                                   
      GENTRANIN "det.tem"$                                
;END;                                                     
C                                                         
C  INVERSE CALCULATION                                    
C                                                         
;BEGIN;                                                   
      GENTRANIN "inv.tem"$                                
;END;                                                     
;END;                                                     
\end{framedverbatim} 

The following REDUCE session will create the file {\tt main.f}:
\begin{verbatim}
1: n := 3$ 

2: IN "init.red"$ 

3: GENTRANLANG!* := 'FORTRAN$ 

4: GENTRANIN 
4:      "main.tem" 
4: OUT "main.f"$ 
\end{verbatim}
Contents of file {\tt main.f}:
\begin{framedverbatim}
C                                                         
C  MAIN PROGRAM                                           
C                                                         
      REAL 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,*) ' DET = ', 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 FUNCTION DET(M)                              
      REAL M(3,3)                                       
      DET=M(3,3)*M(2,2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)
     . *M(2,3)*M(1,1))+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)
     . *M(1,2)-(M(3,1)*M(2,2)*M(1,3))
      RETURN                                              
      END                                                 
C                                                         
C  INVERSE CALCULATION                                    
C                                                         
      SUBROUTINE INV(M,MINV)                              
      REAL M(3,3),MINV(3,3)                             
      MINV(1,1)=(M(3,3)*M(2,2)-(M(3,2)*M(2,3)))/(M(3,3)*M(2,2
     . )*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1))
     . +M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(2
     . ,2)*M(1,3)))
      MINV(1,2)=(-(M(3,3)*M(1,2))+M(3,2)*M(1,3))/(M(3,3)*M(2,
     . 2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1)
     . )+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(
     . 2,2)*M(1,3)))
      MINV(1,3)=(M(2,3)*M(1,2)-(M(2,2)*M(1,3)))/(M(3,3)*M(2,2
     . )*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1))
     . +M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(2
     . ,2)*M(1,3)))
      MINV(2,1)=(-(M(3,3)*M(2,1))+M(3,1)*M(2,3))/(M(3,3)*M(2,
     . 2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1)
     . )+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(
     . 2,2)*M(1,3)))
      MINV(2,2)=(M(3,3)*M(1,1)-(M(3,1)*M(1,3)))/(M(3,3)*M(2,2
     . )*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1))
     . +M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(2
     . ,2)*M(1,3)))
      MINV(2,3)=(-(M(2,3)*M(1,1))+M(2,1)*M(1,3))/(M(3,3)*M(2,
     . 2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1)
     . )+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(
     . 2,2)*M(1,3)))
      MINV(3,1)=(M(3,2)*M(2,1)-(M(3,1)*M(2,2)))/(M(3,3)*M(2,2
     . )*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1))
     . +M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(2
     . ,2)*M(1,3)))
      MINV(3,2)=(-(M(3,2)*M(1,1))+M(3,1)*M(1,2))/(M(3,3)*M(2,
     . 2)*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1)
     . )+M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(
     . 2,2)*M(1,3)))
      MINV(3,3)=(M(2,2)*M(1,1)-(M(2,1)*M(1,2)))/(M(3,3)*M(2,2
     . )*M(1,1)-(M(3,3)*M(2,1)*M(1,2))-(M(3,2)*M(2,3)*M(1,1))
     . +M(3,2)*M(2,1)*M(1,3)+M(3,1)*M(2,3)*M(1,2)-(M(3,1)*M(2
     . ,2)*M(1,3)))
      RETURN                                              
      END                                                 
\end{framedverbatim} 

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 {\it n}, and reloading the
file init.red.

\subsection{Template Processing and Generation of Type Declarations}
\label{template:type}
\index{GENDECS switch} \index{type declarations}
In Section~\ref{control:type} we described the {\bf GENDECS} flag.  We
explained that type declarations are not generated when this flag is
turned off.  Now that the concept of template processing has been
explained, it is appropriate to continue our discussion of generation
of type declarations.

When the {\bf GENDECS} flag is off, type declaration information is not
simply discarded --- it is still maintained in the symbol table.  Only the
automatic extraction of this information in the form of declarations is
disabled.  When the {\bf GENDECS} flag is turned off, all type
information associated with a specific subprogram can be retrieved in the
form of generated declarations by calling the {\bf GENDECS} function with
the subprogram name as argument.  The template processor recognizes
function and subroutine headings.  It always keeps track of the name of
the subprogram it is processing.  Therefore, the declarations associated with
a particular subprogram {\it subprogname} can be generated with a call to
{\bf GENDECS} as follows:
\begin{center}
{\bf GENDECS} {\it subprogname}\$
\end{center}

By using the {\bf GENDECS} flag and function together with the template
processing facility, it is possible to have type information
inserted into the symbol table during a first pass over a template file, and
then to have it extracted during a second pass.  Consider the following
example in which the original template file is transformed into an
intermediate template during the first pass, and then into the final file
of FORTRAN code during the second pass:

Contents of file {\tt junk.tem}:
\begin{framedverbatim}
;BEGIN;                                       
MAXEXPPRINTLEN!* := 50$                       
OFF GENDECS$                                  
;END;                                         
      SUBROUTINE CALC(X,Y,Z,A,B,RES)          
;BEGIN;                                       
GENTRAN LITERAL ";BEGIN;", CR!*,              
                "GENDECS CALC$", CR!*,        
                 ";END;", CR!*$                
;END;                                         
      X=3.75                                  
      Y=-10.2                                 
      Z=16.473                                
;BEGIN;                                       
GENTRAN                                       
<<                                            
    DECLARE X,Y,Z,A,B,RES : REAL;           
    RES :=: (X + Y + Z)^3*(A + B)^2           
>>$                                           
;END;                                         
      RETURN                                  
      END                                     
;BEGIN;                                       
GENTRAN LITERAL ";END;", CR!*$                
;END;                                         
;END;                                         
\end{framedverbatim} 

Invocation of the template processor on this file produces an
intermediate template file:
\begin{verbatim}
1: GENTRANIN 
1:     "junk.tem" 
1: OUT "#junk.tem"$ 
\end{verbatim}
Contents of file {\tt \#junk.tem}:
\begin{framedverbatim}
      SUBROUTINE CALC(X,Y,Z,A,B,RES)          
;BEGIN;                                       
GENDECS CALC$                                 
;END;                                         
      X=3.75                                  
      Y=-10.2                                 
      Z=16.473                                
      T0=A**2*X**3+3.0*A**2*X**2*Y            
      T0=T0+3.0*A**2*X**2*Z+3.0*A**2*X*Y**2   
      T0=T0+6.0*A**2*X*Y*Z+3.0*A**2*X*Z**2    
      T0=T0+A**2*Y**3+3.0*A**2*Y**2*Z         
      T0=T0+3.0*A**2*Y*Z**2+A**2*Z**3         
      T0=T0+2.0*A*B*X**3+6.0*A*B*X**2*Y       
      T0=T0+6.0*A*B*X**2*Z+6.0*A*B*X*Y**2     
      T0=T0+12.0*A*B*X*Y*Z+6.0*A*B*X*Z**2     
      T0=T0+2.0*A*B*Y**3+6.0*A*B*Y**2*Z       
      T0=T0+6.0*A*B*Y*Z**2+2.0*A*B*Z**3       
      T0=T0+B**2*X**3+3.0*B**2*X**2*Y         
      T0=T0+3.0*B**2*X**2*Z+3.0*B**2*X*Y**2   
      T0=T0+6.0*B**2*X*Y*Z+3.0*B**2*X*Z**2    
      T0=T0+B**2*Y**3+3.0*B**2*Y**2*Z         
      RES=T0+3.0*B**2*Y*Z**2+B**2*Z**3        
      RETURN                                  
      END                                     
;END;                                         
\end{framedverbatim} 
Another pass of the template processor produced the final file of FORTRAN
code:
\begin{verbatim}
2: GENTRANIN 
2:     "#junk.tem" 
2: OUT "junk.f"$ 
\end{verbatim}
Contents of file {\tt junk.f}:
\begin{framedverbatim}
      SUBROUTINE CALC(X,Y,Z,A,B,RES)          
      REAL X,Y,Z,A,B,RES,T0                 
      X=3.75                                  
      Y=-10.2                                 
      Z=16.473                                
      T0=A**2*X**3+3.0*A**2*X**2*Y            
      T0=T0+3.0*A**2*X**2*Z+3.0*A**2*X*Y**2   
      T0=T0+6.0*A**2*X*Y*Z+3.0*A**2*X*Z**2    
      T0=T0+A**2*Y**3+3.0*A**2*Y**2*Z         
      T0=T0+3.0*A**2*Y*Z**2+A**2*Z**3         
      T0=T0+2.0*A*B*X**3+6.0*A*B*X**2*Y       
      T0=T0+6.0*A*B*X**2*Z+6.0*A*B*X*Y**2     
      T0=T0+12.0*A*B*X*Y*Z+6.0*A*B*X*Z**2     
      T0=T0+2.0*A*B*Y**3+6.0*A*B*Y**2*Z       
      T0=T0+6.0*A*B*Y*Z**2+2.0*A*B*Z**3       
      T0=T0+B**2*X**3+3.0*B**2*X**2*Y         
      T0=T0+3.0*B**2*X**2*Z+3.0*B**2*X*Y**2   
      T0=T0+6.0*B**2*X*Y*Z+3.0*B**2*X*Z**2    
      T0=T0+B**2*Y**3+3.0*B**2*Y**2*Z         
      RES=T0+3.0*B**2*Y*Z**2+B**2*Z**3        
      RETURN                                  
      END                                     
\end{framedverbatim} 

\subsection{Referencing Subprogram and Parameter Names}
\index{"!\$n parameters} \index{"!\$0 subprogram name}
In some code generation applications in which template processing is used,
it is useful to be able to reference the names of the parameters
given in the subprogram header.  For this reason, the special
symbols {\bf !\$1}, {\bf !\$2},~\dots, {\bf !\${\it n}}, where {\it n}
is the number
of parameters, can be used in computations and code generation commands in
active parts of template files.  Each of these symbols will be replaced by
the corresponding parameter name when code is generated.  In addition, the
special symbol {\bf !\$0} will be replaced by the subprogram name.  This is
useful when FORTRAN or RATFOR functions are being generated.  Finally, the
\index{"!\$"!\# in GENTRAN}
special global variable {\bf !\$!\#} is bound to the number of parameters in
the subprogram header.

\section{Output Redirection}\label{GENTRAN:output}
\index{GENTRAN ! file output}
Many examples given thus far in this manual have sent all generated code to
the terminal screen.  In actual code generation applications, however,
code must be sent to a file which will be compiled at a later
time.  This section explains methods of redirecting code to a
file as it is generated.  Any number of output files can be open
simultaneously, and generated code can be sent to any combination
of these open files.

\subsection{File Selection Commands}
\label{file:selection}
\index{OUT command} \index{SHUT command}
REDUCE provides the user with two file handling commands for output
redirection: {\bf OUT} and {\bf SHUT}.  The {\bf OUT} command takes a
single file name as argument and directs all REDUCE output to that
file from then on, until another {\bf OUT} changes the output file, or
{\bf SHUT} closes it.  Output can go to only one file at a time,
although many can be open.  If the file has previously been used for
output during the current job and not {\bf SHUT}, then the new output
is appended onto the end of the file.  Any existing file is erased
before its first use for output in a job.  To output on the terminal
without closing the output file, the reserved file name {\bf T} (for
terminal) may be used.

The REDUCE {\bf SHUT} command takes a list of names of files which
have been previously opened via an {\bf OUT} command and closes them.
Most systems require this action by the user before he ends the REDUCE
job; otherwise the output may be lost.  If a file is {\bf SHUT} and a
further {\bf OUT} command is issued for the same file, the file is
erased before the new output is written.  If it is the current output
file that is {\bf SHUT}, output will switch to the terminal.

These commands are suitable for most applications in which REDUCE
output must be saved.  However, they have two deficiencies when
considered for use in code generation applications.  First, they are
inconvenient.  {\bf OUT} tells REDUCE to direct {\it all\/} output to
a specified file.  Thus in addition to output written as side effects
of functions, returned values are also written to the file (unless the
user is careful to terminate all statements and commands with a {\bf
\$}, in which case only output produced by side effects is written).
If code generation is to be accomplished interactively; i.e., if
algebraic computations and code generation commands are interleaved,
then {\bf OUT} {\it filename\/}{\bf \$} must be issued before every
group of code generation requests, and {\bf OUT T\$} must be issued
after every group.  Secondly, the {\bf OUT} command does not allow
output to be sent to two or more files without reissuing the {\bf OUT}
with another file name.  In an effort to remove these deficiencies and
make the code generation commands flexible and easy to use, separate
file handling commands are provided by GENTRAN which redirect
generated code {\it only}.

\index{GENTRANOUT command} \index{GENTRANSHUT command}
The {\bf GENTRANOUT} and {\bf GENTRANSHUT} commands are identical to
the REDUCE {\bf OUT} and {\bf SHUT} commands with the following
exceptions:

\begin{itemize}
\item {\bf GENTRANOUT} and {\bf GENTRANSHUT} redirect {\it only\/} code which
is printed as a side effect of GENTRAN commands.
\item {\bf GENTRANOUT} allows more than one file name to be given
to indicate that generated code is to be sent to two or more
files.  (It is particularly convenient to be able to
have generated code sent to
the terminal screen and one or more file simultaneously.)
\item {\bf GENTRANOUT} does not automatically erase existing files; it prints
a warning message on the terminal and asks the user whether the existing
file should be erased or the whole command be aborted.
\end{itemize}
The next two subsections describe these commands in detail.

\index{GENTRANOUT command}
\subsubsection{GENTRANOUT}
\begin{describe}{Syntax:}
{\bf GENTRANOUT} {\it f1,f2,\dots\ ,fn;}
\end{describe}
\begin{describe}{Arguments:}
{\it f1,f2,\dots\ ,fn\/} is a list of one or more {\it f\/}'s, where each 
{\it f\/} is one of:
\begin{center}
\begin{tabular}{lll}
{\it an atom} & = & an output file\\
{\bf T} & = & the terminal\\
{\bf NIL} & = & the current output file(s)\\
{\bf ALL!*} & = & all files currently open for output \\
& & by GENTRAN\\
\end{tabular}
\end{center}
\end{describe}
\begin{describe}{Side Effects:}
GENTRAN maintains a list of files currently open for output by
GENTRAN {\it only}.  {\bf GENTRANOUT} inserts each file name represented by
{\it f1,f2,\dots\ ,fn\/} into that list and opens each one for output.  It
also resets the current output file(s) to be all files in {\it f1,f2,\dots\
 ,fn}.
\end{describe}
\begin{describe}{Returned Value:}
{\bf GENTRANOUT} returns the list of files represented by
{\it f1,f2,\dots\ ,fn\/};
i.e., the current output file(s) after the command has been executed.
\end{describe}
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** OUTPUT FILE ALREADY EXISTS
    OVERWRITE FILE? (Y/N)

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe}
\begin{describe}{\example}
Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(5,2)(0,0)
\put(0,0) {\framebox(1.5,.75){T}}
\put(.75,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(.7,1.5) {\vector(0,-1){.75}}
\end{picture}}

\begin{verbatim}
1: GENTRANOUT "f1"; 

"f1"
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(5,2)(0,0)
\put(0,0) {\framebox(1.5,.75){T}}
\put(1.5,0) {\framebox(1.5,.75){"f1"}}
\put(2.25,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(2.2,1.5) {\vector(0,-1){.75}}
\end{picture}}

\begin{verbatim}
2: GENTRANOUT "f2"; 

"f2"
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(5,2)(0,0)
\put(0,0) {\framebox(1.5,.75){T}}
\put(1.5,0) {\framebox(1.5,.75){"f1"}}
\put(3,0) {\framebox(1.5,.75){"f2"}}
\put(3.75,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(3.7,1.5) {\vector(0,-1){.75}}
\end{picture}}


\begin{verbatim}
3: GENTRANOUT T,"f3"; 

{T,"f3"}
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1.5,.75){T}}
\put(1.5,0) {\framebox(1.5,.75){"f1"}}
\put(3,0) {\framebox(1.5,.75){"f2"}}
\put(4.5,0) {\framebox(1.5,.75){"f3"}}
\put(5.5,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(5.25,1.5) {\vector(0,-1){.75}}
\put(5.45,1.5) {\line(-1,0){4.70}}
\put(.75,1.5) {\vector(0,-1){.75}}
\end{picture}}


\begin{verbatim}
4: GENTRANOUT "f1"; 

"f1"
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1.5,.75){T}}
\put(1.5,0) {\framebox(1.5,.75){"f1"}}
\put(3,0) {\framebox(1.5,.75){"f2"}}
\put(4.5,0) {\framebox(1.5,.75){"f3"}}
\put(2.25,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(2.2,1.5) {\vector(0,-1){.75}}
\end{picture}}

\begin{verbatim}
5: GENTRANOUT NIL,"f4"; 

{"f1","f4"}
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1.5,.75){T}}
\put(1.5,0) {\framebox(1.5,.75){"f1"}}
\put(3,0) {\framebox(1.5,.75){"f2"}}
\put(4.5,0) {\framebox(1.5,.75){"f3"}}
\put(6,0) {\framebox(1.5,.75){"f4"}}
\put(7.5,1.5) {\makebox(0,0)[bl]{\tt current-output}}
\put(6.75,1.5) {\vector(0,-1){.75}}
\put(2.25,1.5) {\vector(0,-1){.75}}
\put(7.45,1.5) {\line(-1,0){5.2}}
\end{picture}}


\ttindex{ALL"!*}
\begin{verbatim}
6: GENTRANOUT ALL!*; 

{"f1","f2","f3","f4"}
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1.5,.75){T}}
\put(1.5,0) {\framebox(1.5,.75){"f1"}}
\put(3,0) {\framebox(1.5,.75){"f2"}}
\put(4.5,0) {\framebox(1.5,.75){"f3"}}
\put(6,0) {\framebox(1.5,.75){"f4"}}
\put(7.5,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(6.75,1.5) {\vector(0,-1){.75}}
\put(5.25,1.5) {\vector(0,-1){.75}}
\put(3.75,1.5) {\vector(0,-1){.75}}
\put(2.25,1.5) {\vector(0,-1){.75}}
\put(7.45,1.5) {\line(-1,0){5.2}}
\end{picture}}

\end{describe}

\subsubsection{GENTRANSHUT}
\index{GENTRANSHUT command}
\begin{describe}{Syntax:}
{\bf GENTRANSHUT} {\it  f1,f2,\dots\ ,fn;\/}
\end{describe}
\begin{describe}{Arguments:}
{\it f1,f2,\dots\ ,fn\/} is a list of one or more {\it f\/}'s, where each 
{\it f\/} is one of:
\begin{center}
\begin{tabular}{lll}
{\it an atom} & = & an output file\\
{\bf NIL} & = & the current output file(s)\\
{\bf ALL!*} & = & all files currently open for output \\
& & by GENTRAN\\
\end{tabular}
\end{center}
\end{describe}
\begin{describe}{Side Effects:}
{\bf GENTRANSHUT} creates a list of file names from {\it f1,f2,\dots\ ,fn},
deletes each from the output file list, and closes the
corresponding files.  If (all of) the current output file(s) are
closed, then the current output file is reset to the terminal.
\end{describe}
\begin{describe}{Returned Value:}
{\bf GENTRANSHUT} returns the current output file(s) after the command has
been executed.
\end{describe}
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** FILE NOT OPEN FOR OUTPUT

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1,.75){T}}
\put(1,0) {\framebox(1,.75){"f1"}}
\put(2,0) {\framebox(1,.75){"f2"}}
\put(3,0) {\framebox(1,.75){"f3"}}
\put(4,0) {\framebox(1,.75){"f4"}}
\put(5,0) {\framebox(1,.75){"f5"}}
\put(6,0) {\framebox(1,.75){"f6"}}
\put(7,0) {\framebox(1,.75){"f7"}}
\put(2,1.5) {\makebox(0,0) [br]{\tt current-output}}
\put(3.5,1.5) {\vector(0,-1){.75}}
\put(4.5,1.5) {\vector(0,-1){.75}}
\put(7.5,1.5) {\vector(0,-1){.75}}
\put(2.05,1.5) {\line(1,0){5.45}}
\end{picture}}

\begin{verbatim}
1: GENTRANSHUT "f1","f2","f7"; 

{"f3","f4"}
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1,.75){T}}
\put(1,0) {\framebox(1,.75){"f3"}}
\put(2,0) {\framebox(1,.75){"f4"}}
\put(3,0) {\framebox(1,.75){"f5"}}
\put(4,0) {\framebox(1,.75){"f6"}}
\put(4.5,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(1.5,1.5) {\vector(0,-1){.75}}
\put(2.5,1.5) {\vector(0,-1){.75}}
\put(4.45,1.5) {\line(-1,0){2.95}}
\end{picture}}

\begin{verbatim}
2: GENTRANSHUT NIL; 

T
\end{verbatim}
Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1,.75){T}}
\put(1,0) {\framebox(1,.75){"f5"}}
\put(2,0) {\framebox(1,.75){"f6"}}
\put(.55,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(.5,1.5) {\vector(0,-1){.75}}
\end{picture}}

\begin{verbatim}
3: GENTRANSHUT ALL!*; 

T
\end{verbatim}

Output file list:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(1,.75){T}}
\put(.55,1.5) {\makebox(0,0) [bl]{\tt current-output}}
\put(.5,1.5) {\vector(0,-1){.75}}
\end{picture}}

\end{describe}

\subsection{The Output File Stack}
Section~\ref{file:selection}
\index{files ! in GENTRAN} 
explained the {\bf GENTRANOUT} and {\bf GENTRANSHUT}
commands which are very similar to the REDUCE {\bf OUT} and {\bf SHUT}
commands but redirect {\it only code generated as side effects of GENTRAN
commands\/} to files.  This section describes another pair of file
handling commands provided by GENTRAN.

In some code generation applications it may be convenient to be
able to send generated code to one (set of) file(s), then
temporarily send code to another (set of) file(s), and later
resume sending generated code to the first (set of) file(s).  In
other words, it is convenient to think of the output files as
being arranged in a stack which can be pushed whenever new
files are to be written to temporarily, and popped whenever
previously written-to files are to be appended onto.  {\bf GENTRANPUSH}
\index{GENTRANPUSH command} \index{GENTRANPOP command}
and {\bf GENTRANPOP} enable the user to manipulate a stack of open
output files in these ways.

{\bf GENTRANPUSH} simply pushes a (set of) file(s) onto
the stack and opens each one that is not already open for
output.  {\bf GENTRANPOP} deletes the top-most occurrence of
the given file(s) from the stack and closes each one that is no
longer in the stack.  The stack is initialized to one element:  the
terminal.  This element is always on the bottom of the stack, and thus,
is the default output file.  The current output file is always the
file(s) on top of the stack.

\subsubsection{GENTRANPUSH}
\index{GENTRANPUSH command}
\begin{describe}{Syntax:}
{\bf GENTRANPUSH} {\it f1,f2,\dots\ ,fn;}
\end{describe}
\begin{describe}{Arguments:}
{\it f1,f2,\dots\ ,fn\/} is a list of one or more {\it f\/}'s, where each
{\it f\/} is one of:
\begin{center}
\begin{tabular}{lll}
{\it an atom} & = & an output file\\
{\bf T} & = & the terminal\\
{\bf NIL} & = & the current output file(s)\\
{\bf ALL!*} & = & all files currently open for output \\
& & by GENTRAN\\
\end{tabular}
\end{center}
\end{describe}
\begin{describe}{Side Effects:}
{\bf GENTRANPUSH} creates a list of file name(s) represented by
{\it f1,f2,\dots\ ,fn\/} and pushes that list onto the output stack.  Each file
in the list that is not already open for output is opened at this time.  The
current output file is reset to this new element on the top of the stack.
\end{describe}
\begin{describe}{Returned Value:}
{\bf GENTRANPUSH} returns the list of files represented by 
{\it f1,f2,\dots\ ,fn\/};
i.e., the current output file(s) after the command has been executed.
\end{describe}
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** OUTPUT FILE ALREADY EXISTS
    OVERWRITE FILE? (Y/N)

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,1)(0,0)
\put(0,0) {\framebox(3,1){}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,.5) {\vector(-1,0){1}}
\put(4.1,.5) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}


\begin{verbatim}
1: GENTRANPUSH "f1"; 

"f1"
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,1.5)(0,0)
\put(0,0) {\framebox(3,1.5){}}
\put(0.25,1) {\makebox(0,0)[cl]{"f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,1) {\vector(-1,0){1}}
\put(4.1,1) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
2: GENTRANPUSH "f2","f3"; 

{"f2","f3"}
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2)(0,0)
\put(0,0) {\framebox(3,2){}}
\put(0.25,1.5) {\makebox(0,0)[cl]{"f2" "f3"}}
\put(0.25,1) {\makebox(0,0)[cl]{"f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,1.5) {\vector(-1,0){1}}
\put(4.1,1.5) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
3: GENTRANPUSH NIL,T; 

{"f2","f3",T}
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2.5)(0,0)
\put(0,0) {\framebox(3,2.5){}}
\put(0.25,2) {\makebox(0,0)[cl]{"f2" "f3" T}}
\put(0.25,1.5) {\makebox(0,0)[cl]{"f2" "f3"}}
\put(0.25,1) {\makebox(0,0)[cl]{"f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,2) {\vector(-1,0){1}}
\put(4.1,2) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
4: GENTRANPUSH "f1"; 

"f1"
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,3)(0,0)
\put(0,0) {\framebox(3,3){}}
\put(0.25,2.5) {\makebox(0,0)[cl]{"f1"}}
\put(0.25,2) {\makebox(0,0)[cl]{"f2" "f3" T}}
\put(0.25,1.5) {\makebox(0,0)[cl]{"f2" "f3"}}
\put(0.25,1) {\makebox(0,0)[cl]{"f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,2.5) {\vector(-1,0){1}}
\put(4.1,2.5) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
5: GENTRANPUSH ALL!*; 

{"f1","f2","f3"}
\end{verbatim}

Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,3.5)(0,0)
\put(0,0) {\framebox(3,3.5){}}
\put(0.25,3) {\makebox(0,0)[cl]{"f1" "f2" "f3"}}
\put(0.25,2.5) {\makebox(0,0)[cl]{"f1"}}
\put(0.25,2) {\makebox(0,0)[cl]{"f2" "f3" T}}
\put(0.25,1.5) {\makebox(0,0)[cl]{"f2" "f3"}}
\put(0.25,1) {\makebox(0,0)[cl]{"f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,3) {\vector(-1,0){1}}
\put(4.1,3) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\end{describe}

\subsubsection{GENTRANPOP}
\index{GENTRANPOP command}
\begin{describe}{Syntax:}
{\bf GENTRANPOP} {\it f1,f2,\dots\ ,fn;}
\end{describe}
\begin{describe}{Arguments:}
{\it f1,f2,\dots\ ,fn\/} is a list of one or more {\it f\/}'s, where each 
{\it f\/} is one of:
\begin{center}
\begin{tabular}{lll}
{\it an atom} & = & an output file\\
{\bf T} & = & the terminal\\
{\bf NIL} & = & the current output file(s)\\
{\bf ALL!*} & = & all files currently open for output \\
& & by GENTRAN\\
\end{tabular}
\end{center}
\end{describe}
\begin{describe}{Side Effects:}
{\bf GENTRANPOP} deletes the top-most occurrence of the single element
containing the file name(s) represented by {\it f1,f2,\dots\ ,fn\/}
from the output stack.  Files whose names have been completely removed from
the output stack are closed.  The current output file is reset to the
(new) element on the top of the output stack.
\end{describe}
\begin{describe}{Returned Value:}
{\bf GENTRANPOP} returns the current output file(s) after this command
has been executed.
\end{describe}
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** FILE NOT OPEN FOR OUTPUT

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,4)(0,0)
\put(0,0) {\framebox(3,4){}}
\put(0.25,3.5) {\makebox(0,0)[cl]{"f4"}}
\put(0.25,3) {\makebox(0,0)[cl]{"f4" "f2" T}}
\put(0.25,2.5) {\makebox(0,0)[cl]{"f4"}}
\put(0.25,2) {\makebox(0,0)[cl]{T}}
\put(0.25,1.5) {\makebox(0,0)[cl]{"f3"}}
\put(0.25,1) {\makebox(0,0)[cl]{"f2" "f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,3.5) {\vector(-1,0){1}}
\put(4.1,3.5) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
1: GENTRANPOP NIL; 

{"f4","f2",T}
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,3.5)(0,0)
\put(0,0) {\framebox(3,3.5){}}
\put(0.25,3) {\makebox(0,0)[cl]{"f4" "f2" T}}
\put(0.25,2.5) {\makebox(0,0)[cl]{"f4"}}
\put(0.25,2) {\makebox(0,0)[cl]{T}}
\put(0.25,1.5) {\makebox(0,0)[cl]{"f3"}}
\put(0.25,1) {\makebox(0,0)[cl]{"f2" "f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,3) {\vector(-1,0){1}}
\put(4.1,3) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
2: GENTRANPOP NIL; 

"f4"
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,3)(0,0)
\put(0,0) {\framebox(3,3){}}
\put(0.25,2.5) {\makebox(0,0)[cl]{"f4"}}
\put(0.25,2) {\makebox(0,0)[cl]{T}}
\put(0.25,1.5) {\makebox(0,0)[cl]{"f3"}}
\put(0.25,1) {\makebox(0,0)[cl]{"f2" "f1"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,2.5) {\vector(-1,0){1}}
\put(4.1,2.5) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
3: GENTRANPOP "f2","f1"; 

"f4"
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,2.5)(0,0)
\put(0,0) {\framebox(3,2.5){}}
\put(0.25,2) {\makebox(0,0)[cl]{"f4"}}
\put(0.25,1.5) {\makebox(0,0)[cl]{T}}
\put(0.25,1) {\makebox(0,0)[cl]{"f3"}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,2) {\vector(-1,0){1}}
\put(4.1,2) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\begin{verbatim}
4: GENTRANPOP ALL!*; 

T
\end{verbatim}
Output stack:

{\setlength{\unitlength}{1cm}
\begin{picture}(10,1)(0,0)
\put(0,0) {\framebox(3,1){}}
\put(0.25,.5) {\makebox(0,0)[cl]{T}}
\put(4,.5) {\vector(-1,0){1}}
\put(4.1,.5) {\makebox(0,0)[cl]{\tt current-output}}
\end{picture}}

\end{describe}

\subsection{Temporary Output Redirection}
Sections~\ref{translation} and ~\ref{templates}
explain how to use the code generation and
template processing commands.  The syntax for these two commands
is:
\index{output redirection (temporary)}
\index{GENTRAN command} \index{GENTRANIN command}

\begin{tabular}{lll}
&\multicolumn{2}{l}{{\bf GENTRAN} {\it stmt\/} [{\bf OUT} {\it f1,f2,\dots\
 ,fn\/}]{\it ;}}\\
&&and\\
&\multicolumn{2}{l}{{\bf GENTRANIN} {\it f1,f2,\dots\ ,fm\/} [{\bf OUT}
 {\it  f1,f2,\dots\ ,fn\/}]{\it ;}}\\
\end{tabular}

The optional parts of these two commands can be used for {\it temporary}
output redirection; they can be used when the current output
file is to be temporarily reset, for this command only.

Thus the following two sequences of commands are equivalent:
\begin{verbatim}
10: GENTRANPUSH "f1",T$ 

11: GENTRAN ... $

12: GENTRANPOP NIL$
\end{verbatim}

and

\begin{verbatim}
10: GENTRAN 
10:    ...
10: OUT "f1",T$
\end{verbatim}

\section{Modification of the Code Generation Process}\label{GENTRAN:mod}

GENTRAN is designed to be flexible enough to be used in a variety of
code generation applications.  For this reason, several mode
switches and variables are provided to enable the user to tailor the
code generation process to meet his or her particular needs.

\subsection{Mode Switches}
\index{GENTRAN package ! switches}
The following GENTRAN mode switches can be turned on and off with the
REDUCE {\bf ON} and {\bf OFF} commands.

\begin{describe}{DOUBLE}
\index{DOUBLE switch} \index{precision}
\begin{itemize}
\item When turned on, causes (where appropriate):
\begin{itemize}
\item floating point numbers to be printed in double precision format;
\item intrinsic functions to be replaced by their double precision
counterparts;
\item generated type declarations to be of double precision form.
\end{itemize}
See also section~\ref{precision} on page~\pageref{precision}.
\item default setting: off
\end{itemize}
\end{describe}

\begin{describe}{GENDECS}
\index{GENDECS switch}
\begin{itemize}
\item when turned on, allows type declarations to be generated automatically;
otherwise, type information is stored in but not automatically retrieved
from the symbol table.  See also sections~\ref{explicit:type} on
page~\pageref{explicit:type}, \ref{more:type} on page~\pageref{more:type},
and \ref{template:type} on page~\pageref{template:type}.
\item default setting:  on
\end{itemize}
\end{describe}

\begin{describe}{GENTRANOPT}
\index{GENTRANOPT switch}
\begin{itemize}
\item when turned on, replaces each block of straightline code by
an optimized sequence of assignments.
The Code Optimizer takes a sequence of assignments and replaces common
subexpressions with temporary variables.  It returns the resulting assignment
statements with common-subexpression-to-temporary-variable assignment
statements preceding them
\item default setting:  off
\end{itemize} 
\end{describe} 

\begin{describe}{GENTRANSEG} 
\index{GENTRANSEG switch}
\begin{itemize}
\item when turned on, checks the print length of expressions and breaks
those expressions that are longer than {\bf MAXEXPPRINTLEN!*} down
\ttindex{MAXEXPPRINTLEN"!*}
into subexpressions which are assigned to temporary variables.
See also section~\ref{segmentation} on page~\pageref{segmentation}.
\item default setting:  on
\end{itemize}
\end{describe}

\begin{describe}{GETDECS}
\index{GETDECS switch}
\begin{itemize}
\item when on, causes:
\begin{itemize}
\item the indices of loops to be declared integer;
\item objects without an explicit type declaration to be declared of the type
given by the variable {\bf DEFTYPE!*}. \ttindex{DEFTYPE"!*}
\end{itemize}
See also section~\ref{implicit:type} on page~\pageref{implicit:type}.
\item default setting:  off
\end{itemize}
\end{describe}

\begin{describe}{KEEPDECS}
\index{KEEPDECS switch}
\begin{itemize}
\item when on, prevents declarations being removed from the symbol table when
type declarations are generated.
\item default: off
\end{itemize}
\end{describe}

\begin{describe}{MAKECALLS}
\index{MAKECALLS switch}
\begin{itemize}
\item when turned on, causes GENTRAN to translate functional expressions as
subprogram calls.
\item default setting: on
\end{itemize}
\end{describe}

\begin{describe}{PERIOD}
\index{PERIOD switch}
\begin{itemize}
\item when turned on, causes all integers to be printed out as floating point
numbers except:
\begin{itemize}
\item exponents;
\item variable subscripts;
\item index values in DO-type loops;
\item those which have been declared to be integers.
\end{itemize}
\item default setting:  on
\end{itemize}
\end{describe}


\subsection{Variables}
\index{GENTRAN package ! variables}
Several global variables are provided in GENTRAN to enable the
user to
\begin{itemize}
\item select the target language
\item control expression segmentation
\item change automatically generated variable names and statement numbers
\item modify the code formatter
\end{itemize}

The following four subsections describe these variables\footnote{
Note that when an atomic value (other than an integer) is assigned to a
variable, that value must be quoted.  For example,
{\bf GENTRANLANG!* := 'FORTRAN\$}
assigns the atom {\bf FORTRAN} to the variable {\bf GENTRANLANG!*}.}.

\subsubsection{Target Language Selection}
\begin{describe}{GENTRANLANG!*}
\ttindex{GENTRANLANG"!*}
\begin{itemize}
\item target language (FORTRAN, RATFOR, PASCAL or C)
See also section~\ref{gentranlang} on page~\pageref{gentranlang}.
\item value type:  atom
\item default value:  FORTRAN
\end{itemize}
\end{describe}

\subsubsection{Expression Segmentation Control}
\begin{describe}{MAXEXPPRINTLEN!*}
\ttindex{MAXEXPPRINTLEN"!*}
\begin{itemize}
\item value used to determine whether or not an expression should be
segmented; maximum number of characters permitted in an expression
in the target language (excluding spaces printed for formatting).
See also section~\ref{segmentation} on page~\pageref{segmentation}.
\item value type:  integer
\item default value:  800
\end{itemize}
\end{describe} 

\subsubsection{Variable Names \& Statement Numbers}
\begin{describe}{TEMPVARNAME!*}
\ttindex{TEMPVARNAME"!*}
\begin{itemize}
\item name used as prefix in generating temporary variable names.
See also section~\ref{tempvars} on page~\pageref{tempvars}.
\item value type:  atom
\item default value:  T
\end{itemize}
\end{describe}

\begin{describe}{TEMPVARNUM!*}
\ttindex{TEMPVARNUM"!*}
\begin{itemize}
\item number appended to {\bf TEMPVARNAME!*} to create a temporary variable
name. If the temporary variable name resulting from appending
{\bf TEMPVARNUM!*} onto {\bf TEMPVARNAME!*} has already been generated
and still holds a useful value, then {\bf TEMPVARNUM!*} is incremented
and temporary variable names are compressed until one is found which
was not previously generated or does not still hold a significant value.
See also section~\ref{tempvars} on page~\pageref{tempvars}.
\item value type:  integer
\item default value:  0
\end{itemize}
\end{describe}

\begin{describe}{TEMPVARTYPE!*}
\ttindex{TEMPVARTYPE"!*}
\begin{itemize}
\item target language variable type (e.g., INTEGER, REAL!*8, FLOAT, etc) used
as a default for automatically generated variables whose type cannot be
determined otherwise.  If {\bf TEMPVARTYPE!*} is NIL, then generated
temporary variables whose type cannot be determined are not automatically
declared.  See also section~\ref{tempvars} on page~\pageref{tempvars}.
\item value type:  atom
\item default value:  NIL
\end{itemize}
\end{describe}

\begin{describe}{GENSTMTNUM!*}
\ttindex{GENSTMTNUM"!*}
\begin{itemize}
\item number used when a statement number must be generated
\item value type:  integer
\item default value:  25000
\end{itemize}
\end{describe}

\begin{describe}{GENSTMTINCR!*}
\ttindex{GENSTMTINCR"!*}
\begin{itemize}
\item number by which {\bf GENSTMTNUM!*} is increased each time a new
statement number is generated.
\item value type:  integer
\item default value:  1
\end{itemize}
\end{describe}

\begin{describe}{DEFTYPE!*}
\ttindex{DEFTYPE"!*}
\begin{itemize}
\item default type for objects when the switch {\bf GETDECS} is on.  See also
section~\ref{implicit:type} on page~\pageref{implicit:type}.
\item value type: atom
\item default value: real
\end{itemize}
\end{describe}

\subsubsection{Code Formatting}
\begin{describe}{FORTCURRIND!*}
\ttindex{FORTCURRIND"!*}
\begin{itemize}
\item number of blank spaces printed at the beginning of each line of
generated FORTRAN code beyond column 6
\item value type:  integer
\item default value:  0
\end{itemize}
\end{describe}

\begin{describe}{RATCURRIND!*}
\ttindex{RATCURRIND"!*}
\begin{itemize}
\item number of blank spaces printed at the beginning of each line of
generated RATFOR code.
\item value type:  integer
\item default value:  0
\end{itemize}
\end{describe}

\begin{describe}{CCURRIND!*}
\ttindex{CCURRIND"!*}
\begin{itemize}
\item number of blank spaces printed at the beginning of each line of
generated C code.
\item value type:  integer
\item default value:  0
\end{itemize}
\end{describe}

\begin{describe}{PASCCURRIND!*}
\ttindex{PASCCURRIND"!*}
\begin{itemize}
\item number of blank spaces printed at the beginning of each line of
generated PASCAL code.
\item value type:  integer
\item default value:  0
\end{itemize}
\end{describe}

\begin{describe}{TABLEN!*}
\ttindex{TABLEN"!*}
\begin{itemize}
\item number of blank spaces printed for each new level of indentation.
\item value type:  integer
\item default value:  4
\end{itemize}
\end{describe}

\begin{describe}{FORTLINELEN!*}
\ttindex{FORTLINELEN"!*}
\begin{itemize}
\item maximum number of characters printed on each line of generated FORTRAN
code.
\item value type:  integer
\item default value:  72
\end{itemize}
\end{describe}

\begin{describe}{RATLINELEN!*}
\ttindex{RATLINELEN"!*}
\begin{itemize}
\item maximum number of characters printed on each line of generated RATFOR
code.
\item value type:  integer
\item default value:  80
\end{itemize}
\end{describe}

\begin{describe}{CLINELEN!*}
\ttindex{CLINELEN"!*}
\begin{itemize}
\item maximum number of characters printed on each line of generated C code.
\item value type:  integer
\item default value:  80
\end{itemize} 
\end{describe}

\begin{describe}{PASCLINELEN!*}
\ttindex{PASCLINELEN"!*}
\begin{itemize}
\item maximum number of characters printed on each line of generated PASCAL
code.
\item value type:  integer
\item default value:  70
\end{itemize}
\end{describe}

\begin{describe}{MINFORTLINELEN!*}
\ttindex{MINFORTLINELEN"!*}
\begin{itemize}
\item minimum number of characters printed on each line of generated FORTRAN
code after indentation.
\item value type:  integer
\item default value:  40
\end{itemize} 
\end{describe}

\begin{describe}{MINRATLINELEN!*}
\ttindex{MINRATLINELEN"!*}
\begin{itemize}
\item minimum number of characters printed on each line of generated RATFOR
code after indentation.
\item value type:  integer
\item default value:  40
\end{itemize} 
\end{describe}
 
\begin{describe}{MINCLINELEN!*}
\ttindex{MINCLINELEN"!*}
\begin{itemize}
\item minimum number of characters printed on each line of generated C
code after indentation.
\item value type:  integer
\item default value:  40
\end{itemize} 
\end{describe}

\begin{describe}{MINPASCLINELEN!*}
\ttindex{MINPASCLINELEN"!*}
\begin{itemize}
\item minimum number of characters printed on each line of generated PASCAL
code after indentation.
\item value type:  integer
\item default value:  40
\end{itemize} 
\end{describe} 

\section{Examples}\label{GENTRAN:examples}
\index{GENTRAN package ! example}

Short examples have been given throughout this manual to illustrate
usage of the GENTRAN commands.  This section gives complete code
generation examples.

\subsection{Interactive Code Generation} \index{GENTRAN package ! example}
\index{interactive code generation}
Suppose we wish to generate a FORTRAN subprogram which can be used for
\index{Graeffe's Root-Squaring Method}
computing the roots of a polynomial by Graeffe's Root-Squaring Method\footnote{
This is for instance convenient for ill-conditioned polynomials.  More
details are given in {\it Introduction to Numerical Analysis\/} by
C. E. Froberg, Addison-Wesley Publishing Company, 1966.}. This
method states that the roots $x_i$ of a polynomial
$$P_n(x) = \sum_{i=0}^{n}{a_i x^{n-i}} $$
can be found by constructing the polynomial
$$P^{*}_n\left({x^2}\right) = \left( a_0x^n + a_2x^{n-2} + \dots\right)^2 -
\left( a_1x^{n-1} + a_3x^{n-3} + \dots\right)^2$$
with roots $x_i^2$
When read into REDUCE, the following file of REDUCE statements
will place the coefficients of $P^{*}_n$
into the list B for some user-entered value of n greater than zero.

Contents of file {\tt graeffe.red}:\footnote{
In accordance with section~\ref{explicit:type},
the subscripts of A are I+1 instead of I.}
\begin{framedverbatim}
OPERATOR A$                                               
Q := FOR I := 0 STEP 2 UNTIL n   SUM (A(I+1)*X^(n-I))$
R := FOR I := 1 STEP 2 UNTIL n-1 SUM (A(I+1)*X^(n-I))$    
P := Q^2 - R^2$                                           
LET X^2 = Y$                                              
B := COEFF(P,Y)$                                             
END$                                                      
\end{framedverbatim}

Now a numerical subprogram can be generated with assignment
statements for the coefficients of $P^{*}_n$ (now stored in list B in
REDUCE).  Since these coefficients are given in terms of the coefficients
of $P_n$ (i.e., operator A in REDUCE), the subprogram will need two
parameters:  A and B, each of which must be arrays of size n+1.

The following REDUCE session will create subroutine GRAEFF for a polynomial
of degree n=10 and write it to file {\tt graeffe.f}:
{\small
\begin{verbatim}
1: n := 10$ 

2: IN "graeffe.red"$

3: GENTRANLANG!* := 'FORTRAN$ 

4: ON DOUBLE$

5: GENTRAN 
5: ( 
5:      PROCEDURE GRAEFF(A,B); 
5:      BEGIN 
5:      DECLARE 
5:      << 
5:          GRAEFF : SUBROUTINE; 
5:          A(11),B(11) : REAL
5:      >>; 
5:      LITERAL 
5:       "C",CR!*, 
5:       "C",TAB!*,"GRAEFFE ROOT-SQUARING METHOD TO FIND",CR!*,
5:       "C",TAB!*,"ROOTS OF A POLYNOMIAL",CR!*, 
5:       "C",CR!*; 
5:      B(1) :=: PART (B,1);
5:      B(2) :=: PART (B,2);
5:      B(3) :=: PART (B,3);
5:      B(4) :=: PART (B,4);
5:      B(5) :=: PART (B,5);
5:      B(6) :=: PART (B,6);
5:      B(7) :=: PART (B,7);
5:      B(8) :=: PART (B,8);
5:      B(9) :=: PART (B,9);
5:      B(10) :=: PART (B,10);
5:      B(11) :=: PART (B,11)
5:      END 
5: ) 
5: OUT "graeffe.f"$ 
\end{verbatim}
}

Contents of file {\tt graeffe.f}:
\begin{framedverbatim}
      SUBROUTINE GRAEFF(A,B)
      DOUBLE PRECISION A(11),B(11)
C
C     GRAEFFE ROOT-SQUARING METHOD TO FIND
C     ROOTS OF A POLYNOMIAL
C
      B(1)=A(11)**2
      B(2)=2.0D0*A(11)*A(9)-A(10)**2
      B(3)=2.0D0*A(11)*A(7)-(2.0D0*A(10)*A(8))+A(9)**2
      B(4)=2.0D0*A(11)*A(5)-(2.0D0*A(10)*A(6))+2.0D0*A(9)*A(7
     . )-A(8)**2
      B(5)=2.0D0*A(11)*A(3)-(2.0D0*A(10)*A(4))+2.0D0*A(9)*A(5
     . )-(2.0D0*A(8)*A(6))+A(7)**2
      B(6)=2.0D0*A(11)*A(1)-(2.0D0*A(10)*A(2))+2.0D0*A(9)*A(3
     . )-(2.0D0*A(8)*A(4))+2.0D0*A(7)*A(5)-A(6)**2
      B(7)=2.0D0*A(9)*A(1)-(2.0D0*A(8)*A(2))+2.0D0*A(7)*A(3)-
     . (2.0D0*A(6)*A(4))+A(5)**2
      B(8)=2.0D0*A(7)*A(1)-(2.0D0*A(6)*A(2))+2.0D0*A(5)*A(3)-
     . A(4)**2
      B(9)=2.0D0*A(5)*A(1)-(2.0D0*A(4)*A(2))+A(3)**2
      B(10)=2.0D0*A(3)*A(1)-A(2)**2
      B(11)=A(1)**2
      RETURN
      END
\end{framedverbatim}

\subsection{Code Generation, Segmentation \& Temporary Variables}
\index{GENTRAN package ! example}
The following 3 x 3 inertia matrix M was derived in the course of
some research \footnote{For details see:
Bos, A. M. and M. J. L. Tiernego.  ``Formula Manipulation in the
Bond Graph Modelling and Simulation of Large Mechanical Systems'',
{\it Journal of the Franklin Institute} , Pergamon Press Ltd.,
Vol. 319, No. 1/2, pp. 51-65, January/February 1985.}:
\begin{eqnarray*}
M(1,1) & = & 18*\cos (q_3)*\cos (q_2)*m_{30}*p^2 - \sin ^2(q_3) *j_{30}y +
 \sin ^2(q_3) \\
  & & *j_{30}z - 9*\sin ^2(q_3) *m_{30}*p^2  + j_{10}y + j_{30}y +
 m_{10}*p^2  + \\
 & & 18*m_{30}*p^2\\
M(1,2) & = & 9*\cos (q_3)*\cos (q_2)*m_{30}*p^2  - \sin ^2(q_3) *j_{30}y
 +\sin ^2(q_3) \\
  & & *j_{30}z - 9*\sin ^2(q_3) *m_{30}*p^2 + j_{30}y + 9* m_{30}*p^2\\
M(2,1) & = & M(1,2)\\
M(1,3) & = & - 9*\sin (q_3)*\sin (q_2)*m_{30}*p^2\\
M(3,1) & = & M(1,3)\\
M(2,2) & = & - \sin ^2(q_3) *j_{30}y + \sin ^2(q_3) *j_{30}z -
 9*\sin ^2(q_3)*m_{30}*p^2 \\
& & + j_{30}y + 9*m_{30}*p^2\\
M(2,3) & = & 0\\
M(3,2) & = & M(2,3)\\
M(3,3) & = & 9*m_{30}*p^2 + j_{30}x\\
\end{eqnarray*}
We know M is symmetric.  We wish to generate numerical code
to compute values for M and its inverse matrix.

\subsubsection{Code Generation}
\label{code:example}
Generating code for matrix M and its inverse matrix is
straightforward.  We can simply generate an assignment statement
for each element of M, compute the inverse matrix MIV, and generate
an assignment statement for each element of MIV.  Since we
know M is symmetric, we know that MIV will also be symmetric.  To
avoid duplicate computations, we will not generate assignments
for elements below the main diagonals of these matrices.  Instead,
we will copy elements across the main diagonal by generating
nested loops.  The following REDUCE session will write to the file {\tt m1.f}:

\begin{verbatim}
1: IN "m.red"$ % Initialize M

2: GENTRANOUT "m1.f"$ 

3: GENTRANLANG!* := 'FORTRAN$

4: ON DOUBLE$

5: FOR J := 1 : 3 DO 
5:      FOR K := J : 3 DO 
5:          GENTRAN M(J,K) ::=: M(J,K)$

6: MIV := M^(-1)$ 

7: FOR J := 1 : 3 DO 
7:      FOR K := J : 3 DO 
7:          GENTRAN MIV(J,K) ::=: MIV(J,K)$

8: GENTRAN 
8:      FOR J := 1 : 3 DO 
8:          FOR K := J+1 : 3 DO 
8:          << 
8:              M(K,J) := M(J,K); 
8:              MIV(K,J) := MIV(J,K) 
8:          >>$ 

9: GENTRANSHUT "m1.f"$
\end{verbatim}
The contents of {\tt m1.f} are reproduced in~\ref{appc} on page~\pageref{appc}.

This code was generated with the segmentation facility turned off.  However,
most FORTRAN compilers cannot handle statements more than 20 lines
long.  The next section shows how to generate segmented assignments.

\subsubsection{Segmentation}
\label{seg:example}
\index{segmented assignments}
Large arithmetic expressions can be broken into pieces of manageable
size with the expression segmentation facility.  The following REDUCE
session will write segmented assignment statements to the
file {\tt m2.f}.  Large arithmetic expressions will be broken into
subexpressions of approximately 300 characters in length.

\begin{verbatim}
1: IN "m.red"$ % Initialize M

2: GENTRANOUT "m2.f"$ 

3: ON DOUBLE$

4: ON GENTRANSEG$ 

5: MAXEXPPRINTLEN!* := 300$ 

6: FOR J := 1 : 3 DO 
6:      FOR K := J : 3 DO 
6:          GENTRAN M(J,K) ::=: M(J,K)$ 

7: MIV := M^(-1)$ 

8: FOR J := 1 : 3 DO 
8:      FOR K := J : 3 DO 
8:          GENTRAN MIV(J,K) ::=: MIV(J,K)$ 

9: GENTRAN 
9:      FOR J := 1 : 3 DO 
9:          FOR K := J+1 : 3 DO 
9:          << 
9:              M(K,J) := M(J,K); 
9:              MIV(K,J) := MIV(J,K) 
9:          >>$ 

10: GENTRANSHUT "m2.f"$ 
\end{verbatim}

The contents of file {\tt m2.f} are reproduced in~\ref{appc} on
page~\pageref{appc}.

\subsubsection{Generation of Temporary Variables to Suppress Simplification}
\label{tempvar:example}
We can dramatically improve the efficiency of the code generated
in sections~\ref{code:example} on page~\pageref{code:example} and
\ref{seg:example} on page~\pageref{seg:example}
by replacing expressions by temporary variables before computing the
inverse matrix.  This effectively suppresses simplification; these
expressions will not be substituted into later computations.  We
will replace each non-zero element of the REDUCE matrix M by a
generated variable name, and generate a numerical assignment statement
to reflect that substitution in the numerical program being generated.

The following REDUCE session will write to the file {\tt m3.f}:
\begin{verbatim}
1: in "m.red"$ % Initialize M

2: GENTRANOUT "m3.f"$ 

3: GENTRANLANG!* := 'FORTRAN$ 

4: ON DOUBLE$

5: FOR J := 1 : 3 DO 
5:      FOR K := J : 3 DO 
5:          GENTRAN M(J,K) ::=: M(J,K)$ 

6: SHARE VAR$ 

7: FOR J := 1 : 3 DO 
7:      FOR K := J : 3 DO 
7:          IF M(J,K) NEQ 0 THEN 
7:          << 
7:              VAR := TEMPVAR(NIL)$ 
7:              MARKVAR VAR$ 
7:              M(J,K) := VAR$ 
7:              M(K,J) := VAR$ 
7:              GENTRAN 
7:                  EVAL(VAR) := M(EVAL(J),EVAL(K)) 
7:          >>$ 

8: COMMENT ** Contents of matrix M: **$ 

9: M; 

[T0  T1  T2]
[          ]
[T1  T3  0 ]
[          ]
[T2  0   T4]


10: MIV := M^(-1)$ 

11: FOR J := 1 : 3 DO 
11:      FOR K := J : 3 DO 
11:          GENTRAN MIV(J,K) ::=: MIV(J,K)$ 

12: GENTRAN 
12:      FOR J := 1 : 3 DO 
12:          FOR K := J+1 : 3 DO 
12:          << 
12:              M(K,J) := M(J,K); 
12:              MIV(K,J) := MIV(J,K) 
12:          >>$ 

13: GENTRANSHUT "m3.f"$ 
\end{verbatim}

Contents of file {\tt m3.f}:

\begin{framedverbatim}
      M(1,1)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*Y*J30)+DSIN(DBLE(Q3))**2*J30Z+18.0D0*DCOS(DBLE
     . (Q3))*DCOS(DBLE(Q2))*P**2*M30+18.0D0*P**2*M30+P**2*M10
     . +J30Y+J10Y
      M(1,2)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*J30Y)+DSIN(DBLE(Q3))**2*J30Z+9.0D0*DCOS(DBLE(
     . Q3))*DCOS(DBLE(Q2))*P**2*M30+9.0D0*P**2*M30+J30Y
      M(1,3)=-(9.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*P**2*M30)
      M(2,2)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*J30Y)+DSIN(DBLE(Q3))**2*J30Z+9.0D0*P**2*M30+
     . J30Y
      M(2,3)=0.0D0
      M(3,3)=9.0D0*P**2*M30+J30X
      T0=M(1,1)
      T1=M(1,2)
      T2=M(1,3)
      T3=M(2,2)
      T4=M(3,3)
      MIV(1,1)=-(T4*T3)/(T4*T1**2-(T4*T3*T0)+T2**2*T3)
      MIV(1,2)=(T4*T1)/(T4*T1**2-(T4*T3*T0)+T2**2*T3)
      MIV(1,3)=(T2*T3)/(T4*T1**2-(T4*T3*T0)+T2**2*T3)
      MIV(2,2)=(-(T4*T0)+T2**2)/(T4*T1**2-(T4*T3*T0)+T2**2*
     . T3)
      MIV(2,3)=-(T1*T2)/(T4*T1**2-(T4*T3*T0)+T2**2*T3)
      MIV(3,3)=(T1**2-(T3*T0))/(T4*T1**2-(T4*T3*T0)+T2**2*T3)
      DO 25009 J=1,3
          DO 25010 K=J+1,3
              M(K,J)=M(J,K)
              MIV(K,J)=MIV(J,K)
25010     CONTINUE
25009 CONTINUE
\end{framedverbatim}

\subsection{Template Processing} \index{template processing}
\index{GENTRAN package ! example} \index{Automatic Circuitry Code Generator}
Circuit simulation plays a vital role in computer hardware
development.  A recent paper\footnote{Loe, K. F., N. Ohsawa, and E.
Goto.  ``Design of an Automatic Circuitry Code Generator (ACCG)'',
{\it RSYMSAC Proceedings}, Wako-shi, Saitama, Japan.  1984.} describes
the design of an Automatic Circuitry Code Generator (ACCG), which
generates circuit simulation programs based on user-supplied circuit
specifications.  The actual code generator consists of a series of
REDUCE {\bf WRITE} statements, each of which writes one line of
FORTRAN code.

This section presents an alternative implementation for the ACCG
which uses GENTRAN's template processor to generate code.  Template
processing is a much more natural method of code generation than the
REDUCE {\bf WRITE} statement method.

First we will put all REDUCE calculations into two files:  {\tt rk.red} and
{\tt ham.red}.

Contents of file {\tt rk.red}:\footnote{
Line 11 of procedure RUNGEKUTTA was changed from
\begin{center}
{\tt K41 := HH*SUB(TT=TT+HH, P=P+K31, Q=Q+K32, P2);}
\end{center}
as given in (Loe84), to
\begin{center}
{\tt K42 := HH*SUB(TT=TT+HH, P=P+K31, Q=Q+K32, P2);}
\end{center}
}
\begin{framedverbatim}
COMMENT  -- RUNGE-KUTTA METHOD --$                        
PROCEDURE RUNGEKUTTA(P1, P2, P, Q, TT);                   
BEGIN                                                     
SCALAR K11,K12,K21,K22,K31,K32,K41,K42;                   
K11 := HH*P1;                                             
K12 := HH*P2;                                             
K21 := HH*SUB(TT=TT+HH/2, P=P+K11/2, Q=Q+K12/2, P1);      
K22 := HH*SUB(TT=TT+HH/2, P=P+K11/2, Q=Q+K12/2, P2);      
K31 := HH*SUB(TT=TT+HH/2, P=P+K21/2, Q=Q+K22/2, P1);      
K32 := HH*SUB(TT=TT+HH/2, P=P+K21/2, Q=Q+K22/2, P2);      
K41 := HH*SUB(TT=TT+HH,   P=P+K31,   Q=Q+K32,   P1);      
K42 := HH*SUB(TT=TT+HH,   P=P+K31,   Q=Q+K32,   P2);
PN := P + (K11 + 2*K21 + 2*K31 + K41)/6;                  
QN := Q + (K12 + 2*K22 + 2*K32 + K42)/6                   
END$                                                      
END$                                                      
\end{framedverbatim}

Contents of file {\tt ham.red}:

\begin{framedverbatim}
COMMENT  -- HAMILTONIAN CALCULATION --$                   
DIFQ := DF(H,P)$                                          
DIFP := -DF(H,Q) - SUB(QDOT=P/M, DF(D,QDOT))$             
RUNGEKUTTA(DIFP, DIFQ, P, Q, TT)$                         
END$                                                      
\end{framedverbatim}

Next we will create a template file with an outline of the target
FORTRAN program and GENTRAN commands.

Contents of file {\tt runge.tem}:

\begin{framedverbatim}
      PROGRAM RUNGE                                       
      IMPLICIT DOUBLE PRECISION (K,M)                                 
C                                                         
C  INPUT                                                  
C                                                         
      WRITE(6,*) 'INITIAL VALUE OF P'                     
      READ(5,*) P                                         
      WRITE(6,*) ' P = ', P                               
      WRITE(6,*) 'INITIAL VALUE OF Q'                     
      READ(5,*) Q                                         
      WRITE(6,*) ' Q = ', Q                               
      WRITE(6,*) 'VALUE OF M'                             
      READ(5,*) M                                         
      WRITE(6,*) ' M = ', M                               
      WRITE(6,*) 'VALUE OF K0'                            
      READ(5,*) K0                                        
      WRITE(6,*) ' K0 = ', K0                             
      WRITE(6,*) 'VALUE OF B'                             
      READ(5,*) B                                         
      WRITE(6,*) ' B = ', B                               
      WRITE(6,*) 'STEP SIZE OF T'                         
      READ(5,*) HH                                        
      WRITE(6,*) ' STEP SIZE OF T = ', HH                 
      WRITE(6,*) 'FINAL VALUE OF T'                       
      READ(5,*) TP                                        
      WRITE(6,*) ' FINAL VALUE OF T = ', TP               
C                                                         
C  INITIALIZATION                                         
C                                                         
      TT=0.0D0
;BEGIN;  
      GENTRAN                                             
        LITERAL                                           
          TAB!*, "WRITE(9,*) ' H = ", EVAL(H), "'", CR!*, 
          TAB!*, "WRITE(9,*) ' D = ", EVAL(D), "'", CR!*$ 
;END;                                                     
      WRITE(9,901) C                                      
901   FORMAT(' C= ',D20.10)                               
      WRITE(9,910) TT, Q, P                               
910   FORMAT(' '3D20.10)                                  
C                                                         
C  LOOP                                                   
C                                                         
;BEGIN;                                                   
      GENTRAN                                             
          REPEAT                                          
          <<                                              
              PN :=: PN;                                  
              Q  :=: QN;                                  
              P  := PN;                                   
              TT := TT + HH;                              
              LITERAL                                     
                TAB!*, "WRITE(9,910) TT, QQ, P", CR!*     
          >>                                              
          UNTIL TT >= TF$                                 
;END;                                                     
      STOP                                                
      END                                                 
;END;                                                     
\end{framedverbatim}

Now we can generate a circuit simulation program simply by starting
a REDUCE session and following three steps:
\begin{enumerate}
\item Enter circuit specifications.
\item Perform calculations.
\item Call the GENTRAN template processor.
\end{enumerate}
For example, the following REDUCE session will write a simulation
program to the file {\tt runge.f}:
\begin{verbatim}
1: COMMENT  -- INPUT --$ 

2: K := 1/(2*M)*P^2$    % kinetic energy 

3: U := K0/2*Q^2$       % potential energy 

4: D := B/2*QDOT$       % dissipating function 

5: H := K + U$          % hamiltonian 

6: COMMENT  -- CALCULATIONS --$ 

7: IN "rk.red", "ham.red"$ 

8: COMMENT  -- FORTRAN CODE GENERATION --$ 

9: GENTRANLANG!* := 'FORTRAN$ 

10: ON DOUBLE$

11: GENTRANIN "runge.tem" OUT "runge.f"$ 
\end{verbatim}

Contents of file {\tt runge.f}:
\begin{framedverbatim}
      PROGRAM RUNGE
      IMPLICIT DOUBLE PRECISION (K,M)
C
C  INPUT
C
      WRITE(6,*) 'INITIAL VALUE OF P'
      READ(5,*) P
      WRITE(6,*) ' P = ', P
      WRITE(6,*) 'INITIAL VALUE OF Q'
      READ(5,*) Q
      WRITE(6,*) ' Q = ', Q
      WRITE(6,*) 'VALUE OF M'
      READ(5,*) M
      WRITE(6,*) ' M = ', M
      WRITE(6,*) 'VALUE OF K0'
      READ(5,*) K0
      WRITE(6,*) ' K0 = ', K0
      WRITE(6,*) 'VALUE OF B'
      READ(5,*) B
      WRITE(6,*) ' B = ', B
      WRITE(6,*) 'STEP SIZE OF T'
      READ(5,*) HH
      WRITE(6,*) ' STEP SIZE OF T = ', HH
      WRITE(6,*) 'FINAL VALUE OF T'
      READ(5,*) TP
      WRITE(6,*) ' FINAL VALUE OF T = ', TP
C
C  INITIALIZATION
C
      TT=0.0D0                     
      WRITE(9,*) ' H = (M*Q**2*K0+P**2)/(2.0D0*M)'
      WRITE(9,*) ' D = (B*QDOT)/2.0D0'
      WRITE(9,901) C
901   FORMAT(' C= ',D20.10)
      WRITE(9,910) TT, Q, P
910   FORMAT(' '3D20.10)
C
C  LOOP
C
25001 CONTINUE
          PN=(-(12.0D0*B*M**2*HH)+2.0D0*B*M*K0*HH**3+24.0D0*
     .     M**2*P-(24.0D0*M**2*Q*K0*HH)-(12.0D0*M*P*K0*HH**2)
     .     +4.0D0*M*Q*K0**2*HH**3+P*K0**2*HH**4)/(24.0D0*M**2
     .     )
          Q=(-(12.0D0*B*M*HH**2)+B*K0*HH**4+48.0D0*M**2*Q+
     .     48.0D0*M*P*HH-(24.0D0*M*Q*K0*HH**2)-(8.0D0*P*K0*HH
     .     **3)+2.0D0*Q*K0**2*HH**4)/(48.0D0*M**2)
          P=PN
          TT=TT+HH
          WRITE(9,910) TT, QQ, P
      IF (.NOT.TT.GE.TF) GOTO 25001
      STOP
      END
\end{framedverbatim}

\section{Symbolic Mode Functions}
\index{symbolic mode ! in GENTRAN}

Thus far in this manual, commands have been presented which are meant
to be used primarily in the algebraic mode of REDUCE.  These commands
are designed to be used interactively.  However, many code generation
applications require code to be generated under program control\footnote{
\cite{vandenHeuvel:86ms} contains one such example.}. In these
applications, it is generally more convenient to generate code from
(computed) prefix forms.  Therefore, GENTRAN provides code generation
and file handling functions designed specifically to be used in the
symbolic mode of REDUCE.  This section presents the symbolic functions
which are analogous to the code generation, template processing, and
output file handling commands presented in sections \ref{GENTRAN:inter},
 \ref{GENTRAN:template}, and \ref{GENTRAN:output}.

\subsection{Code Generation and Translation}
Sections~\ref{translation} through \ref{comments}
describe interactive commands and functions which
generate and translate code, declare variables to be of 
specific types, and insert literal strings of characters into the
stream of generated code.  This section describes analogous symbolic
mode code generation functions.

\subsubsection{Translation of Prefix Forms}
In algebraic mode, the {\bf GENTRAN} command translates algorithmic
specifications supplied in the form of REDUCE statements into
numerical code.  Similarly, the symbolic function {\bf SYM!-GENTRAN}
\index{SYM"!-GENTRAN command}
translates algorithmic specifications supplied in the form of REDUCE
prefix forms into numerical code.

\begin{describe}{Syntax:}
{\bf SYM!-GENTRAN} {\it form\/};
\end{describe}
\begin{describe}{Function Type:}
expr
\end{describe} 
\begin{describe}{Argument:}
{\it form\/} is any LISP prefix form that evaluates to a
REDUCE prefix form that can be translated by GENTRAN into the target 
language\footnote{
See~\ref{appa} on page~\pageref{appa} for a complete listing of REDUCE
prefix forms that can be translated.}.
{\it form\/} may contain any number of occurrences of the special forms 
\ttindex{EVAL} \ttindex{LSETQ} \ttindex{RSETQ} \ttindex{LRSETQ}
\ttindex{DECLARE} \ttindex{LITERAL}
{\bf EVAL}, {\bf LSETQ}, {\bf RSETQ}, {\bf LRSETQ}, {\bf DECLARE}, and 
{\bf LITERAL} (see sections~\ref{sym:cg} through \ref{special} on
pages~\pageref{sym:cg}--\pageref{special}).
\end{describe}
\begin{describe}{Side Effects:}
{\bf SYM!-GENTRAN} translates {\it form\/} into formatted code in the target
language and writes it to the file(s) currently selected for output.
\end{describe}
\begin{describe}{Returned Value:}
{\bf SYM!-GENTRAN} returns the name(s) of the file(s) to which code
was written.  If code was written to one file, the returned value is an atom;
otherwise, it is a list.
\end{describe} 
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** OUTPUT FILE ALREADY EXISTS

   OVERWRITE FILE? (Y/N)

***** WRONG TYPE OF ARG
\end{verbatim}
{\it exp}
\begin{verbatim}
***** CANNOT BE TRANSLATED
\end{verbatim}
\end{describe} 
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: SYMBOLIC$ 

2: GENTRANLANG!* := 'FORTRAN$

3:   SYM!-GENTRAN '(FOR I (1 1 n) DO (SETQ (V I) 0))$

     DO 25001 I=1,N
          V(I)=0.0
25001 CONTINUE

4: GENTRANLANG!* := 'RATFOR$

5: SYM!-GENTRAN '(FOR I (1 1 N) DO 
5:                    (FOR J ((PLUS I 1) 1 N) DO 
5:                         (PROGN 
5:                            (SETQ (X J I) (X I J)) 
5:                            (SETQ (Y J I) (Y I J)))))$ 

DO I=1,N
   DO J=I+1,N
        {
            X(J,I)=X(I,J)
            Y(J,I)=Y(I,J)
        }

6: GENTRANLANG!* := 'C$ 

7: SYM!-GENTRAN '(SETQ P (FOR I (1 1 N) PRODUCT I))$

{
    P=1;
    for (I=1;I<=N;++I)
        P*=I;
}

8:  GENTRANLANG!* := 'PASCAL$

9: SYM!-GENTRAN '(SETQ C
9:     (COND ((LESSP A B) A) (T B)))$
IF A<B THEN
    C:=A;
ELSE
    C:=B;

\end{verbatim}
\end{describe}


\subsubsection{Code Generation} \index{code generation}
\label{sym:cg}
Sections~\ref{eval} through~\ref{lrsetq} on
pages~\pageref{eval}--\pageref{lrsetq} described the special functions
and operators {\bf EVAL}, {\bf ::=}, {\bf :=:}, and {\bf ::=:} that
could be included in arguments to the {\bf GENTRAN} command to
indicate that parts of those arguments were to be given to REDUCE FOR
Evaluation prior to translation.  This section describes the analogous
functions that can be supplied in prefix form to the {\bf SYM!-GENTRAN}
function.

The following special forms may be interleaved arbitrarily in forms
supplied as arguments to {\bf SYM!-GENTRAN} to specify partial
\ttindex{EVAL} \ttindex{LSETQ} \ttindex{RSETQ} \ttindex{LRSETQ}
evaluation:  {\bf EVAL}, {\bf LSETQ}, {\bf RSETQ}, and {\bf LRSETQ}.
Sections~\ref{sym:eval} through \ref{sym:lrsetq} describe these forms. Then
section~\ref{lispeval} through \ref{share}
present examples of the usage of these
forms for evaluation of expressions in both symbolic and algebraic modes.

\paragraph{The EVAL Form}
\label{sym:eval}
\begin{describe}{Syntax:} \ttindex{EVAL}
{\bf (EVAL} {\it form\/}{\bf )}
\end{describe} 
\begin{describe}{Argument:}
{\it form\/} is any LISP prefix form that evaluates to a REDUCE prefix form
that can be translated by GENTRAN into the target language.
\end{describe} 

\paragraph{The LSETQ Form} \ttindex{LSETQ}
\begin{describe}{Syntax:}
{\bf (LSETQ} {\it svar exp\/}{\bf )}
\end{describe} 
\begin{describe}{Arguments:}
{\it svar\/} is a subscripted variable in LISP prefix form.  Its subscripts
must evaluate to REDUCE prefix forms that can be translated
into the target language.  {\it exp\/} is any REDUCE expression in
prefix form that can be translated by GENTRAN.
\end{describe} 

\paragraph{The RSETQ Form} \ttindex{RSETQ}
\begin{describe}{Syntax:}
{\bf (RSETQ} {\it var exp\/}{\bf )}
\end{describe}
\begin{describe}{Arguments:}
{\it var\/} is a variable in REDUCE prefix form.  {\it exp\/} is a LISP
prefix form which evaluates to a translatable REDUCE prefix form.
\end{describe} 

\paragraph{The LRSETQ Form} \ttindex{RSETQ}
\label{sym:lrsetq}
\begin{describe}{Syntax:}
{\bf (LRSETQ} {\it svar exp\/}{\bf )}
\end{describe} 
\begin{describe}{Arguments:}
{\it svar\/} is a subscripted variable in LISP prefix form with
subscripts that evaluate to REDUCE prefix forms
that can be translated by GENTRAN.  {\it exp\/} is a LISP prefix
form that evaluates to a translatable REDUCE prefix form.
\end{describe}

\paragraph{Symbolic Mode Evaluation}
\label{lispeval}
The symbolic mode evaluation forms that have just been described are
analogous to their algebraic mode counterparts, except that
by default, they evaluate their argument(s) in symbolic mode.  The
following is an example of evaluation of subscripts in symbolic mode:
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: SYMBOLIC$

2: FOR i:=1:2 DO 
2:     FOR j:=1:2 DO 
2:         SYM!-GENTRAN '(LSETQ (M i j) 0)$

     M(1,1)=0.0
     M(1,2)=0.0
     M(2,1)=0.0
     M(2,2)=0.0
\end{verbatim}
\end{describe} 

\paragraph{Algebraic Mode Evaluation}
As we have just seen, the symbolic mode evaluation forms evaluate their
argument(s) in symbolic mode.  This default evaluation mode can be
overridden by explicitly requesting evaluation in algebraic mode with
the REDUCE {\bf AEVAL} function.\ttindex{AEVAL}

\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: ALGEBRAIC$

2: F := 2*x^2 - 5*X + 6$ 

3: SYMBOLIC$ 

4: SYM!-GENTRAN '(SETQ Q (QUOTIENT 
4:                           (EVAL (AEVAL 'F)) 
4:                           (EVAL (AEVAL '(DF F X)))))$

     Q=(2.0*X**2-5.0*X+6.0)/(4.0*X-5.0)

5: ALGEBRAIC$ 

6: M := MAT(( A,   0,  -1,  1), 
6:          ( 0, B^2,   0,  1), 
6:          (-1,   B, B*C,  0), 
6:          ( 1,   0,  -C, -D))$ 

7: SYMBOLIC$ 

8: FOR i:=1:4 DO 
8:      SYM!-GENTRAN '(LRSETQ (M i i) 
                    (AEVAL (MKQUOTE (LIST 'M i i))))$

     M(1,1)=A
     M(2,2)=B**2
     M(3,3)=B*C
     M(4,4)=-D
\end{verbatim}
\end{describe}

\paragraph{SHAREd Variables}
\label{share} \index{SHARE command}
The REDUCE {\bf SHARE} command enables variables to be shared
between algebraic and symbolic modes.  Thus, we can derive an expression in
algebraic mode, assign it to a shared variable, and then access the value
of that variable to generate code from symbolic mode.

\begin{describe}{Example:}
\begin{verbatim}
1: ALGEBRAIC$

2: SHARE dfx1$

3: dfx1 := DF(X**4 - X**3 + 2*X**2 + 1, X)$

4: SYMBOLIC$

5: SYM!-GENTRAN '(RSETQ DERIV dfx1)$
      DERIV=4.0*X**3-(3.0*X**2)+4.0*X
\end{verbatim}
\end{describe} 

\subsubsection{Special Translatable Forms}
\label{special}
Sections~\ref{explicit:type} through \ref{comments} described special
functions that could be used to declare variable types and insert
literal strings of characters into generated code.  This section
contains explanations of analogous prefix forms for usage in symbolic
mode.

\paragraph{Explicit Type Declarations}
A similar form of the algebraic mode {\bf DECLARE} function is provided in
symbolic mode:
\begin{describe}{Syntax:} \index{DECLARE function}
\begin{tabular}{ll}
{\bf (DECLARE} & {\bf (}{\it type1 v1 v2 \dots\  vn1\/}{\bf )}\\
& {\bf (}{\it type2 v1 v2 \dots\  vn2\/}{\bf )}\\
& \ \ \ :\\
& {\bf (}{\it typen v1 v2 \dots\  vnn\/}{\bf )) }\\
\end{tabular}
\end{describe} 
\begin{describe}{Arguments:}
Each {\it v1 v2 \dots\ vn\/} is a sequence of one or more variables
(optionally subscripted to indicate array dimensions -- in prefix form), or
variable ranges (two letters concatenated together with "-" in between). {\it
v\/}s are not evaluated unless given as arguments to {\bf EVAL}.

Each {\it type\/} is a variable type in the target language.  Each
must be an atom, optionally concatenated to the atom {\bf IMPLICIT!\ }
(note the trailing space).  \index{IMPLICIT"!  atom}
{\it type\/}s are not evaluated unless given as arguments to {\bf EVAL}.
\end{describe} 
\begin{describe}{Side Effect:}
Entries are placed in the symbol table for each variable or
variable range declared in the call to this function.  The
function call itself is removed from the statement group
being translated.  Then after translation, type declarations are
generated from these symbol table entries before the resulting
executable statements are printed.
\end{describe}
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: SYMBOLIC$ 

2: GENTRANLANG!* := 'FORTRAN$

3: SYM!-GENTRAN 
3:    '(PROGN 
3:        (DECLARE (IMPLICIT! REAL!*8 A!-H O!-Z) 
3:                 (INTEGER (M 4 4))) 
3:        (FOR I (1 1 4) DO 
3:             (FOR J (1 1 4) DO 
3:                  (COND ((EQUAL I J) (SETQ (M I J) 1)) 
3:                        (T (SETQ (M I J) 0))))) 
3:        (DECLARE (INTEGER I J)) 
      :
      :
3:     )$ 

     IMPLICIT REAL*8 (A-H,O-Z)
     INTEGER M(4,4),I,J
     DO 25001 I=1,4
          DO 25002 J=1,4
              IF (I.EQ.J) THEN
                  M(I,J)=1
              ELSE
                  M(I,J)=0
              ENDIF
25002     CONTINUE
25001 CONTINUE
      :
      :

4: GENTRANLANG!* := 'RATFOR$

5: SYM!-GENTRAN 
5:    '(PROCEDURE FAC NIL EXPR (N) 
5:        (BLOCK () 
5:               (DECLARE (FUNCTION FAC) 
5:                        (INTEGER FAC N)) 
5:               (SETQ F (FOR I (1 1 N) PRODUCT I)) 
5:               (DECLARE (INTEGER F I)) 
5:               (RETURN F)))$

INTEGER FUNCTION FAC(N)
INTEGER N,F,I
{
    F=1
    DO I=1,N
        F=F*I
}
RETURN(F)
END

6: GENTRANLANG!* := 'C$

7: SYM!-GENTRAN 
7:    '(PROCEDURE FAC NIL EXPR (N) 
7:        (BLOCK () 
7:               (DECLARE (INTEGER FAC N I F)) 
7:               (SETQ F (FOR I (1 1 N) PRODUCT I)) 
7:               (RETURN F)))$ 

int FAC(N)
int N;
{
    int I,F;
    {
        F=1;
        for (I=1;I<=N;++I)
            F*=I;
    }
    return(F);
}

8:  GENTRANLANG!* := 'PASCAL$

9:  SYM!-GENTRAN
9:     '(PROCEDURE FAC NIL EXPR (N)
9:         (BLOCK ()
9:                (DECLARE (INTEGER FAC N I F))
9:                (SETQ F (FOR I (1 1 N) PRODUCT I))
9:                (RETURN F)))$
FUNCTION FAC(N:INTEGER):INTEGER;
LABEL
    99999;
VAR
    I,F: INTEGER;
BEGIN
    BEGIN
        F:=1;
        FOR I:=1 TO N DO
            F:=F*I
    END;
    BEGIN
        FAC:=F;
        GOTO 99999{RETURN}
    END;
99999:
END;

\end{verbatim}
\end{describe} 

\paragraph{Comments and Literal Strings}
\index{comments ! in GENTRAN} \index{literals ! in GENTRAN}
\ttindex{LITERAL}
A form similar to the algebraic mode {\bf LITERAL} function is provided in
symbolic mode:
\begin{describe}{Syntax:}
{\bf (LITERAL} {\it arg1 arg2 \dots\  argn\/}{\bf )}
\end{describe} 
\begin{describe}{Arguments:}
{\it arg1 arg2 \dots\  argn\/} is an argument sequence containing one or more
{\it arg\/}s, where each {\it arg\/} either is, or evaluates to, an atom.  The
atoms {\bf TAB!*} and {\bf CR!*} have special meanings. \ttindex{TAB"!*}
\ttindex{CR"!*} {\it arg\/}s are
not evaluated unless given as arguments to {\bf EVAL}.
\end{describe} 
\begin{describe}{Side Effect:}
This form is replaced by the character sequence resulting from
concatenation of the given atoms.  Double quotes are stripped from
all string type {\it arg\/}s, and the reserved atoms {\bf TAB!*}
and {\bf CR!*} are replaced by a tab to the current level of indentation,
and an end-of-line character, respectively.
\end{describe} 
\begin{describe}{\example}\index{GENTRAN package ! example}
\begin{verbatim}
1: SYMBOLIC$ 

2: GENTRANLANG!* := 'FORTRAN$

3: N := 100$

4: SYM!-GENTRAN 
4:  '(PROGN 
4:    (LITERAL C TAB!* "--THIS IS A FORTRAN COMMENT--"
4:             CR!* C CR!*) 
4:    (LITERAL TAB!* "DATA N/" (EVAL N) "/" CR!*))$

C     --THIS IS A FORTRAN COMMENT--
C
     DATA N/100/

5: GENTRANLANG!* := 'RATFOR$

6: SYM!-GENTRAN 
6:  '(FOR I (1 1 N) DO 
6:      (PROGN 
6:       (LITERAL TAB!* "# THIS IS A RATFOR COMMENT" CR!*) 
6:       (LITERAL TAB!* "WRITE(6,10) (M(I,J),J=1,N)" CR!* 
6:         10 TAB!* "FORMAT(1X,10(I5,3X))" CR!*)))$

DO I=1,N
   {
        # THIS IS A RATFOR COMMENT
        WRITE(6,10) (M(I,J),J=1,N)
10      FORMAT(1X,10(I5,3X))
   }

7: GENTRANLANG!* := 'C$

8: SYM!-GENTRAN 
8:  '(PROGN 
8:    (SETQ X 0) 
8:    (LITERAL "/* THIS IS A" CR!* "
8:             C COMMENT */" CR!*))$

{
    X=0.0;
/* THIS IS A
   C COMMENT */
}

9: GENTRANLANG!* := 'PASCAL$

10: SYM!-GENTRAN
10:  '(PROGN
10:     (SETQ X (SIN Y))
10:     (LITERAL "{ THIS IS A PASCAL COMMENT }" CR!*))$
BEGIN
    X:=SIN(Y)
{ THIS IS A PASCAL COMMENT }
END;

\end{verbatim}
\end{describe} 

\subsection{Template Processing}
\index{template processing}
The template processor can be invoked from either algebraic or
symbolic mode.  Section~\ref{templates} described the algebraic mode
command.  This section describes the analogous symbolic mode function.
\begin{describe}{Syntax:}\index{SYM"!-GENTRANIN command}
{\bf SYM!-GENTRANIN} {\it list-of-fnames\/};
\end{describe} 
\begin{describe}{Function Type:}
expr
\end{describe} 
\begin{describe}{Argument:}
{\it list-of-fnames\/} evaluates to a LISP list containing one or more
{\it fname\/}s, where each {\it fname\/} is one of:

\begin{tabular}{lll}
{\it an atom} & = & a template (input) file\\
{\bf T} & = & the terminal\\
\end{tabular}
\end{describe} 
\begin{describe}{Side Effects:}
{\bf SYM!-GENTRANIN} processes each template file in {\it list-of-fnames\/}
sequentially.

A template file may contain any number of parts, each of which
is either an active or an inactive part.  All active parts start with
the character sequence {\bf ;BEGIN;} and end with {\bf ;END;}.  The end
of the template file is indicated by an extra {\bf ;END;} character sequence.

Inactive parts of template files are assumed to contain code in
the target language (FORTRAN, RATFOR, PASCAL or C, depending on
the value of the global varibale {\bf GENTRANLANG!*}).  All
inactive parts are copied to the output.  Comments delimited
by the appropriate characters are also copied in their entirety
to the output.  Thus the character sequences {\bf ;BEGIN;} and {\bf ;END;}
have no special meanings within comments. \index{;BEGIN; marker}
\index{;END; marker}

Active parts may contain any number of REDUCE expressions, statements,
and commands.  They are not copied directly to the output.  Instead,
they are given to REDUCE for evaluation in algebraic mode\footnote{
Active parts are evaluated in algebraic mode unless the mode is
explicitly changed to symbolic from within the active part itself.
This is true regardless of which mode the system was in when the
template processor was called.}.  All output generated by each
evaluation is sent to the file(s) currently selected for output.
Returned values are only printed on the terminal.

Active parts will most likely contain calls to GENTRAN 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.
\end{describe} 
\begin{describe}{Returned Value:}
{\bf SYM!-GENTRANIN} returns the name(s) of the file(s) to which code was
written.  If code was written to one file, the returned value is an atom;
otherwise, it is a list.
\end{describe} 
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** OUTPUT FILE ALREADY EXISTS

   OVERWRITE FILE? (Y/N)

***** NONEXISTENT INPUT FILE

***** TEMPLATE FILE ALREADY OPEN FOR INPUT

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe} 

\subsection{Output Redirection}
\index{output redirection (temporary)}
Section~\ref{GENTRAN:output} describes four slgebraic mode commands
which select, open, and close output files.  The algebraic mode commands
\index{GENTRANOUT command} \index{GENTRANSHUT command}
\index{GENTRANPUSH command} \index{GENTRANPOP command}
{\bf GENTRANOUT}, {\bf GENTRANSHUT}, {\bf GENTRANPUSH}, and {\bf
GENTRANPOP} are analogous to the symbolic mode {\bf
SYM!-GENTRANOUT}, {\bf SYM!-GENTRANSHUT}, {\bf SYM!-GENTRANPUSH}, and
{\bf SYM!-GENTRANPOP} functions, respectively.

\subsubsection{SYM!-GENTRANOUT} \index{SYM"!-GENTRANOUT command}
\begin{describe}{Syntax:}
{\bf SYM!-GENTRANOUT} {\it list-of-fnames\/};
\end{describe} 
\begin{describe}{Function Type:}
expr
\end{describe} 
\begin{describe}{Argument:}
{\it list-of-fnames\/} evaluates to a LISP list containing one or more
{\it fname\/}s, where each {\it fname} is one of:

\begin{tabular}{lll}
{\it an atom} & = & an output file\\
{\bf T} & = & the terminal\\
{\bf NIL} & = &  the current output file(s)\\
{\bf ALL!*} & = &  all files currently open for output \\
& &  by GENTRAN\\
\end{tabular}
\end{describe}
\begin{describe}{Side Effect:}
GENTRAN maintains a list of files currently open for output by GENTRAN
{\it only}.  {\bf SYM!-GENTRANOUT} inserts each file name represented in
{\it list-of-fnames\/} into that list and opens each one
for output.  It also resets the currently selected output file(s) to be
all of the files represented in {\it list-of-fnames}.
\end{describe} 
\begin{describe}{Returned Value:}
{\bf SYM!-GENTRANOUT} returns the name(s) of the file(s) represented
by {\it list-of-fnames\/}; i.e., the current output file(s) after the
command has been executed.  If there is only one file
selected for output, the returned value is an atom; otherwise, it is
a list.
\end{describe} 
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}

*** OUTPUT FILE ALREADY EXISTS

   OVERWRITE FILE? (Y/N)

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe} 

\subsubsection{SYM!-GENTRANSHUT}\index{SYM"!-GENTRANSHUT command}
\begin{describe}{Syntax:}
{\bf SYM!-GENTRANSHUT} {\it list-of-fnames\/} ;
\end{describe} 
\begin{describe}{Function Type:}
expr
\end{describe} 
\begin{describe}{Argument:}
{\it list-of-fnames\/} evaluates to a LISP list containing one or more 
{\it fnames}, where each {\it fname\/} is one of:

\begin{tabular}{lll}
{\it an atom} & = &  an output file\\
{\bf NIL} & = & the current output file(s)\\
{\bf ALL!*} & = & all files currently open for output \\
& & by GENTRAN\\
\end{tabular}
\end{describe} 
\begin{describe}{Side Effects:}
{\bf SYM!-GENTRANSHUT} creates a list of file names from {\it list-of-fnames},
deletes each from the output file list,
and closes the corresponding files.  If (all of) the
current output file(s) are closed, then the current output
file is reset to the terminal.
\end{describe} 
\begin{describe}{Returned Value:}
{\bf SYM!-GENTRANSHUT} returns the name(s) of the file(s) selected for
output after the command has been executed.  If there is
only one file selected for output, the returned value is an atom;
otherwise, it is a list.
\end{describe} 
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** FILE NOT OPEN FOR OUTPUT

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe} 

\subsubsection{SYM!-GENTRANPUSH}\index{SYM"!-GENTRANPUSH command}
\begin{describe}{Syntax:}
{\bf SYM!-GENTRANPUSH} {\it  list-of-fnames\/};
\end{describe} 
\begin{describe}{Function Type:}
expr
\end{describe} 
\begin{describe}{Argument:}
{\it list-of-fnames\/} evaluates to a LISP list containing one or more 
{\it fname}s, each of which is one of:

\begin{tabular}{lll}
{\it an atom} & = &  an output file\\
{\bf T} & = & the terminal\\
{\bf NIL} & = & the current output file(s)\\
{\bf ALL!*} & = & all files currently open for output \\
& & by GENTRAN\\
\end{tabular}
\end{describe} 
\begin{describe}{Side Effects:}
{\bf SYM!-GENTRANPUSH} creates a list of file name(s) from
{\it lis-of-fnames\/}
and pushes that list onto the output stack.  Each file in the list that
is not already open for output is opened at this time.  The current
output file is reset to this new element on the top of the stack.
\end{describe} 
\begin{describe}{Returned Value:}
{\bf SYM!-GENTRANPUSH} returns the name(s) of the file(s) represented by 
{\it list-of-fnames\/}; i.e., the current output
file(s) after the command has been executed.  If there is
only one file selected for output, the returned value is an
atom; otherwise, it is a list.
\end{describe} 
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** OUTPUT FILE ALREADY EXISTS

   OVERWRITE FILE? (Y/N)

***** WRONG TYPE OF ARG
\end{verbatim}
\end{describe}

\subsubsection{SYM!-GENTRANPOP} \index{SYM"!-GENTRANPOP command}
\begin{describe}{Syntax:}
{\bf SYM!-GENTRANPOP} {\it list-of-fnames\/};
\end{describe} 
\begin{describe}{Function Type:}
expr
\end{describe} 
\begin{describe}{Argument:}
{\it list-of-fnames\/} evaluates to a LISP list containing one or more
{\it fname\/}s, where each {\it fname\/} is one of:

\begin{tabular}{lll}
{\it an atom} & = &  an output file\\
{\bf T} & = & the terminal\\
{\bf NIL} & = & the current output file(s)\\
{\bf ALL!*} & = & all files currently open for output \\
& & by GENTRAN\\
\end{tabular}
\end{describe} 
\begin{describe}{Side Effects:}
{\bf SYM!-GENTRANPOP} deletes the top-most occurrence of the
single element containing the file name(s) represented by
{\it list-of-fnames\/} from the output stack.  Files whose names have been
completely removed from the output stack are closed.  The current output file
is reset to the (new) element on the top of the output stack.
\end{describe} 
\begin{describe}{Returned Value:}
{\bf SYM!-GENTRANPOP} returns the name(s) of the file(s)
selected for output after the command has been executed.  If there is
only one file selected for output, the returned value is an atom; otherwise,
it is a list.
\end{describe} 
\begin{describe}{Diagnostic Messages:}
\begin{verbatim}
*** FILE NOT OPEN FOR OUTPUT

***** WRONG TYPE OF ARG

\end{verbatim}
\end{describe}

\section{Translatable REDUCE Expressions \& Statements}
\label{appa}
A substantial subset of all REDUCE expressions and statements
can be translated by GENTRAN into semantically equivalent code
in the target numerical language\footnote{
It should be noted that call-by-value parameter passing is used
in REDUCE, whereas call-by-address parameter passing is normally
used in FORTRAN and RATFOR.  GENTRAN does {\it not} attempt
to simulate call-by-value passing in FORTRAN and RATFOR, although
this could be done by generating temporary variables, assigning
values to them, and using them in subprogram calls.
\index{call-by-value} \index{call-by-address}}. This
section contains examples and a formal definition of translatable REDUCE
expressions and statements.

\subsection{Examples of Translatable Statements}
The following three tables contain listings of REDUCE statement types
that can be translated by GENTRAN.  An example of each statement
type is shown, and FORTRAN, RATFOR, PASCAL and C code generated for each
example is also shown.

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf FORTRAN CODE} \\ \hline\hline
    simple     &{\bf V:=X\^{}2+X\$} &\verb!      V=X**2+X!\\
& & \\
    matrix     &{\bf M:=MAT((U,V),} &\verb!      M(1,1)=U!\\
& {\bf\ \ \ \ \ \ \ \ (W,X))\$ } &\verb!      M(1,2)=V!\\
& &\verb!      M(2,1)=W!\\
& &\verb!      M(2,2)=X!\\
& & \\
    sum &{\bf S:=FOR I:=1:10} &\verb!      S=0.0!\\
&{\bf\ \ \ \ \ \ SUM V(I)\$} &\verb!      DO 25001 I=1,10!\\
& &\verb!          S=S+V(I)!\\
& &\verb!25001 CONTINUE!\\
& & \\
    product    &{\bf P:=FOR I:=2 STEP 2} &\verb!      P=1!\\
&{\bf\ \ \ \ \ \ \ \ UNTIL N} &\verb!      DO 25002 I=2,N,2!\\
&{\bf \ \ \ \ PRODUCT I\$} &\verb!          P=P*I!\\
& &\verb!25002 CONTINUE!\\
& & \\
conditional & {\bf X := IF A$<$B THEN} &\verb!      IF (A.LT.B) THEN!\\
& {\bf \ \ \ \ \ \ \ \ A ELSE B\$} &\verb!          X=A!\\
& &\verb!      ELSE!\\
& &\verb!          X=B!\\
& &\verb!      ENDIF!\\
& & \\ \hline\hline
\end{tabular}
\caption{REDUCE assignments translatable to FORTRAN}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf FORTRAN CODE} \\ \hline\hline
    for &{\bf FOR I:=1:8 DO} &\verb!      DO 25003 I=1,8!\\
&{\bf \ \ \ \ V(I):=0.0\$} &\verb!          V(I)=0.0!\\
& &\verb!25003 CONTINUE!\\
& & \\
    while      &{\bf WHILE F(N)$>$0.0 DO} &\verb!25004 IF(.NOT.F(N).GT.0.0)!\\
               &                          &\verb!     .   GOTO 25005!\\
&{\bf \ \ \ \ N:=N+1\$} &\verb!          N=N+1!\\
& &\verb!          GOTO 25004!\\
& &\verb!25005 CONTINUE!\\
& & \\
   repeat     &{\bf REPEAT X:=X/2.0} &\verb!25006 CONTINUE!\\
&{\bf \ \ \ \ UNTIL F(X)$<$0.0\$} &\verb!          X=X/2.0!\\
& &\verb!      IF(.NOT.F(X).LT.0.0)!\\
& &\verb!     .   GOTO 25006!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE Loop structures translatable to FORTRAN}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf FORTRAN CODE} \\ \hline\hline
  Conditionals:&     &\\
&     &\\
    if  &{\bf IF X$>$0.0} &\verb!  IF (X.GT.0.0) THEN!\\
& {\bf \ \ \ \ \ \ \  THEN Y:=X\$} &\verb!      Y=X!\\
& &\verb!  ENDIF!\\
&     &\\
    if - else  &{\bf IF X$>$0.0 THEN Y:=X} &\verb!  IF (X.GT.0.0) THEN!\\
&{\bf\ \ \ \  ELSE Y:=-X\$}&\verb!      Y=X!\\
&     &\verb!  ELSE!\\
&     &\verb!      Y=-X!\\
&     &\verb!  ENDIF!\\
& & \\\hline
  Unconditional&     &\\
  Transfer of  &     &\\
  Control:     &     &\\
&     &\\
    goto&{\bf GOTO LOOP\$} &\verb!  GOTO 25010!\\
&     &\\
    call&{\bf CALCV(V,X,Y,Z)\$} &\verb!  CALL CALCV(V,X,Y,Z)!\\
&     &\\
    return     &{\bf RETURN X\^{}2\$} &\verb!  !{\it
 functionname\/}\verb!=X**2!\\
&     &\verb!  RETURN!\\
& & \\\hline
Sequences \&    &     &\\
Groups: &     &\\
&     &\\
    sequence   &{\bf $<$$<$ U:=X\^{}2;}&\verb!  U=X**2!\\
& {\bf \ \ \ \ \ \ \ \ V:=Y\^{}2$>$$>$\$}    &\verb!  V=Y**2!\\
&     &\\
    group      &{\bf BEGIN}&\verb!  U=X**2!\\
&{\bf\ \ \ \  U:=X\^{}2;}&\verb!  V=Y**2!\\
&{\bf\ \ \ \  V:=Y\^{}2} &\\
&{\bf END\$}&\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE control structures translatable to FORTRAN}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf RATFOR CODE} \\ \hline\hline

Assignments: & &\\
& & \\
    simple     &{\bf V:=X\^{}2+X\$} &\verb!V=X**2+X!\\
& & \\
    matrix     &{\bf M:=MAT((U,V),(W,X))\$} &\verb!M(1,1)=U!\\
& &\verb!M(1,2)=V!\\
& &\verb!M(2,1)=W!\\
& &\verb!M(2,2)=X!\\
& & \\
    sum &{\bf S:=FOR I:=1:10} &\verb!S=0.0!\\
&{\bf\ \ \ \ \ \ SUM V(I)\$} &\verb!DO I=1,10!\\
& &\verb!    S=S+V(I)!\\
& & \\
    product    &{\bf P:=FOR I:=2 STEP 2} &\verb!P=1!\\
&{\bf\ \ \ \ \ \ \ \ UNTIL N} &\verb!DO I=2,N,2!\\
&{\ \ \ \ PRODUCT I\$} &\verb!    P=P*I!\\
& & \\
conditional & {\bf X := IF A$<$B THEN} &\verb!IF (A<B)!\\
& {\bf \ \ \ \ \ \ \ \ A ELSE B\$} &\verb!    X=A!\\
& &\verb!ELSE!\\
& &\verb!    X=B!\\
& & \\\hline
Control & & \\
Structures: & &\\
& & \\
  Loops: & &\\
& &\\
    for &{\bf FOR I:=1:8 DO} &\verb!DO I=1,8!\\
&{\bf \ \ \ \ V(I):=0.0\$} &\verb!    V(I)=0.0!\\
& & \\
    while      &{\bf WHILE F(N)$>$0.0 DO} &\verb!WHILE(F(N)>0.0)!\\
&{\bf \ \ \ \ N:=N+1\$} &\verb!    N=N+1!\\
& & \\
   repeat     &{\bf REPEAT X:=X/2.0} &\verb!REPEAT!\\
&{\bf \ \ \ \ UNTIL F(X)$<$0.0\$} &\verb!    X=X/2.0!\\
& &\verb!UNTIL(F(X)<0.0)!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE forms translatable to RATFOR}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf RATFOR CODE} \\ \hline\hline
  Conditionals:&     &\\
&     &\\
    if  &{\bf IF X$>$0.0 THEN Y:=X\$} &\verb!IF(X>0.0)!\\
&     &\verb!    Y=X!\\
&     &\\
    if - else  &{\bf IF X$>$0.0 THEN Y:=X} &\verb!IF(X>0.0)!\\
&{\bf\ \ \ \  ELSE Y:=-X\$}&\verb!    Y=X!\\
&     &\verb!ELSE!\\
&     &\verb!    Y=-X!\\
& & \\\hline
  Unconditional&     &\\
  Transfer of  &     &\\
  Control:     &     &\\
&     &\\
    goto&{\bf GOTO LOOP\$} &\verb!GOTO 25010!\\
&     &\\
    call&{\bf CALCV(V,X,Y,Z)\$} &\verb!CALL CALCV(V,X,Y,Z)!\\
&     &\\
    return     &{\bf RETURN X\^{}2\$} &\verb!RETURN(X**2)!\\
& & \\\hline
Sequences \&    &     &\\
Groups: &     &\\
&     &\\
    sequence   &{\bf $<$$<$ U:=X\^{}2;V:=Y\^{}2$>$$>$\$}&\verb!U=X**2!\\
&     &\verb!V=Y**2!\\
&     &\\
    group      &{\bf BEGIN}&\verb!{!\\
&{\bf\ \ \ \  U:=X\^{}2;}& \verb!      U=X**2!\\
&{\bf\ \ \ \  V:=Y\^{}2} & \verb!      V=Y**2!\\
&{\bf END\$}&\verb!}!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE forms translatable to RATFOR}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf PASCAL CODE} \\ \hline\hline
Assignments: & &\\
& & \\
    simple     &{\bf V:=X\^{}2+X\$} &\verb!V=X**2+X;!\\
& & \\
    matrix     &{\bf M:=MAT((U,V),} &\verb!BEGIN!\\
& {\bf \ \ \ \ \ \ \ \ (W,X))\$} &\verb!    M(1,1)=U;!\\
& &\verb!    M(1,2)=V;!\\
& &\verb!    M(2,1)=W;!\\
& &\verb!    M(2,2)=X;!\\
& &\verb!END;!\\
& & \\
    sum &{\bf S:=FOR I:=1:10} &\verb!BEGIN!\\
&{\bf\ \ \ \ \ \ SUM V(I)\$} &\verb!    S=0.0!\\
& &\verb!    FOR I:=1 TO 10 DO!\\
& &\verb!        S:=S+V(I)!\\
& &\verb!END;!\\
& & \\
    product    &{\bf P:=FOR I:=2:N} &\verb!BEGIN!\\
&{\bf \ \ \ \ PRODUCT I\$} &\verb!    P:=1;!\\
& &\verb!    FOR I:=2 TO N DO!\\
& &\verb!        P:=P*I!\\
& &\verb!END;!\\
& & \\
conditional & {\bf X := IF A$<$B THEN} &\verb!IF (A<B) THEN!\\
& \ \ \ \ \ \ {\bf \ \ \ \ \ \ \ \ A ELSE B\$} &\verb!    X:=A;!\\
& &\verb!ELSE!\\
& &\verb!    X:=B;!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE forms translatable to PASCAL}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf PASCAL CODE} \\ \hline\hline
Control & & \\
Structures: & &\\
& & \\
  Loops: & &\\
& &\\
    for &{\bf FOR I:=1:8 DO} &\verb!FOR I:=1 TO 8 DO!\\
&{\bf \ \ \ \ V(I):=0.0\$} &\verb!    V(I):=0.0;!\\
& & \\
    while      &{\bf WHILE F(N)$>$0.0 DO} &\verb!WHILE (F(N)>0.0)!\\
&{\bf \ \ \ \ N:=N+1\$} &\verb!    N:=N+1.0;!\\
& & \\
   repeat     &{\bf REPEAT X:=X/2.0} &\verb!REPEAT!\\
&{\bf \ \ \ \ UNTIL F(X)$<$0.0\$} &\verb!    X:=X/2.0!\\
& &\verb!UNTIL F(X)<0.0;!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE forms translatable to PASCAL}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf PASCAL CODE} \\ \hline\hline
  Conditionals:&     &\\
&     &\\
    if  &{\bf IF X$>$0.0 THEN Y:=X\$} &\verb!IF X>0.0 THEN!\\
& &\verb!    Y:=X;!\\
&     &\\
    if - else  &{\bf IF X$>$0.0 THEN Y:=X} &\verb!IF X>0.0 THEN!\\
&{\bf\ \ \ \  ELSE Y:=-X\$}&\verb!    Y:=X;!\\
&     &\verb!ELSE!\\
&     &\verb!    Y:=-X;!\\
& & \\\hline
  Unconditional&     &\\
  Transfer of  &     &\\
  Control:     &     &\\
&     &\\
    goto&{\bf GOTO LOOP\$} &\verb!GOTO 25010;!\\
&     &\\
    call&{\bf CALCV(V,X,Y,Z)\$} &\verb!CALCV(V,X,Y,Z);!\\
&     &\\
    return     &{\bf RETURN X\^{}2\$} &{\it functionname\/}\verb!=X**2;!\\
&     &\verb!GOTO 99999{RETURN}!\\
&     &\verb!99999;!\\
& & \\\hline
Sequences \&    &     &\\
Groups: &     &\\
&     &\\
    sequence   &{\bf $<$$<$ U:=X\^{}2;V:=Y\^{}2$>$$>$\$}&\verb!BEGIN!\\
&&\verb!    U:=X**2;!\\
&&\verb!    V:=Y**2!\\
&&\verb!END;!\\
&     &\\
    group      &{\bf BEGIN}&\verb!BEGIN!\\
&{\bf\ \ \ \  U:=X\^{}2;}&\verb!    U:=X**2;!\\
&{\bf\ \ \ \  V:=Y\^{}2} &\verb!    V:=Y**2!\\
&{\bf END\$}&\verb!END!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE forms translatable to PASCAL}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE}
 & \multicolumn{1}{c||}{\bf C CODE} \\ \hline\hline
Assignments: & &\\
& & \\
    simple     &{\bf V:=X\^{}2+X\$} &\verb!V=power(X,2)+X;!\\
& & \\
    matrix     &{\bf M:=MAT((U,V),(W,X))\$} &\verb!M[1][1]=U;!\\
& &\verb!M[1][2]=V;!\\
& &\verb!M[2][1]=W;!\\
& &\verb!M[2][2]=X;!\\
& & \\
    sum &{\bf S:=FOR I:=1:10} &\verb!S=0.0;!\\
&{\bf\ \ \ \ \ \ SUM V(I)\$} &\verb!for(I=1;I<=10;++I)!\\
& &\verb!    S+=V[I];!\\
& & \\
    product    &{\bf P:=FOR I:=2 STEP 2} &\verb!P=1;!\\
&{\bf\ \ \ \ \ \ \ \ UNTIL N} &\verb!for(I=2;I<=N;++I)!\\
&{\ \ \ \ PRODUCT I\$} &\verb!    P*=I;!\\
& & \\
conditional & {\bf X := IF A$<$B THEN} &\verb!if (A<B)!\\
& {\bf \ \ \ \ \ \ \ \ A ELSE B\$} &\verb!    X=A;!\\
& &\verb!else!\\
& &\verb!    X=B;!\\
& & \\\hline
Control & & \\
Structures: & &\\
& & \\
  Loops: & &\\
& &\\
    for &{\bf FOR I:=1:8 DO} &\verb!for(I=1;I<=8;++I)!\\
&{\bf \ \ \ \ V(I):=0.0\$} &\verb!    V[I]=0.0;!\\
& & \\
    while      &{\bf WHILE F(N)$>$0.0 DO} &\verb!while(F(N)>0.0)!\\
&{\bf \ \ \ \ N:=N+1\$} &\verb!    N+=1;!\\
& & \\
   repeat     &{\bf REPEAT X:=X/2.0} &\verb!do!\\
&{\bf \ \ \ \ UNTIL F(X)$<$0.0\$} &\verb!    X/=2.0;!\\
& &\verb!while(F(X)>=0.0);!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE forms translatable to C}
\end{table}

\begin{table}
\begin{tabular}{||l|l|l||}\hline\hline
\multicolumn{1}{||c|}{\bf TYPE} & \multicolumn{1}{c|}{\bf EXAMPLE} &
 \multicolumn{1}{c||}{\bf C CODE} \\ \hline\hline
  Conditionals:&     &\\
&     &\\
    if  &{\bf IF X$>$0.0 THEN Y:=X\$} &\verb!if(X>0.0)!\\
&     &\verb!    Y=X;!\\
&     &\\
    if - else  &{\bf IF X$>$0.0 THEN Y:=X} &\verb!if(X>0.0)!\\
&{\bf\ \ \ \  ELSE Y:=-X\$}&\verb!    Y=X;!\\
&     &\verb!else!\\
&     &\verb!    Y=-X;!\\
& & \\\hline
  Unconditional&     &\\
  Transfer of  &     &\\
  Control:     &     &\\
&     &\\
    goto&{\bf GOTO LOOP\$} &\verb!goto LOOP;!\\
&     &\\
    call&{\bf CALCV(V,X,Y,Z)\$} &\verb!CALCV(V,X,Y,Z);!\\
&     &\\
    return     &{\bf RETURN X\^{}2\$} &\verb!return(power(X,2) );!\\
& & \\\hline
Sequences \&    &     &\\
Groups: &     &\\
&     &\\
    sequence   &{\bf $<$$<$ U:=X\^{}2;V:=Y\^{}2$>$$>$\$}&\verb!U=power(X,2);!\\
&     &\verb!V=power(Y,2);!\\
&     &\\
    group      &{\bf BEGIN}&\verb!{!\\
&{\bf\ \ \ \  U:=X\^{}2;}& \verb!      U=power(x,2);!\\
&{\bf\ \ \ \  V:=Y\^{}2} & \verb!      V=power(Y,2);!\\
&{\bf END\$}&\verb!}!\\
& & \\\hline\hline
\end{tabular}
\caption{REDUCE forms translatable to C}
\end{table}

\subsection{Formal Definition}
The remainder of this section contains a formal definition of all
REDUCE expressions, statements, and prefix forms that can be translated by
GENTRAN into FORTRAN, RATFOR, PASCAL and C code.

\begin{describe}{Preliminary Definitions}
An {\it id\/} is an identifier.  Certain {\it id\/}'s are reserved words
and may not be used as array names or subprogram names.  The
complete list appears in the {\it Reserved Words\/} section.

A {\it string\/} consists of any number of characters (excluding double
quotes) which are enclosed in double quotes.
\end{describe}

\begin{describe}{Reserved Words}\index{reserved words}
The following reserved words may not be used as array names or
subprogram names\footnote{Note that names of other built-in REDUCE functions
{\it can\/} be translated, but remember that they will be translated
{\it literally\/} unless {\bf EVAL}'d first.  For example:
{\bf GENTRAN~DERIV~:=~DF(2*X\^{}2-X-1,~X)\$}
generates {\tt DERIV=DF(2*X**2-X-1,X)}
whereas
{\bf GENTRAN~DERIV~:=:~DF(2*X\^{}2-X-1,~X)\$}
generates {\tt DERIV=4*X-1} }:

{\bf AND, BLOCK, COND, DIFFERENCE, EQUAL, EXPT, FOR, GEQ,
GO, GREATERP, LEQ, LESSP, MAT, MINUS, NEQ, NOT, OR,
PLUS, PROCEDURE, PROGN, QUOTIENT, RECIP, REPEAT,
RETURN, SETQ, TIMES, WHILE, WRITE}
\end{describe} 

\subsubsection{Translatable REDUCE Expressions and Statements}
\begin{describe}{Expressions}
\begin{tabular}{lll}
\multicolumn{3}{l}{Arithmetic Expressions:} \\
& & \\
exp & ::= & {\it number} $\mid$  var  $\mid$  funcall  $\mid$  - exp $\mid$
/ exp  $\mid$  exp + exp  $\mid$ \\
	& & exp - exp $\mid$ exp * exp  $\mid$  exp / exp  $\mid$  exp ** exp
 $\mid$ \\
        & & exp \^{} exp  $\mid$ ( exp )\\\\
& & \\
var & ::= & {\it id} $\mid$ {\it id} ( exp$_1$, exp$_2$, \dots\ , exp$_n$ )
 $n > 0$ \\
& & \\
funcall & ::= & {\it id} ( arg$_1$, arg$_2$, \dots\ , arg$_n$ ) $n \geq 0$ \\
& & \\
arg & ::=  & exp $\mid$ logexp $\mid$ {\it string} \\
& &\\
\multicolumn{3}{l}{Logical Expressions:}\\
& & \\
logexp & ::= & {\it T} $\mid$ {\it NIL} $\mid$  var  $\mid$  funcall $\mid$
        exp $>$ exp  $\mid$  exp $>$= exp $\mid$\\
        & & exp = exp  $\mid$ exp {\it NEQ} exp $\mid$ exp $<$ exp $\mid$ \\
	& & exp $<$= exp $\mid$ {\it NOT\/} logexp  $\mid$ logexp {\it AND\/}
 logexp $\mid$ \\
        & & logexp {\it OR\/} logexp  $\mid$  ( logexp )\\
\end{tabular}
\end{describe}

\begin{describe}{Operator Precedence}
The following is a list of REDUCE arithmetic and logical
operators in order of decreasing precedence:
\begin{center}
** (or \^{})  /  *  ---  +  $<$  $<$=  $>$  $>$=  NEQ  = NOT  AND  OR
\end{center}

When unparenthesised expressions are translated which contain
operators whose precedence in REDUCE differs from that in the
target language, parentheses are automatically generated.  Thus
the meaning of the original expression is preserved\footnote{
For example in REDUCE, {\bf NOT~A~=~B} and {\bf NOT~(A~=~B)}
are equivalent, whereas in C, {\bf !~A~==~B} and {\bf (!A)~==~B}
are equivalent.  Therefore, {\bf NOT~A~=~B}
is translated into C code which forces the REDUCE precedence rules:
{\bf !(A~==~B)}
}.
\end{describe}
\begin{describe}{Statements}
\begin{tabular}{lll}
stmt & ::= & assign  $\mid$  break  $\mid$  cond  $\mid$  while $\mid$
           repeat  $\mid$  for  $\mid$  goto  $\mid$  label $\mid$ \\
& &   call  $\mid$  return  $\mid$  stop  $\mid$  stmtgp \\
\end{tabular}

Assignment Statements:

\begin{tabular}{llll}
assign & ::= & \multicolumn{2}{l}{var := assign'  $\mid$  matassign $\mid$
 cond}\\
& & & \\
assign' & ::= & \multicolumn{2}{l}{exp  $\mid$  logexp}\\
& & & \\
matassign & ::= & {\it id} := {\it MAT\/}(&(exp$_{11}$, \dots\ , exp$_{1m}$),\\
 & & &(exp$_{21}$, \dots\ , exp$_{2m}$ ),\\
 & & & \ \ \ \ \ \ :\\
 & & & \ \ \ \ \ \ :\\
 & & &( exp$_{n1}$, \dots\ , exp$_{nm}$ ) ) $n,m > 0$ \\
\end{tabular}

Break Statement:

break  ::= {\it BREAK()}

Conditional Statements:

\begin{tabular}{lll}
cond & ::= & {\it IF\/} logexp {\it THEN\/} stmt\\
& & {\it IF\/} logexp {\it THEN\/} stmt {\it ELSE\/} stmt\\
\end{tabular}

Loops:
\index{FOR loop} \index{WHILE loop} \index{REPEAT loop}

\begin{tabular}{lll} 
while & ::= & {\it WHILE\/} logexp {\it DO\/} stmt\\
& &\\
repeat & ::= & {\it REPEAT\/} stmt {\it UNTIL\/} logexp\\
& &\\
for & ::= & {\it FOR\/} var := exp {\it STEP\/} exp {\it UNTIL\/} exp
{\it DO\/} stmt $\mid$\\
& &{\it FOR\/} var := exp {\it UNTIL\/} exp {\it DO\/} stmt $\mid$\\
& &{\it FOR\/} var := exp : exp {\it DO\/} stmt $\mid$\\
& &var := for' $\mid$ \\
& &\\
for' & ::= & var := for' $\mid$\\
& &{\it FOR\/} var := exp {\it STEP\/} exp {\it UNTIL\/} exp {\it SUM\/} exp
 $\mid$\\
& &{\it FOR\/} var := exp {\it UNTIL\/} exp {\it SUM\/} exp $\mid$\\
& &{\it FOR\/} var := exp : exp {\it SUM\/} exp $\mid$\\
& &{\it FOR\/} var := exp {\it STEP\/} exp {\it UNTIL\/} exp\\
& & \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ {\it PRODUCT\/} exp $\mid$ \\
& &{\it FOR\/} var := exp {\it UNTIL\/} exp {\it PRODUCT\/} exp $\mid$\\
& &{\it FOR\/} var := exp : exp {\it PRODUCT\/} exp\\
\end{tabular}

Goto Statement:

\begin{tabular}{lll}
goto & ::= & {\it GOTO\/} label  $\mid$ {\it GO TO\/} label\\
label & ::= & {\it id\/} :\\
\end{tabular}

Subprogram Calls \& Returns \footnote{ Note that return statements can
only be translated from inside of procedure definitions.
\index{LITERAL command} The LITERAL function must be used to generate
a return statement from anywhere else.}:

\begin{tabular}{lll}
call & ::= & {\it id\/} ( arg$_1$, arg$_2$, \dots\ , arg$_n$ ) $n \geq 0$\\
& &\\
return & ::= & {\it RETURN\/} $\mid$ {\it RETURN\/} arg\\
\end{tabular}

Stop \& Exit Statements \footnote{
In certain cases it may be convenient to generate a FORTRAN
STOP statement or a C EXIT statement.  Since there is no
semantically equivalent REDUCE statement, STOP() can be used
and will be translated appropriately.}:

stop  ::= {\it STOP\/}()

Statement Groups \footnote{
Note that REDUCE BEGIN\dots\ END statement groups are translated
into RATFOR or C \{\dots\ \} statement groups, whereas
REDUCE $<$$<$\dots\ $>$$>$ statement groups are translated into RATFOR or
C statement {\it sequences}.  When the target language is FORTRAN, both
types of REDUCE statement groups are translated into statement
sequences.}:

\begin{tabular}{lll}
stmtgp & ::= & $<$$<$ stmt$_1$ ; stmt$_2$ ; \dots\  ; stmt$_n$ $>$$>$
 $\mid$\\
& &{\it BEGIN\/} stmt$_1$ ; stmt$_2$ ; \dots\  ; stmt$_n$ {\it END\/} $ n >
 0$\\
\end{tabular}
\end{describe}
\begin{describe}{Subprogram Definitions}
\begin{tabular}{lll} 
defn & ::= & {\it PROCEDURE id\/} ({\it id$_1$, id$_2$, \dots\ , id$_n$\/}) ;
 stmt $\mid$\\
& & {\it PROCEDURE id\/} ({\it id$_1$, id$_2$, \dots\ , id$_n$\/}) ;
 exp\ \ \ \ \ \  $n \geq 0$ \\
\end{tabular}
\end{describe}

\subsubsection{Translatable REDUCE Prefix Forms}
\begin{describe}{Expressions}

Arithmetic Expressions:

\begin{tabular}{lll}
exp & ::= & {\it number\/} $\mid$  funcall  $\mid$  var  $\mid$ 
({\it DIFFERENCE\/} exp exp) $\mid$\\
& &({\it EXPT\/} exp exp)  $\mid$  ({\it MINUS\/} exp)  $\mid$  ({\it PLUS\/}
 exp exp') $\mid$\\
& & ({\it QUOTIENT\/} exp exp)  $\mid$  ({\it RECIP\/} exp) $\mid$\\
& & ({\it TIMES\/} exp exp exp')  $\mid$  ({\it !*SQ\/} sqform)\\
\end{tabular}

where sqform is a standard quotient form equivalent to any acceptable prefix
form.

exp' ::=  exp$_1$ exp$_2$ \dots\  exp$_n$  $n \geq 0$

Logical Expressions:

\begin{tabular}{lll}
logexp & ::= & {\it NIL\/} $\mid$ {\it T\/} $\mid$  funcall  $\mid$  var
$\mid$\\
& &  ({\it AND\/} logexp logexp logexp')  $\mid$  ({\it EQUAL\/} exp exp)
$\mid$\\
& & ({\it GEQ\/} exp exp)  $\mid$  ({\it GREATERP\/} exp exp)  $\mid$ \\
& & ({\it LEQ\/} exp exp) $\mid$ ({\it LESSP\/} exp exp)  $\mid$ \\
& & ({\it NEQ\/} exp exp) $\mid$ ({\it NOT\/} logexp) $\mid$ \\
& & ({\it OR\/} logexp logexp logexp')\\
& &\\
logexp' & ::= & logexp$_1$ logexp$_2$ \dots\  logexp$_n$  $n \geq 0$\\
\end{tabular}
\end{describe}

\begin{describe}{Statements}
\begin{tabular}{lll}
stmt & ::= &  assign  $\mid$  break  $\mid$  call  $\mid$  cond  $\mid$
for  $\mid$  goto $\mid$\\
& & label  $\mid$  read  $\mid$  repeat  $\mid$  return  $\mid$  stmtgp
$\mid$\\
& & stop  $\mid$  while  $\mid$  write \\
& &\\
stmt' &  ::= & stmt$_1$ stmt$_2$ \dots\  stmt$_n$   $n \geq 0$\\
\end{tabular}

Assignment Statements:

assign  ::=  ({\it SETQ\/} var exp)  $\mid$  ({\it SETQ\/} var logexp) $\mid$
             ({\it SETQ\/} id ({\it MAT\/} list list'))

Conditional Statements:

\begin{tabular}{lll}
cond & ::= & ({\it COND\/} (logexp stmt) cond1) \\
& & \\
cond1 & ::= & (logexp stmt$_1$) \dots\  (logexp stmt$_n$) $n \geq 0$\\
\end{tabular}

Loops:

\begin{tabular}{lll}
for & ::= & ({\it FOR\/} var (exp exp exp) {\it DO\/} stmt) $\mid$\\
& &  ({\it SETQ\/} var ({\it FOR\/} var (exp exp exp) {\it SUM\/} exp) $\mid$\\
& & ({\it SETQ\/} var ({\it FOR\/} var (exp exp exp) \\
& & \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ {\it PRODUCT\/} exp)\\
& &\\
repeat & ::= & ({\it REPEAT\/} stmt logexp)\\
& &\\
while & ::= & ({\it WHILE\/} logexp stmt)
\end{tabular}

Go To Statements:

\begin{tabular}{lll} 
break & ::= & ({\it BREAK\/})\\
& & \\
goto & ::= & ({\it GO\/} label)\\
& & \\
label & ::= & {\it id}\\
\end{tabular}

Subprogram Calls \& Returns:

\begin{tabular}{lll}
call & ::= & ({\it id\/} arg')\\
& &\\
return & ::= & ({\it RETURN\/})  $\mid$  ({\it RETURN\/} arg)\\
\end{tabular}

Stop \& Exit Statements:

stop ::= ({\it STOP\/})

Statement Groups:

stmtgp  ::=  ({\it PROGN\/} stmt stmt')  $\mid$  ({\it BLOCK\/} (id') stmt')

I/O Statements:

\begin{tabular}{lll}
read & ::= & ({\it SETQ\/} var ({\it READ\/}))\\
& &\\
write & ::= & ({\it WRITE\/} arg arg')\\
\end{tabular}

Subprogram Definitions:

defn  ::=  ({\it PROCEDURE id NIL EXPR\/} (id') stmt)

\end{describe}

\begin{describe}{Miscellaneous}
\begin{tabular}{lll} 
funcall & ::= & ({\it id\/} arg')\\
& &\\
var & ::= & {\it id\/} $\mid$  ({\it id\/} exp exp')\\
& &\\
arg & ::= & {\it string\/} $\mid$  exp  $\mid$  logexp\\
& &\\
arg' & ::= & arg$_1$ arg$_2$ \dots\  arg$_n$  $n \geq 0$ \\
& &\\
list & ::= & (exp exp')\\
& &\\
list' & ::= & list$_1$ list$_2$ \dots\  list$_n$   $n \geq 0$ \\
& &\\
id' &  ::= & {\it id$_1$ id$_2$} \dots\ {\it id$_n$}  $n \geq 0$ \\
\end{tabular}
\end{describe}

\section{List of Commands, Switches, \& Variables}
\label{appb}
\begin{describe}{COMMANDS}
\index{GENTRAN command}
{\bf GENTRAN} {\it stmt\/} [{\bf OUT}{\it  f1,f2,\dots\ ,fn\/}]{\it ;}

\index{GENTRANIN command}
{\bf GENTRANIN} {\it f1,f2,\dots\ ,fm\/} [{\bf OUT}{\it  f1,f2,\dots\
,fn\/}]{\it ;}

\index{GENTRANOUT command}
{\bf GENTRANOUT} {\it f1,f2,\dots\ ,fn;}

\index{GENTRANSHUT command}
{\bf GENTRANSHUT} {\it f1,f2,\dots\ ,fn;}

\index{GENTRANPUSH command}
{\bf GENTRANPUSH} {\it f1,f2,\dots\ ,fn;}

\index{GENTRANPOP command}
{\bf GENTRANPOP} {\it f1,f2,\dots\ ,fn;}
\end{describe}

\begin{describe}{SPECIAL FUNCTIONS \& OPERATORS}

\ttindex{EVAL}
{\bf EVAL} {\it exp}

\index{::=}
{\it var} {\bf ::=} {\it exp;}

\index{:=:}
{\it var} {\bf :=:} {\it exp;}

\index{::=:}
{\it var} {\bf ::=:} {\it exp;}

\ttindex{LSETQ}
{\it var} {\bf LSETQ} {\it exp;}

\ttindex{RSETQ}
{\it var} {\bf RSETQ} {\it exp;}

\ttindex{LRSETQ}
{\it var} {\bf LRSETQ} {\it exp;}

\index{DECLARE function}
{\bf DECLARE} {\it v1,v2,\dots\ ,vn\/}{\bf :} {\it  type;}

\begin{tabular}{ll}
{\bf DECLARE}\\
{\bf $<$$<$}\\
&{\it v11,v12,\dots\ ,v1n} {\bf :} {\it type1\/}{\bf ;}\\
&{\it v12,v22,\dots\ ,v2n} {\bf :} {\it type2\/}{\bf ;}\\
& \ \ \ :\\
& \ \ \ :\\
&{\it vm1,vm2,\dots\ ,vmn} {\bf :} {\it typen\/}{\bf ;}\\
{\bf $>$$>$}{\it ;}
\end{tabular}

\ttindex{LITERAL}
{\bf LITERAL} {\it arg1,arg2,\dots\ ,argn;}
\end{describe}

\begin{describe}{MODE SWITCHES}
{\bf PERIOD} \index{PERIOD switch}

{\bf GENTRANSEG} \index{GENTRANSEG switch}

{\bf GENDECS} \index{GENDECS switch}

{\bf DOUBLE} \index{DOUBLE switch}

{\bf MAKECALLS} \index{MAKECALLS switch}

{\bf KEEPDECS} \index{KEEPDECS switch}

{\bf GETDECS} \index{GETDECS switch}

\end{describe}

\begin{describe}{VARIABLES}
{\bf GENTRANLANG!*}  \ttindex{GENTRANLANG!*}

{\bf MAXEXPPRINTLEN!*}  \ttindex{MAXEXPPRINTLEN!*}

{\bf TEMPVARNAME!*}  \ttindex{TEMPVARNAME!*}

{\bf TEMPVARNUM!*}  \ttindex{TEMPVARNUM!*}

{\bf TEMPVARTYPE!*}  \ttindex{TEMPVARTYPE!*}

{\bf GENSTMTNUM!*}  \ttindex{GENSTMTNUM!*}

{\bf GENSTMTINCR!*}  \ttindex{GENSTMTINCR!*}

{\bf TABLEN!*}  \ttindex{TABLEN!*}

{\bf FORTLINELEN!*}  \ttindex{FORTLINELEN!*}

{\bf RATLINELEN!*}  \ttindex{RATLINELEN!*}

{\bf CLINELEN!*}  \ttindex{CLINELEN!*}

{\bf PASCLINELEN!*}  \ttindex{PASCLINELEN!*}

{\bf MINFORTLINELEN!*}  \ttindex{MINFORTLINELEN!*}

{\bf MINRATLINELEN!*}  \ttindex{MINRATLINELEN!*}

{\bf MINCLINELEN!*}  \ttindex{MINCLINELEN!*}

{\bf MINPASCLINELEN!*}  \ttindex{MINPASCLINELEN!*}

{\bf DEFTYPE!*} \ttindex{DEFTYPE!*}
\end{describe}

\begin{describe}{TEMPORARY VARIABLE GENERATION, MARKING \& UNMARKING}
{\bf TEMPVAR} {\it type;} \ttindex{TEMPVAR}

{\bf MARKVAR} {\it var;} \ttindex{MARKVAR}

{\bf UNMARKVAR} {\it var;} \ttindex{UNMARKVAR}
\end{describe}

\begin{describe}{EXPLICIT GENERATION OF TYPE DECLARATIONS}
{\bf GENDECS} {\it subprogname;} \ttindex{GENDECS switch}
\end{describe}

\begin{describe}{SYMBOLIC MODE FUNCTIONS}
{\bf SYM!-GENTRAN} {\it form;} \index{SYM"!-GENTRAN command}

{\bf SYM!-GENTRANIN} {\it list-of-fnames;} \index{SYM"!-GENTRANIN command}

{\bf SYM!-GENTRANOUT} {\it list-of-fnames;} \index{SYM"!-GENTRANOUT command}

{\bf SYM!-GENTRANSHUT} {\it list-of-fnames;} \index{SYM"!-GENTRANSHUT command}

{\bf SYM!-GENTRANPUSH} {\it list-of-fnames;} \index{SYM"!-GENTRANPUSH command}

{\bf SYM!-GENTRANPOP} {\it list-of-fnames;} \index{SYM"!-GENTRANPOP command}
\end{describe}

\begin{describe}{SYMBOLIC MODE SPECIAL FORMS}
\begin{tabular}{ll}
\ttindex{DECLARE}
{\bf (DECLARE} & {\bf (}{\it type1 v11 v12 \dots\  v1n\/}{\bf )}\\
& {\bf (}{\it type2 v21 v22 \dots\  v2n\/}{\bf )}\\
& \ \ \ :\\
& \ \ \ :\\
& {\bf (}{\it typen vn1 vn2 \dots\  vnn\/}{\bf ))}\\
\end{tabular}

{\bf (LITERAL} {\it arg1 arg2 \dots\  argn\/}{\bf )} \ttindex{LITERAL}

{\bf (EVAL} {\it exp\/}{\bf )} \ttindex{EVAL}

{\bf (LSETQ} {\it var exp\/}{\bf )} \ttindex{LSETQ}

{\bf (RSETQ} {\it var exp\/}{\bf )} \ttindex{RSETQ}

{\bf (LRSETQ} {\it var exp\/}{\bf )} \ttindex{LRSETQ}
\end{describe}

\section{The Programs {\tt M1.F} and {\tt M2.F}.}
\label{appc}

This section contains the two files generated in chapter 6.
Contents of file m1.f:
\begin{framedverbatim}
      M(1,1)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*Y*J30)+DSIN(DBLE(Q3))**2*J30Z+18.0D0*DCOS(DBLE
     . (Q3))*DCOS(DBLE(Q2))*P**2*M30+18.0D0*P**2*M30+P**2*M10
     . +J30Y+J10Y
      M(1,2)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*J30Y)+DSIN(DBLE(Q3))**2*J30Z+9.0D0*DCOS(DBLE(
     . Q3))*DCOS(DBLE(Q2))*P**2*M30+9.0D0*P**2*M30+J30Y
      M(1,3)=-(9.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*P**2*M30)
      M(2,2)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*J30Y)+DSIN(DBLE(Q3))**2*J30Z+9.0D0*P**2*M30+
     . J30Y
      M(2,3)=0.0D0
      M(3,3)=9.0D0*P**2*M30+J30X
      MIV(1,1)=(-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2)-(
     . 9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y)+9.0D0*DSIN(DBLE
     . (Q3))**2*P**2*M30*J30Z-(9.0D0*DSIN(DBLE(Q3))**2*P**2*
     . M30*J30X)-(DSIN(DBLE(Q3))**2*J30Y*J30X)+DSIN(DBLE(Q3))
     . **2*J30Z*J30X+81.0D0*P**4*M30**2+9.0D0*P**2*M30*J30Y+
     . 9.0D0*P**2*M30*J30X+J30Y*J30X)/(729.0D0*DSIN(DBLE(Q3))
     . **4*DSIN(DBLE(Q2))**2*P**6*M30**3+81.0D0*DSIN(DBLE(Q3
     . ))**4*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Y-(81.0D0*DSIN(
     . DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Z)+
     . 81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*M30**2*J30-(81.0D0*
     . DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)+9.0D0*DSIN(DBLE(Q3
     . ))**4*P**2*Y*M30*J30Y*J30-(9.0D0*DSIN(DBLE(Q3))**4*P**
     . 2*Y*M30*J30Z*J30)+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*
     . J30X*J30-(9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN
     . (DBLE(Q3))**4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*
     . J30Y*J30X*J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(
     . DSIN(DBLE(Q3))**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y
     . *J30Z*J30X-(729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**
     . 2*P**6*M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2)
     . )**2*P**4*M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6
     . *M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*
     . DSIN(DBLE(Q3))**2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P
     . **4*M30**2*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*
     . J30Y*M10)+9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(
     . 9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN
     . (DBLE(Q3))**2*P**2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3
     . ))**2*P**2*Y*M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**
     . 2*M30*J30Y**2-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*
     . J10Y)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y+9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0*DSIN(DBLE
     . (Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))**2*P**2*
     . J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*M10*J30X-(
     . DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE(Q3))**2*
     . J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*J30X)+DSIN(
     . DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(DBLE(Q3))**2
     . *DCOS(DBLE(Q2))**2*P**6*M30**3)-(81.0D0*DCOS(DBLE(Q3))
     . **2*DCOS(DBLE(Q2))**2*P**4*M30**2*J30X)+729.0D0*P**6*
     . M30**3+81.0D0*P**6*M30**2*M10+81.0D0*P**4*M30**2*J30Y+
     . 81.0D0*P**4*M30**2*J10Y+81.0D0*P**4*M30**2*J30X+9.0D0*
     . P**4*M30*J30Y*M10+9.0D0*P**4*M30*M10*J30X+9.0D0*P**2*
     . M30*J30Y*J10Y+9.0D0*P**2*M30*J30Y*J30X+9.0D0*P**2*M30*
     . J10Y*J30X+P**2*J30Y*M10*J30X+J30Y*J10Y*J30X)
      MIV(1,2)=(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Y-(9.0D0*DSIN(DBLE(Q3))
     . **2*P**2*M30*J30Z)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*
     . J30X+DSIN(DBLE(Q3))**2*J30Y*J30X-(DSIN(DBLE(Q3))**2*
     . J30Z*J30X)-(81.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P**4*
     . M30**2)-(9.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P**2*M30*
     . J30X)-(81.0D0*P**4*M30**2)-(9.0D0*P**2*M30*J30Y)-(
     . 9.0D0*P**2*M30*J30X)-(J30Y*J30X))/(729.0D0*DSIN(DBLE(
     . Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30**3+81.0D0*DSIN(DBLE
     . (Q3))**4*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Y-(81.0D0*
     . DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Z)+
     . 81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*M30**2*J30-(81.0D0*
     . DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)+9.0D0*DSIN(DBLE(Q3
     . ))**4*P**2*Y*M30*J30Y*J30-(9.0D0*DSIN(DBLE(Q3))**4*P**
     . 2*Y*M30*J30Z*J30)+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*
     . J30X*J30-(9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN
     . (DBLE(Q3))**4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*
     . J30Y*J30X*J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(
     . DSIN(DBLE(Q3))**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y
     . *J30Z*J30X-(729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**
     . 2*P**6*M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2)
     . )**2*P**4*M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6
     . *M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*
     . DSIN(DBLE(Q3))**2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P
     . **4*M30**2*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*
     . J30Y*M10)+9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(
     . 9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN
     . (DBLE(Q3))**2*P**2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3
     . ))**2*P**2*Y*M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**
     . 2*M30*J30Y**2-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*
     . J10Y)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y+9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0*DSIN(DBLE
     . (Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))**2*P**2*
     . J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*M10*J30X-(
     . DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE(Q3))**2*
     . J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*J30X)+DSIN(
     . DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(DBLE(Q3))**2
     . *DCOS(DBLE(Q2))**2*P**6*M30**3)-(81.0D0*DCOS(DBLE(Q3))
     . **2*DCOS(DBLE(Q2))**2*P**4*M30**2*J30X)+729.0D0*P**6*
     . M30**3+81.0D0*P**6*M30**2*M10+81.0D0*P**4*M30**2*J30Y+
     . 81.0D0*P**4*M30**2*J10Y+81.0D0*P**4*M30**2*J30X+9.0D0*
     . P**4*M30*J30Y*M10+9.0D0*P**4*M30*M10*J30X+9.0D0*P**2*
     . M30*J30Y*J10Y+9.0D0*P**2*M30*J30Y*J30X+9.0D0*P**2*M30*
     . J10Y*J30X+P**2*J30Y*M10*J30X+J30Y*J10Y*J30X)
      MIV(1,3)=(-(81.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**
     . 4*M30**2)-(9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2
     . *M30*J30Y)+9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2
     . *M30*J30Z+81.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*P**4*
     . M30**2+9.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*P**2*M30*
     . J30Y)/(729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**
     . 6*M30**3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P
     . **4*M30**2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2
     . ))**2*P**4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*
     . Y*M30**2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*
     . J30Y)+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)+9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30X*J30-(9.0D0*DSIN(DBLE
     . (Q3))**4*P**2*M30*J30Y**2)+9.0D0*DSIN(DBLE(Q3))**4*P**
     . 2*M30*J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y
     . *J30X)+DSIN(DBLE(Q3))**4*Y*J30Y*J30X*J30-(DSIN(DBLE(Q3
     . ))**4*Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3))**4*J30Y**2*J30X
     . )+DSIN(DBLE(Q3))**4*J30Y*J30Z*J30X-(729.0D0*DSIN(DBLE(
     . Q3))**2*DSIN(DBLE(Q2))**2*P**6*M30**3)-(81.0D0*DSIN(
     . DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Y)-(
     . 729.0D0*DSIN(DBLE(Q3))**2*P**6*M30**3)-(81.0D0*DSIN(
     . DBLE(Q3))**2*P**6*M30**2*M10)-(81.0D0*DSIN(DBLE(Q3))**
     . 2*P**4*Y*M30**2*J30)+81.0D0*DSIN(DBLE(Q3))**2*P**4*M30
     . **2*J30Z-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*J10Y)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*J30X)-(9.0D0*DSIN
     . (DBLE(Q3))**2*P**4*M30*J30Y*M10)+9.0D0*DSIN(DBLE(Q3))
     . **2*P**4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30*M10*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*M30*J30Y
     . *J30)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*M30*J30X*J30)+
     . 9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2-(9.0D0*DSIN(
     . DBLE(Q3))**2*P**2*M30*J30Y*J10Y)+9.0D0*DSIN(DBLE(Q3))
     . **2*P**2*M30*J30Z*J10Y+9.0D0*DSIN(DBLE(Q3))**2*P**2*
     . M30*J30Z*J30X-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J10Y*
     . J30X)-(DSIN(DBLE(Q3))**2*P**2*J30Y*M10*J30X)+DSIN(DBLE
     . (Q3))**2*P**2*J30Z*M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*
     . J30X*J30)+DSIN(DBLE(Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3
     . ))**2*J30Y*J10Y*J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X
     . -(729.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30
     . **3)-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0*
     . P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2*
     . M30*J30Y*J30X+9.0D0*P**2*M30*J10Y*J30X+P**2*J30Y*M10*
     . J30X+J30Y*J10Y*J30X)
      MIV(2,2)=(-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*
     . P**4*M30**2)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2)-(
     . 9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*M30*J30)+9.0D0*DSIN(
     . DBLE(Q3))**2*P**2*M30*J30Z-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*M30*J30X)-(DSIN(DBLE(Q3))**2*Y*J30X*J30)+DSIN(DBLE
     . (Q3))**2*J30Z*J30X+162.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2
     . ))*P**4*M30**2+18.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P
     . **2*M30*J30X+162.0D0*P**4*M30**2+9.0D0*P**4*M30*M10+
     . 9.0D0*P**2*M30*J30Y+9.0D0*P**2*M30*J10Y+18.0D0*P**2*
     . M30*J30X+P**2*M10*J30X+J30Y*J30X+J10Y*J30X)/(729.0D0*
     . DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30**3+81.0D0
     . *DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Y-
     . (81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*M30**
     . 2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*M30**2*J30-(
     . 81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)+9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*DSIN(DBLE(Q3))
     . **4*P**2*Y*M30*J30Z*J30)+9.0D0*DSIN(DBLE(Q3))**4*P**2*
     . Y*M30*J30X*J30-(9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y
     . **2)+9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0
     . *DSIN(DBLE(Q3))**4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))
     . **4*Y*J30Y*J30X*J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30
     . )-(DSIN(DBLE(Q3))**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*
     . J30Y*J30Z*J30X-(729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2
     . ))**2*P**6*M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE
     . (Q2))**2*P**4*M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*
     . P**6*M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10
     . )-(81.0D0*DSIN(DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*
     . DSIN(DBLE(Q3))**2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P
     . **4*M30**2*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*
     . J30Y*M10)+9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(
     . 9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN
     . (DBLE(Q3))**2*P**2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3
     . ))**2*P**2*Y*M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**
     . 2*M30*J30Y**2-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*
     . J10Y)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y+9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0*DSIN(DBLE
     . (Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))**2*P**2*
     . J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*M10*J30X-(
     . DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE(Q3))**2*
     . J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*J30X)+DSIN(
     . DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(DBLE(Q3))**2
     . *DCOS(DBLE(Q2))**2*P**6*M30**3)-(81.0D0*DCOS(DBLE(Q3))
     . **2*DCOS(DBLE(Q2))**2*P**4*M30**2*J30X)+729.0D0*P**6*
     . M30**3+81.0D0*P**6*M30**2*M10+81.0D0*P**4*M30**2*J30Y+
     . 81.0D0*P**4*M30**2*J10Y+81.0D0*P**4*M30**2*J30X+9.0D0*
     . P**4*M30*J30Y*M10+9.0D0*P**4*M30*M10*J30X+9.0D0*P**2*
     . M30*J30Y*J10Y+9.0D0*P**2*M30*J30Y*J30X+9.0D0*P**2*M30*
     . J10Y*J30X+P**2*J30Y*M10*J30X+J30Y*J10Y*J30X)
      MIV(2,3)=(81.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**4*
     . M30**2+9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2*M30
     . *J30Y-(9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2*M30
     . *J30Z)-(81.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*DCOS(DBLE
     . (Q3))*DCOS(DBLE(Q2))*P**4*M30**2)-(81.0D0*DSIN(DBLE(Q3
     . ))*DSIN(DBLE(Q2))*P**4*M30**2)-(9.0D0*DSIN(DBLE(Q3))*
     . DSIN(DBLE(Q2))*P**2*M30*J30Y))/(729.0D0*DSIN(DBLE(Q3))
     . **4*DSIN(DBLE(Q2))**2*P**6*M30**3+81.0D0*DSIN(DBLE(Q3)
     . )**4*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Y-(81.0D0*DSIN(
     . DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Z)+
     . 81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*M30**2*J30-(81.0D0*
     . DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)+9.0D0*DSIN(DBLE(Q3
     . ))**4*P**2*Y*M30*J30Y*J30-(9.0D0*DSIN(DBLE(Q3))**4*P**
     . 2*Y*M30*J30Z*J30)+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*
     . J30X*J30-(9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN
     . (DBLE(Q3))**4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*
     . J30Y*J30X*J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(
     . DSIN(DBLE(Q3))**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y
     . *J30Z*J30X-(729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**
     . 2*P**6*M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2)
     . )**2*P**4*M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6
     . *M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*
     . DSIN(DBLE(Q3))**2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P
     . **4*M30**2*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*
     . J30Y*M10)+9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(
     . 9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN
     . (DBLE(Q3))**2*P**2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3
     . ))**2*P**2*Y*M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**
     . 2*M30*J30Y**2-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*
     . J10Y)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y+9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0*DSIN(DBLE
     . (Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))**2*P**2*
     . J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*M10*J30X-(
     . DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE(Q3))**2*
     . J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*J30X)+DSIN(
     . DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(DBLE(Q3))**2
     . *DCOS(DBLE(Q2))**2*P**6*M30**3)-(81.0D0*DCOS(DBLE(Q3))
     . **2*DCOS(DBLE(Q2))**2*P**4*M30**2*J30X)+729.0D0*P**6*
     . M30**3+81.0D0*P**6*M30**2*M10+81.0D0*P**4*M30**2*J30Y+
     . 81.0D0*P**4*M30**2*J10Y+81.0D0*P**4*M30**2*J30X+9.0D0*
     . P**4*M30*J30Y*M10+9.0D0*P**4*M30*M10*J30X+9.0D0*P**2*
     . M30*J30Y*J10Y+9.0D0*P**2*M30*J30Y*J30X+9.0D0*P**2*M30*
     . J10Y*J30X+P**2*J30Y*M10*J30X+J30Y*J10Y*J30X)
      MIV(3,3)=(9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30-(9.0D0
     . *DSIN(DBLE(Q3))**4*P**2*M30*J30Y)+DSIN(DBLE(Q3))**4*Y*
     . J30Y*J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30)-(DSIN(DBLE(Q3)
     . )**4*J30Y**2)+DSIN(DBLE(Q3))**4*J30Y*J30Z-(81.0D0*DSIN
     . (DBLE(Q3))**2*P**4*M30**2)-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **4*M30*M10)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*M30*J30)+
     . 9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z-(9.0D0*DSIN(DBLE
     . (Q3))**2*P**2*M30*J10Y)-(DSIN(DBLE(Q3))**2*P**2*J30Y*
     . M10)+DSIN(DBLE(Q3))**2*P**2*J30Z*M10-(DSIN(DBLE(Q3))**
     . 2*Y*J30Y*J30)+DSIN(DBLE(Q3))**2*J30Y**2-(DSIN(DBLE(Q3)
     . )**2*J30Y*J10Y)+DSIN(DBLE(Q3))**2*J30Z*J10Y-(81.0D0*
     . DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*M30**2)+
     . 81.0D0*P**4*M30**2+9.0D0*P**4*M30*M10+9.0D0*P**2*M30*
     . J30Y+9.0D0*P**2*M30*J10Y+P**2*J30Y*M10+J30Y*J10Y)/(
     . 729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30**
     . 3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*M30
     . **2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P
     . **4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*M30**
     . 2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)+
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)+9.0D0*DSIN(DBLE
     . (Q3))**4*P**2*Y*M30*J30X*J30-(9.0D0*DSIN(DBLE(Q3))**4*
     . P**2*M30*J30Y**2)+9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*
     . J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y*J30X)
     . +DSIN(DBLE(Q3))**4*Y*J30Y*J30X*J30-(DSIN(DBLE(Q3))**4*
     . Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3))**4*J30Y**2*J30X)+DSIN
     . (DBLE(Q3))**4*J30Y*J30Z*J30X-(729.0D0*DSIN(DBLE(Q3))**
     . 2*DSIN(DBLE(Q2))**2*P**6*M30**3)-(81.0D0*DSIN(DBLE(Q3)
     . )**2*DSIN(DBLE(Q2))**2*P**4*M30**2*J30Y)-(729.0D0*DSIN
     . (DBLE(Q3))**2*P**6*M30**3)-(81.0D0*DSIN(DBLE(Q3))**2*P
     . **6*M30**2*M10)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*Y*M30**
     . 2*J30)+81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*J30Z-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*J10Y)-(81.0D0*
     . DSIN(DBLE(Q3))**2*P**4*M30**2*J30X)-(9.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30*J30Y*M10)+9.0D0*DSIN(DBLE(Q3))**2*P**
     . 4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*M10*
     . J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*M30*J30Y*J30)-(
     . 9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*M30*J30X*J30)+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2-(9.0D0*DSIN(DBLE(Q3
     . ))**2*P**2*M30*J30Y*J10Y)+9.0D0*DSIN(DBLE(Q3))**2*P**2
     . *M30*J30Z*J10Y+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*
     . J30X-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J10Y*J30X)-(
     . DSIN(DBLE(Q3))**2*P**2*J30Y*M10*J30X)+DSIN(DBLE(Q3))**
     . 2*P**2*J30Z*M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*J30X*
     . J30)+DSIN(DBLE(Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3))**2
     . *J30Y*J10Y*J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X-(
     . 729.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30**
     . 3)-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0
     . *P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2
     . *M30*J30Y*J30X+9.0D0*P**2*M30*J10Y*J30X+P**2*J30Y*M10*
     . J30X+J30Y*J10Y*J30X)
      DO 25005 J=1,3
          DO 25006 K=J+1,3
              M(K,J)=M(J,K)
              MIV(K,J)=MIV(J,K)
25006     CONTINUE
25005 CONTINUE
\end{framedverbatim}

\newpage

Contents of file m2.f:
\begin{framedverbatim}
      M(1,1)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*Y*J30)+DSIN(DBLE(Q3))**2*J30Z+18.0D0*DCOS(DBLE
     . (Q3))*DCOS(DBLE(Q2))*P**2*M30+18.0D0*P**2*M30+P**2*M10
     . +J30Y+J10Y(1,2)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(
     . DSIN(DBLE(Q3))**2*J30Y)+DSIN(DBLE(Q3))**2*J30Z+9.0D0*
     . DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P**2*M30+9.0D0*P**2*M30+
     . J30Y(1,3)=-(9.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*P**2*
     . M30)
      M(2,2)=-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30)-(DSIN(DBLE(
     . Q3))**2*J30Y)+DSIN(DBLE(Q3))**2*J30Z+9.0D0*P**2*M30+
     . J30Y
      M(2,3)=0.0D0
      M(3,3)=9.0D0*P**2*M30+J30X
      T1=-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2)-(9.0D0*DSIN(
     . DBLE(Q3))**2*P**2*M30*J30Y)+9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*M30*J30Z-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30X)-(
     . DSIN(DBLE(Q3))**2*J30Y*J30X)+DSIN(DBLE(Q3))**2*J30Z*
     . J30X+81.0D0*P**4*M30**2+9.0D0*P**2*M30*J30Y+9.0D0*P**2
     . *M30*J30X+J30Y*J30X
      T0=729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30
     . **3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**
     . 2*P**4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*
     . M30**2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)
     . +9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)
      T0=T0+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30X*J30-(
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))
     . **4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*J30Y*J30X*
     . J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3)
     . )**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y*J30Z*J30X-(
     . 729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**6*M30**
     . 3)
      T0=T0-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6*M30**3)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(81.0D0*DSIN
     . (DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*DSIN(DBLE(Q3))
     . **2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*
     . J30X)
      T0=T0-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Y*M10)+9.0D0
     . *DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*
     . M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2
     . -(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*J10Y)+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y
      T0=T0+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))
     . **2*P**2*J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*
     . M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE
     . (Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*
     . J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(
     . DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30**3)
      T0=T0-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0*
     . P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2*
     ; M30*J30Y*J30X
      MIV(1,1)=T1/(T0+9.0D0*P**2*M30*J10Y*J30X+P**2*J30Y*M10*
     . J30X+J30Y*J10Y*J30X)
      T0=81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2+9.0D0*DSIN(DBLE
     . (Q3))**2*P**2*M30*J30Y-(9.0D0*DSIN(DBLE(Q3))**2*P**2*
     . M30*J30Z)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30X+DSIN(
     . DBLE(Q3))**2*J30Y*J30X-(DSIN(DBLE(Q3))**2*J30Z*J30X)-(
     . 81.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P**4*M30**2)-(
     . 9.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P**2*M30*J30X)-(
     . 81.0D0*P**4*M30**2)-(9.0D0*P**2*M30*J30Y)
      T1=729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30
     . **3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**
     . 2*P**4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*
     . M30**2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)
     . +9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)
      T1=T1+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30X*J30-(
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))
     . **4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*J30Y*J30X*
     . J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3)
     . )**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y*J30Z*J30X-(
     . 729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**6*M30**
     . 3)
      T1=T1-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6*M30**3)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(81.0D0*DSIN
     . (DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*DSIN(DBLE(Q3))
     . **2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*
     . J30X)
      T1=T1-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Y*M10)+9.0D0
     . *DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*
     . M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2
     . -(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*J10Y)+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y
      T1=T1+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))
     . **2*P**2*J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*
     . M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE
     . (Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*
     . J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(
     . DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30**3)
      T1=T1-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0*
     . P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2*
     . M30*J30Y*J30X
      MIV(1,2)=(T0-(9.0D0*P**2*M30*J30X)-(J30Y*J30X))/(T1+
     . 9.0D0*P**2*M30*J10Y*J30X+P**2*J30Y*M10*J30X+J30Y*J10Y*
     . J30X)
      T0=729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30
     . **3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**
     . 2*P**4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*
     . M30**2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)
     . +9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)
      T0=T0+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30X*J30-(
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))
     . **4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*J30Y*J30X*
     . J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3)
     . )**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y*J30Z*J30X-(
     . 729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**6*M30**
     . 3)
      T0=T0-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6*M30**3)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(81.0D0*DSIN
     . (DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*DSIN(DBLE(Q3))
     . **2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*
     . J30X)
      T0=T0-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Y*M10)+9.0D0
     . *DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*
     . M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2
     . -(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*J10Y)+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y
      T0=T0+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))
     . **2*P**2*J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*
     . M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE
     . (Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*
     . J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(
     . DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30**3)
      T0=T0-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0*
     . P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2*
     . M30*J30Y*J30X
      MIV(1,3)=(-(81.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**
     . 4*M30**2)-(9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2
     . *M30*J30Y)+9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2
     . *M30*J30Z+81.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*P**4*
     . M30**2+9.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*P**2*M30*
     . J30Y)/(T0+9.0D0*P**2*M30*J10Y*J30X+P**2*J30Y*M10*J30X+
     . J30Y*J10Y*J30X)
      T0=-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*
     . M30**2)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2)-(9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*Y*M30*J30)+9.0D0*DSIN(DBLE(Q3))
     . **2*P**2*M30*J30Z-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*
     . J30X)-(DSIN(DBLE(Q3))**2*Y*J30X*J30)+DSIN(DBLE(Q3))**2
     . *J30Z*J30X+162.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P**4*
     . M30**2+18.0D0*DCOS(DBLE(Q3))*DCOS(DBLE(Q2))*P**2*M30*
     . J30X+162.0D0*P**4*M30**2
      T1=729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30
     . **3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**
     . 2*P**4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*
     . M30**2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)
     . +9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)
      T1=T1+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30X*J30-(
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))
     . **4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*J30Y*J30X*
     . J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3)
     . )**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y*J30Z*J30X-(
     . 729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**6*M30**
     . 3)
      T1=T1-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6*M30**3)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(81.0D0*DSIN
     . (DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*DSIN(DBLE(Q3))
     . **2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*
     . J30X)
      T1=T1-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Y*M10)+9.0D0
     . *DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*
     . M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2
     . -(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*J10Y)+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y
      T1=T1+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))
     . **2*P**2*J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*
     . M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE
     . (Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*
     . J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(
     . DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30**3)
      T1=T1-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0*
     . P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2*
     . M30*J30Y*J30X
      MIV(2,2)=(T0+9.0D0*P**4*M30*M10+9.0D0*P**2*M30*J30Y+
     . 9.0D0*P**2*M30*J10Y+18.0D0*P**2*M30*J30X+P**2*M10*J30X
     . +J30Y*J30X+J10Y*J30X)/(T1+9.0D0*P**2*M30*J10Y*J30X+P**
     . 2*J30Y*M10*J30X+J30Y*J10Y*J30X)
      T0=729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30
     . **3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**
     . 2*P**4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*
     . M30**2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)
     . +9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)
      T0=T0+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30X*J30-(
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))
     . **4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*J30Y*J30X*
     . J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3)
     . )**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y*J30Z*J30X-(
     . 729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**6*M30**
     . 3)
      T0=T0-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6*M30**3)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(81.0D0*DSIN
     . (DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*DSIN(DBLE(Q3))
     . **2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*
     . J30X)
      T0=T0-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Y*M10)+9.0D0
     . *DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*
     . M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2
     . -(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*J10Y)+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y
      T0=T0+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))
     . **2*P**2*J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*
     . M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE
     . (Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*
     . J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(
     . DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30**3)
      T0=T0-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0*
     . P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2*
     . M30*J30Y*J30X
      MIV(2,3)=(81.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**4*
     . M30**2+9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2*M30
     . *J30Y-(9.0D0*DSIN(DBLE(Q3))**3*DSIN(DBLE(Q2))*P**2*M30
     . *J30Z)-(81.0D0*DSIN(DBLE(Q3))*DSIN(DBLE(Q2))*DCOS(DBLE
     . (Q3))*DCOS(DBLE(Q2))*P**4*M30**2)-(81.0D0*DSIN(DBLE(Q3
     . ))*DSIN(DBLE(Q2))*P**4*M30**2)-(9.0D0*DSIN(DBLE(Q3))*
     . DSIN(DBLE(Q2))*P**2*M30*J30Y))/(T0+9.0D0*P**2*M30*J10Y
     . *J30X+P**2*J30Y*M10*J30X+J30Y*J10Y*J30X)
      T0=9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30-(9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*M30*J30Y)+DSIN(DBLE(Q3))**4*Y*J30Y*
     . J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30)-(DSIN(DBLE(Q3))**4*
     . J30Y**2)+DSIN(DBLE(Q3))**4*J30Y*J30Z-(81.0D0*DSIN(DBLE
     . (Q3))**2*P**4*M30**2)-(9.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30*M10)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*M30*J30)+
     . 9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z
      T0=T0-(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J10Y)-(DSIN(
     . DBLE(Q3))**2*P**2*J30Y*M10)+DSIN(DBLE(Q3))**2*P**2*
     . J30Z*M10-(DSIN(DBLE(Q3))**2*Y*J30Y*J30)+DSIN(DBLE(Q3))
     . **2*J30Y**2-(DSIN(DBLE(Q3))**2*J30Y*J10Y)+DSIN(DBLE(Q3
     . ))**2*J30Z*J10Y-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2
     . ))**2*P**4*M30**2)+81.0D0*P**4*M30**2+9.0D0*P**4*M30*
     . M10+9.0D0*P**2*M30*J30Y
      T1=729.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**6*M30
     . **3+81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y-(81.0D0*DSIN(DBLE(Q3))**4*DSIN(DBLE(Q2))**
     . 2*P**4*M30**2*J30Z)+81.0D0*DSIN(DBLE(Q3))**4*P**4*Y*
     . M30**2*J30-(81.0D0*DSIN(DBLE(Q3))**4*P**4*M30**2*J30Y)
     . +9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Y*J30-(9.0D0*
     . DSIN(DBLE(Q3))**4*P**2*Y*M30*J30Z*J30)
      T1=T1+9.0D0*DSIN(DBLE(Q3))**4*P**2*Y*M30*J30X*J30-(
     . 9.0D0*DSIN(DBLE(Q3))**4*P**2*M30*J30Y**2)+9.0D0*DSIN(
     . DBLE(Q3))**4*P**2*M30*J30Y*J30Z-(9.0D0*DSIN(DBLE(Q3))
     . **4*P**2*M30*J30Y*J30X)+DSIN(DBLE(Q3))**4*Y*J30Y*J30X*
     . J30-(DSIN(DBLE(Q3))**4*Y*J30Z*J30X*J30)-(DSIN(DBLE(Q3)
     . )**4*J30Y**2*J30X)+DSIN(DBLE(Q3))**4*J30Y*J30Z*J30X-(
     . 729.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**6*M30**
     . 3)
      T1=T1-(81.0D0*DSIN(DBLE(Q3))**2*DSIN(DBLE(Q2))**2*P**4*
     . M30**2*J30Y)-(729.0D0*DSIN(DBLE(Q3))**2*P**6*M30**3)-(
     . 81.0D0*DSIN(DBLE(Q3))**2*P**6*M30**2*M10)-(81.0D0*DSIN
     . (DBLE(Q3))**2*P**4*Y*M30**2*J30)+81.0D0*DSIN(DBLE(Q3))
     . **2*P**4*M30**2*J30Z-(81.0D0*DSIN(DBLE(Q3))**2*P**4*
     . M30**2*J10Y)-(81.0D0*DSIN(DBLE(Q3))**2*P**4*M30**2*
     . J30X)
      T1=T1-(9.0D0*DSIN(DBLE(Q3))**2*P**4*M30*J30Y*M10)+9.0D0
     . *DSIN(DBLE(Q3))**2*P**4*M30*J30Z*M10-(9.0D0*DSIN(DBLE(
     . Q3))**2*P**4*M30*M10*J30X)-(9.0D0*DSIN(DBLE(Q3))**2*P
     . **2*Y*M30*J30Y*J30)-(9.0D0*DSIN(DBLE(Q3))**2*P**2*Y*
     . M30*J30X*J30)+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y**2
     . -(9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Y*J10Y)+9.0D0*
     . DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J10Y
      T1=T1+9.0D0*DSIN(DBLE(Q3))**2*P**2*M30*J30Z*J30X-(9.0D0
     . *DSIN(DBLE(Q3))**2*P**2*M30*J10Y*J30X)-(DSIN(DBLE(Q3))
     . **2*P**2*J30Y*M10*J30X)+DSIN(DBLE(Q3))**2*P**2*J30Z*
     . M10*J30X-(DSIN(DBLE(Q3))**2*Y*J30Y*J30X*J30)+DSIN(DBLE
     . (Q3))**2*J30Y**2*J30X-(DSIN(DBLE(Q3))**2*J30Y*J10Y*
     . J30X)+DSIN(DBLE(Q3))**2*J30Z*J10Y*J30X-(729.0D0*DCOS(
     . DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**6*M30**3)
      T1=T1-(81.0D0*DCOS(DBLE(Q3))**2*DCOS(DBLE(Q2))**2*P**4*
     . M30**2*J30X)+729.0D0*P**6*M30**3+81.0D0*P**6*M30**2*
     . M10+81.0D0*P**4*M30**2*J30Y+81.0D0*P**4*M30**2*J10Y+
     . 81.0D0*P**4*M30**2*J30X+9.0D0*P**4*M30*J30Y*M10+9.0D0*
     . P**4*M30*M10*J30X+9.0D0*P**2*M30*J30Y*J10Y+9.0D0*P**2*
     . M30*J30Y*J30X
      MIV(3,3)=(T0+9.0D0*P**2*M30*J10Y+P**2*J30Y*M10+J30Y*
     . J10Y)/(T1+9.0D0*P**2*M30*J10Y*J30X+P**2*J30Y*M10*J30X+
     . J30Y*J10Y*J30X)
      DO 25007 J=1,3
          DO 25008 K=J+1,3
              M(K,J)=M(J,K)
              MIV(K,J)=MIV(J,K)
25008     CONTINUE
25007 CONTINUE
\end{framedverbatim}
\bibliography{gentran}
\bibliographystyle{plain}
\end{document}
