Live and learn!

mcalhoun_at_ksu.edu
Date: 03/26/05


Date: 25 Mar 2005 21:50:06 -0600

I've written FORTRAN since 1965 and have often thought (perhaps too
cockily, if that is a word?) that I was getting pretty good at it.
But I got "bitten" a few days ago! As a (former) teacher, let me
work up to the point. Here is a simple program which writes the
contents of a list three different ways:

      PROGRAM Example1

c---- Declare/initialize a list of vowels (reason for *4 comes later)
      CHARACTER*4 Vowels(5)/'A', 'E', 'I', 'O', 'U'/
      INTEGER I

c---- Write Vowels three different ways
      WRITE (*,*) 'Test #1'
      WRITE (*,'(5(2x,a))') Vowels ! An array name

      WRITE (*,*) 'Test #2'
      DO I = 1, 5 ! Explicit DO
         WRITE (*,'(2x,a)') Vowels(I)
      END DO

      WRITE (*,*) 'Test #3'
      WRITE (*,'(5(2x,a))') (Vowels(I), I=1,5) ! Implied DO

      END
------------------------------------------------------------------

Instead of the program referring to the list directly, let
a (statement) function make the references:

      PROGRAM Example2

      CHARACTER*4 Vowels, List(5)/'A', 'E', 'I', 'O', 'U'/
      INTEGER I

c---- Define statement function which returns a List element
      Vowels(I) = List(I)

c---- Test #1 does not compile, so comment it out:
c WRITE (*,*) 'Test #1'
c WRITE (*,'(5(2x,a))') Vowels ! An array name

      WRITE (*,*) 'Test #2'
      DO I = 1, 5 ! Explicit DO
         WRITE (*,'(2x,a)') Vowels(I)
      END DO

      WRITE (*,*) 'Test #3'
      WRITE (*,'(5(2x,a))') (Vowels(I), I=1,5) ! Implied DO

      END
------------------------------------------------------------------

To hide some details, let's make the statement function to an EXTERNAL
function (if it were separately compiled years ago, by now it probably
would be "out of sight, out of mind"):

      PROGRAM Example3

      CHARACTER*4 Vowels
      EXTERNAL Vowels
      INTEGER I

      WRITE (*,*) 'Test #2'
      DO I = 1, 5 ! Explicit DO
         WRITE (*,'(2x,a)') Vowels(I)
      END DO

      WRITE (*,*) 'Test #3'
      WRITE (*,'(5(2x,a))') (Vowels(I), I=1,5) ! Implied DO

      END

c***************************************************************************
      CHARACTER*4 FUNCTION Vowels(I)

c---- External function which returns a List element via subscription

      CHARACTER List(5)/'A', 'E', 'I', 'O', 'U'/
      INTEGER I

      Vowels = List(I)

      END

------------------------------------------------------------------

The actual function (which created ANSI escape sequences and which I
did write long ago) also needed number(s) in the output, so I used a
WRITE statement instead of subscription (main program is UNchanged):

      CHARACTER*4 FUNCTION Vowels(I)

c---- External function which returns a List element via WRITE statement

      CHARACTER List(5)/'A', 'E', 'I', 'O', 'U'/
      INTEGER I

      WRITE (Vowels,1) List(I), I
    1 FORMAT (a, '(', i1, ')')

      END

The output for this last version is:

Test #2
A(1)
E(2)
I(3)
O(4)
U(5)
Test #3
G:\tt4.FOR(10) : run-time error F6205: WRITE(internal)
- A edit descriptor expected for CHARACTER

The output from the "regular" DO stilled worked, but the implied-DO did
NOT. Although I'm using Microsoft FORTRAN 5.10, I think my real problem
was that I violated section 12.11 of the '77 standard:

     12.11 Restrictions on Function References and List Items

     A function must not be referenced within an expression appearing
     anywhere in an input/output statement if such a reference causes
     an input/output statement to be executed.

What is especially interesting is that I have used my external cursor-
control functions for years without any problem -- until I tried using
one of them with an implied-DO!

FWIW, I solved the problem by rewriting the function this way
(again, main program is UNchanged):

      CHARACTER*4 FUNCTION Vowels(I)

c---- External function which returns a List element via subscription
c and a little character manipulation

      CHARACTER List(5)/'A', 'E', 'I', 'O', 'U'/
      INTEGER I

      Vowels = List(I) // '(' // CHAR(I+ICHAR('0')) // ')'

      END

Live and learn!

-- 
--Myron A. Calhoun.
Five boxes preserve our freedoms:  soap, ballot, witness, jury, and cartridge
PhD EE (retired).   "Barbershop" tenor.   CDL(PTXS).  W0PBV.   (785) 539-4448
NRA Life Member and Certified Instructor (Home Firearm Safety, Rifle, Pistol)

Quantcast