Although it is possible to write EGS4 User Codes entirely in FORTRAN, we strongly urge you to use Mortran because of how easily one can write readable (and therefore more likely correct) code, because of its flexibility, and because of its ability to improve execution time by allowing for in-line code generation.
Note: The user is referred to Appendix 5 of SLAC-265 for a discussion of system considerations concerning using Mortran3.
The structured language is implemented as a set of macros which are used by the macro processor to translate the language into FORTRAN. The resulting FORTRAN program is then run like any other FORTRAN program. User-defined macros are easily added to the standard (language-defining) set of macros so that the language is "open-ended" in the sense that extensions to the language may be made at any time by the user. Extensions have ranged from very simple ones like matrix multiplication, to complex ones like those which define new data types.
Users need not concern themselves with the method of implementation or the macro facility in order to take advantage of the structured language which is provided by the standard set of macros. The features of this language include:
The Mortran3 processor is a FORTRAN program of approximately 2000 statements. The 1966 ANSI standard has been observed throughout, so that transportability of the processor is assured.
Character strings comprising Hollerith fields are enclosed in apostrophes (as in 'THIS IS HOLLERITH DATA'). If an embedded apostrophe is desired as a character within a quoted string, use a pair of apostrophes to represent each such embedded apos- trophe (as in 'DON''T').
Comments in Mortran are enclosed in quotation marks (as in "COMMENT") and may be inserted anywhere in the program (except in character strings or macros).
In Mortran, an alphanumeric label is a character sequence of arbitrary length enclosed in colons (as in :TOMATOES:). The characters which comprise the sequence may be any combination of letters and digits. An alphanumeric label may be used anywhere a FORTRAN statement label is allowed.
Multiple blanks (a sequence of two or more blanks) in a Mortran program are equivalent to a single blank except in quoted strings, where all blanks are preserved, and in macros (discussed in Section A4.5).
Summary of coding rules:
It should be pointed out that any extensions provided by a particular FORTRAN compiler may be used, provided that they do not conflict with Mortran's coding conventions. However, if transportability of the programs being written in Mortran is a consideration, the ANSI FORTRAN standard should be adhered to. The standard set of macros which define the language described in this Guide do not generate non-ANSI FORTRAN.
S1; S2; S3;...Sk;...Sn; (A4.3-1)
be a sequence of statements. The sequence becomes a block when it is enclosed in brackets
[ S1; S2; S3;...Sk;...Sn; ] . (A4.3-2)
Note: the ellipses (...) are meta-symbols indicating arbitrary repetition. The brackets are not meta-symbols; they are delimiters in the Mortran language.
Blocks may be nested. That is, any of the statements in a block may be replaced by a block. For example, in sequence (A4.3-2) we could replace Sk by a block and write
[ S1; S2; S3;...[ T1; T2; T3;...Tm; ]...Sn; ] (A4.3-3)
The block containing the sequence T1;...Tm; is completely contained, or nested, within the block containing the sequence S1;...Sn;. We will frequently write an ellipsis enclosed in brackets [...] to denote a block.
Example of a block: [ X=Y; CALL SUB(A); B=1; ].
The simplest form of a conditional statement in Mortran is written
IF e [...] (A4.3-4)
where e is an arbitrary logical expression, and the ellipsis enclosed in brackets denotes a block as described above. If e is true then the statements in the block are executed. If e is false, control is transferred to the first statement following the block. For example:
IF A.LT.B [ C=D; E=F; ] G=H;
If A is less than B then the statements C=D and E=F are executed after which G=H is executed. If A is not less than B control is transferred directly to the statement G=H.
Next in complexity is the IF-ELSE statement, which is written
IF e [...] ELSE [...] (A4.3-5)
If e is true then the statements in the first block are executed and control is transferred to the statement following the second block. If e is false then the statements in the second block are executed and control is transferred to the statement following the second block. For example, consider
IF A.LT.B [C=D; E=F;] ELSE [G=H; I=J;] K=L;
If A is less than B the statements C=D and E=F are executed after which control is transferred to the statement K=L. If A is not less than B the statements G=H and I=J are executed after which control is transferred to the statement K=L.
Consider
IF A.EQ.B [ X=Y;]
Here the block to be executed, whenever A is equal to B, consists of the single statement X=Y;. An alternate form acceptable in Mortran is the standard FORTRAN logical IF:
IF (A.EQ.B) X=Y;
IF-ELSE statements may be nested to any depth. Even so, the IF-ELSE is not really adequate (in terms of clarity) for some problems that arise. For example, consider the following "case analysis" problem. Suppose that we have four logical expressions p, q, r, and s, and five blocks of statements A, B, C, D, and E.
Now suppose that p, q, r, and s are to be tested sequentially. When the first TRUE expression is found we want to execute the statements in the corresponding block (p corresponds to A, q to B, etc.) and then transfer control to the statement following block E. If none of them is true we want to execute block E. Using nested IF-ELSE statements we could write
IF p [A] ELSE [ IF q [B] ELSE [ IF r [C] ELSE [ IF s [D] ELSE [E] ] ] ]
While this does what we want, it is awkward because each ELSE increases the level of nesting. Mortran offers the ELSEIF statement as an alternative:
IF p [A] ELSEIF q [B] ELSEIF r [C] (A4.3-6) ELSEIF s [D] ELSE [E]
Using ELSEIF instead of ELSE allows all the tests to be written at the same nest level.
In summary, an IF statement may be optionally followed by any number of ELSEIF clauses which in turn may be optionally followed by a single ELSE clause.
A Mortran loop is a block which is preceded by, and optionally followed by, a "control phrase". One such phrase is " WHILE e ". One of the loops we may write with this phrase is
WHILE e [...] (A4.3-7)The logical expression e is tested first. If e is true the block is executed and then control is returned to test e again. When e becomes false, control is transferred to the first statement following the block.
Another control phrase is " LOOP ". If we wanted to test at the end of the loop instead of the beginning, we could write
LOOP [...] WHILE e ; (A4.3-8)
In (A4.3-8) the block is executed first. Then, if the logical expression e is true, the block is executed again. When e becomes false control is transferred to the statement following the loop (that is, the statement following the " WHILE e ;" ).
The logical converse of the WHILE loop is the UNTIL loop.
UNTIL e [...] (A4.3-9)
The logical expression e is tested first. If e is false the block is executed and then control is returned to test e again. When the logical expression becomes true, control is transferred to the first statement following the block. Similarly, the logical converse of (A4.3-8) may be written by replacing the WHILE in (A4.3-8) by UNTIL.
Tests for loop termination may be made at both ends of a loop. For example, if e and f are logical expressions
WHILE e [...] UNTIL f ; WHILE e [...] WHILE f ; UNTIL e [...] WHILE f ; UNTIL e [...] UNTIL f ; ,all test at both the beginning and the end. The above list is by no means exhaustive, but we must develop other "control phrases" in order to complete the discussion.
The iteration control phrases discussed above do not involve "control variables"; that is, variables whose values are automatically changed for each execution of the loop. The following loop involves a control variable:
FOR v = e TO f BY g [...] (A4.3-10)
where v is the control variable and e, f, and g are arbitrary arithmetic expressions. The control variable v must be of type REAL or INTEGER, and may be an array element (subscripted variable). The value of any of the arithmetic expressions may be positve or negative. Moreover, the magnitudes as well as the signs of f and g may change during the execution of the loop.
The control variable v is set to the value of e and the test for loop termination (see below) is made. If the test is passed then the block is executed, after which v is incremented by the value of g and control is returned to the test. Note that the block is never executed if the test fails the first time.
The "test" for the termination of a FOR-loop refers to the logical expression
g * (v-f) .GT. 0 (A4.3-11)
If the value of (A4.3-11) is true, then the test is said to have failed and control is transferred to the statement following the loop. Multiplication by g in (A4.3-11) assures that loops in which the increment is (or becomes) negative will terminate properly.
The "FOR-loop" (A4.3-10) has two alternate forms
FOR v = e BY g TO f [...] (A4.3-12) and FOR v = e TO f [...] (A4.3-13)
In (A4.3-13) no increment is given, so it is assumed to be one.
The iteration control phrase "DO I=J,K,N" also involves a control variable. In this case I,J,K, and N must all be of type INTEGER and may not be array elements or expressions (these are the standard FORTRAN rules for DO-loops). The following generates a standard FORTRAN DO-loop:
DO I=J,K,N [...] (A4.3-14)
There is one exception to the rule that loops must be preceded by control phrases; namely, the compact DO-loop notation
[I=J,K,N;...] (A4.3-15)
which generates a standard FORTRAN DO-loop. This form permits compact notation for nests like
[I=1,N1; [J=1,N2; [K=1,N3; A(I,J,K)=exp; ]]].
(The use of the compact DO-loop notation is controversial; some people feel that it obscures the loop control. If desired, it can be be removed from the language by deleting a single macro from the standard set).
The Mortran FOR- and DO-loops apply only to blocks of statements, not to I/O lists. The usual FORTRAN implied DO should be used within READ or WRITE statements.
There remains one more type of loop to be discussed. This loop is sometimes referred to as the "forever loop". One writes the forever loop in Mortran by preceding a block with the phrase "LOOP":
LOOP [...] REPEAT (A4.3-16) or simply LOOP [...] (A4.3-17)
The block is executed and control is transferred back to the beginning of the loop. The optional phrase "REPEAT" in (A4.3-16) is sometimes useful as a visual aid in locating the ends of deeply nested loops.
A reasonable question might be: "How do you get out of a forever loop? Or, for that matter, any of the loops?". One rather obvious way is to write
GO TO :CHICAGO: ;
where the label :CHICAGO: is on some statement (or block) outside the loop. If a convenient label doesn't already exist, creating one for the sole purpose of jumping out of the loop can be annoying and distracting. For the case in which the jump is to the statement following the loop, the GO TO may be replaced by the Mortran "EXIT;" statement, which is written
EXIT; (A4.3-18)
or, with a conditional statement
IF (e) EXIT; (A4.3-19) or IF e [...EXIT;] (A4.3-20)In any Mortran loop, the occurrence of the statement "EXIT;" causes a transfer of control to the first statement following the loop in which it occurs.
A companion to the "EXIT;" statement is the "NEXT;" statement, which is written
NEXT; (A4.3-21)
or, with a conditional statement
IF (e) NEXT; (A4.3-22) or IF e [...NEXT;] (A4.3-23)
The occurrence of a "NEXT;" statement (which is short-hand for "go to the next iteration of this loop") in any Mortran loop causes a transfer of control to the beginning of the loop in which it occurs, incrementing the control variable (if any) before mak- ing the test for continuation in the loop. In loops which test at both ends of the loop, only the test at the beginning of the loop is made; tests at the end of the loop are made only when the end of the loop is reached. The tests of control variables in FOR- and DO-loops are considered to be at the beginning of the loop.
Any Mortran loop may be optionally preceded by a label. We will call loops which are preceded by labels "labeled loops". Any EXIT or NEXT statement may be optionally followed by a label. Any labeled loop may contain one or more statements of the form
EXIT :label: ; (A4.3-24)
which transfers control to the first statement following the labeled loop. For example EXIT :ALPHA:; would transfer control to the statement following the loop which had been labeled :ALPHA:. This transfer of control takes place regardless of nesting, and thus provides a "multi-level" EXIT capability. The statement
NEXT :label: ; (A4.3-25)
transfers control in the manner described above for the NEXT; statement.
Suppose we have a nest of loops which search some arrays. The outer loop has been labeled :SEARCH:, and two of the inner loops have been labeled :COLUMN: and :ROW:. Now we may write
NEXT :ROW: ; or NEXT :COLUMN: ; or EXIT :SEARCH: ;
when the transfer involves more than one level of nesting, or
NEXT; or EXIT;
when only one nest level is involved. Of course, the form
EXIT :label:;
may also be used to exit a single level if desired. We can now summarize Mortran loops in the following chart:
| WHILE a | | UNTIL b | | NEXT; | | LOOP | | EXIT; | | WHILE c; | |:label:| FOR v=x BY y TO z [...| EXIT :label:;| ...] | UNTIL d; | | FOR v=x TO y BY z| | NEXT :label:;| | REPEAT | | FOR v=x TO y | | DO i=j,k,n | where a, b, c, and d are arbitrary logical expressions, x, y, and z are arbitrary arithmetic expressions, v is a subscripted or non-subscripted variable of type INTEGER or REAL, j, k, and n are non-subscripted INTEGER variables or INTEGER constants, and i is a non-subscripted INTEGER variable. | | indicates "choose one", [ ] indicates "optional", and ... indicates a (possibly null) sequence of statements.
/ p,q,r...,z / = e (A4.4-1)
where p,q,r,...,z are variables and e is an expression. The expression e assigned to each variable in turn. For example,
/ I, A(I,K), J / = SQRT(X/2.0);
produces the following FORTRAN statements:
I = SQRT(X/2.0) A(I,K) = SQRT(X/2.0) J = SQRT(X/2.0)
Note: This represents a change from the way things were done in Mortran2.
Another instance in which the creation of a label can be annoying because it is used only once and contains no mnemonic information is the following:
READ (5,:NONSENSE:) i/o list; :NONSENSE: FORMAT(format list);
In Mortran one may write
INPUT i-o list; (format list); (A4.4-2) or OUTPUT i-o list; (format list); (A4.4-3)
whenever the input or output is to the standard FORTRAN input or output units (5 and 6, respectively). (If your FORTRAN compiler is already "extended" to allow the keywords INPUT and OUTPUT or if these keywords are already used in other contexts, the macros defining these statements may be removed or modified to use other keywords. Similarly, the input and output units may be easily changed to units other than 5 and 6.)
<, <="," ~=",">, >=, and >.
Logical operators may be denoted by:
& (and), | (or), and ~ (not).
The usual FORTRAN notation is still valid, but one must NOT mix modes within a single statement (i.e., (A>B.AND.C>D) will be translated incorrectly.
Macro definitions are written in the following form:
REPLACE {pattern} WITH {replacement} (A4.5-1)
Macro definitions are not statements and therefore need not be terminated by semicolons (if you put one in it will be ignored). Macro definitions are "free field" in the sense that you may write more than one definition on one line, or extend one definition to several lines.
The pattern and replacement parts of a macro definition are character strings in the sense described in Section A4.2. Since embedded strings are permitted in macro definitions, the usual rules regarding the doubling of apostrophes apply.
The simplest kind of macro is one which contains neither parameters nor embedded strings. For example, one could write
REPLACE {ARRAYSIZE} WITH {50} (A4.5-2)
after which all occurrences of the characters ARRAYSIZE in the program text would be replaced by 50. For example,
DIMENSION X(ARRAYSIZE); ... DO J=1,ARRAYSIZE [...]...
would produce the same FORTRAN program as if
DIMENSION X(50);... DO J=1,50 [...]...
had been written.
Blanks are generally not significant when searching for occurrences of the pattern in the program text. For example, the macro
REPLACE {SIGMA(1)} WITH {SIGMA1}
would match the program text
SIGMA (1)
as well as
SIGMA(1)
In some cases it is desirable to require that one or more blanks be present in the program text in order that a match occur; this can be done by writing a single blank in the pattern part of the macro. For example the macro
REPLACE {DUMP X;} WITH {OUTPUT X; (F10.2);}
would match
DUMP X;
but not
Y = DUMPX;
Normally, the text generated by a macro is itself elegible for replacement by other macros, or even by the the same macro that generated the text.
The pattern part of a macro definition may contain up to nine formal (or "dummy") parameters, each of which represents a variable length character string. The parameters are denoted by the symbol #. For example,
{EXAMPLE#PATTERN#DEFINITION} (A4.5-3)
contains two formal parameters. The formal parameters are "positional". That is, the first formal parameter is the first # encountered (reading left to right), the second formal parameter is the second # encountered and so on. The corres- ponding actual parameters are detected and saved during the matching process. For example, in the string
EXAMPLE OF A PATTERN IN A MACRO DEFINITION (A4.5-4)
(assuming (A4.5-3) is the pattern to be matched), the first actual parameter is the string "OF A", and the second actual parameter is the string "IN A MACRO". The parameters are saved in a "holding buffer" until the match is completed.
After a macro is matched, it is "expanded". The expansion process consists of deleting the program text which matched the pattern part of the macro and substituting for it the replacement part of the macro.
The replacement part may contain an arbitrary number of occurrences of formal parameters of the form {Pi} (i=1,2,...,9). During expansion, each formal parameter {Pi} of the replacement part is replaced by the i-th actual parameter. A given formal parameter may appear zero or more times in the replacement part. For example, the pattern part of the macro definition
REPLACE {PLUS #;} WITH {{P1}={P1}+1;} (A4.5-5)
would match the program text
PLUS A(I,J,K); (A4.5-6)
During the matching process the actual parameter A(I,J,K) is saved in the holding buffer. Upon completion of the matching process (that is when the semicolon in the program text matches the semicolon in the pattern part), the "expansion" of the macro takes place, during which the actual parameter A(I,J,K) replaces all occurrences of the corresponding formal parameter, producing
A(I,J,K)=A(I,J,K)+1; (A4.5-7)
Note that the single formal parameter {P1} occurs twice in the replacement part and therefore the single actual parameter A(I,J,K) occurs twice in the resulting string.
The program text which may be substituted for the formal (dummy) parameter is arbitrary except for the following restrictions:
Each of these control cards begins with a "%" in column 1, and should not contain embedded blanks or program text.
Column 1 | V %% Signals end of Mortran input. This is the ONLY control card that is required. All others are optional. Unlike Mortran2, %% signals the final end of input and must not be used to signal end of input from this particular unit. %F Switch to FORTRAN mode (initial mode is Mortran). While in FORTRAN mode, cards are read and written without any processing. This feature allows the interspersion of FORTRAN and Mortran text. If this feature is used, all FORTRAN statement labels should be restricted to four digits (or less) in order to avoid possible conflict with Mortran generated statement labels, all of which are five digits long (in the default mode). %M Switch back to Mortran mode (initial mode is Mortran). %E Eject (start new page) in Mortran listing. %L List (i.e., turn on Mortran listing (initally ON)). %N Nolist (i.e., turn off Mortran listing). %In Indent n places per nest level in Mortran listing, where n=0,1,2,...,99 (initally 0). (Note: leading blanks are automatically suppressed when n>0 so that "ragged" programs will be "straightened" by Mortran). %Cn Set input line width to n, where n=10,11,...,80 (initially n=72). Characters in columns n+1 thru 80 will appear in the Mortran listing, but will be ignored by the processor. %An Annotation mode switch. Controls the generation of Mortran source as comments in the generated FORTRAN as follows: n=0 Suppress Mortran text in FORTRAN file (initially n=0). n=1 Interleave Mortran text as comments in the FORTRAN program starting in column 2 and extending through column 80. If column 80 of the Mortran source line is not blank, a second comment line is generated containing the 80th character. n=2 Interleave the Mortran text as comments in the FORTRAN program in columns 40 thru 80. Each Mortran source line will appear as two comment lines in the FORTRAN listing, each of which contains one half of the Mortran source line. %Qn Quote switch (initally n=0). Controls Mortran comments as follows: n=0 Comments must be fully enclosed in quotation marks ("). n=1 All comments not closed at the end of each line will be closed by Mortran. %Un Unit switch. Causes Mortran to switch to FORTRAN input unit n for further input, where n=1,2,3...99. When an end-of-file is read from unit n, input is switched back again to the unit from which the %Un was read. If another %Un is read before an end-of-file, the current input unit is stacked and the Mortran input unit is again switched. This control statement provides a facility similar to that implemented in other languages by "COPY" or "INCLUDE" statements. It is particularly convenient for introducing standard declarations, common blocks, or macro definitions from a predefined external file.
Free-form directives begin with an exclamation point ("bang!") and end with a semicolon. The following are of particular use with EGS4/PEGS4:
!ANNOTATE; Interleave Mortran source in FORTRAN output. Mortran statements become COMMENTs in FORTRAN output. [!NOANNOTATE; means "Turn Off !ANNOTATE"]. !COMMENTS; Print Mortran comments as FORTRAN comments. Mortran comments are output to FORTRAN file with 'C' in column one. [!NOCOMMENTS; means "Turn Off !COMMENTS"]. !INDENT Mn; Set automatic indentation of Mortran listing to n columns per nesting level (same as %In above). !INDENT Fn; Set automatic indentation of FORTRAN source to n columns per nesting level (like !INDENT Mn;). !INDENT Cn; Set automatic indentation of FORTRAN comments to n columns per nesting level (but the 'C' remains in column one). !LIST; Turn on Mortran listing. Same as %L above. [!NOLIST; means "Turn Off !LIST;"]. !LABELS n; Reset FORTRAN statement label generator to n.
last updated 09/28/01