home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / lang / pascal / 5087 < prev    next >
Encoding:
Text File  |  1992-08-29  |  2.6 KB  |  90 lines

  1. Newsgroups: comp.lang.pascal
  2. Path: sparky!uunet!utcsri!torn!news.ccs.queensu.ca!mast.queensu.ca!dmurdoch
  3. From: dmurdoch@mast.queensu.ca (Duncan Murdoch)
  4. Subject: Passing local procedures
  5. Message-ID: <dmurdoch.77.715018832@mast.queensu.ca>
  6. Lines: 79
  7. Sender: news@knot.ccs.queensu.ca (Netnews control)
  8. Organization: Queen's University
  9. Date: Fri, 28 Aug 1992 16:20:32 GMT
  10.  
  11. In TP, it's possible to have procedure parameters with declarations like
  12.  
  13.   type
  14.     Tproc = procedure(arg1:integer);
  15.  
  16.   var
  17.     proc : Tproc;
  18.  
  19. and then any far procedure with a declaration that looks like the one for
  20. Tproc can be assigned to the proc variable.  However, it doesn't work with 
  21. local procedures, or with object methods, because those both have hidden 
  22. parameters being passed.
  23.  
  24. I've just worked out what's necessary to do this with local procedures, and 
  25. figured I'd post it in case someone else is interested.  It would be nice if 
  26. the language supported this more directly; I've sent a note to Borland 
  27. suggesting it.
  28.  
  29. This is how it works:  A local procedure is actually called with one extra 
  30. parameter after all the others, which is the BP value of the caller.  To 
  31. call one of these indirectly, just make the procedural type declaration 
  32. include one more parameter than the procedure, and put the correct BP value 
  33. there when you call it.  As far as I've seen, you can't typecast a local 
  34. procedure into this procedural type, so it's necessary to pass the address 
  35. of the local procedure as an untyped parameter.  This is where language 
  36. support would help a lot:  it's easy to get the declaration wrong, and the 
  37. compiler won't tell you.
  38.  
  39. Here's an example, and a little assembler function to retrieve the 
  40. appropriate BP value.
  41.  
  42. function context(n:word):word;  assembler;
  43. { Returns the BP value n stack frames back }
  44. asm
  45.   push bp
  46.   mov cx,n
  47.   inc cx
  48. @1:
  49.   mov bp,[bp]
  50.   loop @1
  51.   mov ax,bp
  52.   pop bp
  53. end;
  54.  
  55. type
  56.   localproc = procedure(j,k:integer;context:word);
  57.   { This is the declaration for a local procedure declared as:
  58.       procedure myproc(j,k:integer);  }
  59.  
  60. { This is a sample caller for that type of localproc }
  61.  
  62. procedure Callit(p:pointer;j,k:integer);
  63. var
  64.   proc : LocalProc absolute p;
  65. begin
  66.   proc(j,k,context(1));     { The "1" here denotes the stack frame of
  67.                   whatever procedure called Callit }
  68. end;
  69.  
  70. { Here's how to use the above: }
  71.  
  72. procedure outer;
  73.  
  74. var
  75.   i : integer;
  76.  
  77.   procedure inner(j,k:integer); far;
  78.   begin
  79.     i := j+k;    { note the access to the variable i in the outer frame }
  80.   end;
  81.  
  82. begin
  83.   callit(@inner,3,4);    { This will set i to 7 }
  84.   writeln('i is now ',i);
  85. end;
  86.  
  87. begin
  88.   outer;
  89. end.
  90.