× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.



Booth,

Scott made a very good case for using a SELECT clause: It is much easier to read and maintain.

In our business tobacco taxes and the methodologies (if you want to call 'em that) that taxing jurisdictions define run the gamut. Every once in awhile (just when you think they've exhausted all possibilities) someone comes up with a new way to tax. When they do, I just create a new method (subprocedure) and invoke it by adding it to the existing SELECT clause. Even an RPG II programmer could understand it.



* Jerry C. Adams
*IBM System i Programmer/Analyst
B&W Wholesale Distributors, Inc.* *
voice
615.995.7024
fax
615.995.1201
email
jerry@xxxxxxxxxxxxxxx <mailto:jerry@xxxxxxxxxxxxxxx>



Booth Martin wrote:
Scott, and everyone else... Thanks pots & pots. This has possibilities. (I am expecting a whole lot of entries, added over time, by some future programmer and i am trying to present him/her with the fewest possible places to screw up.)

Scott Klement wrote:
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 thread ...

Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

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.