HP 3000 Manuals

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