Jump to content United States-English
HP.com Home Products and Services Support and Drivers Solutions How to Buy
» Contact HP
More options
HP.com home
HP Fortran 90 Programmer's Reference: HP Fortran 90 Programmer's Reference > Chapter 5 Expressions and assignment

Expressions

» 

Technical documentation

Complete book in PDF
» Feedback
Content starts here

 » Table of Contents

 » Glossary

An expression is the specification of data and, possibly, a set of operations that enable the computer to evaluate the expression and produce a value. Because an expression results in a value, it has a type, kind, and shape. If an expression is of the character type, it also has a length parameter.

The general form of an expression is:

[operand1] operator operand2
operand1, operand2

are data objects or expressions that evaluate to data. They may be array-valued or scalar-valued.

operator

is either an intrinsic or defined operator. If operator is unary, operand1 must not be specified.

The following sections describe operands, operators, and expressions in more detail.

Operands

An operand may be any of the following:

  • A constant or a variable, such as 1.0, 'ab', or a

  • An array element or an array section, such as a(1,3) or a(1,2:3)

  • A character substring or a structure component, such as ch(1:3) or employee%name

  • An array constructor, such as (/1.0,2.0/)

  • A structure constructor, such as employee(8, "Wilson", 123876)

  • A function reference, such as SQRT(x)

  • An expression in parentheses, such as (b + SIN(y)**2)

Any variable or function reference used as an operand in an expression must have been previously defined. Likewise, any pointer must have been previously associated with a target. If an operand has the POINTER attribute, the target associated with it is the operand.

When an operand is a whole array reference, the complete array is referenced. An assumed-size array variable cannot be an operand. An array section of an assumed-size array can be an operand if the extent of the last dimension of the section is defined by the use of a subscript, a section subscript with an extent for the upper bound, or a vector subscript. (Assumed-size arrays are discussed in “Assumed-size arrays”, and array sections in “Array sections”.)

If two operands in an expression are arrays, they must have the same shape. If one operand is a scalar, it is treated as if it were an array of the same shape as the other operand, in which all elements have the value of the scalar. The result of the operation is an array in which each element is the result of applying the operator repeatedly to corresponding elements of the two operands.

The rules governing how the use of operands in an expression vary, depending on the type of expression. For example, some operands that may appear on the right-hand side of an assignment statement but not in an initialization expression. See “Special forms of expression” for detailed information about the different forms of an expression and the restrictions that those forms impose on operands.

Operators

HP Fortran 90 recognizes the following types of operators:

  • Arithmetic operators

  • Relational operators

  • Concatenation operator

  • Logical operators

  • Bitwise operators

  • Defined operators

All of these except the last are intrinsic operators—that is, the operations they perform are defined by HP Fortran 90. Intrinsic operators are described in the following sections. Defined operators are those that the programmer defines—or overloads, if the operator already has already been defined—using the INTERFACE statement. Defined operators and overloading are discussed in “Defined operators”.

Arithmetic operators

The arithmetic operators are:

  • Additive operators (+ and -). These can be used either as unary operators or binary operators.

  • Multiplicative operators (/, *, and **). These are binary.

Two operands joined by a binary operator can be of different numeric types or different kind type parameters. The type of the result is:

  • If the type and kind type parameters of the operands are the same, the result has the same type and kind type parameter.

  • If the type of the operands is the same but the kind type parameters differ, the result has the same type and the larger kind type parameter.

  • If either operand is of type complex, the result is of type complex.

  • If either operand is of type real and the other operand is not of type complex, the result is of type real.

Except for a value raised to an integer power, each operand that differs in type or kind type parameter from that of the result is converted to a value with the type and kind type of the result before the operation is performed.

Logical and integer operands can be combined with arithmetic operators. The logical operand is treated as an integer of the same kind type parameter, and the result of the operation is of type integer. If the operands have different kind type parameters, the shorter is considered to be extended as a signed integer. For information about logical values, see “Logical operators”.

The arithmetic operators behave as expected, with the following qualifications:

  • The division of an integer by an integer is defined to be the integer closest to the true result that is between zero and the true result.

  • Exponentiation of an integer to a negative integer—i1**i2, where i2 is negative—is interpreted as 1/(i1**(-i2)), where the division is interpreted as described for division of one integer by another.

  • If x1 and x2 are real and x1 is negative, then x1**x2 could be an invalid expression, as the result could be complex. Note, however, that CMPLX(x1)**x2 is valid; the result is the principal value.

The following are HP extensions to Standard:

  • The exponentiation operator may be followed by a signed entity, as in the following example:

    i ** -j 

    (The Standard does not allow adjacent operators.)

  • Operands of logical and integer types may be combined with the arithmetic operators. The logical variable is treated as an integer of equivalent size, and the result of the operation is an integer value. When different lengths of operands are involved, the shorter is considered extended as a signed integer. The following is an example:

    LOGICAL(1) :: boolean1 = -4
    LOGICAL(4) :: boolean4 = 2**16 + 27
    INTEGER(1) :: flag1
    INTEGER(4) :: flag4

    flag4 = boolean4 - boolean1 !set flag4 to 2**16 + 31

    ! a relational operator with a logical operand
    IF (boolean4 > 65536) THEN
    flag1 = -(boolean4/65536) !set flag1 to -1
    ENDIF

Relational operators

The relational operators are .EQ., .NE., .GT., .GE., .LT., .LE., ==, /=, >, >=, <, and <=. All relational operators are binary. The letter forms of the relational operators have the same meaning as the symbol forms. Thus, .EQ. is a synonym for ==, .NE. is a synonym for /=, and so on.

If the operands in a relational operation are numerical expressions with different type or kind type parameters, the operands are converted to the type and kind type parameters that the sum of the operands would have and are then compared; see “Arithmetic operators” for information about the result of mixed arithmetic expressions.

If the operands are character expressions, the shorter operand is blank-padded to the length of the other prior to the comparison. The comparison starts at the first character and proceeds until a character differs or equality is confirmed. See Appendix C for the collating sequence.

Concatenation operator

The concatenation operator is //. It is binary.

In a concatenation operation, each operand of the concatenation operator must be of type character and have the same kind type parameter. The character length parameter of the result is the sum of the character length parameters of the operands.

Logical operators

The logical operator are .AND., .OR., .EQV., .NEQV., .XOR., and .NOT.. The .NOT. operator is unary; the others are binary. The .XOR. is an HP extension having the same meaning as the .NEQV. operator.

As an HP extension, the operands of a logical expression may be of type integer. Functions returning integers may appear in logical expressions, and functions returning logicals may appear in integer expressions.

If the operands of a logical operation have different kind type parameters, the operand with the smaller parameter is converted to a value with the larger parameter before the operation is performed. The result has the larger kind type parameter.

Table 5-1 “Logical operators” shows the behavior of the logical operators for the different permutations of operand values. Note that the .XOR. operator is a synonym for the .NEQV. operator and behaves similarly.

Table 5-1 Logical operators

opnd1

opnd2

.AND.

.OR.

.EQV.

.NEQV.

.NOT. opnd1

.TRUE.

.TRUE.

.TRUE.

.TRUE.

.TRUE.

.FALSE.

.FALSE.

.TRUE.

.FALSE.

.FALSE.

.TRUE.

.FALSE.

.TRUE.

.FALSE.

.FALSE.

.TRUE.

.FALSE.

.TRUE.

.FALSE.

.TRUE.

.TRUE.

.FALSE.

.FALSE.

.FALSE.

.FALSE.

.TRUE.

.FALSE.

.TRUE.

 

Bitwise operators

As an extension to the Standard, HP Fortran 90 allows logical operators to be used as bitwise operators on integer operands. The logical operations are bitwise; that is, they are performed for each bit of the binary representations of the integers. When the operands are of different lengths, the shorter is considered to be extended to the length of the other operand as if it were a signed integer, and the result has the length of the longer operand.

When logical operators are used on integer operands, any nonzero value is considered .TRUE., and a zero value is considered .FALSE. .

In general, an actual argument of type integer may not be used in a reference to a procedure when the corresponding dummy argument is of type logical, nor may an actual argument of type logical be used when the dummy argument is of type integer. As an HP extension, logical and integer arguments may be used interchangeably in calls to bit manipulation intrinsics. See Chapter 11 “Intrinsic procedures” for information about the bit manipulation intrinsics.

The following example shows the use of the .AND. operator to perform a bitwise AND operation:

INTEGER i, j

i = 5
j = 3
PRINT *, i .AND. j

! Output from the PRINT statement: 1

The next example shows the use of logical operators to perform bit-masking operations.

INTEGER(2) mask2
INTEGER(4) mask4
DATA mask2/ -4 /
DATA mask4/Z"ccc2"/

mask4 = mask4 .NEQV. mask2 !set mask4 to Z"ffff333e"

mask2 = .NOT. mask4 !set mask2 to Z"ccc1"

The next example makes a standard-conforming reference to a bit manipulation intrinsic:

INTEGER :: mask = 65535
LOGICAL :: is_even = .FALSE.
IF (IAND(mask,1) /= 0) is_even = .TRUE.

HP Fortran 90 allows the following nonstandard version of the preceding example:

LOGICAL :: mask = z"ffff"

INTEGER :: is_even = .FALSE.
IF (IAND(mask,1)) is_even = .TRUE.

Operator precedence

When an expression expands to

operand1 operator1 operand2 operator2 operand3 ...

each operator is assigned a precedence. The defined order of evaluation is that any subexpressions containing an operator with higher precedence than the adjacent operators is evaluated first. Where operators are of equal precedence, evaluation is from left to right. The exception to this rule is the exponentiation operator (**), which is evaluated from right to left.

Any expression or subexpression may be enclosed in parentheses. These expressions are always evaluated first, using the rules explained above. This usage of parentheses is therefore equivalent to normal mathematical usage.

Table 5-2 “Operator precedence” lists the precedence of the operators, and Table 5-3 “Examples of operator precedence” gives example expressions that illustrate operator precedence.

Table 5-2 Operator precedence

Precedence

Operators

Highest

User defined unary operators

.

**

.

* /

.

Unary + Unary -

.

+ -

.

//

.

.EQ. .NE. .LT. .LE. .GT. .GE.

== /= < <= > >=

.

.NOT.

.

.AND.

.

.OR.

.

.EQV. .NEQV. .XOR.

Lowest

User-defined binary operators

 

Table 5-3 Examples of operator precedence

Expression

How evaluated

Explanation

a+b*c

a + (b*c)

* has a higher precedence than +.

a/b*c

(a/b)*c

/ and * have the same precedence, and evaluation is left to right.

a**b**c

a**(b**c)

** evaluates right to left.

a.AND.b.AND.c.OR.d

((a.AND.b).AND.c).OR.d)

Logical operators evaluate left to right.

 

The Standard allows the compiler to generate code that evaluates an expression by any sequence that produces a result mathematically equivalent to the sequence implied by the statement. This laxity permits code optimization, including (for example) the reordering of expressions and the promotion of common subexpressions.

Because the order of evaluation is not defined by the Standard, a function reference within an expression may not modify any of the other operands within the same expression. For example, fun(x)+x is indeterminate if the reference to fun modifies the value of the argument x.

Special forms of expression

Certain language constructs allow only restricted forms of expressions. For example, the value specified for a named constant in a PARAMETER statement may be defined by an expression, but it must be possible to evaluate the expression at compile-time. This means that the expression must not contain any operands that depend on program execution for their value. To take another example, a bound of a dummy array argument may be specified as an expression, but it must be possible to evaluate this expression on entry to the subprogram.

There are special restrictions imposed on operands and operators that may appear in an expression, depending on whether the expression is one of the following:

  • Constant expressions

  • Initialization expressions

  • Specification expressions

The following sections describe the special forms of expression.

Constant expressions

A constant expression is either a constant or an expression containing only intrinsic operators and constant operands. This restriction also applies to any clearly defined part of a constant—for example, a substring with constant start and end points, or an array or structure constructor. A constant expression may include references to intrinsic functions that can be evaluated at compile-time. A constant expression may appear in any context in which any expression may appear.

The following are examples of constant expressions:

123                   ! an integer literal

"Hello " // " World" ! a character constant expression

3.0_single ! a real literal constant where single is
! a named integer constant

coord(0.0,infinity) ! a structure constructor in which
! "infinity" is a named constant

(/ SQRT(x), x, x*x /) ! an array constructor in which x is a
! named real constant

x*x + 2*x*y + y*y ! a constant numeric expression where x
! and y are named constants

SUM(iterations,DIM=1) ! reference to a transformational
! intrinsic where iterations is an
! array-valued named constant

SHAPE(matrix) ! a reference to an inquiry intrinsic in
! which "matrix" is an array with
! constant bounds

Initialization expressions

An initialization expression is a more specialized form of constant expression that can appear as the initial value in a declaration statement. Initialization expressions have these additional restrictions:

  • Exponentiation is only allowed if the second operand is an integer.

  • Any subexpression within the expression must itself be an initialization expression.

  • All arguments to intrinsic function references must be initialization expressions.

  • Only the following transformational intrinsic functions may be referenced:

    • REPEAT

    • RESHAPE

    • SELECTED_INT_KIND

    • SELECTED_REAL_KIND

    • TRANSFER

    • TRIM

  • Any inquiry intrinsic that is referenced may interrogate a property of an entity (such as bounds or kind type parameter) only if the property is a constant.

  • Any elemental intrinsic functions must have integer or character arguments and an integer or character result.

Initialization expressions are required for the following:

  • Values of named constants. Any entity declared with the PARAMETER attribute must be initialized with an initialization expression.

  • Kind parameter in a type specification statement.

  • The KIND dummy argument of a type conversion intrinsic function.

  • Initial values in type declaration statements.

  • Expressions in structure constructors in DATA statements.

  • Case values in CASE statements.

  • Subscript expressions or substring ranges in EQUIVALENCE statements.

The following entities may not be initialized:

  • Dummy arguments

  • Function results

  • Allocatable arrays

  • Pointers

  • External names

  • Intrinsic names

  • Automatic objects

The following are examples of initialization expressions:

-456                   ! an integer literal

("Hello "// "World") ! a character constant expression

pi * r ** 2 ! a constant numeric expression, where
! pi and r are named constants

ABS(i * j) ! reference to an elemental intrinsic,
! where i and j are named integer
! constants

SELECTED_REAL_KIND(7) ! reference to a transformational intrinsic

The following are illegal initialization expressions:

x ** 2.5               ! the power operand is not an integer

LOG(10.0) ! the intrinsic function is neither
! integer nor character type

SUM( (/ i, 2 /) ) ! reference to a prohibited function

For information about initializing arrays with an array constructor, see “Array constructors”.

Specification expressions

A specification expression has a scalar value, is of type integer, and can be evaluated on entry to the scoping unit in which it appears. A specification expression may appear (for example) as a bound in an array declaration or as the length in a CHARACTER type declaration.

An operand in a specification expression is one of the following:

  • A literal or named constant or part of a constants.

  • A variable that is available by argument, host, or use association or is in common.

  • An array constructor or structure constructor where each element or component is also a specification expression or is a variable in an implied-DO loop appearing in the array constructor.

  • A dummy argument having neither the OPTIONAL attribute nor the INTENT(OUT) attribute.

  • An argument to an intrinsic function.

  • A reference to an elemental intrinsic function that returns an integer result.

  • A reference to any of the following transformational intrinsic functions:

    • REPEAT

    • RESHAPE

    • SELECTED_INT_KIND

    • SELECTED_REAL_KIND

    • TRANSFER

    • TRIM

  • Any inquiry intrinsic except ALLOCATED, ASSOCIATED, and PRESENT. Other inquiry intrinsics may be referenced so long as the property interrogated is not defined by either a pointer assignment or ALLOCATE statement. Furthermore, an inquiry intrinsic may not interrogate the following properties of an assumed size array:

    • Upper bound of the last dimension

    • Extent of the last dimension

    • Size of the array

    • Shape of the array

The differences between specification expressions and initialization expressions are summarized in Table 5-4 “Initialization and specification expressions”.

Table 5-4 Initialization and specification expressions

Initialization expressionSpecification expression

Can be either scalar or array-valued.

Must be scalar-valued.

Can be of any type.

Must be of type integer.

Must be a constant expression.

Can reference variables by host, argument, or use storage association; can reference variables in common.

Except for ALLOCATED, ASSOCIATED, and PRESENT, can reference inquiry intrinsics to interrogate a property of an entity, provided that the property is constant.

Can reference inquiry intrinsic functions, except for ALLOCATED, ASSOCIATED, and PRESENT. The arguments must be specification expressions or variables whose bounds or type parameters inquired about are not assumed, are not defined by the ALLOCATE statement, or are not defined by pointer assignment.

 

The following are examples of specification expressions:

789                    ! an integer literal constant

MAX(m+n,0) ! m and n are integer dummy arguments

LEN(c) ! c is a character variable accessible via
! host association

SELECTED_INT_KIND(5) ! reference to a transformational
! intrinsic

UBOUND(arr,DIM=n) ! reference to an array inquiry
! intrinsic in which arr is an array
! accessible via USE and n is a
! variable in common
Printable version
Privacy statement Using this site means you accept its terms Feedback to webmaster
© Hewlett-Packard Development Company, L.P.