Calling particular functions in an external Rexx script
Asked Answered
P

4

5

I have a Rexx script which functions standalone, and I wish to use another Rexx script to call particular functions within it. I am aware I can call both an entire external Rexx file and internal Rexx functions with call, but am I able to call a single function inside an external script? The following example illustrates what I want to do:

/* REXXA */
say 'hello'

run_test:
say 'test'

...

/* REXXB */
call 'REXXA' /* will say both 'hello' and 'test' */

How can I modify REXXB to say only 'test'?

EDIT: Further research indicates I might be looking for RxFuncAdd - can anyone confirm if that works with mainframe Rexx scripts? Most of the references involving it have been with regards to DLL libraries...

EDIT 2: Apparently not... anybody got any better ideas? RxFuncAdd routine not found

EDIT 3: I mustn't have explained my requirements properly, sorry about that - as per the comment under NealB's response, I essentially want something akin to calling a 'sin' function inside a 'math' class. The code I am writing is REXXB in the example above, and I want to change REXXA as little as possible.

Protestantism answered 9/1, 2012 at 5:11 Comment(0)
B
6

Directly there's no way to address internal labels in another program.

My first gut reaction is that you would have to slightly modify REXXA to add a wrapper function with a function code, something like

/* REXX A */

arg a1 a2 a3 a4 a5 (etc.)
select
when a1 = 'SIN'
  call sin a2 a3 ....
when a1 = 'COS'
  call cos a2 a3 ....
end
exit rc

sin:
  return some equation involving a2 that I last saw about 33 years ago

cos:
  return some equation involving a2 that I last saw about 33 years ago

/* REXX B */
call 'REXXA' 'sin 85' 

However, REXX under TSO does support external functions and subroutines which can be written in many languages, including REXX. The TSO/E REXX Reference External functions and subroutines, and function packages, z/OS V11 flavor describes how to do this.

There is a note in the doc about optionally compiling the REXX. If you don't have it, you may be able to find someone who is licensed for it who could compile it for use with ALTLIB (no license necessary).

Belew answered 10/1, 2012 at 16:42 Comment(2)
Thanks for that, that was what I was expecting. The existing rexx script uses a similar concept to your code (it's used to interpret commands entered into an ISPF panel) so I'll see if I can tap into that. It's already a member of an EXEC PDS so none of the other solutions are really suitable.Protestantism
I've always wanted to try building an external function set for REXX, but I've never had the opportunity. Someday, hopefully...Belew
T
2

cschneid has the right idea... The following works under both TSO (z/os) and Windows ooRexx:

REXXA:

/* REXXA */
parse source . as_a .
if as_a = 'COMMAND' then
   say 'hello'

run_test:
say 'test'
return

REXXB:

/* REXXB */
call 'REXXA' /* will say 'test' */
return

From the TSO or Windows Comand Line prompt: Typing REXXA will print both hello and test. Typing REXXB will print only test.

I must admit that I find this requirement a bit strange...

Tyrus answered 9/1, 2012 at 17:37 Comment(1)
Thanks for that, I might have overcomplicated it a bit - I want to make as few changes to REXXA as possible, e.g. in VB.NET if I have a class called 'math' and a function called 'sin' within it, I can call 'sin' from different code by doing math.sin()... If I have an existing bunch of functions inside a rexx script (ie. REXXA) can I call just one of them from REXXB, without modifying REXXA? The key requirement is that the 'library' (i.e. REXXA or the hypothetical 'math' class) remains largely unchanged.Protestantism
L
1

You might be able to use PARSE SOURCE to determine if you're being called standalone or by another Rexx exec. I haven't done this, but the documentation seems to indicate it would work.

Regarding your later edit: Ah, you want to write the moral equivalent of a DLL in Rexx, multiple entry points with none of them primary. I don't believe there's a way to do that just using Rexx on System z.

The only technique that comes to mind is to have a primary entry point to which you pass the name of the actual function you want to execute, along with its arguments. The main entry point would then call the specified function and return. Kludgy, sorry.

Likeminded answered 9/1, 2012 at 12:46 Comment(0)
G
0

As said before, there is no built-in way. But there is the possibility to create the same effect. It can be useful for utility execs, but is probably not something that should be used everywhere.

Using your example, you can alter it to this:

/* REXXA */
parse upper arg function parameter /* Get the function name and its parameter */
label_names = "RUN_TEST OTHER_FUNC" /* Names of the functions */
if wordpos(function,label_names) > 0 then signal value function /* Go to the valid function */

/* Execute old code if no valid function is found */
say 'hello'

run_test:
say 'test'
return /* Return to REXXB */

other_func: /* for demo */
return

...

/* REXXB */
call 'REXXA' 'run_test'
return

As you can see, it will require some changes to REXXA. But it is possible. "parameter" is not needed in your example, but it could be used in other cases.

The "signal" keyword is REXXs goto instruction. And with "signal value" you go to the label name, which is equal to the value of the variable following the keywords ("function" in the example). If signal is used with an invalid label name, then the exec has an error. So, make sure you test the input. The REXX interpreter casts everything outside of strings to upper case, so use the label names in upper case in strings. A difference between signal and call is, that you don't increase the call stack. A return does not bring you back to where the signal was used, but to the level above (REXXB in the example).

I hope this helped after such a long time.

Gyrocompass answered 14/8 at 16:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.