|
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.
This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.