[comp.lang.pascal] IMPLEMENT GOTO ACROSS MODULES IN TURBO PASCAL??

CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl Brendel) (01/06/91)

In article <11647@j.cc.purdue.edu>, zhou@brazil.psych.purdue.edu
 (Albert Zhou) wrote:

>Here is the problem:
>   Suppose there is such a structure in the main part of the
>program:
>
>        repeat
>           statemetn 1
>           statement 2
>                .
>                .
>                .
>           statement n
>        until whatever
>
>  Now I need to write a subroutine to point the program to statement
>n. It seems there is no way to do it in turbo pascal, since goto
>statement can not go out of a subroutine.

Try reworking your repeat statement so that each statement 1..n has
an associated value. Set that value in the subroutine(s). The loop
would look something like:

var
  flag_val : byte;
...
  flag_val := 0;
  repeat
    if flag_val <= 1 then statement1;
    if flag_val <= 2 then statement2;
      ...
    if flag_val <= n then statementn;
    flag_val := 0;
  until whatever;

(Note that appropriate manipulation of flag_val allows statementI to
cause a skip of a range of following statements I+1..n.)

+--------------------------------------------------------------------+
| Karl Brendel                           Centers for Disease Control |
| Internet: CDCKAB@EMUVM1.BITNET         Epidemiology Program Office |
| Bitnet: CDCKAB@EMUVM1                  Atlanta, GA, USA            |
|                        Home of Epi Info 5.0                        |
+--------------------------------------------------------------------+

zhou@brazil.psych.purdue.edu (Albert Zhou) (01/06/91)

In article <25404@adm.brl.mil> CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl Brendel) writes:
>In article <11647@j.cc.purdue.edu>, zhou@brazil.psych.purdue.edu
> (Albert Zhou) wrote:
>
>Try reworking your repeat statement so that each statement 1..n has
>an associated value. Set that value in the subroutine(s). The loop
>would look something like:
>
>var
>  flag_val : byte;
>...
>  flag_val := 0;
>  repeat
>    if flag_val <= 1 then statement1;
>    if flag_val <= 2 then statement2;
>      ...
>    if flag_val <= n then statementn;
>    flag_val := 0;
>  until whatever;
>
>(Note that appropriate manipulation of flag_val allows statementI to
>cause a skip of a range of following statements I+1..n.)

However, this only works when the error arises at the second level of the
structure (suppose the repeat-until statement is at the first level). If 
the error arises at a deeper level, it will be a long way before going to
statement n at the first level. Consider the following example:

	statement 2 calls proc1,
	procedure proc1;
        begin
          ...
	  proc2;
	  ...
	end;

        procedure proc2;
	begin
 	  ...
 	  proc3;
          ...
	end;

        procedure proc3;   
	begin
	  ...
	  { this statement might cause error so I insert the error processing
            you suggested}
          if an error then begin
            val_flage = n;
   	    exit;
	  end;
	  ...
	end;
	 
	So when the error comes up, it will continue to finish proc2 and
proc1 before returning to the first level. But any attemp to continue the
execution of proc2 and proc1 after an error arises will cause problem.

decomyn@penguin.uss.tek.com (01/07/91)

In article <11656@j.cc.purdue.edu> zhou@brazil.psych.purdue.edu (Albert Zhou) writes:
>In article <25404@adm.brl.mil> CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl Brendel) writes:
>>In article <11647@j.cc.purdue.edu>, zhou@brazil.psych.purdue.edu
>> (Albert Zhou) wrote:
>>
>>Try reworking your repeat statement so that each statement 1..n has
>>an associated value. Set that value in the subroutine(s). The loop
>>would look something like:

[code example deleted]

>
>However, this only works when the error arises at the second level of the
>structure (suppose the repeat-until statement is at the first level). If 
>the error arises at a deeper level, it will be a long way before going to
>statement n at the first level. Consider the following example:
>
>	statement 2 calls proc1,
>	procedure proc1;
>        begin
>          ...
>	  proc2;
>	  ...
>	end;
>
>        procedure proc2;
>	begin
> 	  ...
> 	  proc3;
>          ...
>	end;
>
>        procedure proc3;   
>	begin
>	  ...
>	  { this statement might cause error so I insert the error processing
>            you suggested}
>          if an error then begin
>            val_flage = n;
>   	    exit;
>	  end;
>	  ...
>	end;
>	 
>	So when the error comes up, it will continue to finish proc2 and
>proc1 before returning to the first level. But any attemp to continue the
>execution of proc2 and proc1 after an error arises will cause problem.

The solution is to test the value of val_flage after each call.  In fact, 
if a procedure might be called from more than one statement, you can
easily test for a change in the flag.  Using your sample as a base, you
could try:

	statement 2 calls proc1,
	procedure proc1;
	var
	  Save_val : flage;  { assumes type "flage" defined earlier }
        begin
          ...
	  Save_val:=val_flage;
	  proc2;
	  if Save_Val<>val_flage then Exit
	  ...
	end;

        procedure proc2;
	var
	  Save_val : flage;  { assumes type "flage" defined earlier }
	begin
 	  ...
	  Save_val:=val_flage;
 	  proc3;
	  if Save_Val<>val_flage then Exit
          ...
	end;

        procedure proc3;   
	var
	begin
	  ...
	  { this statement might cause error so I insert the error processing
            you suggested}
          if an error then begin
            val_flage = n;
   	    exit;
	  end;
	  ...
	end;

Clear enough?

-------------------------------------------------------------------------------
Brendt Hess a.k.a.             | Disclaimer: Opinions?  I don't even work here!
Vergil William de Comyn a.k.a. |-----------------------------------------------
Payne Hirds                    |       Life is not a zero-sum game:
decomyn@penguin.uss.tek.com    |          don't treat it as such.

zhou@brazil.psych.purdue.edu (Albert Zhou) (01/07/91)

Any other solutions so far I've seen need quite a little extra work than if
a direct goto statement can be implemented. Turbo Pascal doesn't have to
disable cross-module goto to enforce "good programmin practice". Rather, it
could let programmers to make choice, because under exceptional cases such
goto's are the only best solutions.

This reminds me of the suggestion made by some researchers to eliminate goto's
altogether. Personally, I don't promote using goto's even within a block.
Instead of using:

		repeat
		  s1;
		  s2; 
		  if c then goto out;
		  s3;
		until forever;
		out:;

I use:
		repeat
		  s1;
		  s2;
		  s3;	
		until c;

However, in rare cases, s3 can be very time-consuming and by using the first
code, one can save the time to execute s3 when c is true.

My point is, let programmers to control their own programming style. And some
"bad" practice can be the only good solution under exceptional case.

Or a compiler directive (see G+) can be setup to enforce the rule of using
goto directly. Just like range check.

CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl Brendel) (01/07/91)

In article <11656@j.cc.purdue.edu>, zhou@brazil.psych.purdue.edu
 (Albert Zhou) wrote:

>In article <25404@adm.brl.mil> CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl
> Brendel) writes:
>>In article <11647@j.cc.purdue.edu>, zhou@brazil.psych.purdue.edu
>> (Albert Zhou) wrote:
>>
>>Try reworking your repeat statement so that each statement 1..n has
>>an associated value. Set that value in the subroutine(s). The loop
>>would look something like:
>>
>>var
>>  flag_val : byte;
>>...
>>  flag_val := 0;
>>  repeat
>>    if flag_val <= 1 then statement1;
>>    if flag_val <= 2 then statement2;
>>      ...
>>    if flag_val <= n then statementn;
>>    flag_val := 0;
>>  until whatever;
>>
>>(Note that appropriate manipulation of flag_val allows statementI to
>>cause a skip of a range of following statements I+1..n.)
>
>However, this only works when the error arises at the second level of the
>structure (suppose the repeat-until statement is at the first level). If

[...remainder deleted...]

Well, Albert, that isn't what your first posting asked about,
although it apparently is what you _meant_ for it to ask about.

Now you need a "long jump" capability, which you will find in a
number of toolbox collections, including (of course) TurboPower's
Turbo Professional and Object Professional.

Your code would then look something like this:

var
  ejr : JumpRecord; {global}
  flag_val : byte;  {global}
...
  flag_val := 0;
  SetLongJump(ejr);
  repeat
    if flag_val <= 1 then statement1;
    if flag_val <= 2 then statement2;
      ...
    if flag_val <= n then statementn;
    flag_val := 0;
  until whatever;

Then to return to the top of the loop, a routine would do
LongJump(ejr);, setting flag_val as/if appropriate. (Note that ejr
and flag_val need to be declared where they are visible to all
appropriate units.)

+--------------------------------------------------------------------+
| Karl Brendel                           Centers for Disease Control |
| Internet: CDCKAB@EMUVM1.BITNET         Epidemiology Program Office |
| Bitnet: CDCKAB@EMUVM1                  Atlanta, GA, USA            |
|                        Home of Epi Info 5.0                        |
+--------------------------------------------------------------------+

CDCKAB%EMUVM1.BITNET@cunyvm.cuny.edu ( Karl Brendel) (01/09/91)

In article <11661@j.cc.purdue.edu>, zhou@brazil.psych.purdue.edu
  (Albert Zhou) wrote:

>Any other solutions so far I've seen need quite a little extra work
>than if a direct goto statement can be implemented.

[...deleted...]

>My point is, let programmers to control their own programming style.
>And some "bad" practice can be the only good solution under
>exceptional case.
>
>Or a compiler directive (see G+) can be setup to enforce the rule of
>using goto directly. Just like range check.

The "LongJump" solution takes no more work on the programmer's part
(once the appropriate unit has been inserted into the USES
statement) than your desired Goto would: To use a Goto, you must
declare and use a label, then you must call the Goto as required; to
use a LongJump, you must declare a JumpRecord, call SetLongJump,
then call LongJump as required. (As in my second reply, I'm using
Turbo Professional terminology here.)

The fact of the matter is that a _pure_ Goto outside of a routine is
not feasible in a language like Pascal. What happens to the stack
frame of the routine you are going from? How is the stack frame
created for the routine you are going to? And what happens to the
stack frames of routines which were pending returns when you made
the Goto?

The LongJump approach deals with these matters by saving and
restoring a specific stack frame. Even then, there are limitations
(which don't affect your proposed use): you can jump from a lower
stack frame to a higher one, but not vice versa. (I.e., you can jump
"back", but not "forward".)

Cheers--

+--------------------------------------------------------------------+
| Karl Brendel                           Centers for Disease Control |
| Internet: CDCKAB@EMUVM1.BITNET         Epidemiology Program Office |
| Bitnet: CDCKAB@EMUVM1                  Atlanta, GA, USA            |
|                        Home of Epi Info 5.0                        |
+--------------------------------------------------------------------+

dave@tygra.ddmi.com (David Conrad) (01/09/91)

In article <11661@j.cc.purdue.edu> zhou@brazil.psych.purdue.edu (Albert Zhou) writes:
>
>This reminds me of the suggestion made by some researchers to eliminate goto's
>altogether. Personally, I don't promote using goto's even within a block.
>Instead of using:
>
>		repeat
>		  s1;
>		  s2; 
>		  if c then goto out;
>		  s3;
>		until forever;
>		out:;
>
>I use:
>		repeat
>		  s1;
>		  s2;
>		  s3;	
>		until c;
>
>However, in rare cases, s3 can be very time-consuming and by using the first
>code, one can save the time to execute s3 when c is true.
>

You could just use:
               repeat
                 s1;
                 s2;
                 if not c then s3;
               until c;

I've often seen it stated that there are situations where goto's are
unavoidable, but I've never seen an instance of such a situation.  Even
finite state machines can be implemented by case statements, although
if the case statements evaluate to nested if's instead of a jump table
then I can see where one would rather use goto's to emulate the jump
table.  Or, with procedural types (call by name), you could actually
code a jump table in an array.
--
David R. Conrad
dave@tygra.ddmi.com
-- 
=  CAT-TALK Conferencing Network, Computer Conferencing and File Archive  =
-  1-313-343-0800, 300/1200/2400/9600 baud, 8/N/1. New users use 'new'    - 
=  as a login id.  AVAILABLE VIA PC-PURSUIT!!! (City code "MIDET")        =
   E-MAIL Address: dave@DDMI.COM

bobb@vice.ICO.TEK.COM (Bob Beauchaine) (01/10/91)

In article <11661@j.cc.purdue.edu> zhou@brazil.psych.purdue.edu (Albert Zhou) writes:
>I use:
>		repeat
>		  s1;
>		  s2;
>		  s3;	
>		until c;
>
>However, in rare cases, s3 can be very time-consuming and by using the first
>code, one can save the time to execute s3 when c is true.
>

  Seems reasonably straight forward to use this construct to avoid a
  potentially time consuming routine: 


		repeat
		  s1;
		  s2;
		  if not c then s3;	
		until c;


Bob Beauchaine
bobb@vice.ICO.TEK.COM

mcastle@mcs213f.cs.umr.edu (Mike Castle (Nexus)) (01/10/91)

In article <6622@vice.ICO.TEK.COM> bobb@vice.ICO.TEK.COM (Bob Beauchaine) writes:
>In article <11661@j.cc.purdue.edu> zhou@brazil.psych.purdue.edu (Albert Zhou) writes:
>>I use:
>>		repeat
>>		  s1;
>>		  s2;
>>		  s3;	
>>		until c;
>>
>>[stuff deleted]
>		repeat
>		  s1;
>		  s2;
>		  if not c then s3;	
>		until c;

My favorite is:

Procedure DoSomeThing(var parms:etc);

Var 
  Ch := Char;   
  
  Begin
    While True do Begin
       :
      Input data;
       :
      echo data and verify with y/n/q options
      if ch='q' then Exit;   (* jump from procedure.  *)                  
      if ch='y' then Begin
                      :
                    process data
                      :
         process more data? (y/n);
         if ch='n' then Exit;
       End;
     End;
   End;            (* DoSomeThing *)

I assume this is really bad practice, but I like it.  :->

-- 
Mike Castle (Nexus) S087891@UMRVMA.UMR.EDU (preferred)       | ERROR:  Invalid
                mcastle@mcs213k.cs.umr.edu (unix mail-YEACH!)| command 'HELP'
Life is like a clock:  You can work constantly, and be right | try 'HELP'
all the time, or not work at all, and be right twice a day.  |

einstein@cs.mcgill.ca (Michael CHOWET) (01/10/91)

In article <11661@j.cc.purdue.edu> you write:

>Any other solutions so far I've seen need quite a little extra work than if
>a direct goto statement can be implemented. Turbo Pascal doesn't have to
>disable cross-module goto to enforce "good programmin practice". Rather, it
>could let programmers to make choice, because under exceptional cases such
>goto's are the only best solutions.

  Well, not to flame or anything, but my background was kept "GOTO-free". I
was educated (and still am) in the spirit of "good programming" (whatever
*that* may be :-). And even when going through the Pascal manual I found the
GOTO statement, I didn't even bother looking at how to do this. All I saw
was a statement that was a throwback to my BASIC days on an Apple ][+, an Atari
400, or worse on our Commodore VIC-20.

>This reminds me of the suggestion made by some researchers to eliminate goto's
>altogether. Personally, I don't promote using goto's even within a block.

  I must say I wholeheartedly agree. Although you contend that sometimes goto
statements are the best alternative, I have done some rather vast projects,
and I have yet to encounter the need for a goto statement. Goto's can be looked
at as perhaps (again, don't take offense) a lazy person's cop out. Rather than
sitting own with paper and pencil to map out the logical flow of the program,
one does what one feels, then adds a goto to fill in the holes... I *would* 
like to see these statements eliminated.

>Instead of using:
>
>		repeat
>		  s1;
>		  s2; 
>		  if c then goto out;
>		  s3;
>		until forever;
>		out:;
>
>I use:
>		repeat
>		  s1;
>		  s2;
>		  s3;	
>		until c;
>
>However, in rare cases, s3 can be very time-consuming and by using the first
>code, one can save the time to execute s3 when c is true.

  If indeed this is the case, have you ever thought of the following:

	repeat
	  s1;
	  s2;
	  if not c then s3 ;
	until c ;

>My point is, let programmers to control their own programming style. And some
>"bad" practice can be the only good solution under exceptional case.

  Well, I *don't* think one's programming practices should be dictated by the
compiler, but rather create different compilers conforming to different 
programming styles, and allow the programmer the choice of languages. And
one should adhere to the style dictated by the compiler chosen. 


==============================================================================
Today's message was brought to you by the letter 'S', the number 6, and

  		    =====> Einstein@cs.mcgill.ca  <====
             =====> Mike CHOWET | McGill CSUS VP External <=====

			Post back soon, now y'hear...
==============================================================================