From: tswingle@oucsace.cs.ohiou.edu (Tom Swingle)
Newsgroups: comp.lang.pascal
Subject: Re: Procedural Variables
Date: 2 Sep 92 23:31:28 GMT
Organization: Ohio University CS Dept,. Athens

In article <1992Aug31.145029.16564@doug.cae.wisc.edu> chris@castlab.engr.wisc.edu (Christian Rohrmeier) writes:
>Thanks to all those who sent me replies to my question about dynamically calling
>a procedure via a variable.
>
>It seems that is comes down to procedural variables.
>
>The problem is, I can't seem to assign a variable to the proc. variable!
>
>Here sample code given to me by Kjell:
>
>Program TestProc;
>
>Uses Crt;
>
>Var Proc: procedure;
>
>Begin
>  Proc:= ClrScr;
>  Proc;
>End;
>
>This works. However, if I try Proc:='name_of_my_procedure' or to try and assign a
>string varibale to it I get a type mismatch.
>
>Any ideas from the net?
>
>-Chris

This solution is "borrowed" from the comp.lang.c newsgroup, where I have seen
this question posted many times before.

The problem is that, except for debugging information that may or may not be
included in the executable file that you compile to, the names of your 
procedures or functions no longer exist.  Your program must provide the 
correlation between the name of the subroutine being called and its location.
The best way to do this is to bind them together as fields in an array of
records as follows:

-- Begin included program --

program showprocnames;

uses crt;

const
  numcommands=4;
  commandlist:array[1..numcommands] of record
    proc:procedure;
    name:string;
  end=((proc:clrscr;name:'clrscr'),
       (proc:clreol;name:'clreol'),
       (proc:insline;name:'insline'),
       (proc:delline;name:'delline'));

var
  command:string;
  i,line:integer;

begin
  repeat
    clrscr;
    writeln('Enter a command below from the following list:');
    writeln;
    for i:=1 to numcommands do writeln(i:3,'.  ',commandlist[i].name);
    writeln;
    writeln('I''ll put the cursor on the line below and execute it:');
    line:=wherey;  { Figure out what line to put the cursor on }
    writeln('Your command will be executed here.');
    writeln('We are trained professionals.  Don''t try this at home :-).');
    writeln('This is just filler to show the effect of the command.');
    writeln;
    write('Enter your command or "quit" to quit:  ');
    readln(command);
    if command<>'quit' then
      for i:=1 to numcommands do
        if commandlist[i].name=command then begin
          gotoxy(1,line);  { Go to the appropriate line }
          commandlist[i].proc;  { Do the command }
          gotoxy(1,25);
          write('Command executed.  Press any key...');
          while readkey=#0 do;  { Empty keypress read }
        end;
  until command='quit';
end.

-- End included program --

The body of the program is really unimportant, it is just to show that it
works.  The important thing to notice is the way I have declared the record to
be a sort of "lookup table" so you can find what procedure to call when you
have put your command together.  

Note, however, that all the procedures I used here have no parameters.  If you
want to call procedures with parameters, you need to also do the following:

  - Declare a procedural type for each combination of number and type of
    parameter you will be encountering, and either declare separate arrays of
    records to hold each type, or use a variant record so you can store all
    of these types in the same data structure.
  - In addition to the name of the procedure, also store the number and types
    of parameters in the data structure somewhere.
  - Be sure you can reference any variables that your procedure call requires,
    possibly by doing the same trick; i.e., keep a list of variable names and
    pointers to those variables.

What you actually end up doing is writing a little mini-interpreter with only
a subset of commands that are necessary to what you are doing.  A pretty 
formidable project if it grows to significant complexity.
-- 
"The problem you are experiencing is  |  "To be sure of hitting the target, 
not with the network nor with the     |  shoot first and, whatever you hit, 
station.  Please adjust your set."    |  call it the target." 
More ramblings from: tswingle@oucsace.cs.ohiou.edu/tswingle@bigbird.cs.ohiou.edu