In Fortran, calculations are specified by writing expressions. Expressions look much like algebraic formulas in mathematics, particularly when the expressions involve calculations on numerical values.
Expressions often involve nonnumeric values, such as character strings, logical values, or structures; these also can be considered to be formulas that involve nonnumeric quantities rather than numeric ones.
This chapter describes how valid expressions can be formed, how they are interpreted, and how they are evaluated. One of the major uses of expressions is in assignment statements where the value of an expression is assigned to a variable. The assignment statement appears in four forms: intrinsic assignment, defined assignment, masked array assignment, and pointer assignment. In the first three forms, a value is computed by performing the computation specified in an expression and the value is assigned to a variable. In the fourth form, a pointer, the object on the left side, is made to point to the object or target on the right side. The four forms of the assignment statement are also described in this chapter.
Note: The Fortran statement syntax in this manual is defined using the same terms used in the Fortran standard. In this chapter, however, certain terms from the standard have been changed to improve clarity.
Fortran allows you to define data types, operators for these types, and operators for intrinsic types. These capabilities are provided within the general framework for expressions, which consists of three sets of rules:
The rules for forming a valid expression
The rules for interpreting the expression (giving it a meaning)
The rules for evaluating the expression (how the computation may be carried out)
An expression is formed from operators and operands. There is no change from FORTRAN 77 for forming expressions, except for the definition of new class of operators. As well as the classic operators, there are user-defined operators that are either unary or binary operators. They have the form of a sequence of letters surrounded by periods; .INVERSE. and .PLUS. are examples of possible user-defined operators.
The formal (BNF) rules for forming expressions imply an order for combining operands with operators. These rules specify that expressions enclosed in parentheses are combined first and that, for example, the multiply operator * is combined with its operands before the addition operator + is combined with its operands. This order for operators in the absence of specific parentheses is called the operator precedence and is summarized in Section 7.2.5. Modern operators, such as == and >=, have the same precedence and meaning as .EQ. and .GE., respectively.
The formation rules for expressions imply that the defined unary operators have highest precedence of all operators, and defined binary operators have the lowest precedence of all operators. When they appear in a context where two or more of these operators of the same precedence are adjacent, the operands are combined with their operators in a left-to-right manner, as is the case for the familiar + and - operators, or in a right-to-left manner for the exponentiation operator (**).
Intrinsic operators are generic in the sense that they can operate on operands of different types. For example, the plus operator + operates on operands of type integer as well as real and complex. Intrinsic operators can be extended further by the programmer to operate on operands of types for which there are no intrinsic operations. Similarly, you can use defined unary and defined binary operators to operate on operands of types for which there are no previous definitions. The Fortran Language Reference Manual, Volume 2, describes how any operator can be made generic by the programmer using a generic specifier on an interface block.
The rules for interpretation of an expression are provided by the interpretation of each operator in the expression. When the operator is an intrinsic operator such as +, *, or .NOT., and the operands are of intrinsic types allowed for the intrinsic operator, the interpretation is provided by the usual mathematical or symbolic meaning of the operation. Thus, + with two numeric operands means that the two operands are added together. For the user-defined operators, the interpretation is provided by a user-supplied function subprogram with a designation that this subprogram is to be used to define the operation. Fortran allows the intrinsic operator symbols to be extended to cases in which the operands are not of the usual intrinsic types defined by the standard. For example, the + operator can be defined for operands of type RATIONAL (a user-defined type) or for operands of type logical with the interpretation provided by a user-supplied function subprogram. The rules for construction of expressions (the syntax rules) are the same for user-defined operators as for intrinsic operators.
The general rule for evaluation of a Fortran expression states that any method that is mathematically equivalent to that provided by the construction and interpretation rules for the expression is permitted, provided the order of evaluation indicated by explicit parentheses in the expression is followed. Thus, a compiler has a great deal of freedom to rearrange or optimize the computation, provided the rearranged expression has the same mathematical meaning.
Arrays and pointers as objects can appear in expressions and assignment statements. This chapter describes using arrays and pointers in the following contexts:
As operands of intrinsic and user-defined operations
As the variables being assigned in intrinsic assignment statements
As the variables in pointer assignment statements and masked array assignment statements
The result obtained from the evaluation of an expression can be used in many ways. For example, it can be printed or passed to a subprogram. In many cases, however, the value is assigned to a variable and that value can be used later in the program by referencing the variable.
Execution of the assignment statement causes the expression to be evaluated (by performing the computation indicated), and then the value of the expression is assigned to the variable on the left of the equal sign.
The following example shows an assignment statement:
REAL_AGE = REPORTED_AGE + 3.0
REPORTED_AGE + 3.0 is the expression that indicates how to compute a value, which is assigned to the variable REAL_AGE.
The following example involves subscripts:
A(I+3) = PI + A(I-3)
The value of the subscript expression I-3 is determined and the value of the I-3 element of A is added to the value of PI to produce a sum. Before the result of this expression is assigned, the value of the subscript expression I+3 is determined and the value of the sum is assigned to the element I+3 of A.
The previous examples are arithmetic. Fortran has expressions of other types, such as logical, character and derived type. Values of expressions of these other types can be assigned to variables of these other types. As with operators, the programmer can extend the meaning of assignment to types not defined intrinsically and can redefine assignment for two objects of the same derived type. Such assignments are called defined assignments. In addition, arrays and pointers each have special forms of assignment statements called masked array assignment and pointer assignment, respectively. These two assignment statement forms are described later in this chapter.
An assignment statement is only one of the Fortran statements in which expressions may occur. Expressions also can appear in subscripts, actual arguments, IF statements, PRINT statements, WHERE statements, declaration statements, and many other statements.
An expression represents a computation that results in a value and can be as simple as a constant or variable. The value of an expression has a type and can have zero, one, or two type parameter values. If the value is of a derived type or of a type alias that describes a derived type, it has no type parameter. If it is of an intrinsic type, it has a kind type parameter, and if, in addition, it is of the type character, it has a character length parameter. In addition, the value is a scalar (including a structure) or an array.
A complex value or a structure value is a scalar, even though it can consist of more than one value (for example, a complex value consists of two real values).
Arrays and pointers can be used as operands of intrinsic and defined operators. For intrinsic operators, when an array is an operand, the operation is performed element-wise on the elements of the array. For intrinsic operators, when a pointer is an operand, the value of the target pointed to by (associated with) the pointer is used as the operand. For defined operators, the array or pointer is used in a manner determined by the procedure defining the operation.
As indicated in the introduction to this chapter, the presentation of expressions is described in terms of the following three basic sets of rules:
The rules for forming expressions (syntax)
The rules for interpreting expressions (semantics)
The rules for evaluating expressions (optimization)
The syntax rules indicate which forms of expressions are valid. The semantics indicate how each expression is to be interpreted. After an expression has been given an interpretation, a compiler can evaluate another completely different expression, provided the expression evaluated is mathematically equivalent to the one written.
To see how this works, consider the expression 2 * A + 2 * B in the following PRINT statement:
PRINT *, 2 * A + 2 * B
The syntax rules described later in this chapter indicate that the expression is valid and suggest an order of evaluation. The semantic rules specify the operations to be performed, which in this case, are the multiplication of the values of A and B by 2 and the addition of the two results. That is, the semantic rules indicate that the expression is to be interpreted as if it were the following:
((2 * A) + (2 * B))
After the correct interpretation has been determined, the Fortran rules of evaluation allow a different expression to be used to evaluate the expression, provided the different expression is mathematically equivalent to the one written. For example, a processor can first add A and B and then multiply the result by 2, because the following expression is mathematically equivalent to the one written:
2 * (A + B)
Parentheses must not be violated. Consider the following expression:
(2 * A) + (2 * B)
This expression must not be evaluated as follows:
2 * (A + B)
This gives the programmer some control over the method of evaluation.
Integer division is not mathematically equivalent to real division. The value of 3/2 is 1 and so cannot be evaluated as 3*0.5, which is 1.5.
Mathematically equivalent expressions can produce computationally different results because of the implementation of arithmetic and rounding on computer systems. For example, the expression X/2.0 could be evaluated as 0.5*X, even though the results may be slightly different. Also, for example, the expression 2 * A + 2 * B could be evaluated as 2*(A+B); when A and B are of type real, the two mathematically equivalent expressions may yield different values because of different rounding errors and different arithmetic exceptions in the two expressions.