[comp.lang.pascal] Turbo and Standard Pascal

john@cs.utexas.edu (John Baima) (07/06/89)

Turbo Pascal does (as of version 5.0) allow Procedures as parameters.
They have implemented a Procedure type which I believe goes beyond
"stansard" pascal. With the @ operator in version 4.0, it was easy to
pass procedures as parameters anyway.

One of the advantages of Borland's nonstandard Read/Write vs. Get/Put
is the ability to read or write any enumerated type. This is most
useful when one or more variables in a record are enumerated types. As
I remember "standard" Pascal in my distant past, one had to convert
an enumerated  type  to an ordinal type (often a byte or integer) and
then get/put that. That limitation is a real bother when using
records.


John Baima
d024jkb@utarlg		bitnet
texbell!utarlg!john	uucp

dat0@rimfaxe.diku.dk (Dat-0 undervisningsassistent) (07/06/89)

texbell!utafll!john@cs.utexas.edu (John Baima) writes:

>Turbo Pascal does (as of version 5.0) allow Procedures as parameters.
>They have implemented a Procedure type which I believe goes beyond
>"stansard" pascal. With the @ operator in version 4.0, it was easy to
>pass procedures as parameters anyway.

Right, you can do it, but you still can't do it the standard way. ("Oh there
he goes again"). Can anyone tell me, why it wasn't implemented in such a
way as to let standard programs compile without any trouble. 
It can't be that hard to do.

>One of the advantages of Borland's nonstandard Read/Write vs. Get/Put
>is the ability to read or write any enumerated type. This is most
>useful when one or more variables in a record are enumerated types. As
>I remember "standard" Pascal in my distant past, one had to convert
>an enumerated  type  to an ordinal type (often a byte or integer) and
>then get/put that. That limitation is a real bother when using
>records.

This on the other hand is not correct unless you are trying to write record
on text file.


Kristian Damm Jensen 
(dat0@diku.dk)
Institute of datalogi, University of Copenhagen (DIKU)
Universitetsparken 1, DK-2100 Copenhagen \, Denmark


Kristian Damm Jensen 
(dat0@diku.dk)
Institute of datalogi, University of Copenhagen (DIKU)

woody@aurora.uucp (Wayne Wood) (07/07/89)

In article <4822@freja.diku.dk> dat0@rimfaxe.diku.dk (Dat-0 undervisningsassistent) writes:
>texbell!utafll!john@cs.utexas.edu (John Baima) writes:
>
>>Turbo Pascal does (as of version 5.0) allow Procedures as parameters.
>>They have implemented a Procedure type which I believe goes beyond
>>"stansard" pascal. With the @ operator in version 4.0, it was easy to
>>pass procedures as parameters anyway.
>
>Right, you can do it, but you still can't do it the standard way. ("Oh there
>he goes again"). Can anyone tell me, why it wasn't implemented in such a
>way as to let standard programs compile without any trouble. 
>It can't be that hard to do.
>

i've been using Turbo since version 3.0 [still not very long] and i have always
been able to pass procedures and functions as parameters to other
procedures/functions.  and i learned to do it in UCSD PASCAL, it worked the
same for me in both languages.

refer to OH! PASCAL [author name escapes me] for more information.

-- woody
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%   ...tongue tied and twisted, just an earthbound misfit, I...            %%
%%   -- David Gilmour, Pink Floyd                                           %%
%%   woody@aurora.arc.nasa.gov %% my opinions,like my mind,are my own       %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

abcscnuk@csuna.csun.edu (Naoto Kimura) (07/10/89)

In article <4249@eos.UUCP> woody@aurora.UUCP (Wayne Wood) writes:
>In article <4822@freja.diku.dk> dat0@rimfaxe.diku.dk (Dat-0 undervisningsassistent) writes:
>>texbell!utafll!john@cs.utexas.edu (John Baima) writes:
>>
>>>Turbo Pascal does (as of version 5.0) allow Procedures as parameters.
>>>They have implemented a Procedure type which I believe goes beyond
>>>"stansard" pascal. With the @ operator in version 4.0, it was easy to
>>>pass procedures as parameters anyway.
>>
>>Right, you can do it, but you still can't do it the standard way. ("Oh there
>>he goes again"). Can anyone tell me, why it wasn't implemented in such a
>>way as to let standard programs compile without any trouble. 
>>It can't be that hard to do.
>>
>
>i've been using Turbo since version 3.0 [still not very long] and i have always
>been able to pass procedures and functions as parameters to other
>procedures/functions.  and i learned to do it in UCSD PASCAL, it worked the
>same for me in both languages.
>
>refer to OH! PASCAL [author name escapes me] for more information.
>
>-- woody
>%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>%%   ...tongue tied and twisted, just an earthbound misfit, I...            %%
>%%   -- David Gilmour, Pink Floyd                                           %%
>%%   woody@aurora.arc.nasa.gov %% my opinions,like my mind,are my own       %%
>%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The question was not whether you can or cannot, it was that you can't do
it in the standard method.  BTW, for those who might be making the
mistake that several people had made a couple of years back (when this
same discussion came about in this newsgroup the last time), what is
meant by procedural and functional parameters, it does not mean passing
the value returned by a function to a procedure or function.  In other
words, It's not something like:

    y := sin(deg2rad(x));

which is passing the value returned by deg2rad() to sin().  An assembly
language equivalent of the above would go something like this:

    mov  ax,[word x+4]
    push ax
    mov  ax,[word x+2]
    push ax
    mov  ax,[word x]
    push ax
    call deg2rad		; evaluate  deg2rad(x)
    push dx
    push bx
    push ax
    call sin			; send return value off to sin(x)
    mov  [word y],dx		; store value into 'y'
    mov  [word y+2],bx
    mov  [word y+4],ax

Passing a procedure or function to another procedure or function means
basically at the low level, the address of the procedure or function being
passed is passed to the called procedure or function.  The called procedure 
then uses the address to perform an indirect call to the passed procedure
or function:

    PROC	comparison
		ARG	Key1:DWORD,Key2:DWORD
		...
		...
		ret
    ENDP

    PROC	sort
		ARG	list:DWORD,compare:DWORD
		LOCAL	Temp1:DWORD,Temp2:DWORD
		...
		; see if we need to swap records
		mov	ax,[Temp1]
		push	ax
		mov	ax,[Temp2]
		push	ax
		call	far [compare]
		jnc	NoSwap
		; swap records
		...
    NoSwap:	...
		...
		ret
    ENDP

    PROC	caller
		...
		push	ds
		mov	ax,List
		push	ax
		push	cs
		mov	ax,ptr comparison
		push	ax
		call	sort
		...
		ret
    ENDP

To get back to the discussion, Turbo pascal will not compile the
following (the standard method of passing procedural and functional
parameters):

    program bleah(output);

    procedure ugh( argh : integer );
	begin
	    writeln('ugh: passed parameter = ',argh)
	end;

    procedure plbbt( yuck : integer );
	begin
	    writeln('plbbt: passed parameter = ',yuck)
	end;

    procedure oof( procedure foo ( bar : integer ); ick : integer );
	begin
	    writeln('oof: calling passed procedure');
	    foo(ick)
	end;

    begin
	oof(ugh,3);
	oof(plbbt,5)
    end.

To do the above in Turbo pascal, you have to resort to using inline
machine code (some of the code may be incorrect -- I haven't used
version 3.0 for a while...).  You can continue to do the same sort of
thing in versions 4.0 and 5.0, except that with those versions you have
to worry about far references.  Unfortunately, there was no checking to
see if the function or procedure that was passed had the correct number
and types of parameters.

    program bleah(output);

    {for each kind of procedure or function you want to pass as a
     parameter, you'll need to build a similar procedure or function}
    procedure indirect ( parm : integer; proc : integer );
		       { ^^^^^^^^^^^^^^^
			   parameters to be passed should come before
			   the address of procedure to be called, this
			   makes calling the procedure easier
		       }
	begin
	    inline(
		{I don't have it available with me right now, but
		 it went something like the following (in assembly)}
		{mov  sp,bp	; get rid of local variables}
		{pop  bp	; restore bp}
		{pop  ax	; grab return address}
		{pop  bx	; grab address to routine}
		{push ax	; put return address back on stack}
		{jmp near [bx]	; jump to routine -- let it handle
				      stack cleanup}
		)
	end;

    procedure ugh( argh : integer );
	begin
	    writeln('ugh: passed parameter = ',argh)
	end;

    procedure plbbt( yuck : integer );
	begin
	    writeln('plbbt: passed parameter = ',yuck)
	end;

    procedure illegal;
	begin
	    writeln('this should screw up the stack !')
	end;

    procedure oof( foo : integer; ick : integer );
	begin
	    writeln('oof: calling passed procedure');
	    indirect(ick,foo)
	end;

    begin
	oof(addr(ugh),3);
	oof(addr(plbbt),5);

	(* The following should cause some problems with the stack    *)
	(* since calling the 'indirect' procedure will cause an       *)
	(* integer parameter to be passed on the stack, which is      *)
	(* expected to be cleaned up by the procedure it jumps to.    *)
	(* But 'illegal' will not, so it ends up leaving an extra     *)
	(* word on the stack.  This would cause procedure 'oof' to    *)
	(* use that value as the return address when it performs a    *)
	(* 'ret' instruction                                          *)
	oof(addr(illegal),0)
    end.

Version 5.0 introduced the ability to pass procedures and functions as
parameters without having to resort to inline code, though in a
non-standard way.

    program bleah(output);
    type
	procparm	= procedure ( iarg : integer );

    procedure ugh( argh : integer );
	begin
	    writeln('ugh: passed parameter = ',argh)
	end;

    procedure plbbt( yuck : integer );
	begin
	    writeln('plbbt: passed parameter = ',yuck)
	end;

    procedure oof( foo : procparm; ick : integer );
	begin
	    writeln('oof: calling passed procedure');
	    foo(ick)
	end;

    begin
	oof(ugh,3);
	oof(plbbt,5)
    end.

                //-n-\\			 Naoto Kimura
        _____---=======---_____		 (abcscnuk@csuna.csun.edu)
    ====____\   /.. ..\   /____====
  //         ---\__O__/---         \\	Enterprise... Surrender or we'll
  \_\                             /_/	send back your *&^$% tribbles !!

milne@ics.uci.edu (Alastair Milne) (07/12/89)

abcscnuk@csuna.csun.edu (Naoto Kimura) writes:
>    program bleah(output);
....

>    procedure oof( procedure foo ( bar : integer ); ick : integer );
>	begin
>	    writeln('oof: calling passed procedure');
>	    foo(ick)
>	end;
...


    This is the way UCSD Pascal does it (though not, I believe, in versions
    previous to IV.0)  I was sure there was nothing like this in Turbo Pascal.
    Thanks for clearing it up.

    BTW, how is scoping defined for procedures passed by the method you
    describe for Turbo 5.0?


    Alastair Milne

jds@mimsy.UUCP (James da Silva) (07/12/89)

In article <19440@paris.ics.uci.edu> milne@ics.uci.edu (Alastair Milne) writes:
>    BTW, how is scoping defined for procedures passed by the method you
>    describe for Turbo 5.0?

Alastair,

The scoping is static as usual.  Since procedure values cannot be returned,
the implementation is straightforward.  The procedure parameter consists of
a code pointer AND an `environment pointer'.  The environment pointer
points to the frame of the static parent of the procedure parameter.

If you could return local procedures, things would get much more
complicated.

Jaime
...........................................................................
: domain: jds@mimsy.umd.edu				     James da Silva
: path:   uunet!mimsy!jds

schwartz@shire.cs.psu.edu (Scott Schwartz) (07/12/89)

In article <2075@csuna.csun.edu> abcscnuk@csuna.csun.edu (Naoto Kimura) writes:

[ Correctly diagnoses TP's problems with procedure parameters ]

|Passing a procedure or function to another procedure or function means
|basically at the low level, the address of the procedure or function being
|passed is passed to the called procedure or function.  The called procedure 
|then uses the address to perform an indirect call to the passed procedure
|or function:

This is not quite the whole story.  In addition to the address of the
function to be called, you need to pass the context of that function
(the static link).  For this reason, if no other, passing just
addr(func) won't do the job properly.  Even if you didn't screw up the
stack, you'd be unable to correctly access func's global variables.

On a slightly differen subject, handling procedure parameters correctly
is the hardest part of translating Pascal to C mechanically.  The most
common tactic is to just punt.  (Per Bergsten's otherwise excellent
translator punts, for example.)

--
Scott Schwartz		<schwartz@shire.cs.psu.edu>

stephen@ziebmef.uucp (Stephen M. Dunn) (07/18/89)

In article <4822@freja.diku.dk> dat0@rimfaxe.diku.dk (Dat-0 undervisningsassistent) writes:
>refer to OH! PASCAL [author name escapes me] for more information.

Oh! Pascal is by Doug Cooper and Michael Clancy.
-- 
-------------------------------------------------------------------------------
! Stephen M. Dunn              stephen@ziebmef.UUCP ! DISCLAIMER:  Who'd ever !
! My puppy died late last fall                      ! claim such dumb ideas?  !
! He's still rotting in the hall          (O.E.)    ! I sure as heck wouldn't !