ENTRY in main (was re: Jumping from nested subroutine to main directly) 
Author Message
 ENTRY in main (was re: Jumping from nested subroutine to main directly)

Quote:
>== Michael Page writes:
> One way to almost do what he wants is to use an ENTRY statement at
> the point he wants to return to in the main program.  However, I
> suspect he wants something a bit more `automatic' than that, but I
> don't think it exists in fortran.  Does it exist in C, Pascal, ..?

Hmmm... I've been programming FORTRAN for 10ish years (if you count
college) and NEVER thought to put an ENTRY in the main program,
though at first glance it seems to be the only time I might consider
using an ENTRY point (yes, I'm one of the people that frowns :-( on
the use of ENTRY points).

Question: what does this do to the stack?  If you kept jumping back to
the main routine everytime you had an error, and never 'returned' from
the routine causing the error, wouldn't the stack just grow un-
controllably?  Also, wouldn't this be considered recursion, since a
routine subordinate to main (effectively) calls main?  I'm guessing
the code would look like this (pardon the GOTOs :-):

        program example

c       top of main loop:
10          <get input...>
            <process input ...>
            <produce output ...>
            if (.not. done) goto 10
            goto 20
c       end of main loop...

        ENTRY error
        <process error condition>
        if (.not. fatal) goto 10
        goto 20

20      end

Does anybody do this in the real world?

--
----------------------------------------------------------------------
Instrument Approach Procedures Automation              DOT/FAA/AMI-230
----------------------------------------------------------------------



Fri, 12 May 1995 04:46:34 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)

Quote:
(bryan d oakley) writes:
>>== Michael Page writes:
>> One way to almost do what he wants is to use an ENTRY statement at
>> the point he wants to return to in the main program.  However, I
>> suspect he wants something a bit more `automatic' than that, but I
>> don't think it exists in FORTRAN.  Does it exist in C, Pascal, ..?

> Hmmm... I've been programming FORTRAN for 10ish years (if you count
> college) and NEVER thought to put an ENTRY in the main program,
> though at first glance it seems to be the only time I might consider
> using an ENTRY point (yes, I'm one of the people that frowns :-( on
> the use of ENTRY points).

>Question: what does this do to the stack?  If you kept jumping back to
>the main routine everytime you had an error, and never 'returned' from
>the routine causing the error, wouldn't the stack just grow un-
>controllably?  

After I posted, I had this vague recollection that ENTRY could only be
used in subroutines.  But even if this were true the original author's
requirement could be simulated by having an entry statement at the end
of each "level one" subroutine, say called "ENTRY exit<subname>".  I
must confess that the only thing I have ever used ENTRY statements for
is error handling.  (My fatal error messages are all printed out from
a single subroutine with multiple entry points, to avoid cluttering the
code where the error occurs.)

ENTRY statements are a form of global GOTO statement and, much as I
detest and discourage GOTOs, they do have an occasional application,
in particular for error handling.  I'm not encouraging their use but
they do seem to have a place in the language.

Quote:
> Also, wouldn't this be considered recursion, since a routine subordinate
> to main (effectively) calls main?  

Recursion is already possible (and legal?) in standard FORTRAN by simply
having two subroutines which are different only in name that call each
other.  I have no idea what this does to the stack, though.

--
+------------------------------------------------------------------------------+
 Michael Page, Maths Dept, Monash University, Clayton, Victoria, AUSTRALIA 3168

+------------------------------------------------------------------------------+



Fri, 12 May 1995 19:48:07 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)
Well, I can't resist...

What the original poster wants is called non-local GOTO in pascal, and
setjmp/longjmp in C.  In either case, the return stack is unwound to
the invocation record of the function to which control is being returned.
In pascal this is the function containing the label to which control
is being transferred; in C, it is the function that called setjmp.

Ordinarily, unwinding the stack consists of restoring the stack pointer,
possibly the frame pointer; then, control transfer is performed by loading
the program counter (i.e., performing an indirect branch).  Machines
with register windows are more complicated; I'm sure someone can tell us
exactly how it is done on the Sparc.

So, anyway, it should be possible to call setjmp and longjmp from fortran,
assuming they exist on the original poster's system.  Problem is, they
would need fortran entry points, since wrapping a C function around
the original setjmp/longjmp won't work (setjmp must be called from the
function to which control is to return, then that function must not return
before longjmp is called).  If fortran entry point's don't exist, I'd
be inclined to hack the object to create them.

Of course, the ability to do all this is entirely system dependent.

Good luck.
--
Larry Meadows           The Portland Group



Fri, 12 May 1995 22:26:53 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)

Quote:
>>== Michael Page writes:
>> One way to almost do what he wants is to use an ENTRY statement at
>> the point he wants to return to in the main program.

>Hmmm... I've been programming FORTRAN for 10ish years (if you count
>college) and NEVER thought to put an ENTRY in the main program,
>though at first glance it seems to be the only time I might consider
>using an ENTRY point (yes, I'm one of the people that frowns :-( on
>the use of ENTRY points).

>Question: what does this do to the stack?  If you kept jumping back to
>the main routine everytime you had an error, and never 'returned' from
>the routine causing the error, wouldn't the stack just grow un-
>controllably?  Also, wouldn't this be considered recursion, since a
>routine subordinate to main (effectively) calls main?

Interestingly, the FORTRAN standard does not contain language
prohibiting the main program from being called recursively.
Since it does not permit calling the main program at all from
within a running program, perhaps such a restriction was felt
to be superfluous.

In any case, a main program cannot contain an ENTRY statement.
Section 14.2 of X3.9-1978 states

    A main program may contain any other statement except a
    BLOCK DATA, FUNCTION, SUBROUTINE, ENTRY, or RETURN
    statement.

                                        Yours truly,
                                        Robert Corbett
*
*
*
*
*
*
*
*
*
*



Fri, 12 May 1995 13:41:13 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)

   ENTRY statements are a form of global GOTO statement and, much as I
   detest and discourage GOTOs, they do have an occasional application,
   in particular for error handling.  I'm not encouraging their use but
   they do seem to have a place in the language.

No, ENTRY statements are not a form of a global GOTO statement.  You
misunderstand their use entirely, and any success you've had using them
that way is almost certainly nonportable and/or accidental.

   > Also, wouldn't this be considered recursion, since a routine subordinate
   > to main (effectively) calls main?  

   Recursion is already possible (and legal?) in standard FORTRAN by simply
   having two subroutines which are different only in name that call each
   other.  I have no idea what this does to the stack, though.

No, recursion is not legal in standard FORTRAN.  You can't make it so by
duplicating subroutines and renaming one of them.

OK, here is a way to understand what ENTRY means, by way of recoding a
sample use of ENTRY into Fortran code that doesn't use it, but still
preserves all the semantics and meaning:

        SUBROUTINE X(ARG1, ARG2)
        COMMON /FOO/ A, B, C
        INTEGER INVOKE
        SAVE INVOKE
        DATA INVOKE/0/
C
        INVOKE = INVOKE + 1
        ...do real stuff #1...
        RETURN
C
        ENTRY Y(ARG2, ARG3)
        INVOKE = INVOKE + 1
        ...do real stuff #2...
        RETURN
C
        ENTRY Z(INVOQ)
        INVOQ = INVOKE
        END

Note that X and Y share an argument, ARG2, so it can be referenced,
defined, or undefined when X or Y is called -- but not Z.  Meanwhile,
ARG1 can't be touched in the code path used by a call to Y, nor can
ARG3 be touched by Z's code path.  Although I've shown "real stuff" #s
1 and 2 as separate things, they can GOTO back and forth between each
other (to share code) as long as these rules are followed.

Z just returns in its first argument the total number of times X and Y have
been called prior to Z being called.

Note for recursion enthusiasts: once X, Y, or Z is called, the running
program may not call _any_ of X, Y, or Z directly or indirectly until that
first X, Y, or Z returns to its caller.  This means that "real stuff #1"
cannot CALL Z(J), nor can it CALL FROB if FROB does CALL Z(J).

Now, here is the above code recoded without ENTRY in an almost entirely
standard way:

        SUBROUTINE unique-name(WHICH, ARG1, ARG2, ARG3, INVOQ)
        INTEGER WHICH
        COMMON /FOO/ A, B, C
        INTEGER INVOKE
        SAVE INVOKE
        DATA INVOKE/0/
C
        GOTO (10, 20, 30) WHICH
C
10      INVOKE = INVOKE + 1
        ...do real stuff #1...
        RETURN
C
20      INVOKE = INVOKE + 1
        ...do real stuff #2...
        RETURN
C
30      INVOQ = INVOKE
        END

        SUBROUTINE X(ARG1, ARG2)
        CALL unique-name(1, ARG1, ARG2, 0., 0)
        END

        SUBROUTINE Y(ARG2, ARG3)
        CALL unique-name(2, 0., ARG2, ARG3, 0)
        END

        SUBROUTINE Z(INVOQ)
        CALL unique-name(3, 0., 0., 0., INVOQ)
        END

The only nonstandard thing is "unique-name", which the translation must
substitute with a name that is unique across the entire program (easy
for compilers, usually -- GNU Fortran just makes a name unique across
the source file and doesn't make it global, which achieves the same thing).

It might look wrong for X and Y to pass 0 for INVOQ, since INVOQ is modified
by the unique-name procedure, but it isn't -- the variable is only modified
in the case where Z calls unique-name, else the _original_ example was as
nonconforming as this recoding.

f2c handles ENTRY similar to the above method, though since it has the
luxury of translating into C instead of Fortran, it can do some things more
simply (e.g. pass NULL instead of 0. for missing arguments, especially nice
when the missing argument is a large array and, for pure standards
conformance, I think that'd mean a space-wasting unused array would have
to be passed to make the code valid Fortran, while NULL is suitable for
valid C).

Recursion is another story entirely.  If you've been doing something
like

        SUBROUTINE X(ARG1, ARG2, ARG3)
        ...
        ENTRY XERROR
        PRINT *,'Error in X'
        ARG1 = 0.
        END

and calling XERROR when an error is detected in X or by any of the
procedures it calls, you are attempting recursion, and you're also asking
from trouble in other ways (even if X isn't active).

The recursion problem with the above is that the compiler might well
have made lots of internal (invisible) data structures static, meaning
that even the PRINT statement might not work properly on all systems
(even though it might on yours).

The other problem is that XERROR doesn't take ARG1 as an argument, so the
assignment is non-conforming.  If your machine happens to, when X is
active at the point XERROR is invoked, actually set X's ARG1 to 0. as a
result of the assignment, you're lucky or incredibly knowledgable about writing
very nonportable code for your particular machine.  But you're not using
ENTRY correctly from a standard-conformance point of view.

Instead, you have to do something like:

        SUBROUTINE X(ARG1, ARG2, ARG3)
        ...
999     PRINT *,'Error in X'
        ARG1 = 0.
        END

Then, anyplace in the ..., GOTO 999 to do the abort, and anyplace you would
invoke a function or subroutine in the ... that might want to do the abort
directly, recode the function as a subroutine and pass *999 as an alternate-
return argument, to be used by the called subroutine or any of the procedures
it calls (i.e. apply this technique recursively :-).  See my earlier post
about ENTRY for a clearer description.

Also realize that this is not a conforming program in ANSI FORTRAN 77
(or in Fortran 90 for that matter):

        PROGRAM FOO
        CALL BAR
        END

        SUBROUTINE BAR
        LOGICAL FIRST
        SAVE FIRST
        DATA FIRST/.TRUE./
C
        IF (FIRST) THEN
            FIRST = .FALSE.
            CALL BLETCH
        END IF
C
        PRINT *,'BAR'
        END

        SUBROUTINE BLETCH
        PRINT *,'BLETCH'
        CALL BAR
        END

If you're lucky, the above program might print

BLETCH
BAR
BAR

but it is also perfectly standard-conforming for your system to delete
all your files as well, since you're program is not standard-conforming
due to its attempt to recurse.  :-)

Also note that even the following is not permitted by the standard:

        PRINT *,FOO(ICHAR('2'))
        END

        REAL FUNCTION FOO(I)
        CHARACTER*20 IFILE
        IFILE = CHAR(I) // '.3'
        READ (10, IFILE) FOO
10      FORMAT (F3.1)
        END

(Assuming I've got the format and other such sundry details right....)

The above is not _overt_ recursion, but is nevertheless disallowed by
the standard because it has _implicit_ recursion of the Fortran I/O subsystem.
In particular, FOO is invoked after the start of I/O, and then FOO itself
reinvokes the I/O subsystem to do the internal-file READ to translate
"2.3" into a REAL value in FOO.

You might say, "well why didn't they require pre-evaluation of the arguments
to the I/O statement?"  Good question.  First, I'm not sure offhand if
this would be valid:

        WRITE (*,*,ERR=20) (FOO(I), FOO(I), J=1,100)
20      END

        REAL FUNCTION FOO(I)
        FOO = FLOAT (I)
        I = I + 1
        END

If it is valid (which I think it might be, actually), it wouldn't work
if preevaluation was required (I should not always end up with the value
201 or whatever it gets, if there's an error writing to *).

But, more specifically, how would this work?

        READ *, I, FOO(I)
        END

Here, only after the value I is read, and while the I/O is still active,
do we know what to pass to FOO for preevaluation.

Believe me, this kind of thing gives all sorts of problems to those of
us who implement Fortran compiler systems, especially on weird
architectures or under other such constraints!

I don't remember whether Fortran 90 lifts the restriction on recursive
invocation of the I/O subsystem, offhand.  Sure would be nice, since it
seems possible, and it's hard for programmers to keep themselves from
violating the rule (especially given how it is so common to insert
PRINT statements to debug code).
--





Sat, 13 May 1995 04:10:00 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)
|> [...]
|> Interestingly, the FORTRAN standard does not contain language
|> prohibiting the main program from being called recursively.
|> Since it does not permit calling the main program at all from
|> within a running program, perhaps such a restriction was felt
|> to be superfluous.
|>
|> In any case, a main program cannot contain an ENTRY statement.
|> Section 14.2 of X3.9-1978 states
|>
|>     A main program may contain any other statement except a
|>     BLOCK DATA, FUNCTION, SUBROUTINE, ENTRY, or RETURN
|>     statement.

Actually, by excluding those statements, the standard implicitly
denied the possibility of calling the main program.  You can't
all any Fortran procedure which is neither a FUNCTION, a SUBROUTINE,
nor an ENTRY into one of those two.  Main programs comntain no globally
visible names which can be called!  I know, most implementations make
the name given on the PROGRAM statement a global - but that's not
required or necessary.  In any case, a standard conforming code
cannot CALL it - because it's not on the list of things which
can be CALLed.

With respect to the original topic: the committee argued for
ages over some sort of exception handling mechanism for what
became Fortran 90 with no proposal meeting the approval of
anywhere *near* a majority.  Even the concept fell to an
austerity move before the first public review cycle.  At the
time, I didn't even object to its absence - mainly because
I couldn't think of a proposal which could be approved by
such a varied crowd of committee members either.

--
J. Giles



Sat, 13 May 1995 03:41:32 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)
Interesting question.

The much-maligned 'assigned GOTO' is the Standard Fortran version of
setjmp and longjmp.  But assigned GOTO, by the Standard, is limited in
scope to a single program unit.  I've heard that an implementation or two
accidently support passing what amounts to a LABEL data type down the
calling chain.  Then you can 'GOTO label' where you want to longjmp.
(I'd be fascinated to know who supports it!)

        assign 10 to label
        call suba (label)       !! Standard... (see below) !!
     10 continue
        ...
        end
        subroutine suba (label)
        ...
        goto label              !! Non-Standard !!

WARNING: If the above accidently works on your computer, your compiler
vendor will probably consider it to be a bug.  Not a feature.
If your compiler accidently allows this, and you depend on it,
comment your code well.  Because next time you change compilers or
port your code to a different machine it WILL break.

|> Well, I can't resist...
|>
|> What the original poster wants is called non-local GOTO in pascal, and
|> setjmp/longjmp in C.
|> ...
|>   If fortran entry point's don't exist, I'd
|> be inclined to hack the object to create them.

You would have to be careful when using setjmp in a Fortran
program.  You might write a Fortran-callable glue routine in C
for setjmp and longjmp.  But that glue routine would then have
present in the calling tree in order to work (I.e., the glue
routine would then have to call SUBA in the example above).
A simple setjmp interface would not work since there would be
no link back to your original routine after a longjmp was taken.

Maybe a LABEL data type is needed in the next rev of the Standard?
Labels are used in several places - assigned GOTO, alternate RETURN,
formats, etc.  It really isn't wise to overload numeric variable names
with these labels (shades of Hollerith constants?)  IMHO, assigned GOTO
should not have been depricated in Fortran-90 since sometimes there
is no alternative.  For example, consider the following:

        assign 10 to label1
        assign 20 to label2
        call suba (label1,label2)       !! Standard
     10 continue
        ...
     20 format (10x,8f5.3)
        end
        subroutine suba (label1,label2)
        ...
        write (6,label2) array          !! Standard !!
        goto label1                     !! Non-Standard !!

In the above, the label is legal for the format, but is illegal for
a non-local jump.  Kind of inconsistent.

Walt
----
Walt Spector

Sunnyvale, California
_._ _._ _.... _. ._.



Fri, 12 May 1995 22:39:08 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)

Quote:
(Craig Burley) writes:

[... candidate for "best post of the month" in c.l.f. ... ]

your tutorial on entry was great!
only one thing left me a bit puzzled:

|>   REAL FUNCTION FOO(I)
|>   FOO = FLOAT (I)
|>   I = I + 1
|>   END
|>
|>But, more specifically, how would this work?
|>
|>   READ *, I, FOO(I)
|>   END
|>
|>Here, only after the value I is read, and while the I/O is still active,
|>do we know what to pass to FOO for preevaluation.

i wouldn't have dreamed of putting a function in a READ list.
do you really mean FOO to be a function? what's the purpose
of the programmer? FOO returns a value, and what is the READ
supposed to do with this value? replace it with another one,
then throw away anything? it is not stupid after all,
since FOO may do useful things in the meanwhile and we
may not need its result.  alas, i have never seen nor done
such a thing.

or do you perhaps mean FOO to be an array element here?

|>Believe me, this kind of thing gives all sorts of problems to those of
|>us who implement Fortran compiler systems, especially on weird
|>architectures or under other such constraints!

we have no difficulty in believing you

--
Furio Ercolessi
Materials Research Laboratory           |   Intl School for Advanced Studies
Univ. of Illinois at Urbana-Champaign   |   Trieste, Italy



Sat, 13 May 1995 05:40:46 GMT  
 ENTRY in main (was re: Jumping from nested subroutine to main directly)

Quote:
> No, recursion is not legal in standard FORTRAN.  You can't make it so by
> duplicating subroutines and renaming one of them.

Recursion is legal in the current standard Fortran,
which is Fortran 90, adopted as the ISO standard in 1991,
adopted as an ANSI standard in 1992.
--

Unicomp, Inc.                +1-415-949-4052
235 Mt. Hamilton Ave.        +1-415-949-4058 (fax)
Los Altos, CA 94022 USA      "F90--Fortran for the '90s"


Sat, 13 May 1995 06:12:37 GMT  
 
 [ 38 post ]  Go to page: [1] [2] [3]

 Relevant Pages 

1. Jumping from nested subroutine to main directly?

2. Multiple returns (was: Jumping from nested subs to main directly)

3. What does MAIN_ _MAIN_ __MAIN__ mean?(to invoke clapack)

4. if __name__=='__main__': main()

5. python __main__ is similar to java main()

6. Hiding main TK main window

7. I am looking for a VI that login and logout users to a main VI.

8. allocate arrays in subroutine and return it to main

9. C call, in a Fortran subroutine, within a C main program

10. DB/2 binds - main vs. subroutine

11. write a main program into a subroutine

12. Subroutine inexplicably changes variables in main program.

 

 
Powered by phpBB® Forum Software