0.9b (c) 1995 Peter Childs
Syntax
You can include function calls to internal and external routines in an expression anywhere that a data term (such as a string) would be valid, using the notation:
>>--function-name(-+------------------+-)---->< | +------,-------+ | | v | | +-++------------++-+ +-expression-+
function-name is a literal string or a single symbol, that is taken to be a constant.
There can be up to a maximum of 20 expressions, separated by commas, between the parentheses. These expressions are called the arguments to the function. Each argument expression may include further function calls.
The ( must be adjacent to the name of the function, with no blank in between, or the construct is not recognized as a function call. (A blank operator is assumed at this point instead.)
The arguments are evaluated in turn from left to right and they are all then passed to the function. This then executes some operation (usually dependent on the argument strings passed, though arguments are not mandatory) and eventually returns a single character string. This string is then included in the original expression as though the entire function reference had been replaced by the name of a variable that contained that data.
For example, the function SUBSTR is built-in to the language processor and could be used as:
N1='abcdefghijk' Z1='Part of N1 is: 'Substr(N1,2,7) /* would set Z1 to 'Part of N1 is: bcdefgh' */
A function call without any arguments must always include the parentheses to be recognized as a function call.
date() /* returns the date in the default format dd mon yyyy */
Calls to Functions and Subroutines
The mechanism for calling functions and subroutines is the same. The only difference is that functions must return data, whereas subroutines need not. The following types of routines can be called as functions:
Internal If the routine name exists as a label in the program, the current processing status is saved, so that it will later be possible to return to the point of invocation to resume processing. Control is then passed to the first label in the program that matches the name. As with a routine invoked by the CALL instruction, various other pieces of status information (TRACE and NUMERIC settings and so on) are also saved. See the CALL instruction for details of this. If an internal routine is to be called as a function, you must specify an expression in any RETURN instruction to return from the function. This is not necessary if the function is called only as a subroutine.
Example:
/* Recursive internal function execution... */ arg x say x'! =' factorial(x) exit
factorial: procedure /* calculate factorial by.. */ arg n /* .. recursive invocation. */ if n=0 then return 1 return factorial(n-1) * n
FACTORIAL is unusual in that it invokes itself (this is known as recursive invocation). The PROCEDURE instruction ensures that a new variable n is created for each invocation).
Built-in These functions are always available and are defined later in this section.
External You can write or make use of functions that are external to a program and to the language processor. An external function can be written in any language, including REXX, that supports the system-dependent interfaces used by the language processor to invoke it. Again, when called as a function, it must return data to the caller.
Notes:
1. Calling an external REXX program as a function is similar to calling an internal routine. The external routine is, however, an implicit PROCEDURE in that all the caller variables are always hidden and the status of internal values (NUMERIC settings and so on) start with their defaults (rather than inheriting those of the caller).
2. Other REXX programs can be called as functions. You can use either EXIT or RETURN to leave the invoked REXX program; in either case, you must specify an expression.
Search Order
The search order for functions is the same as in the preceding list. That is, internal labels take first precedence, then built-in functions, and finally external functions.
Internal labels are not used if the function name is given as a string (that is, is specified in quotation marks); in this case the function must be built-in or external. This lets you usurp the name of, for example, a built-in function to extend its capabilities, but still be able to invoke the built-in function when needed.
Example:
/* Modified DATE to return sorted date by default */ date: procedure arg in if in='' then in='Sorted' return 'DATE'(in)
Built-in functions have names in uppercase letters. The name in the literal string must be in uppercase for the search to succeed, as in the example. The same is usually true of external functions.
External functions and subroutines have a system-defined search order.
REXX searches for external functions in the following order:
1. Functions that have been loaded into the macrospace for pre-order execution 2. Functions that are part of a function package. 3. REXX functions in the current directory, with the current extension 4. REXX functions along environment PATH, with the current extension 5. REXX functions in the current directory, with the default extension 6. REXX functions along environment PATH, with the default extension 7. Functions that have been loaded into the macrospace for post-order execution.
Errors during Execution
If an external or built-in function detects an error of any kind, the language processor is informed, and a syntax error results. Processing of the clause that included the function call is therefore terminated. Similarly, if an external function fails to return data correctly, this is detected by the language processor and reported as an error.
If a syntax error occurs during the processing of an internal function, it can be trapped (using SIGNAL ON SYNTAX) and recovery may then be possible. If the error is not trapped, the program is terminated.
Return Values
A function normally returns a value that is substituted for the function call when the expression is evaluated.
How the value returned by a function (or any REXX routine) is handled depends on whether it is called by a function call or called as a subroutine with the CALL instruction.
A routine called as a subroutine: If the routine returns a value, that value is stored in the special variable named RESULT. Otherwise, the RESULT variable is dropped, and its value is the string "RESULT".
A routine called as a function: If the function returns a value, that value is substituted into the expression at the position where the function was called. Otherwise, REXX stops with an error message.
Examples:
/* Different ways to call a REXX procedure */ call Beep 500, 100 /* Example 1: a subroutine call */ bc = Beep(500, 100) /* Example 2: a function call */ Beep(500, 100) /* Example 3: result passed as */ /* a command */
o In Example 1, the built-in function BEEP is called as a REXX subroutine. The return value from BEEP is placed in the REXX special variable RESULT.
o Example 2 shows BEEP called as a REXX function. The return value from the function is substituted for the function call. The clause itself is an assignment instruction; the return value from the BEEP function is placed in the variable bc.
o In Example 3, the BEEP function is processed and its return value is substituted in the expression for the function call, just as in Example 2. In this case, however, the clause as a whole evaluates to a single expression; therefore the evaluated expression is passed to the current default environment as a command.
Note: Many other languages (such as C) throw away the return value of a function if it is not assigned to a variable. In REXX, however, a value returned as in Example 3 is passed on to the current environment or subcommand handler. If that environment is CMD (the default), then this action will result in the operating system performing a disk search for what seems to be a command.
Built-in Functions
REXX provides a rich set of built-in functions. These include character manipulation, conversion, and information functions.
Here are some general notes on the built-in functions:
o The parentheses in a function are always needed, even if no arguments are required. The first parenthesis must follow the name of the function with no space in between.
o The built-in functions work internally with NUMERIC DIGITS 9 and NUMERIC FUZZ 0 and are unaffected by changes to the NUMERIC settings, except where stated.
o You can supply a null string where a string is referenced.
o If an argument specifies a length, it must be a nonnegative whole number. If it specifies a start character or word in a string, it must be a positive whole number, unless otherwise stated.
o Where the last argument is optional, you can always include a comma to indicate that you have omitted it; for example, DATATYPE(1,), like DATATYPE(1), would return NUM.
o If you specify a pad character, it must be exactly one character long.
o If a function has a suboption you can select by specifying the first character of a string, that character can be in uppercase or lowercase letters.
o Conversion between characters and hexadecimal involves the machine representation of character strings, and hence returns appropriately different results for ASCII and EBCDIC machines.
o A number of the functions described in this chapter support the double-byte-character-set (DBCS). A complete list and description of these functions is given in the OS/2 Procedures Language 2/REXX Reference.
Inf-HTML End Run - Successful