This manual was produced using the paginating program written Dr. and Mrs J. H. Matthewman.
This manual is not intended as an introduction to programming. Those with no previous experience of programming languages should refer to any of the many commercially available primers on FORTRAN programming. However, this manual should enable those who have used FORTRAN elsewhere to write FORTRAN programs for Titan.
T3 FORTRAN is a dialect of FORTRAN II with some extensions. Users should note that some of the facilities provided - notably the use of general expressions for subscripts, arrays of any dimension, and the POSTMORTEM statement, may not be available on other FORTRAN compilers.
The T3 FORTRAN compiler is part of the Titan Mixed Language System (MLS). Within this system a job is made up of routines, each of which may be written in any language for which a compiler exists in the system, or may be in a pre-compiled binary-symbolic form. Routines are compiled independently into binary-symbolic form, and the routines forming a program are loaded into store by a linking loader, which carries out relocation of store addresses, and ties up cross references between routines. MLS provides facilities for making up a program in this way, and also makes it possible to perform in a convenient and simple manner operations such as editing and macro-generating prior to compilation.
The programs that perform these functions (compiling, editing, etc) are called processors. Initially, the system includes the following processors:
Those who do not wish to use the full facilities of MLS will find in this document sufficient to enable them to run FORTRAN Jobs. For information about the complete system they should refer to:
Input for the T3 compiler may be in any code accepted by the Titan supervisor.
The basic character set is
The alphabet A - Z (Upper and lower case letters are synonymous)
The numerals 0 - 9
Others + - = / ( ) . , * space erase tab backspace
The character ' is available, and is treated everywhere in the same way as a letter. In addition the following equivalences hold:
[ is treated as ( ] is treated as ) × is treated as * : is treated as ,
Runout and stopcode are everywhere ignored.
A FORTRAN program is made up of a set of routines which may be compiled independently. A routine is sometimes called a subprogram. Each routine is made up of a set of statements which will usually occupy one line each, and may be preceded by a label and/or followed by comment. Each statement is made up of a set of items. An item is a name or a number or an element.
The following are the elements of a statement:
Addition operator + Subtraction operator - (binary or unary) Multiplication operator * Division operator / Exponentiation operator ** ((A**B is AB) **+ (A**+B is AB) **- (A**-B is A-B) Bra ( Ket ) Comma ,
A name is any string of letters or digits beginning with a letter, and not containing spaces. Only the first eight characters of a name are used, and names of less than eight characters are left-Justified and filled out with spaces. Thus the names
A1234567 A1234567'
will appear as identical names to the compiler.
There are three sorts of number used in a FORTRAN program.
An integer is any string of digits which, when read as a decimal number, has a value strictly less than 220. That is, an integer must be less than or equal to 1048575.
Examples:
Of the following numbers, all but the last are integers
1 29 029 1028264 001028264 1048576 (not an integer)
For those familiar with Titan, an integer is held in a half-word or B-line with zero octal fraction, and is operated on with B-line orders.
A long integer is any string of digits whose total length (excluding non- significant zeros) is less than or equal to ten, and which does not form an integer.
Examples:
Of the following numbers, all but the last are long integers
1048576 2496273984 0009997943210 10002013270 (not a long integer)
For those familiar with Titan, a long integer is held in a full word of store as a non-standard number with exponent 812. It is operated on using accumulator instructions.
A real number is any string of digits longer than ten characters, or any string of digits containing a decimal point, or followed by an exponent.
Examples
1.0 1. .1 0.1 0.00000656 1002013270
There is no limit on the number of digits in a real number, but only the most significant twelve will be used. The decimal exponent immediately follows the number, and is written by placing E and then the signed or unsigned exponent after the number. Note that the exponent may not stand alone. An exponent should lie between -27 and 27-1.
Examples:
1.23 E2 1.23 E+2 123. E-2 123 E-2
Note that E256 is not a number, but a name.
For those familiar with Titan, a real number is held standardised in a full word, and is operated on with accumulator orders.
In FORTRAN the printed line, or the card, is broken down into a set of four fields. The label field consists of columns 1 - 5 of the card (note that the first column is numbered one not zero) or the positions 1 - 5 on the printed page. The continuation field is column 6 (sometimes called the continuation marker). The statement field is columns 7 to 72 inclusive, and the comment field is columns 73 to 80 for cards, 73 to 120 for paper tape. Anything printed in the comment field is totally ignored, even illegal characters, so great care must be taken to ensure that an instruction never overflows into the comment field. It is not necessary to fill out with spaces any field terminated by a newline.
In addition to characters placed in the comment field, a line will be totally ignored if the character in the first printed position on the page is a C. (For those familiar with line-imagers, it should be noted that although the compiler does line-image, the C must actually be in the first print position. Erase C will not do, nor will space C. See 2.8)
The only other characters which may appear in the label field are digits, spaces, and erases. A label is formed if the field contains any digits. Erase and space are totally ignored in forming the label, as are non-significant zeros. The same label set twice, or referred to but not set, will usually produce a diagnostic at load time, not at compile time.
If there is a printed character, other than erase or zero, in the continuation field, the newline terminating the previous statement is ignored. Thus it is possible for statements to spread over more than one physical line. A continuation line is treated as a continuation of the last non-empty record which was not a comment line. If there was no such line before the current line, then there will be a diagnostic (e.g. if the continuation marker appears on the first line of the routine). If a line contains a continuation marker, the label field is totally ignored.
The characters tab and backspace are correctly dealt with, and the compiler forms an image of the printed line. Note that if the printed line contains overprints or erase, these are preserved in the image, with overprints turned into erase, so that it is possible to have overprints in a comment. Within the label and continuation fields, erases are treated as spaces, and both are wholly ignored in forming a label.
Note that most other line-imaging programs on Titan will remove erases from the label field and shift some characters left from the statement field into the label field. This was not done in T3 FORTRAN in order to make it easy to see whether a continuation marker exists by inspection of column 6 of the printed page. Similarly, on no account will T3 FORTRAN shift characters from the comment field into the statement field. Other line-imagers will, and care must be taken if the program is to be line-imaged by anything other than the T3 compiler. A general rule is that, in the absence of a continuation marker, a tab before both the statement and comment fields will allow successful line-imaging by all the relevant laboratory software.
Within the statement field, erases are ignored, and a space inserted at the end of the statement field. Spaces may appear in the statement field at any point within a number, or at any place between items. Note that nowhere is there any distinction between one, two, or more spaces. The places where spaces cannot occur are
The only place where they must occur is between two names (e.g. INTEGER A) or a name followed by a number (e.g. DO 36).
Diagnostics will refer to a line as
line m after label n or, if there has been no label in this routine, as line m
The first line of the program is line 1. The line number is increased for every line, whether empty or not. The line on which label n appears is line 0 after label n.
Empty lines may appear anywhere, as may lines containing only labels (in which case the label is attached to the next executable statement).
WARNING: This is not true of S3 and other card-oriented FORTRAN systems.
A name may be one of several types
FUNCTION DO PRINT GOTO INTEGER LONGINTEGER
LONG INTEGERis allowed, with an arbitrary number of spaces between LONG and INTEGER. This gives rise to the one exception to the rule that newline continuation marker is ignored. The system name END FILE must occur all on one line. END newline terminates a subroutine no matter what occurs on the next line. If a word is used which matches a system name, and it appears in a place where a system name is not possible - not the first item in the statement field - then it is not treated as a system name, but will be taken as one of the types (iii) to (v) below, on this and every subsequent occurrence.
At the end of each subroutine a list is printed of every name which has appeared of types (iii), (iv), or (v). This should help to locate otherwise undetected punching errors in names.
Any name can have one of three modes:
INTEGER mode LONGINTEGER mode REAL mode
(Built-in functions are somewhat special; the mode of each function is given in 7. If the name begins with X, it is in INTEGER mode. Otherwise it is in REAL mode.) A name may be explicitly declared to be one of the three modes (see 12), but if there is no such declaration, then the mode is assigned in the following manner. If the first character of the name is one of the letters I to N, then the name is taken to be INTEGER. Otherwise it is taken to be in REAL mode.
The mode controls the way in which numbers are stored in the machine. In general, addition and subtraction, and the evaluation of an array element, will be faster with INTEGERS. Multiplication and division will be faster with REALS, followed by LONG INTEGERS. Operations involving the first few INTEGERS appearing in a routine will usually be faster than operations involving those appearing later, or those which have been equivalenced.
For those familiar with Titan, simple integer variables which are arguments (see 3.3), and the first 15 local integer variables (see 3.3)> are held in B-lines. Other integer variables, and any which have been equivalenced, use the low half of a word of store.
INTEGER and LONG INTEGER names can only be used for whole numbers. An INTEGER must be less than 220 in magnitude, and a LONG INTEGER less than 236.
Note that the mode declared for an external function must correspond to the mode declared in the routine defining that function. It corresponds to the mode Of the result which is handed over. The mode of an array is the mode of every element of that array. Note that no matter what mode has been declared for the array, when the array name appears unsubscripted, giving the address of the base of the array, it has INTEGER mode.
A name can have one of three scopes
A name is assumed local unless declared common (by a COMMON declaration, see 10) or argument (by a FUNCTION or SUBROUTINE declaration, see 9).
If a name is local, then space is assigned for the storage of that name within the routine, and this space can only be accessed by other routines by handing the name over as an argument in a CALL statement (see 9.3)
If a name is an argument, then it is assumed that space will have been assigned for it by some outside routine, and this space is used.
If a name is common, then the space it refers to is under the user's control, and it can be used by every routine of the job. Complete details can be found in 10.
General form:
name(argl,arg2,...,argn) Example: A(B,C+D,E*A(B,C,D))
The syntax of function calls and subscripted arrays is identical, but the interpretation of the information differs. In both cases name is the array name or function name, and argl,arg2,...,argn are general expressions (which may contain other function calls or subscripted arrays to any depth). However, for subscripted arrays, each of the subscripts argl, arg2, etc. is evaluated, truncated to an integer (rounding always towards zero), and the result then used to produce the location of the array element thus specified. The value of this element will be of the mode declared for the name. An array name may have as many subscripts as desired (see 11 for further details). For function calls, the arguments argl, arg2, etc. are evaluated to produce a result whose mode is the mode of the expression forming the argument (see 5.4). This result is then handed over as the initial value of the arguments for the routine defining the function. There is no check that the modes of the arguments in the call are the same as the modes in the definition. Users should normally be careful to ensure that this is the case. The function routine is now entered and will produce a value whose mode should agree (again there is no check) with the mode declared in the calling routine.
If a function changes any of its arguments, or any variables which are COMMON, it is dangerous to call it twice in the same statement, as the order of the calls cannot be guaranteed.
An expression is used to produce a value at run-time which can be assigned to a simple or subscripted variable or to an array name. Note that it is not meaningful to assign a value to a function, or to a constant (or constant array name, see 11). This will cause a diagnostic.
An expression is made up of simple or subscripted variables (or array names), arithmetic operators, arithmetic brackets, and function calls (either of external or built-in functions).
Example:
-A+B**-I/JK+B(I, J)/FUN(D)*SQRTF(G)
An expression will produce a result with a certain mode, usually called the mode of the expression.
The operators have the following meanings
+ Addition - Subtraction (or, if unary, sign change) * Multiplication / Division.
In an expression whose mode is real, the result of I/J is a real number - e.g. 3/4 produces 0.75. In an expression whose mode is INTEGER or long integer, the result of I/J is an integer or long integer, produced if necessary by truncation towards zero. Care must be taken that this truncation does not occur when it is not wanted.
** or **+ Exponentiation.
There are two different actions on this operator depending on the expressions on either side of it.
**- Exponentiation
is similar to **+, except that in case (i) a division occurs at the end, and for long integers truncation is applied; and for case (ii) B is negated.
Note: For exponentiation of type (ii), A must be positive. A run-time diagnostic will be given if it is not.
The order in which the operators are obeyed can always be dictated by arithmetic brackets. Parts of an expression within brackets will always be evaluated before parts immediately surrounding the brackets. If brackets do not force an order, then we have the following rules:
**,**+,**- will be obeyed first, unary minus will be obeyed second, * and / will be obeyed third, + and - will be obeyed last.
Where these rules do not completely determine the order, the operators are obeyed from left to right (except where the result is independent of the order, assuming no round-off error or overflow). Thus the following expressions are equivalent:
A**B**C**-D and (((A**B)**C)**(-D)) A/B*C*D/F*G and (((((A/B)*C)*D)/F)*G)
It is, however, good practice always to include brackets in these cases, for although most FORTRAN compilers will obey the hierarchy rules, they will not all obey the left to right evaluation.
If an item in an expression is a function call, or a subscripted array name, it is sometimes important to know at what point its arguments or subscripts are evaluated, and at what point the function is actually called. A sub-expression is:
All sub-expressions are evaluated before evaluation of the main expression is commenced. Similarly, sub-expressions within sub-expressions are evaluated before starting the enclosing sub-expressions. Where this does not decide the order completely, the right-most sub-expression is evaluated first.
Any name within a sub-expression or integer subscript is said to be at a lower level than the other names, which are said to be in the outer level. That is, a name is in the outer level unless it is within a function argument or array subscript. An expression is in integer mode if every name or constant in the outer level is in integer mode. An expression is in long integer mode if every name or constant in the outer level is in integer or long integer mode. Otherwise the expression is in real mode.
Note: For expressions involving both real and integer quantities (mixed mode expressions),these rules are not identical to those of S3 FORTRAN. Programmers wishing to write programs compatible with S3 should keep mixed mode expressions as simple as possible. No difficulty should occur with expressions involving a single operator. Examples:
If I=4, J=3, A=3 I/J * J has integer result 3 I/J * A has real result 4.0
In S3 FORTRAN, these examples would produce results 3, and 3.0
This takes the form
variable = expression
and will assign the value of the expression to the variable. The variable and expression do not need to be of the same mode. If necessary, the result of the expression will be truncated towards zero before assignment to the variable.
Note: Overflow is undetected. If a real expression whose result is out of integer range but within long integer range is assigned to an integer, the result appears modulo 220. If the real was out of long integer range, then the result will bear little relation to the original. Titan Autocode users should note that
variable = variable = expression
(i.e. a multiple assignment) is not permitted.
Any statement other than the declarations may be labelled. The following statements change the order in which a program is obeyed.
General form:
GO TO n or GOTO n
where n is a statement label. Example:
GOTO 5
This causes, the statement with the statement label n to be obeyed next. We say that there is a transfer of control to this statement.
General form:
GO TO (n1,n2,n3,...,nm),i or GOTO (n1,n2,n3,...,nm),i
where n1, n2, etc. are statement labels, and i is a simple integer variable. Example:
GOTO(30,42,50,9),K
Control is transferred to the statement with statement label n1, n2,..., nm depending on whether the value of i at the time is 1, 2, 3, ..., m, respectively. A run-time error diagnostic will occur if the value of i is not in the range 1 to m.
General form:
ASSIGN n TO i
where n is a statement label, and i is a simple integer variable.
Example:
ASSIGN 12 TO K
This statement allows subsequent assigned GOTO (see below) statements to transfer control to the statement labelled n. It can also be used to communicate an address to a machine-code routine.
General form:
GOTO i, (n1,n2, ...,nm) or GO TO i, (n1,n2,. ..,nm)
where i is a simple integer variable, and n1, n2, etc. are statement labels, i must have previously appeared in an ASSIGN statement, or have been set equal to some other variable which has done so.
Example:
GOTO K, (17, 1O, 19)
This statement causes transfer of control to the label held by i. nl , n2, n3, ..., nm are a list of the possible labels. If i does not have a value corresponding to one of these labels, then a run-time diagnostic occurs.
Note: To say that K holds the label 10 does not usually mean that its value is 10. Thus the following sequence will usually produce an error diagnostic:
K = 10 GOTO K, (17,10,19)
This may not be provided in every dialect of FORTRAN, but will be more time-efficient than the checked GOTO. General form:
GO TO i or GOTO i where i is a simple integer variable.
Example:
GOTO K
This statement causes transfer of control to the label held in i. If i is one of the arguments of the routine or in the common list, this can be used to return to a machine-code routine. Machine-code programmers should note that in this case all B-lines will be incorrect, the values of integer arguments will not have been updated, private monitor will not have been reset, and local integer variables in B-lines will not have been preserved. Real and long integer variables and arguments should be correct.
General form:
IF (e)n1,n2,n3
where e is a general expression of any mode, and n1, n2, n3 are statement labels.
Example:
IF(A(J,K)-B)10,14,30
Control is transferred to the statement with label n1,n2, or n3, as the value of e is less than, equal to, or greater than zero, respectively.
Note that REAL arithmetic is subject to round-off errors, so that a value produced by much computation is unlikely to be exactly zero. However, if all intermediate results are whole numbers within long integer range, it can be assumed that real arithmetic is exact. This may not be true on other machines.
General form:
SENSELIGHT i or SENSE LIGHT i where i is 0,1,2,3, or 4
Example:
SENSELIGHT 3
If i is 0, all four notional lights will be turned off; otherwise light i will be turned on.
General form:
IF(SENSELIGHT i) n1,n2 or IF(SENSE LIGHT i) n1,n2
where nl and n2 are statement labels and i is 1, 2, 3, 4
Example:
IF(SENSELIGHT 3)80,40
Control is transferred to the statement with label nl if light i is to n2 if light i is off. The light is turned off. (Mnemonic: on = one)
General form:
DO n i = m1, m2 or DO n i = m1, m2, m3
where n is a statement label, i is a simple integer variable, and m1, m2, m3 are general expressions which must be in INTEGER mode. If m3 is absent it is taken to be 1.
Examples:
DO 3 I = J+3/K, M, -L or DO 7 J' = J+I*K, I1
The DO statement is a command to perform repeatedly the statements which follow, up to and including the statement with label n. These statements are said to be in the range of the DO. Note that if the label n is on an otherwise empty line, the null statement terminates the DO.
If any other DO appears in the range of the DO, then its range must be entirely within the range of the enclosing DO. A diagnostic is given otherwise. The range of two DOs may end on the same statement.
The statements in the range of the DO are obeyed with i = m1, i = m1+m3, i = m1+2m3, and so on. The last value of i for which the statements are obeyed is the last value in this sequence which is less than or equal to m2. If the first character of the expression m3 is a minus sign, the last value of i for which the statements are obeyed is the last value in the sequence for which i is greater than or equal to m2. Note that it is possible for the loop never to be obeyed. e.g.
DO 31 I = 0, 1, -1
will cause the statements up to and including that labelled 31 to be skipped whenever control reaches the DO.
The value of the i, the index of the DO, is preserved when the DO is entered, and restored if it is completed. The expressions m1, m2, m3 are evaluated before the loop is entered, and so cannot be changed by the loop. A transfer of control into the range of the DO from outside of it will thus produce unexpected results. A transfer out of the DO will be successful, with the index holding its current value. The index of the DO is given the first value after evaluation of m1. It has this value during evaluation of m2 and m3.
Titan Autocode programmers should note that the index of a DO may not be REAL, that jumping into a DO is not possible, and that changing the step-length or end-point from within the DO is not possible.
General form:
CONTINUE
This is a dummy statement which has no effect. It is useful in card-oriented FQRTRANs, where it is not possible to place the DO label on an empty line. It is equivalent to the Autocode REPEAT, and should be used to terminate most DO loops.
General form:
STOP
This causes the job to return to the command program to obey the next command.
General form:
RETURN
This causes control to pass from a routine back to the routine calling it. It signifies the end of the routine at run-time, and may appear in several places. If used in the main program, its effect is the same as STOP.
General form:
END
This is the last written statement of a routine, and signals the end of the written routine to the compiler. The next record is not read.
The END statement is not intended to be an executable statement, and will produce a diagnostic if labelled. However, if control should reach it, the effect will be identical to that of RETURN.
These provide a number of commonly used arithmetic operations, including the full range of trigonometric, hyperbolic, and inverse trigonometric functions.
Note: Programs that are to be compatible with S3 FORTRAN must restrict their use of some of the trig functions, as S3 does not provide the full range.
For those familiar with Titan, these functions either compile into extracodes, or into a short sequence of orders. They do not produce a call to another (library) routine.
The functions in this section take a single argument which may be a general expression in REAL, INTEGER, or LONG INTEGER mode. The result of the function is in INTEGER mode if the name of the function begins with X, and in REAL mode otherwise.
SQRTF(V) Square root LOGF(V) Natural logarithm EXPF(V) Exponential function SINF(V) Sine (V is in radians) COSF(V) Cosine (V is in radians) TANF(V) Tangent (V is in radians) ASINF(V) Arcsine. The result is in the first or fourth quadrant, and is in radians ACOSF(X) Arccosine. The result is in the first or second quadrant, and is in radians ATANF(X) Arcstangent. The result is in the first or fourth quadrant, and is in radians SINHF(V) Hyperbolic sine COSHF(V) Hyperbolic cosine TANHF(V) Hyperbolic tangent ABSF(V) Absolute value XABSF(V) Absolute value, with truncation towards zero if the argument is not an integer. INTF(V) Integer part - truncating towards zero, this INTF(3.14) = 3.0 and INTF(-5.3) = -5.0 XINTF(V) As INTF, but the result is in integer mode. XFIXF(V) Synonymous with XINTF FLOATF(V) The result is the REAL form of the argument. If the argument is real, there is no action.
The mode of the result of the following functions is INTEGER if the name begins with X, REAL otherwise.
MODF(A1,A2) Defined as A1-A2*INTF(A1/A2). It gives the value of A1, modulo A2. SIGNF(A1,A2) The result has the sign of A2 and the magnitude of A1 DIMF(A1,A2) Defined as A1-A2 if A1≥ A2 otherwise zero MAX1F(A1,A2,..An) The result is the largest of the two or more arguments. Fourth character is the digit one MIN1F(A1,A2,...An) The result is the smallest of the two or more arguments. XMIN1F(A1,A2,...An) The result is the smallest of the two or more arguments.
The mode of the result of the following functions is INTEGER if the name begins with X, and REAL otherwise.
XMODF(I1,I2) Defined as I1-I2*(I1/I2). It gives the value of I1, modulo I2. XSIGNF(I1,I2) The result has the sign of I2 and the magnitude of I1. XDIMF(I1,I2) Defined as I1-I2 if I1≥ I2 otherwise zero MAX0F(I1,I2,..., In) The result is the largest of the two or more arguments. Fourth character of the name is zero XMAX0F(I1,I2,..., In) The result is the largest of the two or more arguments. Fourth character of the name is zero MIN0F(I1,I2,..., In) The result is the smallest of the two or more arguments. Fourth character of the name is zero XMIN0F(I1,I2,..., In) The result is the smallest of the two or more arguments. Fourth character of the name is zero
User-defined routines (see 9) may be functions or subroutines. Any such routines which may be of general use can be added to the system library, held on the magnetic disc store, and will then be freely available to every program.
A separate document ("The IAL disc library') lists the routines which are currently available.
Each program is made up of a series of routines (sometimes called sub-programs). These may be compiled separately and stored (see "The Titan mixed language system'). A program may be just a single routine.
In general, each routine will have a name by which it is identified, but there may be one routine in each program which is not so named, but is called the main program. It will be the first routine entered. All other routines must begin with one of the two statements:
FUNCTION or SUBROUTINE
These are followed by the name identifying the routine, and by a list of arguments. The only difference between these two statements is that on reaching the RETURN statement at run-time, the FUNCTION routine will plant the value of the name of the routine (which can be used like any other local variable) ready to hand back to the calling routine. This does not occur with the SUBROUTINE routine. There should be a correspondence between routines defined as FUNCTION and routines called as functions in some other routine. Similarly, routines defined as SUBROUTINE should only be called using the CALL statement (see 9.3). There is no check on disobedience of this rule. The following rules will govern the effect of such calls.
This statement, if present, must be the first statement of the routine. General form:
FUNCTION name(a1,a2,a3,...,an)
where the a1 to an are non-subscripted variables, called the arguments. In general, the mode of each argument provided in the call must correspond to the mode of each of these names. There is no check on breaking this rule. Note that there must be at least one argument.
Example:
FUNCTION INTRST ( RATE, YEARS )
The arguments of the routine are initialised to the value supplied in the call, but may then be used exactly as any other variable in the program. If defined as arrays, the base address is initialised to the value supplied by the call. Changing the values of the arguments will change the values of the corresponding variables in the calling routine.
This statement, if present, must be the first statement of the routine. General form:
SUBROUTINE name(a1,a2,a3,...,an) or SUBROUTINE name
where the a1 to an are non-subscripted variables called the arguments. Note that if there are no arguments, the brackets must also be absent. Examples:
SUBROUTINE MATMPY (A,N,M,B,LD,I) SUBROUTINE TIME
The arguments can be used throughout the routine like any other variable in the routine, and any change to the argument will change the value of the variable supplied as the argument in the calling routine (unless such an assignment would be meaningless).
General form:
CALL name (a1,a2,a3,.. .,an) or CALL name
where the a1 to an are general expressions in any mode.
Example:
CALL MATMPY (X,5,10,Y,17,3+4/7) CALL TIME
If the argument is a single variable, possibly subscripted, then any assignment of a value to the corresponding argument in the called routine will change the value of that variable. Otherwise such assignments will have no effect on the calling routine. Note that the arguments may be array names or variables holding the dimensions of an array (see 11). Note also that if an array is being handed over, the name must appear in DIMENSION statements in both the called and the calling routines.
These declarations may be preceded only by the FUNCTION or SUBROUTINE statement, by other COMMON statements, or by mode declarations (see 12). General form:
COMMON name, name, name, name
where name is a non-subscripted name in any mode not declared a subroutine argument. Note that the name may be an array. Example:
COMMON A,B,C
Declaring a variable COMMON is a means of enabling the value of that variable to be available in all other routines. The nth variable declared COMMON in each routine uses the same space.
Note: The first loaded routine of a job must have at least as many items in its common list as any other routine. Note too that an array declared COMMON only takes up a single position in the list - the position holds the base address. (Those using machine code should note that the first variable declared COMMON uses location 101 (decimal), the second 102 etc.).
If a variable is subsequently declared to be an array name, then the common list location is expected to contain the base address of the array, but it is up to the user to put this base address there. The procedure is as follows. The space above the last location used by program (usually called the common area) is available for holding arrays declared COMMON - local arrays have space assigned by the compiler within the routine. The base address of common arrays and their dimensions may be freely varied (see 11).
For compatibility with S3 FORTRAN, if any name is declared COMMON more than once, no action is taken on the second and subsequent declarations. WARNING: This treatment of COMMON is identical to that of the S3 compiler, but differs from that of most other versions of FORTRAN.
This may be preceded only by the FUNCTION or SUBROUTINE statements, COMMON statements, other DIMENSION statements, or by mode declarations (see 12).
General form:
DIMENSION V1, V2, V3, ..., Vn where the V have the general form name (dim1, dim2, dim3, ..., dimn)
where dim1 to dimn are simple variables or constants in integer mode, and name is a non-subscripted variable in any mode. If the mode of the dim are later changed, there will be undetected chaos. The mode of name may be safely changed. Example:
DIMENSION A(10), B(J), C(5,K,6)
name may have argument, common, or local scope. The allowed scopes for dim depend on the scope of name'. The details are as follows. The DIMENSION statement is used to declare a name to be an array name. Each array is characterised by a number of values.
Of these, (i) is absolutely constant throughout the routine, and takes the value implied in the DIMENSION statement, except that any array may at any time be used with only one subscript, (ii) and (iii) can often be changed by the programmer at will.
We consider first the base address.
If name is not common or argument, then the base address is constant, and assigned by the compiler. Any attempt to assign to the unsubscripted name will lead to an error diagnostic.
If name is common, then the base address can be set (or changed) by the programmer at any time by assigning to the unsubscripted array name. However, the value will often be set initially (see 18) and never changed.
If name is an argument, then the base address will be initialised to the value handed over by the calling routine, but can be freely changed by assigning to the unsubscripted array name. Note that if the routine is called using CALL, this will change the base address in the calling routine.
We now consider the dimensions. These are needed for two purposes. First, to discover the amount of store needed by the array, and secondly, to locate an individual element of the array. Example:
DIMENSION A(DIM1, DIM2, DIM3)
then the value of the element A(I,J,K) is to be found at location
base address + I+(J-1 )*DIM1 +(K-1 )*DIM1*DIM2
The array takes up DIM1*DIM2*DIM3 of space.
There are two ways in which the position of this location can be calculated. First by explicit multiplication every time an array element is used, and secondly by forming at the head of the routine a set of multiplication tables which can be looked at to provide the value of each term in the expression. Clearly, in the former case, the dimensions can be varied at any point in the routine, but in the latter case, the dimensions can not be changed. Note too that whilst the former method is the most space-efficient, it is the latter which is most time-efficient. There will be an immediate error diagnostic at run-time if any subscript for which tables are used goes out of range by one. Note that for one-dimensional arrays no tables or multiplication are needed. The dimension is required only to allocate space for local arrays. If the single subscript goes out of range there will be no direct error diagnostic.
In the following description we will refer to values set by PRELUDE. This is a special subroutine (see 18) which can be entered before the remainder of the job is loaded into the store. Its sole purpose is to set initial values in the common list locations.
We can now describe the rules which govern the method used to find the location of an array element. The general rule is: if possible use tables.
WARNING: In many FORTRAN compilers all dimensions are restricted to being constants, and even S3 does not allow a local variable as an array dimension, or run-time alteration or setting of dimensions.
These declarations can occur at any time after the FUNCTION or SUBROUTINE statement, if present, and before the first arithmetic (see 5), control (see 6), format (see 15), or equivalence (see 13) statements.
General forms:
INTEGER name, name, name, ..., name LONGINTEGER name, name, name, ..., name LONG name, name, name, ..., name INTEGER name, name, name, ..., name REAL name, name, name, ..., name
Examples:
INTEGER A, B, XYZ, '1 LONG INTEGER A2, B', B'', I REAL I, KA
These declarations force the mode of the names listed to be of mode integer, long integer, and real, respectively; no matter what is the first letter of the name. The names may already have been used in the SUBROUTINE, FUNCTION, COMMON, or DIMENSION (as an array name) statements. Note that to change the mode of a name which has been used as an array dimension will not be diagnosed, and could lead to chaos.
If the same name is used more than once in such a declaration, it is the last occurrence which determines the mode of the name.
These declarations must follow all COMMON, DIMENSION, and mode declarations, and must precede any arithmetic, control or format statements.
The EQUIVALENCE statement has two functions. First to arrange for two or more simple variables to use the same working space, and secondly to arrange for the space taken by one array to be in a fixed place with respect to another.
General form:
EQUIVALENCE (L,R), (L,R), ..., (L,R)
where L and R take one of the forms (a) to (d) below.
Example:
EQUIVALENCE (A,B), (C,D(K))
An equivalence has no effect on R, only on L. Note that if L was declared COMMON, the space allocated to it in the common list remains allocated, but is not used. (S3 FORTRAN does not assign a location for L), and if it is a local array, space remains allocated for it. A subroutine argument may safely be used as L (or R), but if used as L its initialisation to the value handed over is lost, and any change to its value will not affect the variable in the calling routine.
We now enumerate the allowed combinations of types for L and R, the first and second arguments of each EQUIVALENCE. All other types are diagnosed as errors.
Example:
EQUIVALENCE (A,B), (X,I),(J,W)
L retains its mode, but uses the same storage location as R. Those familiar with Titan should note that there is a small effect on R. If R is in integer mode, and would normally have been held in a B-line, and L is not in integer mode, then the integer R is held in store.
Equivalences of this type can be chained. The compiler forms a pointer from the name L to the name R. Thus the chain can be formed from either end; e.g. (C,D),(A,B),(B,C) is the same as (A,D),(B,D),(C,D).
Using a variable as an L-equivalent twice is diagnosed as an error, as is forming a circular chain.
Example:
EQUIVALENCE (A,B(15)),I,C(J,K+7))
L retains its mode, but uses the location of the array element R for storage.
Note: The subscripts of the array element are evaluated when L is actually used in an arithmetic expression. The mechanism used is to replace L in the compiler's line-image buffer by the sequence of characters of R every time L occurs. Note therefore that an error in R - e.g. incorrect number of subscripts - will be detected when L is first used, not in the EQUIVALENCE statement.
The equivalences (A,B(I)), (I,J(3)) will produce an error diagnostic when A is first used - the subscripts of R may not be equivalenced in this way, or lead through a chain to such an equivalence. An equivalence of this type may be the last element in a chain of equivalences of type (a).
Note that R may have more than one dimension.
Example:
EQUIVALENCE (A,B(I+J))
The effect is to make the first element of A coincide with the (I+J+l)st element of B. This is done by replacing every occurrence of A(P,Q) by A(I+J+P, Q) in the compiler's line-image buffer, and then equivalencing A to E with a type (c) equivalence. These equivalences can not form part of a chain - if B has been equivalenced there will be a diagnostic. As in (b), any attempt at a replacement while in the middle of a replacement will lead to a diagnostic.
WARNING: The EQUIVALENCE statement is largely compatible with S3, but differs from the treatment by other FORTRAN compilers.
Note on efficiency: The compile-time, and run-time efficiency can be reduced by making excessive use of equivalences, especially the equivalencing of array names to subscripted array names, If A is in common, the equivalence (A,B(I+J)) is better done at run-time by A=B+I+J.
Input/output in FORTRAN is geared entirely to fixed format operation. That is, it must be known precisely what is the layout of the information to be input - how many numbers there are on a line, how many digits before and after the decimal point, and how many spaces there are between numbers. All the input/output statements transmitting decimal numbers refer to a FORMAT statement (see 15) which must be provided to supply this information.
This is a perfectly satisfactory procedure for output, or for input from cards, but can be a cause of difficulty with paper-tape input. There is provided in the Titan disc library a set of subroutines to read and line-image a line of input, together with functions to read numbers from it in free format, (much as in Titan Autocode). Full details are to be found in the documentation on the Titan disc library, but a brief summary of the facilities can be found in Appendix 5.
This is obtained by three statements READ, PRINT, PUNCH; General form:
READ n, list PRINT n, list PUNCH n, list
where n is a statement label of a FQRMAT statement (15) and list is a transfer list (14.5).
The user does not need to take any action in the Job Description or command program in order to use the last two. They will come out on streams 0 and 15, respectively, which are created to PRINTER and PUNCH7 if they do not already exist. The READ statement reads information from stream 0.
This is obtained by the statements
READ INPUT TAPE n WRITE OUTPUT TAPE n
These cause information to be read from or written to stream n.
General form:
READ INPUT TAPE n, m, list WRITE OUTPUT TAPE n, m, list
(The spaces in READ INPUT TAPE and WRITE OUTPUT TAPE are optional) where n is an unsigned integer constant, or a simple integer variable, m is the statement label of a FORMAT statement (see 15) and list is a transfer list (see 14.5).
There are two ways of obtaining this transfer.
(a) By creating a stream in the Job Description or command program as a TO TAPE or FROM TAPE stream (see chapters 9 and 10 of 'Titan machine-code programming manual' and 'The MLS Commands'), and then using the READ INPUT TAPE n and WRITE OUTPUT TAPE n statements. This is the recommended procedure. The information can then be subsequently read by either another FORTRAN program, or by other software in the laboratory.
(b) By setting up a tape logical number n, taking care not to create stream n, and using the READ INPUT TAPE n and WRITE OUTPUT TAPE n statements. This procedure is not recommended for two reasons.
(i) Buffer space is required for the transfer, and is taken as locations 28K to 32K. Great care must therefore be taken that this is not overlaid by any arrays in the common area.
(ii) The information is written up in the FORTRAN variable-length record format, and cannot be read by other software in the laboratory. This method should only be used if the tape is to be read elsewhere.
This form of transfer suffers from all the disadvantages of section 14.3 (b). The FORMAT specification nA8, used with the statements of section 14.3 (a), can sometimes be used instead. The transfer enables arbitrary bit patterns to be written to tape or disc, and allows a limited amount of random access - backspace a single record, and rewind a tape - although this is extended by some library routines to skip one record forward, and skip and backspace by one file. Full details are given in 17.
Each input/output statement finishes with a transfer list. This is a list of the quantities which are to be output, or a list of the variables into which input is to be read. The list may sometimes be empty, - as when calling a format statement which contains only text.
General form:
item, item, item, ..., item
In the simplest case, item is an arbitrary expression.
Example:
A, B(3), C(I+J+K), 56,3+4/C(I)
WARNING: Programs that are to be compatible with S3 FORTRAN must restrict their items to variables, possibly subscripted.
The items are transmitted in the order they appear in the list, reading from left to right. Note that if an array name is used unsubscripted, it is the base address of that array which is transmitted. Note too that for transmissions which input information, the information will be lost if the item in the list is not capable of appearing on the left of an arithmetic statement. This situation is not diagnosed.
When it is required to transmit the elements of an array, we can have a more general form for item:
(item, item, ..., item, i = expl , exp2 ) or (item, item, ..., item, i = expl , exp2, exp3)
Note that the items within this item can be either expressions, or other items of this form. This transfer is exactly equivalent to the following:
DO 5 i = expl, exp2, exp3 transfer item, item, . . . , item 5 CONTINUE
The implied DO has a specification identical to that of explicit DO's. (See 6.9).
An example of a complete transfer list for use in an output statement is
I, J+I, SQRT(I), ((A(K,L),K=1,I),B(L),L=1,J,2)
Note that, on input, the new value will be used for any variable read earlier in the list.
Example:
K, (A(I),I=1,K)
can be used to read numbers from an input tape which contains first a count of the number of items. Similarly, K,A(K) can be used to read a number into a specified place.
WARNING:
(i) The operation of S3 FORTRAN in the last example is doubtful.
(ii) S3 allows items of the list to be bracketed:
item, (item), item
It should be noted that such brackets would prevent the item from appearing on the left of an expression, and cannot, therefore appear in an input list in T3 FORTRAN.
A FORMAT statement must be numbered and is written
n FORMAT (<Format specification>)
A format specification is written as a sequence of field specifications and/or control specifications, in general separated by commas or slashes. The specifications are:
When an input/output statement is executed the relevant FORMAT specification is scanned. Whenever a field specification is reached which refers to a list item the next item in the list is processed and transmitted, execution of the input/output statement being ended when all items have been transmitted. If the end of the format specification is reached and items still remain in the list then the format is rescanned from the last nest of repeated field specifications, due regard being paid to any associated count. If there are no repeated groups of field specifications then the format specification is rescanned from the beginning.
During repeated scanning of a format specification the scaling factors q and r, the zero suppression control Z and the sign control S are not reset but have the values as at the end of the previous scan. They are reset at each execution of any input/output statement.
A sequence of adjacent characters to be input or output which are processed together is called a field. The field width is the number of characters concerned and is specified in all field specifications. This width should not cause the field to extend beyond the end of the buffer, it will be appropriately reduced if necessary. On input a field of width zero is treated like an all blank field and on output a zero field width means ignore the next item in the list.
Each type of conversion has a style of adjustment, either right or left.
Each item has a natural field width which may depend on the value of the item: for example, in A-type output the natural width is 8; and I-type it is 1 + max (z,n) where 10n-1 ≤ item < 10n, and z is the specified minimum number of digits to be printed (see control Z). The item is conceptually converted in its natural field width and then put in the specified output field.
If the adjustment is to the left (A,B,L-type), the left-most character of the natural field occupies the left-most position of the actual field. Characters at the right-hand end of the natural field are lost if the actual field is too small; on the other hand, if the actual field is larger than the natural field, spaces are output to the right of the item.
Conversely, if the adjustment is to the right (E,F,G,I,K,O) the right-most character of the natural field occupies the right-most position of the actual field. Characters at the left-hand (i.e. more significant) end of the natural field are lost if the actual field is too small; but if the actual field is larger than the natural field, the characters in the buffer to the left of the natural field are undisturbed.
The input conventions are designed to be compatible, in the sense that anything output can be correctly re-input, provided that the actual fields are big enough. (The converse is not necessarily true). This means that for left-adjusted items, characters are collected starting at the left of the field, ending when either the actual field or the natural field ends. If the natural field ends first, the right-hand part of the actual field is ignored.
For right adjusted items, initial spaces are ignored, and the collection of characters proceeds all the way to the end of the actual field.
The basic field specifications are
Iw, Ew.d and Fw.d
with the successive specifications separated by commas. Thus the statement FORMAT (I2, E12.4 F10.4) might give the line
29 -0.9321E 02 -0.0076
As in this example, the field widths may be made greater than necessary so as to provide spacing blanks between numbers. In this case, there is 1 blank following the 29. 1 blank after the E (automatically supplied except in cases of (a) a negative 2 digit exponent when a minus sign will appear, and (b) a 3 digit exponent, the E being changed to N if negative), and 3 blanks after the 02. Within each field the printed output will always appear in the right-most positions.
It may be desired to print n successive fields within one record with the same specification. This may be specified by giving n before E, F or I. Thus, the statement FORMAT (I2,3E12.4) might give
29 -0.9321E 02 -0.7580E-02 0.5536E 00
T3 provides two ways by which alphanumerical data may be read or written; the specifications for this are Aw and wH. Both result in storing the alphanumerical information in BCD form. The difference is that information handled with the A specification is given a variable or array name and hence can be referred to by means of this name for processing. Information handled with the H specification is not given a name and may not be manipulated in storage in any way. The specification Aw causes w characters to be read into or written from, a variable or array name. On input nAw will store the next n successive fields of w characters as BCD information. If w is greater than 8, only the 8 right-most characters will be significant. If w is less than 8, the characters will be right adjusted and the word filled out with blanks. On output nAw will transmit n successive fields of w characters from storage as BCD characters without conversion. If w exceeds 8 then only 8 characters will be transmitted preceded by w-8 blanks. If w is less than 8 then the w right-most characters will be transmitted.
The specification wH is followed in the FORMAT statement by w alphanumerical characters. For example
28H THIS IS ALPHANUMERICAL DATA
Note that blanks are alphanumerical characters and must be included in the count w. The effect of wH depends on whether it is used with input or output.
(1) Input w characters are extracted from the input record and replace the w characters of the specification.
(2) Output The w characters following the specification, or the characters which replaced them, are written as part of the output record.
Example:
The statement FORMAT ( 1Hb, 3HXY=,F8.3,A8) might produce the following lines:
XY=b-93.21Obbbbbbbb XY=9999.999bbOVFLOW XY=bb28.768bbbbbbbb
(b is used to indicate blank characters: the first H specification is used for carriage control, see 15.3)
This example assumes that there are steps in the source program which read the data 'OVFLOW', store this data in the word to be printed in the format A8 when overflow occurs, and store six blanks in the word when overflow does not occur.
The characters A, B, E, F, G, I, K, L and O specify the conversion of information between internal and external form according to the following table:
Code Internal Form External Form Adjustment A ANY Characters Left B REAL Octal digits Left E REAL Decimal with exponent Right F REAL Decimal without exponent Right G REAL Decimal with or without Right exponent I INTEGER Decimal integer Right K INTEGER Characters Right L Boolean 'TRUE' or 'FALSE' Left This form is not useful in T3 FORTRAN O INTEGER Octal integer Right
The decimal integer, w, following a conversion code letter specifies the field width (i.e. number of characters) in the external form. The decimal integer d in the forms Ew.d. and Fw.d. specifies the number of digits, following the decimal point. On input the decimal point need not be present and if present, need not be in the position indicated by the format specification; if not present the number of decimal places is defined by the format specification. An exponent must be present in an E field and absent from an F field. The internal form is determined by the format specification.
The standard external forms for E, F and G formats have field widths as follows:
Ew.d sign, 1 integral part, max (z,q) where z,q are defined in 15.2 decimal point, 1 fractional, d exponent, 4
Total field width required 6 + d + max (z,q). If this exceeds w the left-most characters are lost and the field adjacent and to the left is not affected.
Fw.d sign, 1 integral part, max (z,n) decimal point, 1 fractional, d
The implicit exponent is -r (see scale factors, below) and n is defined by 10n-1 ≤ internal value * 10r < 10n. The total field width required is 2 + d + max (z,n). If this is greater than w the left-most characters are lost and the the adjacent field to left is not affected.
Gw is as for the F form if the value can be expressed without either an exponent or leading zeros, otherwise the E form is used.
The next character of the line in the external medium to be processed at any stage is identified by a pointer. This pointer is adjusted automatically when fields with specified field widths are processed. It can also be adjusted explicitly by X or Y control. nX moves n places relative to its present position, nY moves it to the specified absolute position. It can be moved backwards or forwards allowing overwriting within the buffer. [Thus 60Y, 4H****, -4X, S*-, I4 will cause an integer to be printed, with preceding asterisks instead of spaces in columns 60-63.] There are checks to prevent the pointer being moved outside the buffer area.
A decimal integer preceding a conversion code A, B, E, F, G, I, K, L or O specifies that the conversion is to be applied to the specified number of consecutive items in the list. A group of conversions (field or control) enclosed in parentheses and preceded by a decimal integer is repeated the specified number of times (once if no integer is explicitly specified). A group is itself a control specification and may occur within another group and so on to depth 8.
Two scale factors q (for E type conversions) and r (for F type) are maintained during processing of a format statement. At the start of execution of an input/output statement they have the values q = 1, r = 0.
These values may be changed by the specifications nP, nQ and nR; P sets them both to the same values (n), Q and R each affects the appropriate one. In E-type output the mantissa is normalised to the range 10q-1 ≤ mantissa < 10q (so that there are q integer places) and the decimal exponent formed accordingly. On input q is irrelevant. In F-type output the number output has the value 10r times the value of the corresponding list item. On input the number read is multiplied by 10-r before assignment to the list item.
Sab is relevant to the output of numerical information. The character to be printed immediately to the left of the left-most digit is specified; a for zero or positive numbers, b for negative. In the absence of this specification blank and - are used.
nZ specifies that n digits are to be printed in I fields, and n digits before the decimal point in E or F fields. It applies to all I, E and F fields processed after this control is processed. In the absence of this control, or before this control is reached, unity is assumed so that all leading zeros are suppressed except that single zero is printed for a zero integer or a zero integral part of a number printed in E or F form.
A line in the buffer is terminated by the character / in the format. Each input or output statement specifies the subsequent action. On input the buffer is filled with the next line from the input document. On output the buffer is taken as the next line of output and is then reset to spaces. In both cases the buffer pointer is reset to the beginning of the line.
In records output for printing, the initial (zeroth) character of each record serves a special purpose: carriage control. Subsequent characters (1 to 120) in the record constitute the line to be printed. The carriage control character determines where the line is to be printed, according to the following code (standard in FORTRAN).
space (single spacing) print on the next line; 0 (double spacing) leave one blank line then print; + print on the same line; 1 print at the top of the next page; A Leave one blank line before printing; B Leave two blank lines before printing; C:F Leave three to six blank lines before printing.
General form:
POSTMORTEM n, m, list or POST MORTEM n, m, list
where m is the statement label of a FORMAT statement, and list is a transfer list.
The action of this statement when obeyed is identical to WRITE OUTPUT TAPE n - it causes the specified information to be output on stream n. However, in the normal running of a program these statements are totally ignored. If an error diagnostic should occur at run-time within the routine containing the statements, or within a routine it calls, (even if it is called indirectly), then and only then will printing take place.
Example; Routine A is entered from the main program, and then enters routine B. We have a run-time error in routine B.
(Note: A calls B calls A will be dealt with correctly if it occurs in error.) The following printing takes place:
(1) <A message stating the error> IN LINE n AFTER LABEL m OF SUBROUTINE B
(2) <The first POSTMORTEM statement written in routine B>
(3) <Subsequent POSTMORTEM statements from B, in the order they were written>
(4) IN LINE n AFTER LABEL m OF SUBROUTINE A [The location of the call for B]
(5) <POSTMORTEM statements written in routine A>
(6) IN LINE n AFTER LABEL m OF MAIN PROGRAM [The location of the call for A]
(7) <POSTMORTEM statements written in the main program>
Note that an error caused by the program being overwritten by data could lead to a second error during the POSTMORTEM printing. In an extreme case it could prevent any of the above printing from occurring. In this case, the supervisor will put out a message
MONITOR FAULT n AT LOCATION x
together with a print-out of the region of store faulted, in machine-code orders. The interpretation of FAULT n is given in chapters 9 and 10 of 'Titan machine-code programming manual1. This case should be very rare.
The POSTMORTEM statements can be placed at any point in the body of the routine, but for the sake of time-efficiency they should not be placed in the middle of tight loops. The best place for them is immediately after a GOTO statement, or a RETURN statement.
General form:
READ TAPE i, list or READTAPE WRITE TAPE i, list or WRITETAPE
where i is a simple integer variable, or integer constant, and list is a transfer list, (l ≤ i ≤ 8). This transfers the bit pattern in the locations specified by list onto BACKING STORE DEVICE (BSD) i. This may be disk or tape, and is set up in the Job Description, or by commands to the command program. The information is written up in FORTRAN variable length record format, and is unreadable to other software. Note that even if a record is not fully read, the tape or disc will nonetheless move to the beginning of the next record after the transfer.
General form:
END FILE i or ENDFILE i REWIND i BACKSPACE i
where i is a simple integer variable, or an unsigned integer constant. (1 ≤ i ≤ 8).
The ENDFILE statement causes an end-of-file mark to be written to BSD i. The REWIND statement causes BSD i to be taken back to its start point. The BACKSPACE statement causes BSD i to move back by one record.
These operations are performed by library subroutines. They all have a single integer argument, and operate on the BSD of that value.
CALL BFFORT(I) Move the device back to the previous end-of-file mark CALL SFFORT(I) Move the device on to the next end-of-file mark. CALL SRFORT(I) Move the device on by one record. CALL ULFORT(l) If the device is a tape, unload it. If the device is disk working space, lose it.
General form:
READ DRUM i, j, list or READDRUM WRITE DRUM i, j, list or WRITEDRUM
DISC, and DISK are synonymous with DRUM. i, j, are both either unsigned integer constants, or simple integer variables.
The transfer is to or from BSD i, beginning at block j. The BSD may be tape or a section of disk created in the command program.
When variables in the common list are used as the dimensions of an array the common list must have values placed in it before the whole of the job is loaded (see 11). To make this possible, the loading may be done in two stages. First a subroutine - which is special only in that it is called PRELUDE and must not require any such presetting - is loaded. Any library routines it needs are loaded too, then the routine PRELUDE is entered. It is written by the user to compute values and plant them in variables of the common list. When the RETURN instruction is obeyed, PRELUDE and any other routines loaded are thrown away, but the common list is retained. The rest of the program is then loaded and entered. PRELUDE is only necessary when there are dimensions of an array which need presetting. It can, however, be used to set any item in the common list.
Note that the common area is also thrown away - it is only the list which is retained.
The setting of the base address of arrays in COMMON can be done at any time before the array is used, but is most conveniently done in a separate routine, which is called by the main program on entry. Note that base addresses must be set in INTEGER or LONG INTEGER mode.
WARNING; This paragraph is totally different from the case of S3 FORTRAN. It was introduced so that programmers could place their common arrays immediately above their programs, and not at the top of their store as in S3.
When loading of the main program is complete, and before it is entered, the common list is examined. Every item of the list which either has not been written to, or has been written to in INTEGER mode, is increased by a constant equal to the location of the next available full word of store above the program. Any location which has been written to in long integer or real mode is unchanged. (Machine-code programmers should note that location 100 is also initialised to this value.) Thus normal initialisation using PRELUDE, and in particular, initialisation of array dimensions, must be done with LONG INTEGERS, or, if floating point, with REALS. (Note that a location written to as a LONG INTEGER looks like an INTEGER as well, so any variables which are to be used as integers can safely be initialised as long integers. The initialisation of the base address of common arrays, however, should be done relative to the base of the common area, and the result planted as an integer. The base of this common area can be found at run-time by reading, in integer mode, from any location in the common list which has never been written to (or from location 100).
For those familiar with Titan, the store is initialised to half-word zeros. In FORTRAN terms, all integers are initialised to zero; long integers and reals will be in a form which can lead to incorrect results or an error diagnostic if used in some ways, but which may sometimes be treated as zero.
Note; All variables local to a routine have their values retained from one exit to the next entry - they are not reinitialised to zero. This should be true of most FORTRAN compilers.
For those who do not require the full range of facilities provided by the supervisor and command program, a simple job involving only FORTRAN and no PRELUDE can be run by submitting a tape of the following form:
RUN ML3(<initials and job number>/<your own title>) LIMOUT 1000 LIMSTORE 10K ***U (FORTRAN, F*) <main program, terminated by END> <first routine, beginning with SUBROUTINE or FUNCTION, and ending with END> <further subroutines> * (ENTEFORT,F*) <data to be read by READ (if any)> * ***Z
The statements FORTRAN, ENTEFORT, *, ***U, and ***Z will not be line-imaged, and must occur at the extreme left of the line. There should be at least one inch of run-out after ***U, 3 inches after ***Z, and about 12 inches of run-out at the start of the tape. The tape should be labelled JD <initials and job number>/<anything> and submitted with a tape-ticket to the computing service.
It is an unfortunate side-effect of the FORTRAN practice of assigning a full word to each variable that integer arrays take up twice as much space as is actually required to hold the information. For programs using integer arrays with a total of more than about 8,000 elements, this can be a large overhead, and the following procedure should be adopted to reduce the wastage. Before describing the procedure, it should be noted that this is very much of an ad hoc fiddle. It will not work with other machines or compilers.
Suppose we use two integer arrays A and B of approximately equal size, and that A is larger. Then
The array B will now be using the high half of the words whose low half is used by A.
Restriction; Avoid assigning a real or long integer expression to an element of B or A. Use B(I) = XFIXF (expression) Violation of this rule cannot of course be detected, and will result in the previous elements of A and B being overwritten if used with B, and the same element of B being overwritten if used with A.
These can be found at the end of 'Titan machine-code programming manual'.
The statements NON-ECON and LISTING which are used in S3 FORTRAN are ignored by the T3 compiler.
Full details of the following routines and others concerned with free-format input can be found in 'The IAL disc library1. This appendix merely gives a summary of their action. NOTE: LABEL is an integer argument and must be set using an ASSIGN statement. All functions are of integer mode if the first letter of the name is I, and of real mode otherwise.
FUNCTION READREAL (LABEL)
The next number from the current stream is read and handed back as the value. The next character to be read is the terminator of the number. If some non-digit occurs before the number, then the routine will return to the place specified by label. The number may contain a decimal point and/or exponent.
FUNCTION IREADINTEGER (LABEL)
Similar to READREAL, but point or exponent terminates the number.
FUNCTION IREADCHAR (lABEL)
The value of the function is the internal code of the next character on the input stream. If the line is empty, it jumps to LABEL.
SUBROUTINE SEIECTINPUT (N)
Selects input stream N.
There are a number of respects in which the compiler differs from most FORTRAN2 compilers:
By writing the statement FORTRAN2 at the head of the first routine compiled, these three points will be treated as in conventional FQRTRAN2 i.e.
Those bringing programs from elsewhere should note the other divergences, which are not affected by this directive:
Details of how to write machine-code subroutines are to be found elsewhere. This section merely indicates some features of T3 FORTRAN which machine-code programmers may find useful, and which are peculiar to FORTRAN.
These are listed below in alphabetical order. Note that the message cannot give more than an indication of the fault. The full details of what produces each message are given after the message. Items in parenthesis indicate the statements concerned in the message. A diagnostic message has the form
<message> IN LINE n AFTER LABEL m OF ROUTINE <name of routine> <a print-out of the current line up to and including the last character read>
The print-out of the current line will usually contain the offending item as the last item of the print-out. However, if the whole line has been read, including the newline, before the offence is noted, then the print-out will contain only the label and continuation fields of the next line, and the line number given will be that of the next line. Any illegal characters in the line will be replaced by decimal point, and two spaces are inserted between the continuation field and the beginning of the statement field.
If more than 30 messages are output in any one routine, and at least one is an error diagnostic, then the remainder of the document is abandoned. The comment
I GIVE UP
appears to indicate this.
The diagnostic messages:
FUNCTION or SUBROUTINE INTEGER COMMON LONG INTEGER DIMENSION REAL EQUIVALENCE in any order
<letter>::= '|A|B|C ... W|X|Y|Z <digit>::= 0|l|2|3|4|5|6|7|8|9 <name>::= <letter> | <name><letter> | <name><digit> | <space><name> <integer>::= <digit> | <integer><digit> | <space><integer> | <integer><space> <exponent marker>::= E | <exponent marker><space> <exponent>::= <exponent marker><integer> | <exponent marker>+<integer> | <exponent marker>-<integer> | <space><exponent> <real mantissa>::= <integer>. | .<integer> | <integer>.<integer> <real number>::= <real mantissa> | <real mantissa><exponent> | <integer><exponent> | <space><real number> | <real number><space> <operator>::= + | - | * | / | ** | **+ | **- | <operator><space> | <space><operator> <subscript list>::= <expression> | <subscript list>,<expression> <subscript>::= (<subscript list>) | <space><subscript> <subscripted name>::= <name><subscript> <operand>::= <name> | <integer> | <real number> | <subscripted name> | (<expression>) <unsigned expression>::= <space><unsigned expression> | <operand> | <unsigned expression><operator><operand> <expression>::= <unsigned expression> | +<unsigned expression> | -<unsigned expression> | <expressicai><space> | <space><expression> <left-hand-side>::= <space><left-hand-side> | <left-hand-side><space> | <name> | <subscripted name> <arithmetic statement>::= <left-hand-side>=<expression>