[comp.lang.pascal] exiting some calling ancestor in Turbo Pascal 5

milne@ICS.UCI.EDU (Alastair Milne) (12/15/89)

   Our project is moving a number of its CAI programs from UCSD Pascal (under
   the p-System, of course) to Turbo Pascal 5.0.  Though it has gone much more
   smoothly overall than one might have expected, a few hard problems keep
   coming up.  A couple have already been addressed by some people on this
   group, so I have some hope for this one:

   UCSD Pascal defines the call "EXIT(procedure-name);", where procedure-name
   must be one of the procedures currently running -- that is, it must have a
   stack-frame currently allocated somewhere up the call stack.  EXIT exits
   the local procedure and every calling procedure until it reaches and exits
   "procedure-name".  Each procedure exited first has its "termination code" 
   executed, which usually is either empty or makes sure any local files are 
   properly closed.  This means that, in exceptional situations, major chunks
   of code can be exited at the option of local routines, without actually
   halting the whole program.

   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?


   Alastair Milne,
   Programming Manager,
   Educational Techology Center

al@crucible.UUCP (Al Evans) (12/15/89)

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:-).

PROCEDURE BigBlock
VAR exitFlag: BOOLEAN;

PROCEDURE SubProcA;
BEGIN
  ...
  {Condition requiring exit from main block found}
  exitFlag:= TRUE;
  EXIT;
  ...
END;

PROCEDURE SubProcB;
BEGIN
  ...
  SubProcA;
  IF exitFlag THEN EXIT;
  ...
END;

BEGIN {BigBlock}
  exitFlag:= FALSE;
  ...
  SubProcB;
  IF exitFlag THEN EXIT;
  ...
END;

It ain't pretty, but it's the only way I've found to accomplish a multilevel
exit under Turbo Pascal.
					--Al Evans--
-- 
Al Evans					"You'd grep to know what
...uunet!execu!sequoia!crucible!al			 you really sed."
							--Referent Blob

d88-eli@nada.kth.se (Erik Liljencrantz) (12/17/89)

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

d88-eli@nada.kth.se (Erik Liljencrantz) (12/18/89)

I mentioned SetJmp and LongJmp in a previous posting. Now they exist! They can
be used like this to accomplish multilevel exit:

VAR
  ErrorOccured:Jmp_Buf;

PROCEDURE WantToExit;
BEGIN
  ...
  LongJmp(ErrorOccured,1);     { Instead of Exit }
  ...
END;

PROCEDURE Demo;
BEGIN
  IF SetJmp(ErrorOccured)<>0 THEN BEGIN
    ...           { LongJmp(ErrorOccured,1) will arrive here }
    Exit;         { Exit out of this function too }
  END;
  ...
  WantToExit;
  ...
END;

Below is a uuencoded version of jmpunit.zoo. Contents:
  jmpunit.pas   Pascal unit source
  jmpunit.asm   Assembly source for SetJmp and LongJmp
  jmpunit.obj   Assembled jmpunit.asm
  testjmp.pas   Demonstration program (very short)
Send your comments (and new nice ideas) to me...
---
Erik Liljencrantz     | "No silly quotes!!"
d88-eli@nada.kth.se   |  Embraquel D. Tuta

begin 644 jmpunit.zoo
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
K``````````````````````````````````````````````````````#\@P``
`
end
-- 
Erik Liljencrantz     | "No silly quotes!!"
d88-eli@nada.kth.se   |  Embraquel D. Tuta

scl@sasha.acc.Virginia.EDU (Steve Losen) (12/18/89)

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

Doesn't turbo allow non-local gotos, which are in the current ISO standard and
have been a Pascal feature since the beginning?  You can declare a label in
an outer block and jump to it from an inner block.  This terminates the
activation of the inner block and all intervening activations back to
the most recent activation of the outer block.  Execution of the outer block
resumes at the goto target label.

This may not be as flexible as the UCSD exit.  You can only non-locally goto
a block that encloses the current block.  Furthermore, the target statement
must be at the outermost nesting level of the block (eg, you cannot jump
into a "for", "while", "if", etc. statement.).  For years folks have used this
for emergency error termination.  You declare a label in the main program and
place it near the final "end.".  Any block that hasn't redeclared the label
can jump back to the main program for a clean exit.  You could also use this
technique in a deeply nested menu driven application to jump back to the code
that displays top of the main menu.

Steve Losen
scl@virginia.edu     University of Virginia Academic Computing Center

tris@alzabo.uucp (Tris Orendorff) (12/19/89)

milne@ICS.UCI.EDU (Alastair Milne) writes:



>   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?

	This Month's issue of PC Magazine (V8, Number 22) has an
implementation of setjmp() and longjmp () for Turbo Pascal on page 298. 
	This should do the trick.


-- 
				Sincerely Yours
				Tris Orendorff
				tris@alzabo.uucp
-----------------------------------------------------------------------

schrader@loligo (David F. Schrader) (12/19/89)

In article <1989Dec18.132328.6049@murdoch.acc.Virginia.EDU> scl@sasha.acc.Virginia.EDU (Steve Losen) 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
>
>  [followup note deleted...]
  
I am not sure that I have followed the entire thread of this sequence but I
believe that what you want to do is possible (at TP5.0/TP5.5 levels at
least). I do not know whether this is supported before TP5.n .
  
Check TP5.0 (and by extension TP5.5) Reference Guide Chapter 15, page 229,
regarding _Exit Procedures_. TP5.0 supports an _ExitProc_ pointer which points
to a procedure (w/o parameters) which is to be executed upon exit from a
program (and program "unit"). By saving, replacing, and later restoring, the
pointer it is possible to "chain" these _Exit Procedure_s. The _Exit Procedure_
must be compiled in _Far_ call model ({$F+}/{$F-}). The brief example that
provide is: 
  
PROGRAM Testexit;
  
VAR
  ExitSave : pointer;
  
{$F+}
PROCEDURE MyExit;
BEGIN
  ExitProc := ExitSave;
  : 
END; {MyExit}
{$F-)
BEGIN {Main/Testexit}
  ExitSave := ExitProc;
  ExitProc := @MyExit;
  : 
END. {Main/Testexit}
  
Note that the manuals is much more expansive in their coverage. Please read
this(these) page(s) before committing yourself to this particular method as
I cannot guarentee this is the solution you are seeking (particularly since
I am coming in in the middle of the thread...).
  
Hope that this helps.
  
David F. Schrader
Disclaimer : FSUCC - "No comment." ; ME - "I reserve the right to qualify
                                           what I said if necessary."