[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Applesoft/Prodos/ONERR GOTO/File existence question
- Subject: Re: Applesoft/Prodos/ONERR GOTO/File existence question
- From: dalloff@gcfn.org (Dave Althoff Jr)
- Date: 25 Oct 2003 01:20:08 -0400
- Newsgroups: comp.sys.apple2
- Organization: GCFN (http://www.gcfn.org/)
- References: <qhfzhxiqn9.fsf@ruckus.brouhaha.com> <53eepv0ot2jbm22j30fcq17hsni9sedtlu@4ax.com>
- Xref: archiver1.google.com comp.sys.apple2:612
Jim (abc@def.ghi) wrote:
(code snipped)
: The reason you are getting "RETURN WITHOUT GOSUB" is because there was
: no GOSUB! You used OnERR GOTO! You can't RETURN from a GOTO! You
: either need an OnERR GOSUB, or just use a GOTO xxx where xxx is
: wherever you want to return to.
: Jim
I snipped the code, but you should look more closely. Schematically it
was something like this (presented as if in Assembly)--
begin Start the program ; Say hello.
main Make things happen ; Main program loop...do stuff.
GOSUB readfile ; jump to read file routine.
ret1 Manipulate file ; RETURN should come back here.
INPUT "Again?";Y$ ; Do it all again?
IF Y$<>"N" THEN main ; Yes; repeat main loop.
END ; Else end main loop.
readfile err = 6 ; Simulate FILE NOT FOUND.
goto errhand ; Don't wait for the error.
read1 open file ; Stuff that can cause
read file ; the expected non-fatal
close file ; and unexpected fatal errors.
file exists = true ; Tell main loop file exists.
RETURN ; Will return to ret1.
errhand if err=6 then fnf ; =FILE NOT FOUND error.
print "Fatal error!" ; unexpected error!
STOP ; stop here!
fnf file exists = false ; Tell main loop file !exists.
REM POKE 216,0 ; Turn off ONERR handling.
RETURN ; Will return to ret1.
This bit of meta-code is more or less what was attempted. Notice that at
"readfile" we don't wait for an error, we just jump to the error handler
at "errhand". Since err was set to 6, "errhand"'s test for an expected
error will succeed, branching to the non-fatal-error handler "fnf" which
sets a "no file" flag and executes a RETURN. That RETURN will go back to
ret1, which is exactly where we want it to go.
The presence of a GOTO in there in the "readfile" routine makes no
difference. We don't want to return to "read1" anyway! So if that code
works (and I assure you, if you translate it into proper Applesoft, it
will), then why does this code fail:
begin Start the program ; Say hello.
main Make things happen ; Main program loop...do stuff.
GOSUB readfile ; jump to read file routine.
ret1 Manipulate file ; RETURN should come back here.
INPUT "Again?";Y$ ; Do it all again?
IF Y$<>"N" THEN main ; Yes; repeat main loop.
END ; Else end main loop.
readfile err = 0 ; Applesoft will set the error code.
onerr goto errhand ; Call handler if something goes wrong.
read1 open file ; Stuff that can cause
read file ; the expected non-fatal
close file ; and unexpected fatal errors.
file exists = true ; Tell main loop file exists.
RETURN ; Will return to ret1.
errhand if err=6 then fnf ; =FILE NOT FOUND error.
print "Fatal error!" ; unexpected error!
STOP ; stop here!
fnf file exists = false ; Tell main loop file !exists.
POKE 216,0 ; Turn off ONERR handling.
RETURN ; Will generate ?RETURN WITHOUT GOSUB.
It's exactly the same, except that now the GOTO is conditional...it will
only be taken if something goes wrong. This means the code in "read1" will
actually be executed, and if successful will hit the first RETURN and go
back to ret1.
If something in "read1" generates an error, control goes to errhand, if
the error was not #6 the program will crash with a "BREAK IN ";errhand+2.
If the error WAS a #6, the FILE NOT FOUND that we expect, we go to the
non-fatal error handler at fnf, which sets the no-file flag, turns off
error handling, and then promptly...generates a ?RETURN WITHOUT GOSUB error.
Structurally, nothing has changed. There is no POP statement in there to
clear the GOSUB, we are still ultimately reaching the error handler via
the original GOSUB to "readfile", so why doesn't it work?
Clearly, the reason is that when Applesoft triggers the error handler and
leaps to "errhand", it clears the stack, POPping the GOSUB address from
"main" and leaving the RETURN from "fnf" with no place to go.
Applesoft does not have an ONERR GOSUB, which is sensible for two reasons.
First and most obviously because it is silly...most recoverable errors
require some recovery procedure, and without knowing exactly where the
error happened you wouldn't want to go back there! Second, since the
GOSUB stack apparently gets trashed in the error trapping process, it
wouldn't work anyway! Most critically, it could put you into a situation
where you have an unknown number of GOSUB nesting layers, which would
cause an otherwise perfect program to either generate a ?RETURN WITHOUT
GOSUB error, a ?NEXT WITHOUT FOR error, or to leave extra data lying on
the stack to cause trouble.
The moral, then, is that if you have non-fatal errors to trap with ONERR
GOTO, do not put them in subroutines, and do not put them in FOR...NEXT
loops. If you have routines that routinely generate non-fatal errors
which must be called from various points in the program, consider doing it
this way to simulate the GOSUB--
REM MAIN PROGRAM LOOP
10 SRC=1:GOTO fread
15 (do stuff)
290 SRC=2:GOTO fread
300 (do stuff)
540 SRC=3:GOTO fread
550 (do stuff)
620 SRC=4:GOTO fread
621 (do stuff)
740 SRC=5:GOTO fread
REM FILE READ ROUTINE...USE ME A LOT
fread ON ERR GOTO frerr
UNLOCK F$
OPEN F$
READ F$
get data
CLOSE F$
RET=0 ; return code = success
POKE 216,0
frexit ON SRC GOTO 15,300,550,621,63990
frerr POKE 216,0
RET=errcode
GOTO frexit
63990 (end program)
I had to throw in that last little trick...line 740 calls the "subroutine"
at fread, but when the routine returns it returns to 63990 instead of to
740+n. Ordinary GOSUB can't do that trick! 8-)
--Dave Althoff, ][.
--
/-\ _ *** Respect rides. They do not respect you. ***
/XXX\ /X\ /X\_ _ /X\__ _ _ _____
/XXXXX\ /XXX\ _/XXXX\_ /X\ /XXXXX\ /X\ /X\ /XXXXX
_/XXXXXXX\__/XXXXX\/XXXXXXXX\_/XXX\_/XXXXXXX\__/XXX\_/XXX\_/\_/XXXXXX