Hi Booth,
I have a series of validations to do. Lets say, for this discussion,
thet there is a listing of colors: BLU, BLK, YLW, RED, PNK, TRQ, and
GRN. I need to run a subroutine for each color.
To try to make this clear in your mind... The names we assign to
subroutines don't really exist. The computer doesn't REALLY search for
a routine named 'GRN' or a routine named 'BLK'. Instead, it runs code
that's stored at a particular address in the comptuers storage! When
you compile your program, it lays out the location of the subroutines.
When you get to the EXSR it jumps to a spot in the computers storage,
runs the machine code there, then jumps back. There's no actual name
used... just an address in storage.
The compiler doesn't know the address of the subroutine you're jumping
to when the field is calculated by the program, and therefore it can't
compile code like the one you've demosntrated.
With a subprocedure, it's possible to retrieve the procedure's address
by using the %paddr() BIF. That way, you can actually specify the
memory address that the computer needs. OF course, this only partially
solves the problem, since %paddr() needs to know the address of the
procedure (i.e. during the binding phase, it needs to be able to figure
out the actual procedure address) which means you can't use a variable
as the parameter to %paddr(), either.
But what you could do (if you really only have static values, like the
color names in your example) is create a lookup table in your program.
Look up the color name to get the procedure address. Here's a proof of
concept program that demonstrates this:
H DFTACTGRP(*NO)
D ds
D colorArray dim(7)
D color 3A overlay(colorArray:1)
D proc * procptr
overlay(colorArray:*Next)
D Array s 3a dim(100)
D Index s 10i 0
D X s 10i 0
D p_callme s * procptr
D callme PR extproc(p_callme)
D BLU PR
D BLK PR
D YLW PR
D RED PR
D PNK PR
D TRQ PR
D GRN PR
/free
// ** This code might go in an INZSR or some similar
// initialization for the program:
//
// Creates a lookup table that corresponds color name to
// a procedure arrays.
color(1) = 'BLU';
proc(1) = %paddr(BLU);
color(2) = 'BLK';
proc(2) = %paddr(BLK);
color(3) = 'YLW';
proc(3) = %paddr(YLW);
color(4) = 'RED';
proc(4) = %paddr(RED);
color(5) = 'PNK';
proc(5) = %paddr(PNK);
color(6) = 'TRQ';
proc(6) = %paddr(TRQ);
color(7) = 'GRN';
proc(7) = %paddr(GRN);
//
// Here's some test data for our proof of concept
//
Array(1) = 'YLW';
Array(2) = 'GRN';
Array(3) = 'BLU';
Array(4) = 'RED';
Array(5) = 'YLW';
//
// Call the appropriate routine based on the values, above
//
for Index = 1 to %elem(Array);
x = %lookup(Array(Index): color);
if (x > 0);
p_callme = proc(x);
callme();
endif;
endfor;
*inlr = *on;
/end-free
P BLU B
D BLU PI
/free
dsply 'Blue';
/end-free
P E
P BLK B
D BLK PI
/free
dsply 'Black';
/end-free
P E
P YLW B
D YLW PI
/free
dsply 'Yellow';
/end-free
P E
P RED B
D RED PI
/free
dsply 'Red';
/end-free
P E
P PNK B
D PNK PI
/free
dsply 'Pink';
/end-free
P E
P TRQ B
D TRQ PI
/free
dsply 'Turquoise';
/end-free
P E
P GRN B
D GRN PI
/free
dsply 'Green';
/end-free
P E
This is very similar to what Arthur mentioned, except that I
incorporated the lookup table. I also used a prototype instead of CALLB
(sorry, Arthur -- but CALLB should *only* be used if you need to support
V3R1. That was the only release of RPG where CALLB made sense to use!)
Now, if for some reason you don't know all of the procedure names at
run-time (and therefore can't hard-code them in a table) another way to
do this is by calling the QleGetExp() API. This API makes use of a
service program's export info (the stuff the binder uses when it looks
up your procedure name and converts it to an address) to find the
address of a subprocedure (in a srvpgm) at run-time.
So you could potentially use QleGetExp to find a procedure pointer for a
subprocedure based on the subprocedure name. It would have to be a
procedure that's exported from a srvpgm, but other than that one
restriction, this would work. You could do something like this:
p_callme = QleGetExp(*omit: *omit: %len(Array(Index)):
Array(Index): *omit: 1: *omit );
callme();
On the other hand, if you really have only 7 static values, a simple
SELECT group would be easier both to code/debug and for the next guy who
has to try to figure out your code.
Something to think about, anyway.
As an Amazon Associate we earn from qualifying purchases.