Subroutines [ HP FORTRAN 77/iX Programmer's Guide ] MPE/iX 5.0 Documentation
HP FORTRAN 77/iX Programmer's Guide
Subroutines
Subroutines are user-written procedures that perform a computational
process or a subtask for another program unit. Subroutines usually
perform part of an overall task, such as solving a mathematical problem,
performing a sort, or printing in a special format. Values are passed to
the subroutine and returned to the calling program unit by using
arguments or common blocks.
Structure of a Subroutine
The first statement of a subroutine must be a SUBROUTINE statement. Here
are some examples of SUBROUTINE statements:
SUBROUTINE next(arg1, arg2)
SUBROUTINE last(a, *, *, b, i, k, *)
SUBROUTINE noarg
The subroutine names are next, last, and noarg. Values are passed to a
subroutine by dummy arguments (arg1, arg2, a, b, i, and k in the above
examples) or common blocks. Dummy arguments are also called formal
arguments. Dummy arguments, common blocks, and asterisks are explained
later in this chapter.
A subroutine can contain any statement except another SUBROUTINE
statement, or a BLOCK DATA, FUNCTION, or PROGRAM statement. As an
extension to the ANSI 77 standard, HP FORTRAN 77 subroutines can be
recursive. That is, a subroutine can call itself either directly or
indirectly. For example, in the program below, the subroutine rsub1
directly calls itself.
PROGRAM recursive ! Main program
INTEGER count
count = 0
CALL rsub1(count)
PRINT *, 'final count = ', count
END
SUBROUTINE rsub1(num) ! Subroutine rsub1
IF (num .LT. 5) THEN
num = num + 1
PRINT *, 'num = ', num
CALL rsub1(num) ! rsub1 directly calls itself
END IF
END
The program produces the following output:
num = 1
num = 2
num = 3
num = 4
num = 5
final count = 5
A program that indirectly calls itself is similar in principle to a
subroutine that calls a procedure that in turn calls the original
subroutine.
The END statement in a subroutine causes control to be passed back to the
calling program.
The RETURN statement also transfers control back to the calling program.
You only need to use RETURN statements for returning to the calling
program from a place other than the end of a subprogram. When the RETURN
statement in the subroutine is executed, control normally returns to the
statement following the CALL statement in the calling program. If
necessary, there can be several RETURN statements in a subprogram.
The STOP statement in a subroutine terminates program execution. For
example, the output of the program:
PROGRAM stopit
CALL sub
PRINT *, 'Hello'
END
SUBROUTINE sub
PRINT *, 'Goodbye'
STOP
END
is:
Goodbye
Invoking Subroutines
A subroutine is executed when a CALL statement is specified in a program
unit. Here are some examples of CALL statements:
CALL next(x, y)
CALL last(a, *10, *20, b, i, k, *30)
CALL noarg
When the subroutine is executed, the actual arguments x, y, a, b, i, and
k in the CALL statement are associated with their equivalent dummy
arguments in this way:
PROGRAM main
.
.
.
CALL sub1(actual_arg1, actual_arg2, actual_arg3)
END
updownarrow updownarrow updownarrow
SUBROUTINE sub1(dummy_arg1, dummy_arg2, dummy_arg3)
END
The subroutine is then executed using the actual argument values.
Arguments can be variable names, array names, array elements, record
names, record field names, constants, and expressions.
Values can also be passed to a subroutine by specifying an alternate
return form using asterisks. The use of arguments and asterisks is
described later in this chapter.
Alternate Returns From Subroutines
Normally control from a subroutine returns to the calling program unit at
the statement following the CALL statement. However, you can specify an
alternate return that allows control to return to the calling program
unit at any labeled executable statement.
An alternate return is specified in the called subroutine by the RETURN
statement with an integer expression or constant that identifies the
number of a statement label in the CALL statement. The SUBROUTINE
statement must contain one or more asterisks (*) or ampersands (&)
corresponding to alternate return labels in the CALL statement. An
example of a CALL statement and its associated SUBROUTINE and alternate
return statements is shown below.
PROGRAM alternate
n = 2
CALL sub(n, *10, *20, *30)
10 i = 1
GO TO 50
20 i = 2
GO TO 50
30 i = 3
50 PRINT *, 'i = ', i
PRINT *, 'n = ', n
END
SUBROUTINE sub(n, *, *, *)
RETURN n ! Return to the nth statement
END
Control returns to the main program from the subroutine as follows:
-----------------------------------
| | |
| Returns To | With This |
| Statement | Value of n |
| | |
-----------------------------------
| | |
| 10 | 1 |
| | |
-----------------------------------
| | |
| 20 | 2 |
| | |
-----------------------------------
| | |
| 30 | 3 |
| | |
-----------------------------------
In this example, because n is equal to two, control returns to statement
20. The value of i will be set to two. The output from the program
looks like this:
i = 2
n = 2
If the RETURN statement contains an expression, the value of the
expression cannot exceed the number of asterisks in the SUBROUTINE
statement. Also, for ease of understanding and portability, the number
of asterisks in the SUBROUTINE should equal the number of alternate
return labels specified in the CALL statement. If an expression in a
RETURN statement has a value that is either less than one or greater than
the number of alternate return labels in the CALL statement, control is
returned to the statement following the CALL statement.
An example of a program that uses alternate returns follows. The
subroutine searches a file named parts to validate a part number. Each
record in parts is an integer array of two elements; the first is the
part number and the second is a code. A negative code indicates an
obsolete part number. All existing part numbers are in the file parts.
The records in the file are ordered by increasing part number and, for
simplicity, the search for a part number is sequential. The return from
the subroutine to the main program is summarized below:
---------------------------------------------------------------------------
| | |
| Condition | Type of Return |
| | |
---------------------------------------------------------------------------
| | |
| Part number is found and the part | Normal return to main |
| number is not obsolete | |
| | |
---------------------------------------------------------------------------
| | |
| Part number is obsolete | First alternate return is |
| | taken |
| | |
---------------------------------------------------------------------------
| | |
| Part number is not found | Second alternate return is |
| | taken |
| | |
---------------------------------------------------------------------------
PROGRAM prog
INTEGER part_number
C Get a part number
PRINT *, 'Enter part number '
READ *, part_number
CALL validate(part_number, *100, *200)
C Normal return. Process for valid part number.
PRINT *, part_number
GO TO 999
C First alternate return. Process for obsolete part number.
100 PRINT *, 'Obsolete part number = ', part_number
GO TO 999
C Second alternate return. Process for invalid part number.
200 PRINT *, 'Invalid part number = ', part_number
999 END
SUBROUTINE validate(part_number, *, *)
INTEGER parts_file_record(2), part_number
LOGICAL obsolete_flag, part_found_flag
C Initialize variables
obsolete_flag = .FALSE.
part_found_flag = .FALSE.
parts_file_record(1) = 0
C Search for part number and set flags accordingly
OPEN(111, FILE='parts', STATUS='OLD')
DO WHILE (parts_file_record(1) .LT. part_number)
READ(111,*) parts_file_record
IF (parts_file_record(1) .EQ. part_number) THEN
part_found_flag = .TRUE.
IF (parts_file_record(2) .LT. 0) obsolete_flag = .TRUE.
ENDIF
END DO
CLOSE(111)
C Return to calling program depending on flags
IF (obsolete_flag) RETURN 1
IF (.NOT. part_found_flag) RETURN 2
RETURN
END
MPE/iX 5.0 Documentation