| Fortran Language Reference Manual, Volume 1 - S-3692-51 | ||
|---|---|---|
| Prev Section | Chapter 7. Expressions and Assignments | Next Section |
An expression is formed from operands, operators, and parentheses. The simplest form of an expression is a constant or a variable.
The values of these simple expressions are the constant value 3.1416, the constant value .TRUE., the value of the variable X, the value of the array Y, the value of the array element Y(K), the value of the array subsection Y(2:10:2), the value of the component N of structure M, and the value of a substring of an array element Y(K), respectively.
An operand in an expression can be one of the following items:
A constant or subobject of a constant
A variable (for example, a scalar, an array, a substring, or a pointer)
An array constructor
A structure constructor
A function reference (returning, for example, a scalar, an array, a character variable, or a pointer)
Another expression in parentheses
The following examples show operands:
A ! scalar or an array B(1) ! array element or function C(3:5) ! array section or a substring (A + COS(X)) ! expression in parentheses (/ 1.2, 2.41 /)! array constructor RATIONAL(1,2) ! structure constructor or function I_PTR ! pointer to an integer target |
There are two forms that operations can take in an expression. One is an operation involving two operands, such as multiplying two numbers together. The other is an operation on one operand, such as making a number negative. These forms are called binary and unary operations, respectively.
Table 7-1 lists the intrinsic operators. You can use function subprograms to define additional operators. User-defined operators are either binary or unary operators.
Table 7-1. Intrinsic Operators and the Allowed Types of their Operands
Operator category | Intrinsic operator | Operand types |
|---|---|---|
Arithmetic | **, *, /, +, -, unary +, unary - | Numeric of any combination of numeric types and kind type parameters or Cray pointer. Cray pointers are only allowed with the + or - operators. |
Character | // | Character of any length. |
Relational | .EQ., .NE., ==, /= | Both of any numeric type and any kind type parameter or Cray pointer, or both of type character with any character length parameter. |
Relational | .GT., .GE., .LT., .LE., >, >=, <, <= | Both of any numeric type (except complex) and any kind type parameter or Cray pointer, or both of type character with any character length parameter. |
Logical | .NOT., .AND., .OR., .XOR., .EQV., .NEQV. | Both of type logical with any combination of kind type parameters. |
Bitwise masking (Boolean) expressions (EXT) | .NOT., .AND., .OR., .XOR., .EQV., .NEQV. | Integer, real, typeless, or Cray pointer. |
Note: The Fortran standard does not specify the bitwise masking (Boolean) expressions, nor does it specify the .XOR. operator as a logical operator.
A binary operator combines two operands, as in the following:
x1 operator x2 |
Examples:
A + B 2 * C |
The examples show an addition between two operands A and B, and a multiplication of two operands, the constant 2 and the operand C.
A unary operation acts on one operand, as in the following:
operator x1 |
Examples:
- C .NOT. L |
The first example results in the value minus C. The second example produces a value that is the logical complement of L; the operator .NOT. is the only intrinsic operator that is a unary operator and is never a binary operator.
Intrinsic operations are those whose definitions are known to the compiler. They are built into Fortran and are always available for use in expressions. Table 7-1, lists the operators built into Fortran as specified by the standard.
The relational operator symbols ==, /=, >, >=, <, and <= are synonyms for the operators .EQ., .NE., .GT., .GE., .LT., and .LE., respectively.
The less than or greater than operation is represented by the <> operator and the .LG. keyword. This operation is suggested by the IEEE standard for floating-point arithmetic, and the Cray Fortran Compiler supports this operator. Only values of type real can appear on either side of the <> or .LG. operators. If the operands are not of the same kind type value, the compiler converts them to equivalent kind types. The <> and .LG. operators perform a less-than-or-greater-than operation as specified in the IEEE standard for floating-point arithmetic.
Note: The Fortran standard does not specify the <> or .LG. operators.
The Cray Fortran Compiler allows abbreviations for the logical and masking operators. The abbreviations .A., .O., .N., and .X. are synonyms for .AND., .OR., .NOT., and .XOR., respectively. If you define the abbreviated operator for any type, the abbreviated form of the intrinsic operator cannot be used in any scope in which the defined operator is accessible.
Note: The Fortran standard does not specify abbreviations for the logical and masking operators.
In addition to the Fortran operators that are intrinsic (built in), there may be user-defined operators in expressions.
Defined operations are those that you define in the Fortran program and are made available to each program unit that uses them. The computation performed by a defined operation is described explicitly in a function that must appear as a subprogram in the Fortran program where it is used. The operator used in a defined operation is called a defined operator. In this way, you extend the repertoire of operations so that computations can be expressed in a natural way using operator notation. Function subprograms that define operators are explained in detail in the Fortran Language Reference Manual, Volume 2.
A defined operator uses a symbol that is either the symbol for an intrinsic operator or is a new operator symbol. The synonyms described above for the relational operators remain synonyms in all contexts, even when there are defined operators. For example, if the operator < is defined for a new type, say STRING, the same definition applies to the operator .LT. for the type STRING; if the operator .LT. is specified as private, the operator < is also private.
A distinction is made between a defined (or new) operator and an extended intrinsic operator. An extended intrinsic operator is one that uses the same symbol as an intrinsically defined Fortran operator, like plus + or multiply *. It also causes the operations to be combined in the same order as is specified for the intrinsic operator. A defined operator is one where the operator symbol is not the same as an intrinsic operator but is new, such as the .INVERSE. operator. Defined operators, however, have a fixed precedence; defined unary operators have the highest precedence of all operators, and defined binary operators have the lowest precedence of all operators. The precedences of all operators are described in more detail in Section 7.2.5.
A defined elemental operation is a defined operation for which the function is elemental.
Note: The masking or Boolean operators and their abbreviations, which are extensions to Fortran, can be redefined as defined operators. If you redefine a masking operator, your definition overrides the intrinsic masking operator definition. See Table 7-1, for a list of the operators.
Expressions are formed by combining operands. Operands can be constants, variables (scalars, array elements, arrays, array sections, structures, structure components, and pointers), array constructors, structure constructors, functions, and parenthesized expressions with intrinsic and defined operators.
The method used to specify the expression formation rules is a collection of syntax rules that determine the forms of expressions. The order of evaluation of the operations in an expression is determined by the usual semantics for the operations, and the syntax rules are designed to be consistent with these semantics. In fact, the order of evaluation defines a precedence order for operators that is summarized in Table 7-2.
Table 7-2. The Hierarchy of Expressions Through Forms
Term | Definition |
|---|---|
expression | [ expression defined_operator ] equivalence_expression |
equivalence_expression | [ equivalence_expression .EQV. ] disjunct_expression equivalence_expression .NEQV. disjunct_expression |
Exclusive OR (extension) | [ disjunct_expression .XOR. ] conjunct_expression |
disjunct_expression | [ disjunct_expression .OR. ] conjunct_expression |
conjunct_expression | [ conjunct_expression .AND. ] not_expression |
not_expression | [ .NOT. ] comparison_expression |
comparison_expression | [ concatenation_expression relational_operator ] concatenation_expression |
concatenation_expression | [ concatenation_expression // ] summation_expression |
summation_expression | [ summation_expression + ] multiplication_expression summation_expression - multiplication_expression + multiplication_expression - multiplication_expression |
multiplication_expression | [ multiplication_expression * ] exponentiation_expression multiplication_expression / exponentiation_expression |
exponentiation_expression | defined_unary_expression [ ** exponentiation_expression ] |
defined_unary_expression | [ defined_operator ] primary |
primary | constant constant_subobject variable array_constructor structure_constructor function_reference (expression) |
The set of syntax rules defines an expression at the highest level in terms of operators and operands, which are themselves expressions. As a result, the formal set of rules is recursive. The basic or lowest level of an expression is a primary, which, for example, can be a variable, a constant, or a function, or recursively an expression enclosed in parentheses. The rules for forming expressions are described from the lowest or most primitive level to the highest or most complex level; that is, the rules are stated from a primary up to an expression.
A primary is defined as follows:
Table 7-3.
| primary | is |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
| constant_subobject | is |
|
A variable that is a primary must not be a whole assumed-size array or a section of an assumed-size array name, unless the last subscript position of the array is specified with a scalar subscript or a section subscript in which the upper bound is specified.
The following examples show primaries:
In the previous examples, ONE is a named constant if it has the PARAMETER attribute or appears in a PARAMETER statement. 'ABCS'(I:I) is a constant subobject even though I may be a variable because its parent ('ABCS') is a constant; the reference 'ABCS'(I:I) is a constant subobject because it cannot be defined like a variable can be defined. RATIONAL is a derived type and FCN is a user-defined function.
When an array variable is a primary, the whole array is used, except in a masked assignment statement. In a masked assignment statement, only that part of the array specified by the mask is used.
When a pointer is a primary, the target associated with (pointed to by) the pointer is used, except possibly when the pointer is an actual argument of a procedure, or is an operand of a defined operation or a defined assignment. Whether the pointer or the target is used in these exceptional cases is determined by the procedure invoked by the reference.
Recall that an assumed-size array is a dummy argument whose shape is not completely specified in the subprogram in that the extent in the last dimension is determined by its corresponding actual argument. The implementation model is that the extent in the last dimension is never known to the subprogram but is specified by the use of a subscript, section subscript, or vector subscript expression that defines an upper bound in the last dimension. Unless the extent is specified in this way, such an object must not be used as a primary in an expression. On the other hand, if a subscript, section subscript with an extent for the upper bound, or a vector subscript is specified for the last dimension, the array value has a well-defined shape and hence can be used as a primary in any expression. For example, if A is declared as REAL A(3,*), array A(:,3) has a well-defined shape and can be used as a primary in an expression.
Expressions can be used as actual arguments in procedure references (function references or subroutine calls). Because actual arguments can be expressions involving operations, actual arguments must not contain assumed-size arrays, unless their shape is well-defined, as described above. An actual argument, however, can be just a variable, which then allows the actual argument to be the name of an assumed-size array. This implies that such actual arguments can be assumed-size arrays, unless the procedure requires the shape of the argument to be specified by the actual argument. Most of the intrinsic procedures that allow array arguments require the shape to be specified for the actual array arguments, and therefore assumed-size arrays cannot be used as actual arguments for most intrinsic functions. The exceptions are all references to the intrinsic function LBOUND(3i), and certain references to the intrinsic functions UBOUND(3i) and SIZE(3i).
Defined unary expressions have the highest operator precedence. A defined unary expression is a defined operator followed by a primary. These are defined as follows:
Table 7-4.
| defined_unary_expr | is |
| |
| defined_operator | is |
|
A defined operator must not contain more than 31 letters.
A defined operator must not be the same as any intrinsic operator (.NOT., .AND., .OR., .EQV., .NEQV., .EQ., .NE., .GT., .GE., .LT., .LE., or .LG.) or any logical literal constant (.FALSE. or .TRUE.).
Note: The Fortran standard does not describe the .LG. operator.
A defined operator can be the same as one of the masking or Boolean operators supported by the Cray Fortran Compiler as an extension to the Fortran standard. The corresponding Cray Fortran operator loses its intrinsic properties. Note that the abbreviations .T., .F., .A., .O., .N., and .X. are synonyms for .TRUE., .FALSE., .AND., .OR., .NOT., and .XOR., respectively. If you define the abbreviated operator for any type, the abbreviated form of the intrinsic operator also cannot be used in any scope in which the defined operator is accessible, and the redefined abbreviated logical constants can no longer be used as logical constants.
The following examples show defined unary expressions:
| Expression | Meaning | |
| .INVERSE. B | A defined unary expression (where .INVERSE. is a defined operator) | |
| A | A primary is also a defined unary expression |
An exponentiation expression is an expression in which the operator is the exponentiation operator **. This is defined as follows:
Note that the definition is right recursive (that is, the defined term appears to the right of the operator **) which indicates that the precedence of the ** operator in contexts of equal precedence is right-to-left. Thus, the interpretation of the expression A ** B ** C is A ** ( B ** C ).
The following examples show exponentiation expressions:
A multiplication expression is an expression in which the operator is either * or /. It is defined as follows:
Table 7-6.
| multiplication_expr | is |
| |
|
| or |
|
Note that the definition is left recursive (that is, the defined term appears to the left of the operator * or /) which indicates that the precedence of the * and / operators in contexts of equal precedence is left-to-right. Thus, the interpretation of the expression A * B * C is (A * B) * C, or A / B * C is (A / B) * C. This left-to-right precedence rule applies to the remaining binary operators except the relational operators.
The following examples show multiplication expressions:
A summation expression is an expression in which the operator is either + or -. It is defined as follows:
Table 7-7.
| summation_expr | is |
| |
|
| or |
|
The following examples show summation expressions:
A concatenation expression is an expression in which the operator is //. It is defined as follows:
The following examples show concatenation expressions:
A comparison expression is an expression in which the operator is a relational operator. It is defined as follows:
Table 7-9.
| comparison_expr | is |
| |
| rel_op | is |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
EXT |
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
|
| or |
| |
EXT |
| or |
|
The operators ==, /=, <, <=, >, >=, and <> are synonyms in all contexts for the operators .EQ., .NE., .LT., .LE., .GT., .GE., and .LG., respectively.
Note: The Fortran standard does not describe the .LG. or <> operators.
Note that the definition of a comparison expression is not recursive, and therefore comparison expressions cannot contain relational operators in contexts of equal precedence.
The following examples show comparison expressions:
A not expression is an expression in which the operator is .NOT.. It is defined as follows:
Note that the definition of a not expression is not recursive, and therefore not expressions cannot contain adjacent .NOT. operators.
The following examples show not expressions:
A conjunct expression is an expression in which the operator is .AND.. It is defined as follows:
Note that the definition of a conjunct expression is left recursive, and therefore the precedence of the .AND. operator in contexts of equal precedence is left-to-right. Thus, the interpretation of the expression A .AND. B .AND. C is (A .AND. B) .AND. C.
The following examples show conjunct expressions:
An inclusive disjunct expression is an expression in which the operator is .OR.. It is defined as follows:
Note that the definition of an inclusive disjunct expression is left recursive, and therefore the precedence of the .OR. operator in contexts of equal precedence is left-to-right. Thus, the interpretation of the expression A .OR. B .OR. C is (A .OR. B) .OR. C.
The following examples show inclusive disjunct expressions:
An equivalence expression is an expression in which the operator is either .EQV. or .NEQV.. It is defined as follows:
Table 7-13.
| equivalence_expr | is |
| |
|
| or |
|
An exclusive disjunct expression is an expression in which the operator is .XOR.. It is defined as follows:
Note: The Fortran standard does not specify the .XOR. operator.
Note the following:
In the following discussion, equivalence expression means either equivalence expression or exclusive disjunct expression.
The definition of an equivalence expression is left recursive, and therefore the precedence of the .EQV. or .NEQV. operators in contexts of equal precedence is left-to-right. Thus, the interpretation of the expression A .EQV. B .NEQV. C is (A .EQV. B) .NEQV. C.
The following examples show equivalence expressions:
The most general form of an expression is defined as follows:
Table 7-15.
| expr | is |
| |
| defined_binary_op | is |
|
Note that the definition of an expression is left recursive, and therefore the precedence of the binary defined operator in contexts of equal precedence is left-to-right. The interpretation of the expression A .PLUS. B .MINUS. C is thus (A .PLUS. B) .MINUS. C (where .MINUS. is a defined operator).
The following examples show expressions:
The previous sections have described in detail the sorts of expressions that can be formed. These expressions form a hierarchy that can best be illustrated by a figure. Figure 7-1, describes the hierarchy by placing the simplest form of an expression, a variable, at the center of a set of nested rectangles. The more general forms of an expression are the enclosing rectangles, from a primary to an exponentiation expression, to a summation expression, and finally to a general expression using a defined binary operator .CROSS.. Figure 7-1 demonstrates that an expression is all of these special case forms, including the simplest form, a primary.
Table 7-2, illustrates the relationship between the different sorts of expressions by summarizing the definitional forms in one table. The simplest form of an expression is at the bottom and is the primary, as in Figure 7-1. The next, more general, form is second from the bottom and is the defined unary expression; it uses the primary in its definition. At the top of the table is the most general form of an expression.
Table 7-16 summarizes the relative precedence of operators, including the precedence when operators of equal precedence are adjacent. An entry of N/A in the rightmost column indicates that the operator cannot appear in such contexts. The left-most column classifies the operators as defined, numeric, character, relational, and logical operators. Note that these operators are not intrinsic operators unless the types of the operands are those specified in Table 7-17.
Table 7-16. Categories of Operations and Relative Precedences
Category of operator | Operator | Precedence | In context of equal precedence |
|---|---|---|---|
Defined | Unary defined-operator | Highest | N/A |
Numeric | ** | . | Right-to-left |
Numeric | * or / | . | Left-to-right |
Numeric | Unary + or - | . | N/A |
Numeric | Binary + or - | . | Left-to-right |
Character | // | . | Left-to-right |
Relational | .EQ., .NE., .LT., .LE., .GT., .GE., .LG., ==, /=, <, <=, >, >=, <> | . | N/A |
Logical or Boolean | .NOT. | . | N/A |
Logical or Boolean | .AND. | . | Left-to-right |
Logical or Boolean | .OR. | . | Left-to-right |
Logical | .EQV. or .NEQV. | . | Left-to-right |
Logical or Boolean | .XOR. | . | Left-to-right |
Defined | Binary defined-operator | Lowest | Left-to-right |
For example, consider the following expression:
A .AND. B .AND. C .OR. D |
Table 7-2, indicates that the .AND. operator is of higher precedence than the .OR. operator, and the .AND. operators are combined left-to-right when in contexts of equal precedence; thus, A and B are combined by the .AND. operator, the result A .AND. B is combined with C using the .AND. operator, and that result is combined with D using the .OR. operator. Thus, this expression is interpreted the same way as the following fully parenthesized expression:
(((A .AND. B) .AND. C) .OR. D) |
Notice that the defined operators have fixed precedences; defined unary operators have the highest precedence of all operators and are all of equal precedence; defined binary operators have the lowest precedence, are all of equal precedence, and are combined left-to-right when in contexts of equal precedence. Both kinds of defined operators may have multiple definitions in the program unit and therefore may be generic just as intrinsic operators and intrinsic procedures are generic.
As a consequence of the expression formation rules, unary operators cannot appear in a context of equal precedence; the precedence must be specified by parentheses. There is thus no left-to-right or right-to-left rule for any unary operators. Similarly, the relational operators cannot appear in a context of equal precedence; consequently, there is no left-to-right or right-to-left rule for the relational operators. Use of some of the operators as Boolean or masking operators is an extension to the Fortran standard that is supported by the Cray Fortran Compiler.
Note: The Fortran standard does not specify the use of operators as Boolean or masking operators.
Intrinsic operations are those known to the processor. For an operation to be intrinsic, an intrinsic operator symbol must be used, and the operands must be of the intrinsic types specified in Table 7-17.
Note: In the following table, the symbols I, R, Z, C, L, B, and P stand for the types integer, real, complex, character, logical, Boolean, and Cray pointer, respectively. Where more than one type for x2 is given, the type of the result of the operation is given in the same relative position in the next column. Boolean and Cray pointer types are extensions of the Fortran standard.
Table 7-17. Operand Types and Results for Intrinsic Operations
Intrinsic operator | Type of x1 | Type of x2 | Type of result |
|---|---|---|---|
Unary +, - |
| I, R, Z, B, P | I, R, Z, I, P |
Binary +, -, *, /, ** | I | I, R, Z, B, P | I, R, Z, I, P |
| R | I, R, Z, B | R, R, Z, R |
| Z | I, R, Z | Z, Z, Z |
| B | I, R, B, P | I, R, B, P |
| P | I, B, P | P, P, P |
| (For Cray pointer, only + and - are allowed.) |
|
|
// | C | C | C |
.EQ., ==, .NE., /= | I | I, R, Z, B, P | L, L, L, L, L |
| R | I, R, Z, B, P | L, L, L, L, L |
| Z | I, R, Z, B, P | L, L, L, L, L |
| B | I, R, Z, B, P | L, L, L, L, L |
| P | I, R, Z, B, P | L, L, L, L, L |
| C | C | L |
.GT., >, .GE., >=, .LT., <, .LE., <= | I | I, R, B, P | L, L, L, L |
| R | I, R, B | L, L, L |
| C | C | L |
| P | I, P | L, L |
.LG., <> | R | R | L |
.NOT. |
| L | L |
|
| I, R, B | B |
.AND., .OR., .EQV., .NEQV., .XOR. | L | L | L |
| I, R, B | I, R, B | B |
Note: The Fortran standard does not specify the use of type Boolean or the use of type Boolean in masking expressions, nor does it describe the .LG. and <> operators.
The intrinsic operations are either binary or unary. The binary operations use the binary intrinsic operator symbols +, -, *, /, **, //, .EQ., .NE., .LT., .GT., .LE., .GE., and .LG.(and their synonyms ==, /=, <>, <, >=, and <>), .AND., .OR., .XOR., .EQV., and .NEQV.. The unary operations use the unary intrinsic operator symbols +, -, and .NOT..
Note that the intrinsic operators .AND., .OR., .NOT., and .XOR. can be abbreviated as .A., .O., .N., or .X.. If a user-defined operator with the same name as the abbreviated name is accessible in a scope, the abbreviated forms of these operators may not be used as synonyms for .AND., .OR., .NOT., or .XOR..
The intrinsic operations are divided into five classes with different rules and restrictions for the types of the operands. The five classes are numeric intrinsic, character intrinsic, logical intrinsic, relational intrinsic operations, and bitwise masking expressions.
The numeric intrinsic operations use the intrinsic operators +, -, *, /, and **. The operands can be of any numeric type and with any kind type parameters. The result of the operation is of a type specified by Table 7-17, and has type parameters as specified in Section 7.2.8.2.
For example, the following expressions, in which I, R, D, and Z are declared to be of types integer, real, double-precision real, and complex, have the types and type parameters of the variables R, I, D, and Z, respectively:
I + R I * I I - D I / Z |
There is only one character intrinsic operation; it uses the intrinsic operator //. The result of a character intrinsic operation is type character.
The logical intrinsic operations use the intrinsic operators .AND., .OR., .NOT., .EQV., and .NEQV., respectively. The result of a logical intrinsic operation is type logical and has type parameters as specified in Section 7.2.8.2.
The relational intrinsic operations use the intrinsic operators .EQ., .NE., .GT., .GE., .LT., .LE., or .LG. or their symbolic synonyms. A relational intrinsic operation is a numeric relational intrinsic operation if its operands are of type integer, real, or complex. A relational intrinsic operation is a character relational intrinsic operation if its operands are of type character. The result of either kind of relational operation is type logical and has type parameters as specified in Section 7.2.8.2.
Note: The Fortran standard does not describe the .LG. operator.
The operators .NOT., .AND., .OR., .EQV., and .XOR. can also be used in the Cray Fortran Compiler's bitwise masking expressions; these are extensions to the Fortran standard. The result is Boolean (or typeless) and has no kind type parameters.
A defined operation is any nonintrinsic operation that is interpreted and evaluated by a function subprogram specified by an interface block with a generic specifier of the following form:
OPERATOR (defined_operator) |
A defined elemental operation is a defined operation for which the function is elemental.
A defined operation uses either a defined operator or an intrinsic operator symbol, and it is either unary or binary. Its forms are as follows:
|
The terms intrinsic_unary_op and intrinsic_binary_op include all intrinsically defined operators; these terms are not specifically defined in any syntax rules.
x1 and x2 are operands. When an intrinsic operator symbol is used, the type of x2 (for a unary operator) and types of x1 and x2 (for a binary operator) must not be the same as the types of the operands specified in Table 7-17, for the particular intrinsic operator symbol. Thus, you cannot redefine intrinsic operations on intrinsic types.
When a defined operation uses an intrinsic operator symbol, the generic properties of that operator are extended to the new types specified by the interface block. When a defined operation uses a defined operator, the defined operation is called an extension operation, and the operator is called an extension operator. An extension operator can have generic properties by specifying more than one function subprogram in an interface block with a generic specifier of the form OPERATOR (defined_operator).
The data type, type parameters, and shape of a complete expression are determined by the data type, type parameters, and shape of each constant, variable, constructor, and function reference appearing in the expression. The determination is inside-out in the sense that the properties are determined first for the primaries. These properties are then determined repeatedly for the operations in precedence order, resulting eventually in the properties for the expression.
For example, consider the expression A + B * C, where A, B, and C are of numeric type. First, the data types, type parameter values, and shapes of the three variables A, B, and C are determined. Because * has a higher precedence than +, the operation B * C is performed first. The type, type parameters, and shape of the expression B * C are determined next, and then these properties for the entire expression are determined from those of A and B * C.
A defined elemental operation is a defined operation for which the function is elemental.
The type, type parameters, and shape of a primary that is a nonpointer variable or constant are straightforward because these properties are determined by specification statements for the variable or named constant, or by the form of the constant. For example, if A is a variable, its declaration in a specification statement such as the following determines it as an explicit-shaped array of type real with a default kind parameter:
REAL A(10, 10) |
For a constant such as the following, the form of the constant indicates that it is a scalar constant of type complex and of default kind:
(1.3, 2.9) |
For a pointer variable, the type, type parameters, and rank are determined by the declaration of the pointer variable. However, if the pointer is of deferred shape, the shape (in particular, the extents in each dimension) is determined by the target of the pointer. Consider the following declarations and assume that pointer A is associated with the target B:
REAL, POINTER :: A(:, :) REAL, TARGET :: B(10, 20) |
The shape of A is (10, 20).
The type and type parameters of an array constructor are determined by the contents of the constructor. Unless the element is of type Boolean (or typeless), its type and type parameters are those of any element of the constructor because they must all be of the same type and type parameters. If the element is of type Boolean, the type and kind type of the array constructor are the same as the default integer type. Therefore, the type and type parameters of the following array constructor are integer and kind value 1:
(/ 1_1, 123_1, -10_1 /) |
Its shape is always of rank one and of size equal to the number of elements.
The type of a structure constructor is the derived type or type alias used as the name of the constructor. A structure has no type parameters. So, the type of the following structure constructor is the derived type PERSON:
PERSON(56, 'Father') |
(See Section 4.8, for the type definition PERSON.)
A structure constructor is always a scalar.
The type, type parameters, and shape of a function are determined by one of the following:
An implicit type declaration for the function within the program unit referencing the function
An explicit type declaration for the function within the program unit referencing the function (just like a variable)
An explicit interface to the function. (When the interface is not explicit, the function is either an external function or a statement function.)
If the interface is explicit, the type, type parameter, and shape are determined by one of the following:
The type and other specification statements for the function in an interface block within the program unit referencing the function
The type and other specification statements for the internal or module procedure specifying the function
The description of the particular intrinsic function being referenced
Note, however, that because intrinsic functions and functions with interface blocks can be generic, these properties are determined by the type, type parameters, and shapes of the actual arguments of the particular function reference.
For example, consider the following statements as part of the program unit specifying an internal function FCN:
REAL FUNCTION FCN(X) DIMENSION FCN(10, 15) |
A reference to FCN(3.3) is of type default real with shape (10,15). As a second example, consider the following:
REAL(SINGLE) X(10, 10, 10) . . . . . . SIN(X) . . . |
The interface to SIN(3i) is specified by the definition of the sine intrinsic function. In this case, the function reference SIN(X) is of type real with kind parameter value SINGLE and of shape (10,10,10).
The interface is implicit if the function is external (and no interface block is provided) or is a statement function. In these cases, the shape is always that of a scalar, and the type and type parameters are determined by the implicit type declaration rules in effect, or by an explicit type declaration for the function name. In the following example, FCN(X) is a scalar of type integer with kind type parameter value SHORT:
IMPLICIT INTEGER(SHORT) (A-F) . . . . . . FCN(X) . . . |
The one case for variables and functions that is not straightforward is the determination of the shape of a variable when it is of deferred shape or of assumed shape. For a deferred-shape array, the rank is known from the declaration but the size of each dimension is determined as the result of executing an ALLOCATE statement or a pointer assignment statement. For an assumed-shape array, the rank is also known from the declaration but the size is determined by information passed into the subprogram. In the case of pointers, the shape of the object is that of the target associated with (pointed to by) the pointer. The shape of deferred-shape and assumed-shape arrays thus cannot be determined in general until execution time.
The type of the result of an intrinsic operation is determined by the type of the operands and the intrinsic operation and is specified by Table 7-17.
For nonnumeric operations, the type parameters of the result of an operation are determined as follows:
For the relational intrinsic operations, the kind type parameter is that for the default logical type.
For logical intrinsic operations, the result kind type parameter depends on that of the operands. If the operands have the same kind type parameter (that is the same value for KIND=value), the kind type parameter is that of the operands. If logical operands have different kind type parameter values, the value of the result is that of the greater kind type parameter value.
For the character intrinsic operation (//), the operands must have the same kind type parameter, so the result has that kind type parameter.
The character length parameter value for the result is the sum of the character length parameters of the operands.
For numeric intrinsic operations, the kind type parameter value of the result is determined as follows:
For unary operations, the kind type parameter value of the result is that of the operand.
Floating-point operands are those of type real or type complex. If an operation includes a floating-point operand and an integer, the result type and kind type parameter value is determined as follows:
The result type is that of the floating-point operand.
The result kind type parameter value is the same as the kind type parameter value of the floating-point operand.
See Table 7-17, for more information.
If an operation includes operands of type complex and type real, the result type and kind type parameter value is determined as follows:
The result type is type complex.
The result kind type parameter value is that of the greater value. That is, the kind type parameter value of each operand is examined, and whichever kind type parameter value is greater is assigned to the result.
See Table 7-17, for more information.
For binary operations, if the operands are of the same type and kind type parameters, the kind type parameter value of the result is the kind type parameter of the operands.
For binary operations, if the operands are both of type integer but with different kind type parameters, the kind type parameter value of the result is the kind type parameter of the operand with the larger sizes. If the sizes of the two kinds are the same, the kind type parameter value of the result is the same as each operand.
For binary operations, if the operands are both of type real or complex but with different kind type parameters, the kind type parameter of the result is the kind type parameter of the operand with the larger precision. If the decimal precisions are the same, the kind type parameter value is that of the operands.
For numeric intrinsic operations, an easy way to remember the result type and type parameter rules is to consider that the numeric types (integer; real; complex; and Cray Fortran Boolean) are ordered by the increasing generality of numbers. Integers are contained in the set of real numbers and real numbers are contained in the set of complex numbers. Within the integer type, the kinds are ordered by increasing sizes. Within the real and complex types, the kinds for each type are ordered by increasing precision.
Using this model, the result type of a numeric intrinsic operation is the same type as the operand of the greater generality. For the result type parameter, the rule is complicated: if one or both of the operands is of type real or complex, the type parameter is that of the set of numbers of the more general type described above and with a precision as large as the precision of the operands; if both are of type integer, the result type parameter is of a set of numbers that has a range as large as the range of the operands.
To illustrate this ordering, consider Figure 7-2, which shows ordering. For integers, KIND=1 is an 8-bit format, KIND=2 is a 16-bit format, KIND=4 is a 32-bit format and KIND=8 is a 64-bit format; all are twos-complement representations. For the three kinds of real and complex data, KIND=4 is a 32-bit format, KIND=8 is a 64-bit format, and KIND=16 is a 128-bit format, with approximately 7, 16 and 34 significant decimal digits, respectively. Let variables of the 6 numeric types be I1, I2, I4, I8, R4, R8, R16, C4, C8, and C16, where the letter designates the type and the digits designate the kind type parameter. Using this ordering, Table 7-18 shows the type and type parameters of some simple expressions.
Table 7-18. Type and Type Parameters of Some Simple Expressions
Expressions | Type and type parameters are the same as the variable |
|---|---|
I4 + R8 | R8 |
I8 * C16 | C16 |
C8 / C16 | C16 |
I4 - I8 | I8 |
I4 ** C8 | C8 |
R16 + C8 | C16 |
C8 ** I4 | C8 |
I8 - R8 | R8 |
The type and type parameter values of a defined operation are determined by the interface block for the referenced operation and are the type and type parameters of the name of the function specified by the interface block. Note that the operator can be generic and therefore the type and type parameters can be determined by the operands. For example, consider the following interface:
INTERFACE OPERATOR (.PLUS.)
TYPE(SET) FCN_SET_PLUS(X, Y)
USE DEFINITIONS
TYPE (SET) X, Y
INTENT(IN) X, Y
END FUNCTION FCN_SET_PLUS
TYPE(RATIONAL) FCN_RAT_PLUS(X, Y)
USE DEFINITIONS
TYPE(RATIONAL) X, Y
INTENT(IN) X, Y
END FUNCTION FCN_RAT_PLUS
END INTERFACE |
The operation A .PLUS. B, where A and B are of type RATIONAL, is an expression of type RATIONAL with no type parameters. The operation C .PLUS. D, where C and D are of type SET is an expression of type SET with no type parameters.
The shape of an expression is determined by the shape of each operand in the expression in the same recursive manner as for the type and type parameters for an expression. That is, the shape of an expression is the shape of the result of the last operation determined by the interpretation of the expression.
However, the shape rules are simplified considerably by the requirement that the operands of binary intrinsic operations must be in shape conformance; two operands are in shape conformance if both are arrays of the same shape, or one or both operands are scalars. The operands of a defined operation have no such requirement but must match the shape of the corresponding dummy arguments of the defining function.
For primaries that are constants, variables, constructors, or functions, the shape is that of the constant, variable, constructor, or function name. Recall that structure constructors are always scalar, and array constructors are always rank-one arrays of size equal to the number of elements in the constructor. For unary intrinsic operations, the shape of the result is that of the operand. For binary intrinsic operations, the shape is that of the array operand if there is one and is scalar otherwise. For defined operations, the shape is that of the function name specifying the operation.
For example, consider the intrinsic operation A + B where A and B are of type default integer and default real respectively; assume A is a scalar and B is an array of shape (3, 5). Then, the result is of type default real with shape (3, 5).
For most contexts, the lower and upper bounds of an array expression are not needed; only the sizes of each dimension are needed to satisfy array conformance requirements for expressions. The bounds of an array expression when it is the ARRAY argument (first positional argument) of the LBOUND(3i) and UBOUND(3i) intrinsic functions are needed, however.
The functions LBOUND(3i) and UBOUND(3i) have two keyword arguments ARRAY and DIM. ARRAY is an array expression and DIM, which is optional, is an integer. If the DIM argument is present, LBOUND(3i) and UBOUND(3i) return the lower and upper bounds, respectively, of the dimension specified by the DIM argument. If DIM is absent, they return a rank-one array of the lower and upper bounds, respectively, of all dimensions of the ARRAY argument. As described below, these functions distinguish the special cases when the array argument is a name or structure component with no section subscript list from the general case when the array argument is a more general expression. Note that if A is a structure with an array component B, A%B is treated as if it were an array name and not an expression.
When the ARRAY argument is an array expression that is not a name or a structure component, the function LBOUND(3i) returns 1 if the DIM argument is specified and returns a rank-one array of 1s if the DIM argument is absent. For the same conditions, the function UBOUND(3i) returns as the upper bound the size of the requested dimension or the size of all dimensions in a rank-one array.
When the ARRAY argument is an array name or a structure component with no section subscript list, there are four cases to distinguish depending on the array specifier for the name. The following sections describe these four cases.
The LBOUND(3i) and UBOUND(3i) functions return the declared lower and upper bounds of the array name or the structure component with no section subscript list.
INTEGER A(2:10, 11:12) . . . TYPE PASSENGER_INFO INTEGER NUMBER INTEGER TICKET_IDS(2:500) END TYPE PASSENGER_INFO . . . TYPE(PASSENGER_INFO) PAL, MANY(3:10) |
In this example, LBOUND(A) has the value (/ 2, 11 /), and UBOUND(A, 1) has the value 10. LBOUND(PAL%TICKET_IDS) has the value (/ 2 /) and UBOUND(MANY%TICKET_IDS(2), 1) has the value 10.
The name is a dummy argument whose extents are determined by the corresponding actual argument. The dummy argument may have its lower bound in a particular dimension specified but if not, the lower bound is defined to be 1. The LBOUND(3i) function returns these lower bounds. The upper bound for a particular dimension is the extent of the actual argument in that dimension, if no lower bound is specified for the dummy argument. It is the extent minus 1 plus the lower bound if a lower bound is specified. The UBOUND(3i) function returns these upper bounds.
REAL C(2:10, 11:12)
. . .
CALL S(C(4:8, 7:9))
CONTAINS
SUBROUTINE S(A)
REAL A(:, 2:)
. . .
! Reference to LBOUND(A) and UBOUND(A)
. . . |
Inside the body of subroutine S, LBOUND(A) has the value (/ 1, 2 /), because the array starts at subscript position 1 by default in the first dimension and starts at subscript position 2 by declaration in the second dimension. UBOUND(A) has the value (/ 5, 4 /), because there are five subscript positions (4 to 8) in the first dimension of the actual argument corresponding to A, and three subscript positions (7 to 9) in the second dimension of the same actual argument and the subscripts are specified to start at 2 by the declaration of the dummy argument A.
The name is a dummy argument whose upper and lower bounds in all but the last dimension are declared for the dummy argument. The lower bound for the last dimension may be specified in the assumed-size specifier but, if absent, the lower bound is 1. The LBOUND(3i) function returns these lower bounds. The upper bound for all dimensions except the last one is known to the subprogram but the upper bound in the last dimension is not known. The UBOUND(3i) function, therefore, must not be referenced with the first argument being the name of an assumed-size array and no second argument, or the first argument being the name of an assumed-size array and the second argument specifying the last dimension of the array. Otherwise, the UBOUND(3i) function returns the upper bounds as declared for all but the last dimension.
REAL C(2:10, 11:12)
. . .
CALL S (C(4:8, 7:9))
CONTAINS
SUBROUTINE S (A)
REAL A(-2:2, *)
. . .
! Reference to LBOUND(A, 1) and UBOUND(A(:, 2))
! A reference to UBOUND(A) would be illegal.
! A reference to UBOUND(A, 2) would be illegal.
. . . |
Inside the body of subroutine S, LBOUND(A, 1) has the value -2. UBOUND(A(:, 2)) has the value 5 because A(:,2) is an expression, which is an array section, not an array name, and has five elements in the first dimension.
The name is the name of an allocatable array, an array pointer, or a structure component with one of its part references being a pointer array. As such, if the array or a part reference has not been allocated or associated with a target, the LBOUND(3i) and UBOUND(3i) functions must not be invoked with the ARRAY argument equal to such an array name. If it is an array pointer, either its target has been allocated by an ALLOCATE statement or its target has become associated with the pointer using a pointer assignment statement. In the former case, the LBOUND(3i) and UBOUND(3i) functions return the lower and upper bounds specified in the ALLOCATE statement. In the latter case, LBOUND is always 1 in pointer assignment, and UBOUND is the extent of the dimension. Note that for zero-sized dimensions, LBOUND is always 1 and UBOUND is always 0.
REAL, ALLOCATABLE :: A(:, :) . . . ALLOCATE ( A(5, 7:9) ) . . .! Reference to LBOUND(A) and UBOUND(A) . . . |
After the ALLOCATE statement above is executed, LBOUND(A) has the value (/ 1, 7 /), and UBOUND(A) has the value (/ 5, 9 /).
Expressions can appear in statements other than assignment statements, in particular in specification statements. In many cases, such expressions are restricted in some way; for example, the operands in expressions in a PARAMETER statement are essentially restricted to constants. The standard and this manual use specific terms for the various categories of expressions allowed in specific syntactic contexts. For example, the expressions that can be used in PARAMETER statements are called initialization expressions and can be evaluated at the time the program is compiled. Initialization expressions are restricted forms of constant expressions.
The expressions that can be used as array bounds and character lengths in specification statements are called specification expressions. These expressions are scalar and of type integer and can be evaluated on entry to the program unit at the time of execution. The remainder of this subsection describes and defines such limited expressions and summarizes where they can be used.
A constant expression is one of the following constant values or is an expression consisting of intrinsic operators whose operands are any of the following constant values:
A literal or named constant, or a subobject of a constant where each subscript, section subscript, or starting and ending point of a substring range is a constant expression.
An array constructor where every subexpression has primaries that are constant expressions or are implied-DO variables of the array constructor.
A structure constructor where each component is a constant expression.
An elemental intrinsic function reference that can be evaluated at compile time.
A transformational intrinsic function reference that can be evaluated at compile time.
A reference to NULL(3i).
A reference to an intrinsic function that is one of the following:
An array inquiry function other than ALLOCATED(3i)
The bit inquiry function BIT_SIZE(3i)
The character inquiry function LEN(3i)
The KIND(3i) inquiry function
A numeric inquiry function
Each argument of the function must be a constant expression or must be a variable whose type parameters or bounds inquired about are not assumed, defined by an expression that is not a constant expression, or definable by an ALLOCATE or pointer assignment statement.
An implied-DO variable within an array constructor in which the bounds and strides of the corresponding implied-DO are constant expressions.
A constant expression enclosed in parentheses.
The restriction in item 4 to intrinsic functions that can be evaluated at compile-time eliminates the use of the intrinsic functions PRESENT(3i), ALLOCATED(3i), and ASSOCIATED(3i). It also requires that each argument of the intrinsic function reference be a constant expression or a variable whose type parameters or bounds are known at compile time. This restriction excludes, for example, named variables that are assumed-shape arrays, assumed-size arrays for inquiries requiring the size of the last dimension, and variables that are pointer arrays or allocatable arrays. For example, if an array X has explicit bounds in all dimensions, an inquiry such as SIZE(X) can be computed at compile-time, and SIZE(X) + 10 is considered a constant expression.
Constant expressions can be used in any executable statement where general expressions (that is, unrestricted expressions) are permitted.
The following examples show constant expressions:
An initialization expression is a constant expression restricted as follows:
The exponentiation operator (**) is allowed only when the power (second operand) is of type integer; that is, X ** Y is allowed only if Y is of type integer.
Subscripts, section subscripts, starting and ending points of substring ranges, components of structure constructors, and arguments of intrinsic functions must be initialization expressions.
The elements of array constructors must be initialization expressions or implied-DOs for which the array constructor values and implied-DO parameters are expressions whose primaries are initialization expressions or implied-DO variables.
An elemental intrinsic function in an initialization expression must have arguments that are initialization expressions and are of type integer or character. These elemental intrinsic functions must return a result of type integer or character.
A transformational intrinsic function in an initialization expression must be one of the intrinsic functions NULL(3i), REPEAT(3i), RESHAPE(3i), SELECTED_INT_KIND(3i), SELECTED_REAL_KIND(3i), TRANSFER(3i), and TRIM(3i), and must have initialization expressions as arguments; this excludes the use of the transformational functions ALL(3i), ANY(3i), COUNT(3i), CSHIFT(3i), DOT_PRODUCT(3i), EOSHIFT(3i), MATMUL(3i), MAXLOC(3i), MAXVAL(3i), MINLOC(3i), MINVAL(3i), PACK(3i), PRODUCT(3i), SPREAD(3i), SUM(3i), TRANSPOSE(3i), and UNPACK(3i).
An inquiry intrinsic function is allowed, except that the arguments must either be initialization expressions or variables whose type parameters or bounds inquired about are not assumed, not defined by an ALLOCATE statement, or not defined by pointer assignment.
Any subexpression enclosed in parentheses must be an initialization expression.
All but the last examples in Section 7.2.9.1, are initialization expressions. The last are not because initialization expressions cannot contain functions that return results of type real (REAL(3i), LOG(3i)), must not reference certain transformational functions (COUNT(3i), SUM(3i)), or cannot use the exponentiation operator when the second operand is of type real.
The following are examples of initialization expressions:
Initialization expressions must be used in the following contexts:
As initial values following the equal signs in PARAMETER statements and in type declaration statements with the PARAMETER attribute.
As initial values following the equal signs in type declaration statements for variables.
As expressions in structure constructors in DATA statement value lists.
As expressions in default initializers.
As kind type parameter values in type declaration statements; in this case, they also must be scalar and of type integer.
As actual arguments for the KIND(3i) dummy argument of the conversion intrinsic functions AINT(3i), ANINT(3i), CHAR(3i), INT(3i), LOGICAL(3i), NINT(3i), REAL(3i), CMPLX(3i); in this case, they also must be scalar and of type integer.
As case values in the CASE statement; in this situation, they must be scalar and of type integer, logical, or character.
As subscript or substring range expressions of equivalence objects in an EQUIVALENCE statement; in this case, they must be scalar and of type integer.
Initialization expressions must be used for situations where the value of the expression is needed at compile time. Note that the initialization expressions do not include intrinsic functions that return values of type real, logical, or complex, or have arguments of type real, logical, or complex.
A specification expression is a restricted expression that has a scalar value and is of type integer. Specification expressions are used as bounds for arrays and length parameter values for character entities in type declarations, attribute specifications, dimension declarations, and other specification statements (see Table 7-19). A constant specification expression is a specification expression that is also a constant.
Specification expressions are forms of restricted expressions (defined below), limited in type and rank. Briefly, a restricted expression is limited to constants and certain variables accessible to the scoping unit whose values can be determined on entry to the program unit before any executable statement is executed. For example, variables that are dummy arguments, are in a common block, are in a host program unit, or are in a module made accessible to the program unit can be evaluated on entry to a program unit. Array constructors, structure constructors, intrinsic function references, and parenthesized expressions made up of these primaries must depend only on restricted expressions as building blocks for operands in a restricted expression.
A restricted expression is an expression in which each operation is intrinsic and each primary is limited to one of the following:
A constant or constant subobject.
A variable that is a dummy argument with neither the OPTIONAL nor the INTENT(OUT) attribute.
A variable that is in a common block.
A variable made accessible from a module.
A variable from the host program unit.
A variable accessible through USE association.
An array constructor in which every expression has primaries that are restricted expressions or are implied-DO variables of the array constructor.
A structure constructor in which each component is a restricted expression.
An elemental intrinsic function whose result is of type integer or character and whose arguments are all restricted expressions of type integer or character.
One of the transformational intrinsic functions (REPEAT(3i), RESHAPE(3i), SELECTED_INT_KIND(3i), SELECTED_REAL_KIND(3i), TRANSFER(3i), or TRIM(3i)), in which each argument is a restricted expression of type integer or character (this excludes the use of the transformational functions ALL(3i), ANY(3i), COUNT(3i), CSHIFT(3i), DOT_PRODUCT(3i), EOSHIFT(3i), MATMUL(3i), MAXLOC(3i), MAXVAL(3i), MINLOC(3i), MINVAL(3i), PACK(3i), PRODUCT(3i), SPREAD(3i), SUM(3i), TRANSPOSE(3i), and UNPACK(3i)).
An inquiry intrinsic function (except for PRESENT(3i), ALLOCATED(3i), and ASSOCIATED(3i)), in which each argument is one of the following:
A restricted expression. Any subscript, section subscript, and starting or ending point of a substring range is a restricted expression.
A variable whose bounds or type parameters inquired about are not assumed, not defined by an ALLOCATE statement, and not defined by a pointer assignment statement
A reference to any other intrinsic function in which each argument is a restricted expression.
A reference to an external function whose result is a nonpointer scalar intrinsic type.
A reference to a specification function in which each argument is a restricted expression.
A function is a specification function if it is a pure function, is not an intrinsic function, is not an internal function, is not a statement function, does not have a dummy procedure argument, and is not RECURSIVE.
Note: The Fortran standard does not specify restricted expressions in which a primary can be a reference to an external function that is not a specification function and with a result that is a nonpointer scalar intrinsic type.
The following rules and restrictions apply to the use of initialization and specification expressions in specification statements.
The type and type parameters of a variable or named constant in one of these expressions must be specified in a prior specification in the same scoping unit, in a host scoping unit, in a module scoping unit made accessible to the current scoping unit, or by the implicit typing rules in effect. If the variable or named constant is explicitly given these attributes in a subsequent type declaration statement, it must confirm the implicit type and type parameters.
If an element of an array is referenced in one of these expressions, the array bounds must be specified in a prior specification.
If a specification expression includes a variable that provides a value within the expression, the expression must appear within the specification part of a subprogram. For example, consider variable N in the following program segment:
INTEGER N COMMON N REAL A (N) |
N is providing a value that determines the size of the array A. This program segment must not appear in a main program but may appear in the specification part of a subprogram.
A prior specification in the above cases may be in the same specification statement, but to the left of the reference. For example, the following declarations are valid:
INTEGER, DIMENSION(4), PARAMETER :: A = (/4, 3, 2, 1 /) REAL, DIMENSION(A (2)) :: B, C(SIZE(B)) |
B and C are of size 3 (the second element of the array A). The following declaration, however, is invalid because SIZE(E) precedes E:
REAL, DIMENSION(2) :: D(SIZE(E)), E |
The various kinds of expressions may be somewhat confusing, and it can be difficult to remember where they can be used. To summarize the differences, Section 7.2.4, specifies the most general kind of expression; the other kinds of expressions are restrictions of the most general kind. The classification of expressions forms two orders, each from most general to least general, as follows:
Expression, restricted expression, and specification expression
Expression, constant expression, and initialization expression
The relationship between the various kinds of expression can be seen in the diagram in Figure 7-3.
Initialization expressions are not a subset of specification expressions because the result of an initialization expression can be of any type, whereas the result of a specification expression must be of type integer and scalar. Also, specification expressions are not a subset of initialization expressions because specification expressions allow certain variables (such as dummy arguments and variables in common blocks) to be primaries, where as initialization expressions do not allow such variables.
Table 7-19, describes the differences between initialization and specification expressions. Table 7-20, summarizes where each kind of expression is used and gives the restrictions as to their type and rank when used in the various contexts. For example, Table 7-19, indicates that initialization and specification expressions are different in that initialization expressions can be array valued, whereas specification expressions are scalar. A consequence of this difference, as indicated in Table 7-20, is that an initialization expression is used in a type declaration statement or a PARAMETER statement to specify the value of a named constant array, whereas a specification expression is used to specify the bounds of an array in a declaration statement.
Table 7-19. Differences and Similarities Between Initialization and Specification Expressions
Kind of expression: | ||
|---|---|---|
Property: | Initialization | Specification |
Character result | Yes | No[1] |
Integer result | Yes | Yes |
Scalar result | Yes | Yes |
Array result | Yes | No |
Variables as primaries (limited to dummy arguments, common block objects, host objects, module objects) | No | Yes |
Elemental intrinsic functions of type integer and character as primaries | Yes | Yes |
Elemental intrinsic functions of type real, complex, logical, derived type, and type alias as primaries | No | No |
Only constants as primaries | Yes | No |
Only constant subscripts, strides, character lengths | Yes | No |
One of the transformational intrinsic functions REPEAT, RESHAPE, SELECTED_INT_KIND, SELECTED_REAL_KIND, TRANSFER, or TRIM as primaries | Yes | Yes |
Inquiry intrinsic functions (not including ALLOCATED, ASSOCIATED, or PRESENT) as primaries | Yes | Yes |
Reference to specific functions | No | Yes |
Reference to scalar external function with intrinsic type result that is not a specification function [2] | No | Yes |
Table 7-20. Kinds of Expressions and Their Uses
Context | Arb. expr. | Init. expr. | Spec. expr. | Type [3] | Rank [4] |
|---|---|---|---|---|---|
Default integer expression |
|
|
|
|
|
Bounds in declaration statement [5] | No | No | Yes | I | Scalar |
Lengths in declaration statement [6] | No | No | Yes | I | Scalar |
Subscripts and substring ranges in EQUIVALENCE statement | No | Yes | No | I | Scalar |
Values in CASE statement | No | Yes | No | I, L, C | Scalar |
Kind parameters in declaration statement | No | Yes | No | I | Scalar |
Kind arguments in intrinsics | No | Yes | No | I | Scalar |
Initial value in PARAMETER and type declaration statement | No | Yes | No | Any | Any |
DATA implied-DO parameters | No | No | I | Scalar | |
Assignment | Yes | Yes | Yes | Any | Any |
Subscripts in executable statement | Yes | Yes | Yes | I | <1 |
Strides in executable statement | Yes | Yes | Yes | I | Scalar |
Substring ranges in executable statement | Yes | Yes | Yes | I | Scalar |
Expression in SELECT CASE | Yes | Yes | Yes | I, L, C | Scalar |
IF statement | Yes | Yes | Yes | L | Scalar |
Arithmetic IF statement | Yes | Yes | Yes | I, R | Scalar |
DO statement | Yes | Yes | Yes | I, R | Scalar |
Mask in WHERE statement | Yes | Yes | Yes | L | Array |
Mask in WHERE construct | Yes | Yes | Yes | L | Array |
IF-THEN statement | Yes | Yes | Yes | L | Scalar |
ELSE-IF statement | Yes | Yes | Yes | L | Scalar |
Output item list | Yes | Yes | Yes | Any | Any |
I/O specifier values except character FMT= specifier [8] | Yes | Yes | Yes | I,C | Scalar |
I/O FMT= specifier value | Yes | Yes | Yes | C | Any |
RETURN statement | Yes | Yes | Yes | I | Scalar |
Computed GO TO statement | Yes | Yes | Yes | I | Scalar |
Array constructor implied-DO parameters | Yes | Yes | Yes | I | Scalar |
Actual arguments | Yes | Yes | Yes | Any | Any |
I/O implied-DO parameters | Yes | Yes | Yes | I,R | Scalar |
FORALL triplet_spec_list | Yes | Yes | Yes | I | Scalar |
FORALL scalar_mask | Yes | Yes | Yes | L | Scalar |
Expressions in statement function definitions | Yes | Yes | Yes | Any | Scalar |
Example 1: The expressions I*3, 1+2*J, 5*J/3, 1, and 10 in the following statement, are all expressions allowed in subscripts and implied-DO parameter expressions in an implied-DO list in a DATA statement:
DATA ((A(I*3), I = 1+2*J, 5*J/3), J = 1, 10) /.../ |
Example 2: An expression such as RADIX(I) is not allowed as a data implied-DO parameter or subscript of a DATA statement object.
An expression such as N, where N is a variable in the scoping unit that contains the DATA statement, is not allowed because N is neither a named constant nor an implied-DO variable in a containing implied-DO list.
Such special expressions in DATA statements are restricted forms of initialization expressions in the sense that the primaries must not include references to any intrinsic function. On the other hand, they are extended forms of initialization expressions in the sense that they permit the use of implied-DO variables that have the scope of the implied-DO list.
| [1] | Expression results of type character are allowed if they are arguments of an intrinsic function. |
| [2] | This is an extension to the Fortran standard. |
| [3] | "Any" in this column means any intrinsic type, derived type, or type alias. |
| [4] | "Any" in this column means that the result may be a scalar or an array of any rank. |
| [5] | The relevant declaration statements are type declaration, component definition, DIMENSION, TARGET, and COMMON statements. |
| [6] | The relevant declaration statements are type declaration, component definition, IMPLICIT, and FUNCTION statements. |
| [7] | A DATA implied-DO parameter may be an expression involving intrinsic operations with constants and DATA implied-DO variables as operands. |
| [8] | If the I/O FMT= specifier is not of type character, it must be a default integer variable. |
| Prev Section | Table of Contents | Title Page | Index | Next Section |
| Expressions and Assignments | Up one level | Interpretation of Expressions |