+-,--------------+
V |
>>-CALL--+-+-name---+----+------------+-+------------------+--;--><
| +-(expr)-+ +-expression-+ |
+-OFF--+-ANY-----------------+--------------------+
| +-ERROR---------------+ |
| +-FAILURE-------------+ |
| +-HALT----------------+ |
| +-NOTREADY------------+ |
| +-USER--usercondition-+ |
+-ON--+-ANY-----------------+--+----------------+-+
+-ERROR---------------+ +-NAME--trapname-+
+-FAILURE-------------+
+-HALT----------------+
+-NOTREADY------------+
+-USER--usercondition-+
CALL calls a routine (if you specify name) or controls the trapping of certain conditions (if you specify ON or OFF).
To control trapping, you specify OFF or ON and the condition you want to trap. OFF turns off the specified condition trap. ON turns on the specified condition trap. All information on condition traps is contained in
Chapter 11, Conditions and Condition Traps.
To call a routine, specify name, which must be a literal string or symbol that is taken as a constant. The usercondition is a single symbol that is taken as a constant. The trapname is a symbol or string taken as a constant. The routine called can be:
- An internal routine
A subroutine that is in the same program as the CALL instruction or function call that calls it. Internal routines are located using label instructions.
- A built-in routine
A function that is defined as part of the Rexx language.
- An external routine
A subroutine that is neither built-in nor a label within the same same program as the CALL instruction call that invokes it. See
Section 7.2.1, “Search Order” for details on the different types of external routines.
If name is a literal string (that is, specified in in quotation marks), the search for internal routines is bypassed, and only a built-in function or an external routine is called. Note that built-in function names are in uppercase. Therefore, a literal string call to a built-in function must also use uppercase characters.
You can also specify (
expr), any valid expression enclosed in parentheses. The expression is evaluated before any of the argument expressions, and the value is the target of the CALL instruction. The language processor does not translate the expression value into uppercase, so the evaluated name must exactly match any label name or built-in function name. (See
Section 1.12.3, “Labels” for a description of label names.)
The called routine can optionally return a result. In this case, the CALL instruction is functionally identical with the clause:
+-,--------------+
V |
>>-result=name(----+------------+-+--)--;----------------------><
+-expression-+
You can use any number of
expressions, separated by
commas. The expressions are evaluated from left to right and form the arguments during execution of the routine. Any ARG, PARSE ARG, or USE ARG instruction or ARG built-in function in the called routine accesses these objects while the called routine is running. You can omit expressions, if appropriate, by including extra commas.
The CALL then branches to the routine called
name, using exactly the same mechanism as function calls. See
Chapter 7, Functions. The search order is as follows:
- Internal routines
These are sequences of instructions inside the same program, starting at the label that matches name in the CALL instruction. If you specify the routine name in quotation marks, then an internal routine is not considered for that search order. The RETURN instruction completes the execution of an internal routine.
- Built-in routines
These are routines built into the language processor for providing various functions. They always return an object that is the result of the routine. (See
Section 7.4.4, “ARG (Argument)”.)
You can call any built-in function as a subroutine. Any result is stored in RESULT. Simply specify CALL
, the function name (with no parenthesis) and any arguments:
Example 2.7. Instructions - CALL
call length "string" /* Same as length("string") */
say result /* Produces: 6 */
- External routines
Users can write or use routines that are external to the language processor and the calling program. You can code an external routine in Rexx or in any language that supports the system-dependent interfaces. If the CALL instruction calls an external routine written in Rexx as a subroutine, you can retrieve any argument strings with the ARG, PARSE ARG, or USE ARG instructions or the ARG built-in function.
During execution of an internal routine, all variables previously known are generally accessible. However, the PROCEDURE instruction can set up a local variables environment to protect the subroutine and caller from each other. The EXPOSE option on the PROCEDURE instruction can expose selected variables to a routine.
Calling an external program or routine defined with a ::ROUTINE directive is similar to calling an internal routine. The external routine, however, is an implicit PROCEDURE in that all the caller's variables are always hidden. The status of internal values, for
example NUMERIC settings, start with their defaults (rather than inheriting those of the caller). In addition, you can use EXIT to return from the routine.
When control reaches an internal routine, the line number of the CALL instruction is available in the variable SIGL (in the caller's variable environment). This can be used as a debug aid because it is possible to find out how control reached a routine. Note that if the internal routine uses the PROCEDURE instruction, it needs to EXPOSE
SIGL to get access to the line number of the CALL.
After the subroutine processed the RETURN instruction, control returns to the clause following the original CALL. If the RETURN instruction specified an expression, the variable RESULT
is set to the value of that expression. Otherwise, the variable RESULT is dropped (becomes uninitialized).
An internal routine can include calls to other internal routines, as well as recursive calls to itself.
Example 2.8. Instructions - CALL
/* Recursive subroutine execution... */
arg z
call factorial z
say z"! =" result
exit
factorial: procedure /* Calculate factorial by */
arg n /* recursive invocation. */
if n=0 then return 1
call factorial n-1
return result * n
During internal subroutine (and function) execution, all important pieces of information are automatically saved and then restored upon return from the routine. These are:
The status of loops and other structures: Executing a SIGNAL within a subroutine is safe because loops and other structures that were active when the subroutine was called are not ended. However, those currently active within the subroutine are ended.
Trace action: After a subroutine is debugged, you can insert a TRACE Off at the beginning of it without affecting the tracing of the caller. If you want to debug a subroutine, you can insert a TRACE Results at the start and tracing is automatically restored to the conditions at entry (for example, Off) upon return. Similarly, ?
(interactive debug) is saved across routines.
NUMERIC settings: The DIGITS, FUZZ, and FORM of arithmetic operations (in
Section 2.16, “NUMERIC”) are saved and then restored on return. A subroutine can, therefore, set the precision, for example, that it needs to use without affecting the caller.
ADDRESS settings: The current and previous destinations for commands (see
Section 2.1, “ADDRESS”) are saved and then restored on return.
Condition traps: CALL ON and SIGNAL ON are saved and then restored on return. This means that CALL ON, CALL OFF, SIGNAL ON, and SIGNAL OFF can be used in a subroutine without affecting the conditions the caller set up.
Condition information: This information describes
the state and origin of the current trapped condition. The CONDITION built-in function returns this information. See
Section 7.4.18, “CONDITION”.
Elapsed-time clocks: A subroutine inherits the elapsed-time clock from its caller (see
Section 7.4.65, “TIME”), but because the time clock is saved across routine calls, a subroutine or internal function can independently restart and use the clock without affecting its caller. For the same reason, a clock started within an internal routine is not available to the caller.