Path: utzoo!attcan!uunet!snorkelwacker!bloom-beacon!eru!luth!sunic!draken!d88-eli From: d88-eli@nada.kth.se (Erik Liljencrantz) Newsgroups: comp.lang.pascal Subject: Re: exiting some calling ancestor in Turbo Pascal 5 Message-ID: <2551@draken.nada.kth.se> Date: 17 Dec 89 14:12:12 GMT References: <8912141752.aa23459@ICS.UCI.EDU> <122@crucible.UUCP> Reply-To: d88-eli@nada.kth.se (Erik Liljencrantz) Organization: Royal Institute of Technology, Stockholm, Sweden Lines: 76 In article <122@crucible.UUCP> al@crucible.UUCP (Al Evans) writes: >In article <8912141752.aa23459@ICS.UCI.EDU> milne@ICS.UCI.EDU (Alastair Milne) writes: >[description of need for multi-level "EXIT" deleted....] >> Turbo Pascal gives only, as far as I know, EXIT (which exits the immediate >> block, but nothing further) and HALT (which kills the whole program). >> Does anybody know of a way in Turbo Pascal to obtain the effect of UCSD >> Pascal's EXIT? >I wish there were. Actually, in UCSD, I think you can even exit procedures >that HAVEN'T been called -- this gives interesting results. I do things >as shown below, in about 60K lines of Pascal that exists under both Turbo and >UCSD (don't ask:-). >[code with boolean exitflag deleted] >It ain't pretty, but it's the only way I've found to accomplish a multilevel >exit under Turbo Pascal. >... >Al Evans "You'd grep to know what >...uunet!execu!sequoia!crucible!al you really sed." > --Referent Blob In C there are a standard method of exiting from several levels of calls. setjmp and longjmp works together to accomplish this. A call to setjmp saves the state of the stack (i.e. SP) and some registers (only BP needed for Turbo) and a returnaddress just after setjmp. A call to longjmp from a deeper level restores the stack and BP and jumps to the setjmp location. This would be possible to accomplish in Turbo Pascal too (just a little assembler). A small example of how it could work: Declarations: FUNCTION SetJmp (Buffer:Save_SP_BP_CS_IP_Record):INTEGER; { Return 0 when explicitly called, or ReturnValue from LongJmp if LongJmp is used. } PROCEDURE LongJmp(Buffer:Save_SP_BP_CS_IP_Record; ReturnValue:INTEGER); { Buffer must have been initialized by a previous call to SetJmp. ReturnValue is the result for SetJmp. It shouldn't be 0 (reserved for explicit call to SetJmp). } Usage: PROGRAM JustATest; USES The_Imaginary_SetJmp_And_LongJmp_Unit; VAR ReturnToMainLoop:Save_SP_BP_CS_IP_Record; PROCEDURE NoReturn; BEGIN LongJmp(ReturnToMainLoop,1); { Transfer control to the mainloop! (Two level exit) } END; PROCEDURE DoSomething; BEGIN NoReturn; WriteLn('It never happens'); END; BEGIN IF SetJmp(ReturnToMainLoop)<>0 THEN BEGIN { SetJmp returns 0 on initialization or something else if LongJmp was called. } WriteLn('A call to LongJmp returned control here!'); END; REPEAT { Never ending main loop } CASE UpCase(ReadKey) OF 'D':DoSomething; 'Q':Halt; END; UNTIL FALSE; END. Well, I hope you get the idea... This isn't a multilevel exit, but it's a method to jump back in the call-chain at least. In C it can be used to exit callingchains when an error is encountered. I hope I will be able to find some time to write the procedures. If you are interested, just email! Comments? Email them too! -- Erik Liljencrantz | "No silly quotes!!" d88-eli@nada.kth.se | Embraquel D. Tuta