[comp.lang.fortran] DO loops, anyone?

bernhold@qtp.ufl.edu (David E. Bernholdt) (03/11/89)

I run the following code on my Sun 3/50 with VMS compatible f77:

      PROGRAM LOOP
      IGO = 1
      DO 501 I = 1, 10
         WRITE (6,*) 'OUTER LOOP, I =',I
         IF (IGO .NE. 0) GOTO 501
         DO 501 J = 1, 5
            WRITE (6,*) 'INNER LOOP, J=',J
 501     CONTINUE
         STOP
         END

And I get the following output:

  OUTER LOOP, I =  1
  INNER LOOP, J=  1
  INNER LOOP, J=  2
  INNER LOOP, J=  3
  INNER LOOP, J=  4
  INNER LOOP, J=  5
  OUTER LOOP, I =  2
  OUTER LOOP, I =  3
  OUTER LOOP, I =  4
  OUTER LOOP, I =  5
  OUTER LOOP, I =  6
  OUTER LOOP, I =  7
  OUTER LOOP, I =  8
  OUTER LOOP, I =  9
  OUTER LOOP, I =  10

Notice that the inner DO loop is executed exactly once.

My questions are these:

1) Is the code standard-conforming?  I think it is, but perhaps I am
mistaken.

2) If the code is standard-conforming, is the execution correct?  As
far as I can tell, the inner DO should never be activated!

Please, no flames about the code itself.  I did not write it - I just
get to port it.
-- 
David Bernholdt			bernhold@qtp.ufl.edu
Quantum Theory Project		bernhold@ufpine.bitnet
University of Florida
Gainesville, FL  32611		904/392 6365

charlie@mica.stat.washington.edu (Charlie Geyer) (03/12/89)

In article <458@orange19.qtp.ufl.edu> bernhold@qtp.ufl.edu 
(David E. Bernholdt) writes:
 
>      PROGRAM LOOP
>      IGO = 1
>      DO 501 I = 1, 10
>         WRITE (6,*) 'OUTER LOOP, I =',I
>         IF (IGO .NE. 0) GOTO 501
>         DO 501 J = 1, 5
>            WRITE (6,*) 'INNER LOOP, J=',J
> 501     CONTINUE
>         STOP
>         END
>
> 1) Is the code standard-conforming?  I think it is, but perhaps I am
> mistaken.

No.  Statement 501 is in the range of the inner DO loop.  So the GOTO
branches into the range of an inactive loop.  This is not allowed.

There was a very long discussion about this about a month ago.

Some compilers are friendlier about this than others.  Two compilers
here execute the code the way you expect.  But there is no "correct"
way to execute this code.

zdenko@csd4.milw.wisc.edu (Zdenko Tomasic) (03/12/89)

In article <458@orange19.qtp.ufl.edu> bernhold@qtp.ufl.edu (David E. Bernholdt) writes:
>
>I run the following code on my Sun 3/50 with VMS compatible f77:
>
>      PROGRAM LOOP
>      IGO = 1
>      DO 501 I = 1, 10
>         WRITE (6,*) 'OUTER LOOP, I =',I
>         IF (IGO .NE. 0) GOTO 501
                               ^^^ This branch is illegal
>         DO 501 J = 1, 5
>            WRITE (6,*) 'INNER LOOP, J=',J
> 501     CONTINUE
 ^^^^ since it jumps into the inner loop from outside
>         STOP
>         END
>

(lines to fool stupid inews, hit n key now)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
--
___________________________________________________________________
Zdenko Tomasic, UWM, Chem. Dept., P.O. Box 413, Milwaukee, WI 53201
UUCP: uwvax!uwmcsd1!uwmcsd4!zdenko
ARPA: zdenko@csd4.milw.wisc.edu

calvin@dinkum.SGI.COM (Calvin H. Vu) (03/13/89)

I hope this will not turn out (for you) to be like the case of a boy's 
returning a book about penguin to the publisher with the explanation : "Sorry 
but this book tells me more about penguins than I ever wanted to know" :-).   
However, this issue has been discussed before without arriving at any 
conclusions so I would like to take this opportunity to chip in my 2c.

First, to answer your question:

<< From bernhold@qtp.ufl.edu Sat Mar 11 07:49:54 1989
<< I run the following code on my Sun 3/50 with VMS compatible f77:
<< 
<<       PROGRAM LOOP
<<       IGO = 1
<<       DO 501 I = 1, 10
<<          WRITE (6,*) 'OUTER LOOP, I =',I
<<          IF (IGO .NE. 0) GOTO 501
<<          DO 501 J = 1, 5
<<             WRITE (6,*) 'INNER LOOP, J=',J
<<  501     CONTINUE
<<          STOP
<<          END
<< 
<< And I get the following output:
<< 
<<   OUTER LOOP, I =  1
<<   INNER LOOP, J=  1
<<   INNER LOOP, J=  2
<<   INNER LOOP, J=  3
<<   INNER LOOP, J=  4
<<   INNER LOOP, J=  5
<<   OUTER LOOP, I =  2
<<   OUTER LOOP, I =  3
<<   OUTER LOOP, I =  4
<<   OUTER LOOP, I =  5
<<   OUTER LOOP, I =  6
<<   OUTER LOOP, I =  7
<<   OUTER LOOP, I =  8
<<   OUTER LOOP, I =  9
<<   OUTER LOOP, I =  10
<< 
<< Notice that the inner DO loop is executed exactly once.
<< 

	The reason the inner loop is executed only once is that there is no
	code generated by the compiler to determine the currently-active DO
	loops.   Hence the jump to label 501 will execute the loop condition
	for the inner loop first.   As you may guess, the value of J is 
	undefined since the inner loop has never been activated (which causes
	the DO variable J to be initialized).   The first time this jump is
	taken, J has the value 0 (as the undefined value on most systems but 
	nobody can guarantee this though) and so the inner loop will get 
	activated as if nothing is wrong (NOTE that if your inner loop were
	DO J=4,5 instead, you will definitely notice something funny going on
	since the inner loop will still be executed from 1 to 5).   On
	exitting the loop, J will now have the value 6 and so subsequent jump
	will not cause the inner loop to be executed.

	To prove this just add one statement to your program as follows:

      ................
      DO 501 I = 1, 10
         WRITE (6,*) 'OUTER LOOP, I =',I
C	Add the following statement to generate a random value from 0 to 6
C	for J before the jump is taken and see how randomly the innerloop
C	gets executed.    Of course, if you want more violent behaviour you
C	can try any random negative values but don't be surprised if it takes
C	a few days to executes those random semi-infinite loops.
	 J = IMOD(IRAND(), 6)
         IF (IGO .NE. 0) GOTO 501
         DO 501 J = 1, 5
	 ...........

	BTW, do not feel p_ssed off if your compiler gives you complete BS.
	Eight out of ten compilers behave thataway.

<< My questions are these:
<< 
<< 1) Is the code standard-conforming?  I think it is, but perhaps I am
<< mistaken.
<< 
<< 2) If the code is standard-conforming, is the execution correct?  As
<< far as I can tell, the inner DO should never be activated!

	1) It conforms with the standard in my interpretation of it.   Several
	people, however, claim that you cannot jump to the terminal statement 
	if that statement is shared with an inside loop.   They use the 
	general definition of the range of DO-loop to claim that since the 
	terminal statement partly belongs to the inner loop it has to belong
	"exclusively" to the inner loop.    Some computer systems also support
	this for expediency reason (I will go into that later with more data
	to support my theory).

	2) The execution is incorrect.   You are right that the inner loop 
	should never gets activated (since it is never active according to ANSI
	definition of active DO loop) but wait until you see all the flames 
	following this ... :-)

<< Please, no flames about the code itself.  I did not write it - I just
<< get to port it.
	To make this bitchy code portable and produce the correct result across 
	most computers that do not declaring this as illegal, just add one
	statement to your code outside both loops to give J a well-define value:

      IGO = 1
C	Initialize J to the value of the inner loop's terminal value.
C	This will make it works on most computers that allows this
C	construction.    However, there are a few
C	@#@#@% compilers (standard UNIX f77, for example) that checks for 
C	J=6 (instead of J>5) as the terminating condition so I can't guarantee 
C	this.
	J = 5
      DO 501 I = 1, 10
         WRITE (6,*) 'OUTER LOOP, I =',I
         IF (IGO .NE. 0) GOTO 501
         DO 501 J = 1, 5




And now for some discussion about an old ghost, if you are not interested hit
'n' quick.   It is going to be lengthy.    Flame me for being long-winded.

<< Tim Hopkins,                  { trh@ukc.ac.uk
<< From: trh@ukc.ac.uk (T.R.Hopkins)
<< "More than one DO-loop may have the same terminal statement"
<< 
<< Section 11.10.2 states
<< A DO-loop is either active or inactive. Initially inactive, a DO-loop
<< becomes active only when its DO statement is executed.
<< 
<< Seems to me that when the GOTO is executed the inner loop is inactive. 
<< The effect of the transfer is thus to increment the outer loop counter
<< (see 11.10.3 and 11.10.4) and restart the outer iteration. 

	Hey, there is one person in the net who thinks the same way as I do.

And this is the work of Steven R Weintraub (cs.utexas.edu!oakhill!devsys!steve)
in the last discussion.   Although he arrived at a different conclusion his
posting seemed to confirm my suspicion why so many people screwed up this
code construction.

<<  Computer                         Compiler         Result Er Msg Comment 
<<  -------------------------------- ---------------- ------ -----  -------
<<  AT&T 3B1 - UNIX PC Model 7300    SVS FORTRAN             Yes    2 
<<  AT&T 3B2/400 - 3B2/3B15 Computer FORTRAN 77 XLA+      92 *
<<  Apollo DN 3000 Aegis 9.7                           65785 *
<<  CRAY COS1.15                                           ? Yes    1
<<  Cray                             CFT                     Yes    4
<<  Cray                             CFT77                   Yes    4
<<  Cyber 205 Vsos 237                                       Yes    2
<<  -------------------------------- ---------------- ------ ----- -------
<<  Cyber 855 Nos 2.5.3                                   82 *
<<  Eta-10Q   R0120N2                                        Yes    2
<<  Harris H-800 VOS 7.1             sauf77               82 Yes
<<  Harris HCX-9 HCX/UX (unix)       f77                  82 No
<<  Harris HCX-9 HCX/UX (unix)       hf77                 92 No
<<  IBM PC/AT                        Professional FORTRAN    Yes    2,5
<<  ISTLA - Toolpack Static Analyser, Version 1.2            Yes    3
<<  -------------------------------- ---------------- ------ ----- -------
<<  Prime                            Fortran 66           92 *
<<  Prime                            Fortran 77            ? *      1
<<  Pyramid OSX4.0                                        80 *
<<  Rolm 1666                        Remora F77 (b-test)     Yes    2
<<  Rolm 1666                        Remora F77 (b-test)  80 Yes    2,6
<<  SUN OS 4.0                                            92 *
<<  SUN OS 4.2 rel 3.5                                    92 *
<<  -------------------------------- ---------------- ------ ----- -------
<<  VAX/VMS 4.7                                           92 *

<< *It should be pointed out that it is probably safe to assume if the result
<< I recieved did not mention a warning message, the compiler probably did not
<< generate one.
<< 
<< Index to comments :
<<  1  Infinite loop generated
<<  2  Error reported from compiler - compiler produced no code.
<<  3  Portability anaylzer, not compiler
<<  4  Final answer not given in post.
<<  5  Compiler made by Ryan-McFarland Corporation
<<  6  Option to enable block jumping turned on. Ansi compatablity warning given.
<< 
<< Let us look at what the proper responses should be.  There are actually
<< three.  The first is that the compiler can error out and produce no code.
<< Of the compilers that were reported, five did this.  One of these had
<< a compiler option to compile through this, generating the next proper
<< response, 80.  80 is the result that is generated when the outer do
<< loop misses the K = K + 1 increment (as if a continue existed at that
<< line).  Only one other compiler generated this result.  The other correct
<< result is 82.  This the 80 result plus two increments for K = K + 1
<< from the outer loop.  Only three compilers got this answer.
<< 
<< Of the wrong answers recieved, they fell into two catagories : 92 and
<< infinitely large (or loops).  92 was the most common response to the
<< code, given by six compilers.  This leads me to suspect I fail to see
<< what the code is to do, but I believe that these compilers do two
<< increments on the internal loop jump-out.  As for the infinite answers
<< three computers answered this way.  I generated this case knowing that
<< on some compilers (specifically the Apollo), DO loops are generated 
<< technically wrong in order to make them perform extensions.

	From this results, I can classify them into 3 groups:

	1)  The Do-it-right:  These are the people who do take care of
	active/inactive loop and produce the correct result of 82.   
	In order to do this they have to pay a price in runtime performance
	and may lose (in sales) to some stupid compiler in some stupid 
	benchmarks. However,  they chose integrity over expediency over this.   
	I would give them three cheers.   It's a pity that they are the 
	minority.
<<  Cyber 855 Nos 2.5.3                                   82 *
<<  Harris H-800 VOS 7.1             sauf77               82 Yes
<<  Harris HCX-9 HCX/UX (unix)       f77                  82 No

	2)  The Cop-out:  These guys sticks with the benchmark but have the 
	decency not to deliberately generate random results for the same
	piece of code depending whatever the stack happens to contain.  They
	cop out and give an error message for this usage.   Note that ETA/Cyber
	belongs to both group 1 and 2.   If they really think that the usage
	is illegal why do they allow it on another system of theirs ?   I know
	for sure that implementing the proper solution for this would create a
	dependency that would severely effect vectorization of the DO loops.
	Therefore, my guess is that they only generate the correct code for 
	the non-vectorizing computers only (Am I correct that Cyber 855 is 
	not a vectorizing computer ?) and generate errors for the vectorizing
	computers (Cyber 205 & ETA10) to save the users from killing themselves
	with random results and to save them from killing themselves in the
	benchmarks.
	This approach is acceptable but I wish that the manufacturers could
	be more honest about it and admit their shortcoming instead of blaming
	the users for writing illegal code.    C'mon, give me a break !
	Where does it say in the ANSI standard that a DO loop termination 
	label does not belong to its own DO loop if that label is shared by 
	an inner loop ?

	3) The Who-cares--You-asked-for-it:   These guys just go merrily along
	and generate the usual loop control code for the shared DO loops
	without caring about ANSI definition of an active loop 
	(ANSI 11.10.2:   "A DO-loop is either active or inactive.  Initially 
	inactive, a DO-loop becomes active only when its DO statement is 
	executed.")    This causes the code to generate random results
	depending what you happened to have on the stack.   Some company
	even goes so far to rationalize their shortcoming as to have this
	in their documentation:

	"If two or more nested DO loops share the same terminal statement, you
	can transfer to that statement only from within the range of the 
	innermost loop.   Any other transfer to that statement constitutes
	a transfer from an outer loop to an inner loop because the shared
	statement is part of the range of the innermost loop."

	The lame excuse consist of two statements that contradict one another.
	And maybe it's perfectly fine with them to give random results in
	executing exactly the same piece of code that's why they never warn
	the users about what REALLY HAPPENS when that "constitutes a transfer
	from an outer loop to an inner loop" occurs.   Unfortunately, they
	are considered the pseudo-standard in forfran compiler so a lot
	of companies can cop out by simply saying "Hey, that's what the
	pseudo standard says and we are not doing any worse than them!".

	It is true that the terminal statement is shared with the inner loop
	but that does not cause the "constitutes blah blah ..." to happen.
	The statement is executed since it belongs to the currently active
	DO loop and the loop control processing should proceed according
	to ANSI rule (see 11.10.4 for details, I'm too lazy to type not that 
	I want to quote anything out of context) :

	"However, if some of the DO-loops sharing the terminal statement 
	are active, execution continues with incrementation processing,
	as described in 11.10.7"

	And ANSI 11.10.7 on incrementation processing:
	"(1) The DO-variable, the iteration count, and the incrementation
	parameter of the active DO-loop whose DO statement was most recently
	executed, are selected for processing."

	Note the words "active", and "DO statement was most recently executed".
	Did the DO statement for the inner loop get executed ?   Then why all
	this constitutes-blah-blah BS ?    Sorry for blowing off steam but,
	IMHO, a compiler, of all programs, has to be correct.   It is simply
	frightening to think that it can deliberately be implemented/documented
	to bluff the users into believing that its incorrect code is correct
	without warning about the subsequent random results.   Remind me of
	a bridge in Australia that collapsed while under construction (with
	a huge cost) due to a programming bug.   Can you guess which way our
	missiles will be flying if some hapless programmers use this kind
	of construction using this kind of compiler ?

	BTW, the result 92 produced by many compilers is due to the 
	initial value of 0 for the inner loop variable the first time the
	jump is taken and the value > terminal value for subsequent jumps.
	In other words, it is exactly the same thing that happened to 
	bernhold@qtp.ufl.edu.


That's all for cataloguing.  Now, for my own history of the world:

The shared terminal statement belongs to both loops but, in no instances, it
belongs to both loops at once.    In other words, it can belong to either
loop at a time but not both.   The rule as to which loop it belongs to 
is the same as the rule for loop control processing i.e. it should belong to
the most current active DO loop.  (It is similar to some guys sharing a 
baseball bat, but only one of them can go to bat at a time).   This would 
explain the example in the ANSI standard (section 11.10.7) and gives the
correct result of N=0.

	N=0
	DO 200 I=1,10
	J=1
	DO 200 K=5,1
	L=K
200	N=N+1
201	CONTINUE

After the DO statement for the inner loop is executed, the shared terminal 
statement falls into its range and will not be executed (since the inner loop 
is K=5,1 and is not executed) even though the outside loop is active and gets 
executed.

Since the terminal statements always belong to the most current active DO-loop
any GOTO statement from inside the DO loop to its own DO label is permitted
and is perfectly legal.    That makes sense, doesn't it ?

I would welcome any discussion on this but please remember that we are
talking about a special case of DO-loops sharing the same terminal statement
so please do not quote the following definition on the range of a DO loop 
(which I can recite backward BTW :-)) and use it as the rule-of-thumb for
everything:
	11.10.1 _Range_of_a_DO-Loop_.  The _range_of_a_DO-Loop_ consists of
	all of the executable statements that appear following the DO
	statement that specifies the DO-Loop, up to and including the terminal
	statement of the DO-loop.

and without quoting the statement following it:
	"More than one DO-loop may have the same terminal statement"
and without explaining what the heck the ANSI rule talks about for 
loop control processing for DO-loops sharing the same terminal statements and
the definition of active/inactive DO loops (the whole purpose of this
active/inactive definitions is just to resolve this exact seemingly
ambiguity anyway).

And please do not tell me that since the two DO-loops have the same terminal
statement, the statement belongs to only one of them (unless you can quote
ANSI to say that the shared statement belongs exclusively to the inner loop
and is not shared with the outer loop).   If that's what English is I think 
I'd better learn Greek  :-).   It can surely save me a lot of headache.


Calvin H. Vu
Silicon Graphics Computer Systems
calvin@sgi.sgi.com

"Since homo sapiens have two arms and two legs  by the official rule of thumb, 
anybody without both arms and both legs is not human".
				Official Definition of Human Range


-------------------------------------------------------------------------
DISCLAIMER:
"Nobody, even my mum, wants to have anything to do with my foul language"

calvin@dinkum.SGI.COM (Calvin H. Vu) (03/14/89)

In my last article I posted the test results from steve without posting
the test itself so it maight be confusing to the people who did not follow
the last discussion.    So, here it is:

	K = 0
	DO 10 I = 1,10
	IF (I.EQ.1.OR.I.EQ.5) GOTO 10
	DO 10 J = 1,10
	IF (J.EQ.3) GOTO 10
10	K = K + 1
	PRINT *,K
	END

BTW, this was NOT a good test since you have no control over the initial
value of J.   So the three compilers (Cyber 855, Harris H-800, and Harris f77)
might have produced the correct result just because J happenned to have an 
uninitialized random value >10 when the test was run.

Sorry for all the doom-saying,

Calvin H. Vu
Silicon Graphics Computer Systems,

steve@oakhill.UUCP (steve) (03/15/89)

I hate long articles but since I did alot of thought on this subject
earlier I though I'd bore you with the benefit of my cognition.  The
test case I posted earlier had three acts that combine to cause
ambiguity.  These are:

  1) Do loops ending on the same statement
  2) The end statement being executable.
  3) A jump in the external Do loop to the terminating statement.

All three of these are needed to result in the ambiguity.  In the test
case posted:

> <<       PROGRAM LOOP
> <<       IGO = 1
> <<       DO 501 I = 1, 10
> <<          WRITE (6,*) 'OUTER LOOP, I =',I
> <<          IF (IGO .NE. 0) GOTO 501
> <<          DO 501 J = 1, 5
> <<             WRITE (6,*) 'INNER LOOP, J=',J
> <<  501     CONTINUE
> <<          STOP
> <<          END

this is not the cause of the problem.  The true cause of the problem
is that the compiler was tring to resolve the chance of ambiguity,
and generated the bad code.  This is the same as the compilers that
generated 92 in the test case I posted.  Let's look at my test case again.

      K = 0
      DO 10 I = 1,10
        IF (I.EQ.1.OR.I.EQ.5) GOTO 10
        DO 10 J = 1,10
          IF (J.EQ.3) GOTO 10
   10 K = K + 1
      PRINT *,K
      END

I claim there are three responses.

 1) Error out.
 2) Execute K = K + 1 as part of the inner loop (Thus the external goto 
    jumps past this statement).  (result 80)
 3) Execute K = K + 1 as part of both loops.  (result 82)

The biggest problem is the the interpretation of what this last statement
means.  The three different interpretation result in the three above results.
The hardest one to implement is the third.  To see why let's look at the
block code generated (For the explaination of the bug that is in the
first code and produced 92 in my case, it is at the end)

For case 2:

   k = 0
   iter1 = 10
   i = 1
LABEL1:
   jump i == 1 or i == 5 LABEL4
   iter2 = 10
   j = 1
LABEL2:
   jump j == 3 LABEL3
LABEL3:
   k = k + 1
   iter2 = iter2 - 1
   j = j + 1
   jump iter2 > 0 LABEL2
LABEL4:
   iter1 = iter1 - 1
   i = i + 1
   jump iter1 > 0 LABEL1
   call print(k)
   end

For case 3:

   k = 0
   iter1 = 10
   i = 1
LABEL1:
   jump i == 1 or i == 5 LABEL4
   iter2 = 10
   j = 1
LABEL2:
   jump j == 3 LABEL3
LABEL3:
   k = k + 1
   iter2 = iter2 - 1
   j = j + 1
   jump iter2 > 0 LABEL2
   jump LABEL5:
LABEL4:
   k = k + 1
LABEL5:
   iter1 = iter1 - 1
   i = i + 1
   jump iter1 > 0 LABEL1
   call print(k)
   end

Note the differences between the two.  The second case must generate 
k = k + 1 twice.  Also it MUST generate the jump to LABEL5:.  It is
the failure to generate this jump that cause the error in the code
(caused the generation of 92 in my case).  The code for the second
case is both slower and harder to generate. 

There is a big temptation to try to tamper with the fragile structure
to speed it up that results in the generation error.  The inifinite
loop errors results from this temptation.  If you allow block jumps
you must use a iteration variable and guard against the iteration
count falling below zero (use <= as opposed ==).  The reason is that
the loop variable can be used outside it's loop.  And if a jump is
made into a do loop, the iteration will be decremented again, a less
than zero will allow the fall through (you can optimize out the
iteration variable only once you determine there is no external jump
into the loop).

Personally I really don't care which interpretation is chosen.  My
theory is that once one or the other is accepted, that the compiler
writer should try to cover the hardship for the user.  The complaints
I've heard about FORTRAN that the lexical analyser is to hard to 
write fall in this catagory.  If the user perfers to start his programs
in column 7, that's his preference.  The compiler writer should do
his work without complaining.

The problem I see is there is a repeated desire to do this code.
Unfortunately the standard refuses to see the upcry, and claims the
whole situation is illegal.  Compiler writers support this extension
(often without warning) to support the market cry, unfortunately
the ambiguity and bad generated code is the unhappy result.

                   enough from this mooncalf - Steven
----------------------------------------------------------------------------
To flame someone for bad spelling or grammer is a discouragement to net
discussion in a timely fashion.
----------------------------------------------------------------------------
These opinions aren't necessarily Motorola's or Remora's - but I'd like to
think we share some common views.
----------------------------------------------------------------------------
Steven R Weintraub                        cs.utexas.edu!oakhill!devsys!steve
Motorola Inc.  Austin, Texas 
(512) 440-3023 (office) (512) 453-6953 (home)
----------------------------------------------------------------------------

maine@pioneer.arc.nasa.gov (Richard Edwin Maine D-OFA) (03/15/89)

Calvin Vu of Silicon Graphics gives a long-winded explanation of
why he thinks the following piece of code is legal.

<<       PROGRAM LOOP
<<       IGO = 1
<<       DO 501 I = 1, 10
<<          WRITE (6,*) 'OUTER LOOP, I =',I
<<          IF (IGO .NE. 0) GOTO 501
<<          DO 501 J = 1, 5
<<             WRITE (6,*) 'INNER LOOP, J=',J
<<  501     CONTINUE
<<          STOP
<<          END

His whole argument is based on the statement that:

<The shared terminal statement belongs to both loops, but in no instance it
<belongs to both loops at once.    In other words, it can belong to either
<loop at a time but not both.   The rule as to which loop it belongs to 
<is the same as the rule for loop control processing i.e. it should belong to
<the most current active DO loop.

There is nothing like this anywhere in the ANSI standard.  In fact,
the ANSI standard (section 11.10.1) makes it quite clear that indeed
the statement DOES belong to the range of both do loops.  Nowhere does
the standard hint that a statement may not belong to the range of
multiple do loops at the same time.  Indeed, the concept of time
is not mentioned at all in conjunction with the range of a do loop.
Time relates to the activation of a do loop, but not to its range.
This claim and concept seems to come solely from the mind of
Calvin Vu (and admitedly others that seem to agree with him).  If
you claim support for this position in the standard, please provide
section reference.

Once this arbitrary rule is dismissed, all is clear.  There are no
contradictions (at least on this subject) in the standard.  The
only contradictions are with this rule, which is not in the standard.

True the terminal statement is in the range of the outer loop, which
is active.  However it is ALSO in the range of the inactive inner loop.
Therefore branching to it is illegal.  Note that nowhere do I use the
term "exclusive".  It is Calvin that is trying to argue that the
statement should belong exclusively to one loop at a time, not I.

Calvin says

<so please do not quote the following definition on the range of a DO loop 
<(which I can recite backward BTW :-)) and use it as the rule-of-thumb for
<everything:
<	11.10.1 _Range_of_a_DO-Loop_.  The _range_of_a_DO-Loop_ consists of
<	all of the executable statements that appear following the DO
<	statement that specifies the DO-Loop, up to and including the terminal
<	statement of the DO-loop.
<
<and without quoting the statement following it:
<	"More than one DO-loop may have the same terminal statement"
< ... and stuff about active/inactive loop definitions.

Ok, I'll quote em both.  And I'll claim that 11.10.1 IS the rule-of-thumb
for everything.  It is after all the standard.  Calvin's claim that
a statement cannot simultaneously be in the range of 2 loops is not
in the standard and is flatly contradicted by 11.10.1.  The statement
that more than one DO-loop may have the same terminal statement makes
no contradictions.

The business about active and inactive loops does NOT have anything
to do with the range of the loops.  You are trying to make a connection
that isn't there.  The range is a static concept that is not a function
of time.

Calvin further states

< to make this bitchy code portable and produce the correct result across 
< most computers that do not declaring this as illegal, just add one
< statement to your code outside both loops to give J a well-define value:
<
<C	Initialize J to the value of the inner loop's terminal value.
<C	This will make it works on most computers that allows this
<C	construction.    However, there are a few
<C	@#@#@% compilers (standard UNIX f77, for example) that checks for 
<C	J=6 (instead of J>5) as the terminating condition so I can't guarantee 
<C	this.
<	J = 5
<       DO 501 I = 1, 10
<         WRITE (6,*) 'OUTER LOOP, I =',I
<         IF (IGO .NE. 0) GOTO 501
<         DO 501 J = 1, 5

Yukk! In the name of "portability" you try to second guess the inner workings
of the compiler?  Remind me not to try porting any of your code.  To make
this code portable, add a continue statement with a separate statement
number as the terminator of the outer DO-loop.  This is not only portable
(really - like it'll run on anything), it is even standard.  What an odd
coincidence.

The only "reasonable" (my term, not ANSI's) thing for a compiler to
do with this code is bitch.  ANSI doesn't demand it, but I do.
(Not that I always get what I demand, but it doesn't stop me).  If
the compiler wants to invent some extension like Calvin's, I suppose
its fine with me, as long as it also warns you that this is non-ANSI.

As an aside, has anyone noticed that the draft 8X standard (at least
the Jun 87 version that I have) DOES require the compiler to provide
diagnostics for code that violates the standard?  I've never seen
much discussion of this "little" change.  I sure like it.  I've
long taken the position that "reasonable" compilers would do this,
but with this clause, I'd be able to make that position quite a
bit stronger (and includable in procurement specifications, etc.)
This would mean that if a compiler did not bitch about non-ANSI
usages (to the extent statically determinable), I could claim
the compiler was not in conformance.

Richard Maine
maine@elxsi.dfrf.nasa.gov
(sending this from maine@pioneer.arc.nasa.gov because we don't have
posting set up on elxsi).

urjlew@ecsvax.UUCP (Rostyk Lewyckyj) (03/16/89)

Arguing about whether this code conforms to the standard, and/or
how it should be interpreted beggs what I think is the real problem
and rational solution.
The problem is that the standard allows a code construction that
easily leads to misuse and stepping over the legal limits. I.e.
the standard permits a DO loop to end with non trivial executable
statements (eg  k=k+1 rather than continue or enddo) and it allows
the closure of multiple DO loops on one statement. 
The defensive/safety minded programmer can easily avoid the problem 
by liberal use of CONTINUE statements to remove ambiguities.
I think that the rational solution is to amend the standard (put it
in 8x or 9x if 8x never makes it) to require DO loops to be terminated
one at a time with CONTINUE or ENDDO statements.
I realize that this will require modifying old source. However since
the cases that need modifying can (I think) be caught by the compiler
it is not as bad a change as the 0 trip vs 1 trip through the loop
change which occured in most 66 to 77 compiler rewrites.
I don't think that issuing a warning is enough.
  
PS.  I tried the test program on IBM VS FOortran rel v 2.2 and the current
compiler on our CONVEX C220.  
 IBM gave two warning messages one for each GOTO 10 and produced
 differnent values of K depending on the initial value of J.
 CONVEX gave no warning messages and also produced different values
 of K.
-----------------------------------------------
  Reply-To:  Rostyslaw Jarema Lewyckyj
             urjlew@ecsvax.UUCP ,  urjlew@tucc.bitnet
       or    urjlew@tucc.tucc.edu    (ARPA,SURA,NSF etc. internet)
       tel.  (919)-962-9107

calvin@dinkum.SGI.COM (Calvin H. Vu) (03/16/89)

I guess I have been so inculcated with the ideas of block-structured
programming where each block has a uniquely-identifiable nested level
associated with it so I could not think straight in the way ANSI does 
in its amorphous definition of DO-loop range.

I thought since the terminal statement was shared by the two ranges it
must belong to both nested levels as an exception to the general rule!   But,
alah, there is no such thing as a nested level in ANSI.   They just have 
a dozen different rules concerning cross-range activities & definitions 
to make sure that they don't mess anything up with their rules.

In other words, a range in ANSI standard doesn't mean anything.   It is
simply a point-A-to-point-B definition and is in no way equivalent to
the idea of a block which has an implied nested level associated with it.
ANSI has to enforce dozens other rules to simulate the illusion of a block
which caught me (and, apparently, some other people) off guard.

In short, there is no such thing as a block in ANSI.    If you want to make
sure whether it is legal to do something according to ANSI standard or not, 
look it up the their numerous rules.   I'm sure it is in there somewhere.

BTW, I realized this after I had time to really peruse the ANSI standard
and realize the full implication of all their rules after my Sunday 
posting/dinner.   I would say that your argument is pretty good though,
although it falls into the ANSI track of cerebration that you have to 
look up in the book and follows the rules instead of relying on your
general concept of programming practice.


> < to make this bitchy code portable and produce the correct result across 
> < most computers that do not declaring this as illegal, just add one
> <
> <C	Initialize J to the value of the inner loop's terminal value.
> <C	This will make it works on most computers that allows this
> <C	construction.    However, there are a few
> <C	@#@#@% compilers (standard UNIX f77, for example) that checks for 
> <C	J=6 (instead of J>5) as the terminating condition so I can't guarantee 
> <C	this.
> 
> Yukk! In the name of "portability" you try to second guess the inner workings
> of the compiler?  Remind me not to try porting any of your code.  To make
> this code portable, add a continue statement with a separate statement
> number as the terminator of the outer DO-loop.  This is not only portable
> (really - like it'll run on anything), it is even standard.  What an odd
> coincidence.
	I was so sure that the original poster knew about your approach that
	was why he asked not to be flamed for it.   And now I got flamed 
	because I wanted to join in the fun and explained the phenomenon
	he encountered and how to hack his way out of it.   I hope you don't
	think that you are the only person who thought of the idea of using
	two different labels for the two loops!
	My approach wouldn't work on vectorizing computer where they use
	their own compiler-generated variables/registers for the DO-loop
	variables (usually they also state that changing the DO-loop variable
	inside the loop will not effect the execution of the loop if that's
	what they implement).    However, I'm sure it will work in the way
	the original poster expected on his Appolo.   (I love gambling so
	I almost always terminate my sentences with "wanna bet ?" but I
	guess I'd better refrain from it in this case.   Etiquette is a
	real pain: It spoils all the fun !).   I don't write program like
	like that and neither does the original poster (as was made
	obvious in his don't-flame-me remark) but why shouldn't we have some 
	fun with it ?   As I said, it would work with MOST computers that
	allow the construction but hey, this is obviously hacking and how 
	can I guarantee a hack ?.

Calvin Vu

"Hackers have more fun!"

khb@fatcity.Sun.COM (Keith Bierman Sun Tactical Engineering) (03/16/89)

In article <22754@ames.arc.nasa.gov> maine@pioneer.arc.nasa.gov.UUCP (Richard Edwin Maine  D-OFA) writes:
>
>
>As an aside, has anyone noticed that the draft 8X standard (at least
>the Jun 87 version that I have) DOES require the compiler to provide
>diagnostics for code that violates the standard?  I've never seen
>much discussion of this "little" change.  I sure like it.  I've
>long taken the position that "reasonable" compilers would do this,
>but with this clause, I'd be able to make that position quite a
>bit stronger (and includable in procurement specifications, etc.)
>This would mean that if a compiler did not bitch about non-ANSI
>usages (to the extent statically determinable), I could claim
>the compiler was not in conformance.

I have not yet studied the current draft (to be voted on in May), but
the general rule of thumb is as f77... define standard conforming
PROGRAMS, not compilers (a standard comforming compiler is that thing
which compiles the entire class of standard comforming compilers
correctly). This is not an oversight, it is a very well thought out
position. Ada (and some other languages) take a very different stand.
But in order to allow compiler vendors to extend the language, the
committee has stuck with the "traditional" fortran design.

So I would not start crafting clauses about diagnostics into your
procurement spec's yet.

btw: For what it is worth, I am no longer a member of the public.
     I am now the SunAlternate to x3j3.

Cheers all.


Keith H. Bierman
It's Not My Fault ---- I Voted for Bill & Opus

charlie@mica.stat.washington.edu (Charlie Geyer) (03/16/89)

In article <6667@ecsvax.UUCP> urjlew@ecsvax.UUCP (Rostyk Lewyckyj) writes:
 
> The problem is that the standard allows a code construction that
> easily leads to misuse and stepping over the legal limits. I.e.
> the standard permits a DO loop to end with non trivial executable
> statements (eg  k=k+1 rather than continue or enddo) and it allows
> the closure of multiple DO loops on one statement. 
> The defensive/safety minded programmer can easily avoid the problem 
> by liberal use of CONTINUE statements to remove ambiguities.
> I think that the rational solution is to amend the standard (put it
> in 8x or 9x if 8x never makes it) to require DO loops to be terminated
> one at a time with CONTINUE or ENDDO statements.
> I realize that this will require modifying old source.

A simpler solution would have compilers do run-time error checking and
not jump into inactive loops.  The beauty of this solution is that it
does not not slow down structured code -- no checking necessary.

Unstructured code would take a performance hit.  Serves it right :-)

It's not failure to end every loop with its own CONTINUE that is the
problem.  It is (surprise!) GOTO's are harmful.

steve@oakhill.UUCP (steve) (03/16/89)

In article <1317@uw-entropy.ms.washington.edu>,
             charlie@mica.stat.washington.edu (Charlie Geyer) writes:
> 
> A simpler solution would have compilers do run-time error checking and
> not jump into inactive loops.  The beauty of this solution is that it
> does not not slow down structured code -- no checking necessary.
> 
> Unstructured code would take a performance hit.  Serves it right :-)
> 
> It's not failure to end every loop with its own CONTINUE that is the
> problem.  It is (surprise!) GOTO's are harmful.

As I stated in my previous post.  There is NO problem with the code as
posted.  It is not ambiguous.  The problem is that the compiler, in
order to prevent any posssible ambiguity, generates bad code.  The
true ambiguity results in the following three elements used together.

  1) Two or more do loops ending on the same line.
  2) One or more of the external do loops (not the inner most)
     jumping to the terminating statement.
  3) The terminating statement being executable (not a CONTINUE).

Admittedly the practice of ending do loops on the same line is not
sound programming.  But it is historic programming, and is still used
today.  As for the performance hit you talk about, well that's part of
the problem here. 

If you looked at the pseudocode I posted Tuesday, the proper code for
is large and slow.  Compiler writers don't like this.  It doesn't sell
compilers.

First you MUST use an iteration count.  Code generators don't like to.
More code.  You can only remove that iteration counter once you are
sure there are no jumps into the DO block (an illegal situation often
supported).  This checking to get things right slows down the
compiler.  The right code is larger and slower than your competition's
(who did things wrong but fast).

Also for the same reason you must check less than equal to zero on the
iteration count.  An operation that is slower on many computers.

Also one interpretation requires either generating the terminating
line's code twice, or making some mechanism which truely does the
checking.  Bulky and slow.  Won't sell the compiler. 

In order to speed up the code, the compiler maker took a short cut
they properly shouldn't have.  The compiler generates faster code on
all DO loops, but it gets a few marginal cases wrong.  Since the
workaround here is obvious and better programming methodology (Put two
terminal statements), they'll be glad to tell you the workaround
and say they are working on the problem.

                   enough from this mooncalf - Steven
----------------------------------------------------------------------------
To flame someone for bad spelling or grammer is a discouragement to net
discussion in a timely fashion.
----------------------------------------------------------------------------
These opinions aren't necessarily Motorola's or Remora's - but I'd like to
think we share some common views.
----------------------------------------------------------------------------
Steven R Weintraub                        cs.utexas.edu!oakhill!devsys!steve
Motorola Inc.  Austin, Texas 
(512) 440-3023 (office) (512) 453-6953 (home)
----------------------------------------------------------------------------

charlie@mica.stat.washington.edu (Charlie Geyer) (03/17/89)

In article <1317@uw-entropy.ms.washington.edu>, I wrote:

  A simpler solution would have compilers do run-time error checking and
  not jump into inactive loops.  The beauty of this solution is that it
  does not not slow down structured code -- no checking necessary.

  Unstructured code would take a performance hit.  Serves it right :-)

  It's not failure to end every loop with its own CONTINUE that is the
  problem.  It is (surprise!) GOTO's are harmful.

In article <1905@devsys.oakhill.UUCP> steve@oakhill.UUCP (steve) replies:
 
> As I stated in my previous post.  There is NO problem with the code as
> posted.  It is not ambiguous.  The problem is that the compiler, in
> order to prevent any posssible ambiguity, generates bad code.  The
> true ambiguity results in the following three elements used together.
>
>  1) Two or more do loops ending on the same line.
>  2) One or more of the external do loops (not the inner most)
>     jumping to the terminating statement.
>  3) The terminating statement being executable (not a CONTINUE).

The code as posted (we are still talking about the original posting aren't
we?) is, as several other people have pointed out, wrong.  It DOES have a
problem.  It jumps into the range of an inactive DO loop.  This is
forbidden.  It is not the job of a compiler to guess what conforming
program the programmer thought he was writing.  It would be nice for
compilers to produce code that catches this error, at least as an option.

> Admittedly the practice of ending do loops on the same line is not
> sound programming.  But it is historic programming, and is still used
> today.  As for the performance hit you talk about, well that's part of
> the problem here. 

So make it an option that can be turned off.

In article <18178@vax5.CIT.CORNELL.EDU> btcx@vax5.cit.cornell.edu (Brian T
Carcich) replies:

> Well, not quite.
> 
> Now, I'm not a GOTO freak, and I learned to only goto CONTINUE's, but
> does anybody realize the origin of the anti-GOTO religion?  And how the above
> statement is a misrepresentation of that origin? (see BTW below) 
> 
> It's not GOTO's that are harmful, but POOR USE OF goto's that's harmful.

O. K., but that would have made a much weaker punchline.  If you want to
be pedantic, unstructured use of GOTO's is harmful, and jumping in and out
of DO loops is about as unstructured as you can get.  Is that o.k.?

> Go back to .c or .pascal or .modula or ... where you belong.  
> leave us dinosaurs alone!

Believe me.  I don't write FORTRAN by choice.  Lately I've taken to
writing some of my FORTRAN in C (thereby incurring who knows what
portability problems).  But you just can't ever get completely
away from FORTRAN.  It's everywhere.

urjlew@ecsvax.UUCP (Rostyk Lewyckyj) (03/17/89)

In article <1317@uw-entropy.ms.washington.edu>, charlie@mica.stat.washington.edu (Charlie Geyer) writes:
> 
> In article <6667@ecsvax.UUCP> urjlew@ecsvax.UUCP (Rostyk Lewyckyj) writes:
>  
> > I think that the rational solution is to amend the standard (put it
> > in 8x or 9x if 8x never makes it) to require DO loops to be terminated
> > one at a time with CONTINUE or ENDDO statements.
> > I realize that this will require modifying old source.
> 
> A simpler solution would have compilers do run-time error checking and
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ???
By run time the compiler is long gone 8-). 
  
> not jump into inactive loops.  The beauty of this solution is that it
> does not not slow down structured code -- no checking necessary.
> 
> Unstructured code would take a performance hit.  Serves it right :-)
> 
If you are dynamically checking your branches at run time you are
using time to do it , i.e. taking a performance hit     NO???
  
> It's not failure to end every loop with its own CONTINUE that is the
> problem.  It is (surprise!) GOTO's are harmful.
  
Baloney! It isn't goGOTOs that are harmfull, its spagetti code that
attempts to bend the legal limits of the rules,and and is convoluted
either because the programmer can't do better or is attempting to
be clever., that is bharmfull.
  
Let me slightly amend my recommentdations.
Pro1 Prohibit gotbranches into the scope of a DO loop, whether to a statement
well inside the loop or the terminal statement. CThExcept to the DO state-
ment itsleelf from a statement outside the DO.
2 Prohibit the extended range of the DO. i.e. branching out of the DO
and then back in.
3 Require a each DO loop to be terminated by its own ENDDO, which can not
be the target of a branch.
  
I am suggesting these stricter rules because I realize that my previous
suggestions could still get misused by transbranching from outside a loop
to the terminal cCONTINUE of any loop. 
  
If the standard were amended in this way , then probabbly a great 
amount of special rules and interpretations could be removed, Thus
making the language more robust and simplifying the standard at the
same time.
Since the adherence to the rules I propose should be checkable 
at compile time there would be no run time performance penalty.
I also think that , bthese changes would permit better program srtructure
analaysis by the compiler and the production of more optimized code.
The onl y problem I see with my suggestions are the at rule 2 will
break too many codes.


-----------------------------------------------
  Reply-To:  Rostyslaw Jarema Lewyckyj
             urjlew@ecsvax.UUCP ,  urjlew@tucc.bitnet
       or    urjlew@tucc.tucc.edu    (ARPA,SURA,NSF etc. internet)
       tel.  (919)-962-9107

steve@oakhill.UUCP (steve) (03/17/89)

In article <1320@uw-entropy.ms.washington.edu>,
             charlie@mica.stat.washington.edu (Charlie Geyer) writes:
> 
> In article <1317@uw-entropy.ms.washington.edu>, I wrote:
> 
>   A simpler solution would have compilers do run-time error checking and
>   not jump into inactive loops.  The beauty of this solution is that it
>   does not not slow down structured code -- no checking necessary.
> 
>   Unstructured code would take a performance hit.  Serves it right :-)
> 
>   It's not failure to end every loop with its own CONTINUE that is the
>   problem.  It is (surprise!) GOTO's are harmful.
> 
> In article <1905@devsys.oakhill.UUCP> steve@oakhill.UUCP (steve) replies:
>  
> > As I stated in my previous post.  There is NO problem with the code as
> > posted.  It is not ambiguous.  The problem is that the compiler, in
> > order to prevent any posssible ambiguity, generates bad code.  The
> > true ambiguity results in the following three elements used together.
> >
> >  1) Two or more do loops ending on the same line.
> >  2) One or more of the external do loops (not the inner most)
> >     jumping to the terminating statement.
> >  3) The terminating statement being executable (not a CONTINUE).
> 
> The code as posted (we are still talking about the original posting aren't
> we?) is, as several other people have pointed out, wrong.  It DOES have a
> problem.  It jumps into the range of an inactive DO loop.  This is
> forbidden.  It is not the job of a compiler to guess what conforming
> program the programmer thought he was writing.  It would be nice for
> compilers to produce code that catches this error, at least as an option.
> 

There are two problems in this code.

  1) It is illegal
  2) People want to do it.

The ANSI standard, as much as they and we would perfer otherwise, do not
live in the real world.  They have ordained this code as illegal. 
But the real world wants to do this.  Thus the compiler writers
support this.  Unfortunately there are some complicated issues of
ambiguity to be resolved.  Usually at this point we would ask the
committe to resolve it.  They say, "we did, it is illegal", and we
are back to square one.  At this point the compiler writer must decide
how to support this extension (which was the point of my post).

Thus compiler writers put this feature in, otherwise their compilers
sit on the shelf.  (Believe me, I wrote this code in a FORTRAN
compiler.  It would error out on jumping into blocks.  The customer
response.  "Gee, could you put in an option which would allow
us to do this".  Thus the compiler now has a command line option
to allow jumping into blocks.  I give you 20-1 the command file
they compile with has this option set, and the option to turn off
non-ansi code warnings).  Having put this feature in, they then want
to be competive.  They take short cuts.  Instead of generating the
true code (which has an extra variable and several extra pieces
of logic), they generate code that is smaller and faster that will
work in 99.5% of the cases.

So you see.  The problem is that the real world is subverting this
problem with a double whammy.  First the market wants a feature the
standard says is illegal.  And in the demand for fast effienct generated
code, the market causes the compiler maker to take short cuts he
can't without badly increasing the size and slowness of the compiler.

> > Admittedly the practice of ending do loops on the same line is not
> > sound programming.  But it is historic programming, and is still used
> > today.  As for the performance hit you talk about, well that's part of
> > the problem here. 
> 
> So make it an option that can be turned off.
 
Read above.  But to leave this feature out means you won't be able to sell
compilers.

> In article <18178@vax5.CIT.CORNELL.EDU> btcx@vax5.cit.cornell.edu
>                    (Brian T >  Carcich) replies:
> [ real meaning of Dykstra's GOTO declaration deleted ]
> 
> O. K., but that would have made a much weaker punchline.  If you want to
> be pedantic, unstructured use of GOTO's is harmful, and jumping in and out
> of DO loops is about as unstructured as you can get.  Is that o.k.?
 
Unfortunately you can't save the unwashed masses from themselves.
Not only can you not prevent them from doing this.  If you forbid
it, they cry and want it.  If you want to sell compilers, this is
something that must be supported.

> Believe me.  I don't write FORTRAN by choice.  Lately I've taken to
> writing some of my FORTRAN in C (thereby incurring who knows what
> portability problems).  But you just can't ever get completely
> away from FORTRAN.  It's everywhere.

Writing in FORTRAN is nothing to be ashamed of.  If you write carefully,
you can do just as complex things in FORTRAN portably as you can in
any other languge.  Admittedly you do have to know how do you do your
own recursion and handle you own pointers, but any programmer with
his salt should know how to do this in his sleep.

I hold a patent in AI.  The system I wrote was in FORTRAN (for constraints
I won't get into).  When presenting a paper on it I would always get
the question (from the a**hole that seems to always sit in the forth row)
"What language did you use, C or LISP".  When I replied FORTRAN, there
were scoffs in the audience.  I would unabashedly point out that the
langauge in no way took away from the concept, and while other people
had their AI systems still on the drawing board in LISP or C, mine was
completed working and part of a marketed system.

                   enough from this mooncalf - Steven
----------------------------------------------------------------------------
To flame someone for bad spelling or grammer is a discouragement to net
discussion in a timely fashion.
----------------------------------------------------------------------------
These opinions aren't necessarily Motorola's or Remora's - but I'd like to
think we share some common views.
----------------------------------------------------------------------------
Steven R Weintraub                        cs.utexas.edu!oakhill!devsys!steve
Motorola Inc.  Austin, Texas 
(512) 440-3023 (office) (512) 453-6953 (home)
----------------------------------------------------------------------------

shapiro@rb-dc1.UUCP (Mike Shapiro) (03/18/89)

In article <1320@uw-entropy.ms.washington.edu> charlie@mica.stat.washington.edu (Charlie Geyer) writes:
   ... much deleted ...
>Believe me.  I don't write FORTRAN by choice.  Lately I've taken to
>writing some of my FORTRAN in C (thereby incurring who knows what
>portability problems).  But you just can't ever get completely
>away from FORTRAN.  It's everywhere.

Have you tried the RATFOR preprocessor?  I haven't recently, but a few
years ago I developed several FORTRAN packages using it.  During the
Software Tools User Group heyday, I remember talking with people who
were using RATFOR to code software whose required delivery language
was FORTRAN -- including such things as word processing and financial
modeling.  I also built some quick prototypes, including a CP/M
graphics and music language for the NCR Decision Mate V personal
computer (How many people remember it and the Dom Deluise TV ads?)
using RATFOR's C-like macro capability.
-- 

Michael Shapiro, Gould/General Systems Division
15378 Avenue of Science, San Diego, CA 92128
(619)485-0910    UUCP: ...sdcsvax!ncr-sd!rb-dc1!shapiro

jlg@lanl.gov (Jim Giles) (03/18/89)

From article <6676@ecsvax.UUCP>, by urjlew@ecsvax.UUCP (Rostyk Lewyckyj):
> [...]
> Pro1 Prohibit gotbranches into the scope of a DO loop, whether to a statement
> well inside the loop or the terminal statement. CThExcept to the DO state-
> ment itsleelf from a statement outside the DO.
> 2 Prohibit the extended range of the DO. i.e. branching out of the DO
> and then back in.
> 3 Require a each DO loop to be terminated by its own ENDDO, which can not
> be the target of a branch.

Your first and second prohibitions are already in the Fortran 77 standard.

ANSI: 11.10.8 Transfer into the Range of a DO-Loop.  Transfer of
      control into the range of a DO-loop from outside the range
      is not permitted.

ANSI: 11.10.1 Range of a DO-Loop.  The range of a DO-loop
      consists of all of the executable statements that appear
      following the DO statement that specifies the Do-loop, up to
      and including the terminal statement of the DO-loop.

These two rules prohibit 'extended range' as well as branches into the
loop - including the terminal statement.

J. Giles

khb@fatcity.Sun.COM (fatcity) (03/18/89)

In article <1913@devsys.oakhill.UUCP> steve@oakhill.UUCP (steve) writes:

>> compilers to produce code that catches this error, at least as an option.
>> .....................
>
>There are two problems in this code.
>
>  1) It is illegal
>  2) People want to do it.
>
>The ANSI standard, as much as they and we would perfer otherwise, do not
>live in the real world.  They have ordained this code as illegal. 
>But the real world wants to do this.

Until 2 years ago (a bit less actually) I was part of the real world.
I never had any trouble explaining why I was fixing someones code to
remove this (relatively RARE, in well tested codes) problem. 

The key "problem" was that compiler writers allowed it to work on some
machine somewhere. Had compiler writers not made the mistake of
ignoring the X3J3 directive, we would not be having this discussion.

People want to do it, only because it exists in some programs. The
correct thing to do (in the best of all possible worlds) is what Lahey
does. Don't allow it. Tell the customer to fix the code. 

Please DO NOT ALTER COMPILERS to start allowing this. Anyone who sells
compilers should STOP ALLOWING it.

We can't solve the worlds problems, but this one does have a solution.

Keith H. Bierman
It's Not My Fault ---- I Voted for Bill & Opus

jlg@lanl.gov (Jim Giles) (03/18/89)

From article <1913@devsys.oakhill.UUCP>, by steve@oakhill.UUCP (steve):
> [...]
> Unfortunately you can't save the unwashed masses from themselves.
> Not only can you not prevent them from doing this.  If you forbid
> it, they cry and want it.  If you want to sell compilers, this is
> something that must be supported.

      do 10 i=1,10
         print *,i
         if (i.gt.5) goto 10
         do 10 j=1,5
            print *,j
 10   continue

This program infinite loops on the Cray with CFT 1.14.  If this is
the behaviour that "must be supported" to sell compilers, I don't
want any part of it.  I consider this to be an _ERROR_ in the 
compiler and I'm reporting it to Cray as such.  To be fair, the CFT
compiler does issue a warning that the branch is illegal.

If a compiler wants to allow the above program it should at least
compile it to something useful.  The only "meaningful" interpretation
of the above I can think of is equivalent to the following:

      do 10a i=1,10
         print *,i
         if (i.gt.5) goto 10a
         do 10 j=1,5
            print *,j
 10      continue
 10a  continue

If a compiler doesn't issue a FATAL message, it should give the above
interpretation - nothing else is acceptable.  (Note, I used '10a' as
the label in the above example to make it clear that it is a compiler
generated label.)

steve@oakhill.UUCP (steve) (03/19/89)

In article <94640@sun.Eng.Sun.COM>, khb@fatcity.Sun.COM (fatcity) writes:
> In article <1913@devsys.oakhill.UUCP> steve@oakhill.UUCP (steve) writes:
> 
> >> compilers to produce code that catches this error, at least as an option.
> >> .....................
> >
> >There are two problems in this code.
> >
> >  1) It is illegal
> >  2) People want to do it.
> >
> >The ANSI standard, as much as they and we would perfer otherwise, do not
> >live in the real world.  They have ordained this code as illegal. 
> >But the real world wants to do this.
> 
> Until 2 years ago (a bit less actually) I was part of the real world.
> I never had any trouble explaining why I was fixing someones code to
> remove this (relatively RARE, in well tested codes) problem. 
> 
> The key "problem" was that compiler writers allowed it to work on some
> machine somewhere. Had compiler writers not made the mistake of
> ignoring the X3J3 directive, we would not be having this discussion.
> 
> People want to do it, only because it exists in some programs. The
> correct thing to do (in the best of all possible worlds) is what Lahey
> does. Don't allow it. Tell the customer to fix the code. 
> 
> Please DO NOT ALTER COMPILERS to start allowing this. Anyone who sells
> compilers should STOP ALLOWING it.
> 
> We can't solve the worlds problems, but this one does have a solution.

I wish this was true.  On the compiler I wrote we had a complete
prohibition of block jumps.  Unfortunatly the people we wish to
sell it to wanted to block jump.  Not just in this case, but into
the middle of if-then blocks.  We were fighting for a limited area
market. Since the competing compiler suppied this ability, it was
add the feature or give the competition a step above us.

To tell the customer to improve the code might be the ideal thing to
do, unfortunately it does not make good business sense to tell the
customer he doesn't know how to code.  And if you are trying for a
sell it might get the door slammed in your face.  I am unhappy that
I had to sell out to the market on this point, but I'm realistic
enough not to become cynical about it.

The compiler does at least give a warning that this code is non-ANSI
standard and generate a proper do loop.  The people who support this
feature wrongly in order to speed up their compiler turn my stomach
(I guess I'm not realistic enough to accept this).

                   enough from this mooncalf - Steven
----------------------------------------------------------------------------
To flame someone for bad spelling or grammer is a discouragement to net
discussion in a timely fashion.
----------------------------------------------------------------------------
These opinions aren't necessarily Motorola's or Remora's - but I'd like to
think we share some common views.
----------------------------------------------------------------------------
Steven R Weintraub                        cs.utexas.edu!oakhill!devsys!steve
Motorola Inc.  Austin, Texas 
(512) 440-3023 (office) (512) 453-6953 (home)
----------------------------------------------------------------------------

steve@oakhill.UUCP (steve) (03/19/89)

In article <10623@lanl.gov>, jlg@lanl.gov (Jim Giles) writes:
> From article <1913@devsys.oakhill.UUCP>, by steve@oakhill.UUCP (steve):
> > [...]
> > Unfortunately you can't save the unwashed masses from themselves.
> > Not only can you not prevent them from doing this.  If you forbid
> > it, they cry and want it.  If you want to sell compilers, this is
> > something that must be supported.
> 
>       do 10 i=1,10
>          print *,i
>          if (i.gt.5) goto 10
>          do 10 j=1,5
>             print *,j
>  10   continue
> 
> This program infinite loops on the Cray with CFT 1.14.  If this is
> the behaviour that "must be supported" to sell compilers, I don't
> want any part of it.  I consider this to be an _ERROR_ in the 
> compiler and I'm reporting it to Cray as such.  To be fair, the CFT
> compiler does issue a warning that the branch is illegal.

This is the second whammy I talked about happening.  The compiler
writer decided that to generate faster code 99% of the time was
more important that creating correct code all of the time.  I
disagree with this decision completely.  At least when the compiler
generates an infinite loop you know you have a compiler problem.
When it generates a bad result, you are in bad shape.  If you realize
it, than you tear your hair out trying to find your error.  There
is no justifing creating bad code.  Unfortunately many compilers
writers forget that to support something extra means supporting
something extra correctly.

> If a compiler wants to allow the above program it should at least
> compile it to something useful.  The only "meaningful" interpretation
> of the above I can think of is equivalent to the following:
> 
>       do 10a i=1,10
>          print *,i
>          if (i.gt.5) goto 10a
>          do 10 j=1,5
>             print *,j
>  10      continue
>  10a  continue
> 
> If a compiler doesn't issue a FATAL message, it should give the above
> interpretation - nothing else is acceptable.  (Note, I used '10a' as
> the label in the above example to make it clear that it is a compiler
> generated label.)

Going back to my code:

      k = 0
      do 10 i = 1,10
       if (i.eq.1.or.i.eq.5) goto 10
        do 10 j = 1,10
          if (j.eq.3) goto 10
   10 k = k + 1

I assume this puts you in the camp that when i = 1 or i = 5 that
k is not incremented.  There is a large segment of coders that think
it should be.  This is the big arguement on ambiguity that started
this arguement.  Personally I'm in your camp.  If the compiler supports
this feature, it should do it right, put out an warning on non-standard
code, and assume the jump in the external DO loop ment to skip this 
statement (Does the next external iteration).  In a perfect world
every compiler will comform perfectly to the standard and not take
short cuts that leave to badly generated code.  But then Elijah
probably would be writing the compilers, and we'd all be out of a 
job :-).

                   enough from this mooncalf - Steven
----------------------------------------------------------------------------
To flame someone for bad spelling or grammer is a discouragement to net
discussion in a timely fashion.
----------------------------------------------------------------------------
These opinions aren't necessarily Motorola's or Remora's - but I'd like to
think we share some common views.
----------------------------------------------------------------------------
Steven R Weintraub                        cs.utexas.edu!oakhill!devsys!steve
Motorola Inc.  Austin, Texas 
(512) 440-3023 (office) (512) 453-6953 (home)
----------------------------------------------------------------------------

btcx@vax5.CIT.CORNELL.EDU (03/22/89)

In article <1913@devsys.oakhill.UUCP> steve@oakhill.UUCP (steve) writes:
>
>I hold a patent in AI.  The system I wrote was in FORTRAN (for constraints
>I won't get into).  When presenting a paper on it I would always get
>the question (from the [person] that seems to always sit in the forth row)
>"What language did you use, C or LISP".  When I replied FORTRAN, there
>were scoffs in the audience.  I would unabashedly point out that the
>langauge in no way took away from the concept, and while other people
>had their AI systems still on the drawing board in LISP or C, mine was
>completed working and part of a marketed system.

Where do these fourth-row-people come from?  Do you suppose it's a secret 
organization or something?

I was at a simulation conference a few years ago, and one of the sessions
was on laser disks.  Now the paper being presented was about a
nice system developed to save various scenarios and put an 
operator-in-training through his paces without human supervision.  It was 
all there, from different events to automatic review of what the system 
"felt" the trainee did not understand.  Sure enough, someone asked 
"What language did you write the simulation in?"  Immediately my ears 
pricked up as I sensed I was in the presence of a True Believer In 
Structured Programming Languages (which is to say, a True Believer in 
Non-existent Entities). "Fortran", came the unashamed reply.  The TBISPL/NE
revealed his true colors with his next question:  "Why Fortran?"  To which
I was overjoyed to hear the presenter respond "Because we're engineers." 

Why am I telling this story for the 100th time?

  (1)  I love it.  (I'm an engineer.)
  (2)  It emphasizes Steve's point above (that apparently cannot be 
       over-emphasized) that it is not the tools, but the USE of the tools
       that should be our focus.  The recurring theme in comp.sw-eng is 
       programmer discipline; they're even telling the managers that it's
       their fault if programmer discipline is not an enforced policy. 

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
How can you tell when an engineer has been using your terminal?
By the White-Out on the screen.  (White-Out = Liquid Paper)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
I once added "Engineers are great" as a (joke) signature to a posting, and
got ripped brilliantly and humourously by someone who had worked with some
engineers and found they usually (mistakenly) think themselves to be the
best hotshot programmers in town.  Mea culpa!  But, as in Steve's example
above, at least my application is on the street and not the drawing board. 

(BTW, this is not intended as an excuse for poor programming practices
 nor as a put down of any language, rather as a response to those who focus 
 on tools instead of techniques.)

jlg@lanl.gov (Jim Giles) (03/24/89)

From article <1917@devsys.oakhill.UUCP>, by steve@oakhill.UUCP (steve):
> [...]
> Going back to my code:
> 
>       k = 0
>       do 10 i = 1,10
>        if (i.eq.1.or.i.eq.5) goto 10
>         do 10 j = 1,10
>           if (j.eq.3) goto 10
>    10 k = k + 1
> 
> I assume this puts you in the camp that when i = 1 or i = 5 that
> k is not incremented.  There is a large segment of coders that think
> it should be. [...]

Consider:
       do 10 i = 1,10
        if (i.eq.1.or.i.eq.5) goto 10
         do 10 j = 1,10
    10 array(j)=array(j)+1

This is the same as your loop except for the final statement (your final
IF statement is a no-op and should be eliminated by a smart compiler
anyway).  Here it is quite clear that the array incrementing should _NOT_
be done as a result of the outer loop GOTO - in the first pass the variable
J hasn't even been defined yet!  As I pointed out before, either the
branch should be illegal or the semantics should be:

       k = 0
       do 10a i = 1,10
        if (i.eq.1.or.i.eq.5) goto 10a
         do 10 j = 1,10
           if (j.eq.3) goto 10
    10 k = k + 1
   10a continue

This interpretation is at least consistent and well defined on both 
examples.

J. Giles
Los Alamos