0
votes

I have a small terminal program which displays a menu. I want to have a function which takes the user's input and an array of procedure names and be able to call the procedure the user chose. I know that I could do that using if or case statements in the main program, but I want to make a unit with the above procedure and a couple of other menu functions, and if this was possible, I could make it call arbitrary procedures. Here's more or less how I would like it to work (I know it's wrong, but so you get a general idea).

program menu;
uses crt;

type procs = array [0..1] of procedure;

procedure call_procs(inp: int; procsy: procs);
    begin
      writeln(procsy[ord(inp)]); {And call it here.}
    end;

var procsx : procs;

begin
procsx[0] := readkey; {I would like to somehow store the procedure here.}
procsx[1] := clrscr;
call_procs(0, procsx); 
end.

Is there any way to do something like this? Thank you in advance.

2
Note that the Pascal standard has no procedural types, only procedural parameters. Procedural types are an extension to the standard, so without mentioning a specific compilers you might get different answers. - tofro

2 Answers

0
votes

There are a few things wrong with your original code which are not cited in your answer.

  • You have an array of procedure but you are calling writeln with these procedure calls as arguments as if they were function, which they are not.

  • readkey is a function, not a procedure, so its type doesn't match the element type of your array

  • Your assignment of the procedures to the array need to use @ to reference the procedure pointer and not actually call the procedure

  • Not sure what compiler or options you're using, but int isn't the standard Pascal integer type, rather integer is.

As a niggle, since you're already using the integer index of the array, you don't need to use ord.

So the minimal changes to your code to make it basically work would be:

program menu;
uses crt;

type procs = array [0..1] of procedure;

procedure call_procs(inp: integer; procsy: procs);
begin
  procsy[inp]; { call the procedure here - removed 'ord' since it's superfluous }
end;

var procsx : procs;

begin
{  procsx[0] := readkey; {- 'readkey' is a function and won't work here }
  procsx[1] := @clrscr;
  call_procs(1, procsx); 
end.

You can create an array of functions that return char which matches the type for readkey:

program menu;
uses crt;

type procs = array [0..1] of function: char;

procedure call_procs(inp: integer; procsy: procs);
begin
  writeln(procsy[inp]);  { call the function; write out the returned char }
end;

function foo: char;
begin
  foo := 'X';
end;

var procsx : procs;

begin
  procsx[0] := @readkey;
  procsx[1] := @foo;
  call_procs(0, procsx);
  call_procs(1, procsx);
end.
0
votes

I figured out how to do this. One can use pointers to a procedure, then create an array of those pointers, and pass them to the procedure I wanted to use. Also, for some reason, it doesn't seem to work with the functions that come with Pascal (such as readkey or clrscr). For this example, one could do this:

program menu;
type
  Tprocptr = procedure; {This creates a pointer to procedures.}
  Tprocarray = array of Tprocptr;

procedure writeHi;
begin
  writeln('Hi!');
end;

procedure writeHello;
begin
  writeln('Hello!');
end;

procedure call_proc(inp: integer; procsy: Tprocarray);
{This now calls functions like one would expect.}
begin
  procsy[ord(inp)];
end;

var 
  proclist : Tprocarray;

begin
  setlength(proclist, 2);
  proclist[0] := @writeHi; {The '@' creates a pointer to those procedures.}
  proclist[1] := @writeHello;
  call_proc(0, proclist);  
end.

This works as expected, calling (in this case) the procedure writeHi, so if you run this program it will output Hi! to the terminal. If you change call_proc(0,proclist) to call_proc(1, proclist), it will call writeHello instead.