NUMERIC parameter value
NUMERIC DIGITS n
NUMERIC FUZZ n
NUMERIC FORM SCIENTIFIC
| ENGINEERING
| "string constant"
| [VALUE] expression
The expression evaluator uses arbitrary length arithmetic for numeric
operations. The precision to which operations are carried out by the
evaluator may be altered using the NUMERIC DIGITS command, and is
initially 9. The number supplied will be the number of digits kept after
each operation, not including the decimal point, or leading zeros, which
are dropped by all arithmetic operations. The upper limit for NUMERIC
DIGITS is about 10000 (defined in const.h). Note that a single
multiplication or division can take many minutes at this precision.
NUMERIC FUZZ is initially zero and is set to zero by each NUMERIC DIGITS
command. It specifies a temporary reduction in the precision of
arithmetic when doing comparisons (remember, for all numeric comparisons,
the two operands are subtracted and the result is compared with zero. It
is the precision of the subtraction which is affected by NUMERIC FUZZ).
The upper limit for NUMERIC FUZZ is clearly one less than the current
value of NUMERIC DIGITS.
NUMERIC FORM is used to set the form of exponents to either `scientific'
mode or `engineering' mode. When an exponent is used, in the scientific
mode there is always precisely one digit, which is non-zero, before the
decimal point. In engineering mode, there are up to three digits before
the decimal point, and the exponent is always a multiple of three.
If an expression is used, it must evaluate to "SCIENTIFIC" or
"ENGINEERING" in upper case. If the expression does not start with a
symbol or string constant, then the keyword VALUE may be omitted.
The NUMERIC settings are saved across function calls, and restored on
return from a function, so a function may set the precision, etc. that
it needs without affecting the caller. Moreover, the settings will be
restored to their default settings just after entering any external
REXX procedure.
DO
There are two uses of DO:
1. DO
...commands...
END
This is a compound statement, i.e. the DO and END are wrapped around
the block of commands so that they appear like one statement and may
be used in IF constructs.
2. DO [ symbol=start [TO finish] ] [WHILE expression_w]
[ [BY step ] ]
[ [FOR count ] ] [UNTIL expression_u]
[ expression_c ]
[FOREVER ]
...commands...
END [symbol]
where start, finish, step, count and the expressions are numerical
expressions. Expression_c and count are required to be non-negative
integers.
This is a repetitive command. If `symbol' is present in the DO
statement, then:
a. `symbol' may be any simple or compound symbol
b. the symbol name may appear after the END statement; if it does,
then it must be the same one as after the DO. The DO symbol and
the END symbol are compared literally, without substituting any
components in the tail of a compound symbol, but the comparison
is case insensitive.
c. the value of start is assigned to the symbol before the loop is
entered.
d. if [TO finish] is present, then the loop is not executed after the
control variable (named by the symbol) passes the finish value.
If it is not present, then the loop may potentially be executed
for ever (unless a FOR clause is present).
e. if [BY step] is present, then the variable is incremented by step
after each pass. Otherwise the variable is incremented by 1.
f. If [FOR count] is present, then the loop is executed at most
count times.
g. The TO, FOR and BY clauses may be specified in any order. (Note:
each should be specified at most once, but specifying one or more
of these twice will not cause an error. The last one encountered
is the one which is used).
If `symbol' is not present, then nothing must follow the END.
If the expression_c is specified, then the loop is executed this number
of times (unless terminated by some other condition). Note that
expression_c must not start with a symbol followed by '=', because it
would then be taken to be a `symbol' as above. This may be prevented
by enclosing the expression in parentheses.
If a WHILE clause is present, then expression_w is evaluated before
each pass and the loop is terminated if the result is false.
If an UNTIL clause is present, then expression_u is evaluated after
each pass and the loop is terminated if the result is true.
A `DO FOREVER' instruction creates a loop which never terminates
(unless a LEAVE instruction is encountered).
Note that if expression_w is false or if the variable clause needs no
repetition, or if count or expression_c is zero, then the body of the
loop will not be executed at all.
An END must appear for each DO construct, and if labelled with a symbol,
must have the correct symbol.
NOTE: The name of any variable specified at the DO statement is
evaluated again each time it is incremented at the end of a
pass through the loop. This means, for example, that in
"DO a.i=1 TO 10", the name of the variable which is incremented
depends on the current value of i. (Altering the value of i is,
of course, not highly recommended).
Example: The code
do name=expri to exprt by exprb for exprf while exprw (or until expru)
... instructions ...
end
will be executed as if it were written thus:
$tempi = expri /* variables staring with $ are */
$tempt = exprt /* invisible to the rest of the */
$tempb = exprb /* program. */
$tempf = exprf
name = $tempi + 0
$loop: if name > $tempt then goto $end /* "goto" is a pseudo-op */
if $tempf = 0 then goto $end /* meaning the obvious */
if \exprw then goto $end
... instructions ...
$iter: if expru then goto $end /* "iterate" will come here */
name = name + $tempb
$tempf = $tempf - 1
goto $loop
$end: /* "leave" will come here */
(If any of the constructs in the original code are left out, the
coresponding lines will be left out of this example).
SELECT [expression]
WHEN expression THEN instruction
WHEN expression THEN instruction
...
[OTHERWISE instructions]
END [SELECT]
If an expression is supplied after SELECT, then this construction is like
a Pascal or Modula `CASE' construction. The expression is compared with
each of the other expressions in turn, until one is found that matches
(using the `=' form of equality). If a match is found, then the
corresponding instruction is executed. If a match is not found, then an
OTHERWISE clause must be specified, or else an error is reported. The
instructions after OTHERWISE will be executed.
If an expression is not specified after SELECT, then the construction
is a list of guarded commands - that is, each expression is evaluated
until a true one is found, and the corresponding action is taken. Again,
if no expression is true and there is no OTHERWISE then an error is
reported.
The word SELECT may be placed after the closing END but is optional.
Adding the word SELECT allows easier detection of missing ENDs.
It is an error for the word WHEN or OTHERWISE to appear anywhere except
immediately inside a SELECT construction.
Precisely one instruction is required after each WHEN, so NOP should be
used if no action is required. NOP need not be used after OTHERWISE.
If multiple instructions are required to follow each WHEN condition,
then they should be contained in a DO ... END block. Multiple
instructions may follow the OTHERWISE keyword.
LOCAL: The optional expression following the SELECT keyword, and the
optional SELECT following the END keyword are features of PL/1
and not of standard REXX.
PARSE [UPPER] string [template] (also: ARG [template], PULL [template])
[PARSE [UPPER]] ARG template
[PARSE [UPPER]] PULL [template]
PARSE [UPPER] LINEIN [template]
PARSE [UPPER] SOURCE template
PARSE [UPPER] VERSION template
PARSE [UPPER] NUMERIC template
PARSE [UPPER] VAR symbol template
PARSE [UPPER] VALUE expression WITH template
This command is a powerful parser which divides the operand up as
specified by the `template'. If the UPPER keyword is specified, then the
operand is uppercased before parsing.
The "ARG template" and "PULL template" commands are short forms of
"PARSE UPPER ARG template" and "PARSE UPPER PULL template" respectively.
The possible operands are as follows:
ARG - the command-line arguments, or the arguments passed by a function
or procedure call, are parsed.
PULL - the top value on the stack, if one exists, is parsed; otherwise
a line of input is read from the standard input and parsed as
described for LINEIN below. See QUEUE/PUSH for details about
the stack.
LINEIN- A line is read directly from stdin. The stack is not affected
by this instruction. In general, PULL is recommended in
preference to LINEIN.
If a line cannot be read because of an I/O error or EOF
condition, then the NOTREADY condition will be raised and an
empty string will be parsed. The NOTREADY condition is ignored
unless trapped by SIGNAL ON or CALL ON, in which case it is
difficult to tell the difference between an empty input line
and an I/O error. However, the STREAM() function may be
used to examine the most recent I/O error on stream "stdin".
NOTE: If the program is interrupted (via ^C) while input is being
read, then the characters which have been read in may be
lost, but the remainder of a partially-input line will
remain to be read again.
SOURCE- An implementation-dependent string representing the `source' of
the program is parsed.
In this implementation, the string contains five words:
1. the system under which the interpreter runs (always UNIX)
2. the way in which the program was called (one of COMMAND,
FUNCTION or SUBROUTINE, depending whether the program was
invoked by a command shell or as a function or subroutine)
3. the name of the file containing the program, with the full
path name (unless no directory was specified and getwd could
not name the current directory)
4. the name by which the program was called (always without a
path name).
5. the environment name which was current when the program
started up
VERSION-A string representing the version of the REXX interpreter is
parsed. This contains five words:
1. A word describing the language, of which the first four
letters are always REXX. In this implementation the word is
REXX/imc.
2. A string representing the version number (e.g. 1.0)
3,4,5. The date on which the interpreter was compiled, in the
same format as the DATE() function (e.g. 18 May 1990).
NUMERIC-The current NUMERIC settings are parsed. There are three words
in the string to be parsed: NUMERIC DIGITS, NUMERIC FUZZ and
NUMERIC FORM respectively.
VAR - The symbol specified is evaluated, and if it represents
a currently defined variable, its value is substituted. The
result is then parsed.
VALUE - The expression between "VALUE" and "WITH" is evaluated and then
parsed (note that WITH is a reserved keyword in this instruction)
If no template is supplied, the information to be parsed is collected and
then thrown away.
The "ARG" and "VALUE" forms may parse more than one string at once. This
comes about with "ARG" when a function or procedure call (note - not a
command line call) passes more than one argument, or with "VALUE" when
the expression contains comma separators. In this case, the parse
template may contain commas. The part of the template before the first
comma applies to the first operand string, that part between the first
and second commas applies to the second string, and so on. E.g.
PARSE VALUE 43 56,5*9,hello,there WITH template1,template2,
Here template1 applies to "43 56"; template2 applies to "5*9" and no
other parsing takes place. Note that there does not have to be a template
for each operand string, and also that there does not have to be an
operand string for each template (in this case the extra templates will
be applied to the empty string).
LOCAL: Parsing multiple strings with the PARSE VALUE construction is a
local extension.
A parse template obeys the following grammar. A symbol in brackets
indicates that that symbol may be optionally present. A character in
single quotes indicates that that character should be typed literally.
A symbol in double quotes is a terminal symbol, indicating the
appropriate REXX entity should be present.
template -> [firstPosition] assignments [assignments]
assignments -> [nextPosition] varlist [stopPosition]
varlist -> varname [varlist]
varname -> "non-constant symbol"
| '.'
firstPosition -> position
nextPosition -> position [nextPosition]
stopPosition -> position
position -> searchPosition
| absPosition
| relPosition
| '(' "expression" ')'
searchPosition -> "string constant"
absPosition -> "integer"
| '=' numexpr
relPosition -> '+' numexpr
| '-' numexpr
numexpr -> "integer"
| '(' "integer expression" ')'
Each position symbol in this grammar indicates a column number to the
parser. Positions are translated to column numbers (numbered from 1 up to
l+1, where l is the length of the string being parsed) in the following
way. Note that the absPosition indicator "1" is implicitly present
before and after any parse template.
absPosition: gives the column number directly, except that numbers not
between 1 and l+1 are translated into 1 or l+1 as
appropriate.
searchPosition: searches for the given string constant in the string
being parsed, starting from the most recent column number
Usually, two column numbers result: the column number of
the first character which matched, and that of the first
character after the matching string. The latter number is
suppressed if the next position indicator (if any) is a
`relPosition'. If the string is not found, then the
single column number l+1 results.
"expression": evaluates the expression and then treats it as the string
constant of a searchPosition
relPosition: The given positive or negative number is added to the
previous column number to give the result. As for an
absolute position, numbers which are out of range are
translated into 1 or l+1 as appropriate.
For example, given the string "hello, world, hello!" and the position
indicators 1 "ello" +4 ! 5 -3 'x' -2 1, the resulting column numbers
would be:
1 (the given number)
2 (the first character of "ello" - the second number is suppressed)
6 (+4 characters from the previous position)
20}{(the first character of "!")
21}{(the first character after "!")
5 (the given number)
2 (-3 characters from 5)
21 (the end of the string, since "x" is not found)
19 (-2 characters from 21)
1 (the given number)
The position indicators are translated into column numbers independent
of the varlist, except in one case described below. Thus the parse
template may be reduced by the above rules into a sequence of column
numbers and varlists. Taking into account the rule that each template is
implicitly prefixed and suffixed by the column number "1", each varlist
thus occurs between two column numbers. Each varlist is treated
separately, as follows:
Denote the varlist, together with the column numbers immediately before
and after the varlist, as m v1 v2 ... vk n. If m<n, or if m=n and
n resulted from a search, then there exists a well-defined substring s of
the string being parsed, which starts at column m and is of length n-m.
(this string ends at, but does not include, column n). Otherwise, let s
be that substring which starts at column m and continues to the end of
the string being parsed. Then the string s is divided between the
variables of the varlist by assigning the blank-delimited tokens to v1,
v2, ... in order. If there are more varnames in the varlist than there
are blank-delimited tokens, then the extra varnames are assigned with the
empty string. The tokens assigned to varnames v1, v2, ... , v(k-1) will
contain no leading or trailing blanks, but the token assigned to vk will
contain all blanks which occur after v(k-1), except for the one blank
immediately after v(k-1).
Each varname is either a symbol name or a dot. If the varname is a dot,
then the token which would be assigned to it is thrown away. Otherwise
the token is assigned to it in the usual way, just as if there had been
an instruction: symbol = token
NOTE: Most versions of REXX allow only a symbol name between parentheses
where this version allows an arbitrary expression.
The one case in which the presence of a varlist may affect the
translation from position indicators to column numbers is when one or
more of the symbols mentioned in an "expression" is also stated in a
varlist. Hence:
PARSE VALUE "s/this/that" WITH 2 delim +1 first (delim) second
will assign "/" to delim, "this" to first and "that" to second. This is
because the variable delim is assigned as soon as the "+1" is reached.
This provides a way to provide commands (such as locate commands) which
take any string parameter and also some options. It allows any delimiter
to separate the parameter from the options.
However,
PARSE VALUE "s / this/that" WITH . delim first (delim) second
will not have the same effect, since delim and first are not assigned
until after the expression (delim) has been searched for.
Note that the symbols are assigned in order from left to right, so
PARSE VALUE "1 2 3" WITH a x.a y.a
will assign 1 to a, then 2 to x.1, then 3 to y.1
Other Examples:
PARSE VALUE "Hello there ! etc.." WITH a b ! . "c" c
will assign "Hello" to a and "there " to b, then throw away " et" and
assign ".." to c.
PARSE VALUE "123456789" WITH a +4 b 6 c
will assign "1234" to a, "5" to b, and "6789" to c.
PARSE VALUE " multiple spaces between words" WITH a b c
will assign "multiple" to a, "spaces" to b and " between words" to c.
PARSE VALUE "a b c d e f" WITH "b" a b "e"
will assign "c" to a and " d " to b.
PARSE VALUE "hello-there" WITH a "-" b -1 c +1
This assigns "hello" to a, "-there" to b and "o" to c.
CALL name [arg][,[arg],...]]
The CALL command evaluates its arguments, if any, and passes them to the
named procedure. The name may be either a symbol or a string constant.
If it is a symbol, then it will be translated to upper case before
use.
The procedure may or may not return a result. If it does return a
result, then this is assigned to the variable RESULT, otherwise this
variable is dropped - that is, it will no longer have a value.
See the section on function or subroutine invocation for more details.
CALL ON condition [NAME symbol]
CALL OFF condition
These call instructions provide error trapping. The possible
conditions which may be trapped are as follows:
FAILURE: A command to the environment returned a "failure" code.
Usually this means a negative return code, but see the
section on commands to the environment.
ERROR: A command to the environment returned an "error" code.
This usually means a non-zero return code. Note that if
"failures" are not being trapped, then "error" will catch
failures also.
NOTREADY: A function from the REXX I/O model (see the separate section)
was unsuccessful because, for example, an input function
encountered an end-of-file condition.
HALT: The user has attempted to halt the program, for example by
typing Control-C. Signals SIGHUP and SIGTERM also raise the
HALT condition.
(These are the same conditions as for SIGNAL ON, except that the two
conditions SYNTAX and NOVALUE may not be trapped by CALL ON).
The CALL ON instruction turns on condition handling. Whenever the
specified condition occurs, a CALL is made to a handling routine. If
the NAME keyword is specified, then the following symbol is taken as
the name of the handling routine. Otherwise the handling routine has
the same name as the condition. On return from the call, execution
proceeds normally. The RESULT variable will not be affected by the
call. During the handling routine, the condition handling will be
set to "DELAY". For the FAILURE, ERROR and NOTREADY conditions, this
means that further conditions will be ignored until the handling routine
returns or until handling is explicitly turned on or off. For the HALT
condition, the program will continue executing but the halt signal will
be remembered until the handling routine returns or until handling is
explicitly turned on or off. At that time the signal will be handled
in an appropriate way.
Condition handling with the CALL ON instruction always occurs at clause
boundaries. When a condition occurs, it is delayed until the currently
executing clause has completed, and then the condition handler is
called.
At any time after the handling routine is called and before it returns,
the CONDITION() builtin function may be used to retrieve information
about the condition which was trapped. The information provided by
this function is saved across function calls. If a further condition
is handled while the handler is still active, this will not affect the
information which may be provided to the current handler.
When a condition handler is activated, the special variable SIGL is set
to the line number of the instruction in which the condition was
raised. Also, for conditions ERROR and FAILURE, the special variable
RC will hold the return code of the command which caused the condition
to be raised.
Condition handling will always remain on until turned off with either
"CALL OFF condition" or "SIGNAL OFF condition". If an external routine
is called, condition handling will be turned off temporarily until the
external routine finishes or turns condition handling on.
The status of condition handling is saved across function calls. If a
subroutine uses a "CALL ON/OFF" or "SIGNAL ON/OFF" instruction, the
condition handling within the current routine will be unaffected.
A CALL OFF instructions cancels condition handling for a particular
condition. If handling is turned off for ERROR, FAILURE or NOTREADY,
then the condition will be ignored whenever it occurs. If handling is
turned off for HALT then the program will halt when the condition
occurs.
NOTE: Because calling the handling routine affects the special variable
SIGL, this variable can no longer be trusted to remain constant
when CALL ON HALT is in effect, since this condition can occur at
any time without notice.
BUG: The routine named in a CALL ON instruction must be an internal
routine. Built-in or external routines are not allowed.
PROCEDURE
PROCEDURE EXPOSE var1 [var2 ...]
PROCEDURE HIDE var1 [var2 ...] (LOCAL)
The PROCEDURE command is used in an internal function or procedure to
hide the caller's variables.
The PROCEDURE command on its own hides all the caller's variables and
makes sure that on return all the current function's variables are
erased. On return from a function containing this instruction, the
caller's old variables are reinstated when the current function's have
been deleted.
The PROCEDURE EXPOSE varlist command is like the form with no arguments
except that all the named variables are left visible. These variables
will all remain when the RETURN statement deletes all the other variables
from the current function. If any of the named variables are not defined,
then they will remain undefined until they are assigned a value. This
value will then be carried back to the calling procedure.
It is not an error to specify a symbol more than once; this will have
the same effect as specifying it just once.
Simple symbols, stems or compound symbols may be exposed. If a stem is
named, then all possible compound symbols starting with that stem will
be exposed.
BUG: It is not possible to expose a stem and one of its compound
symbols at the same time. If a stem is named and one of its
compound symbols appears later, then the compound symbol has in
effect already been exposed and so the expected results will
occur. However, if a stem appears after one of its compound
variables, the stem will be ignored without a warning.
Any symbol(s) in the list following PROCEDURE EXPOSE may be enclosed in
parentheses. In such cases the value of the symbol is used as a list
of extra symbols to expose. For example, if the assignment:
list = "var1 var2 stem. misc.3"
occurred in the calling program, then the instruction:
procedure expose test1 (list) test2
will expose the following symbols (in this order):
test1 list var1 var2 stem. misc.3 test2
Notice that the symbol inside the parentheses is itself exposed before
its value is obtained.
LOCAL: The PROCEDURE HIDE varlist command hides only the named variables,
leaving the rest visible. On return the hidden variables are
deleted, leaving all the others. The action of PROCEDURE HIDE list
is identical to that of
PROCEDURE EXPOSE <every existing variable except those named>.
(in fact what happens is that all existing symbols are exposed and
then the named symbols are deleted from the new variable table.
This command is therefore quite inefficient and should be used
sparingly).
The PROCEDURE HIDE statement may not hide individual compound
variables. Only stems and simple symbols should be specified,
otherwise a syntax error will result.
NOTE: This means that variables which are undefined when the
PROCEDURE HIDE statement is executed will be deleted on return from
the current function. However, if new compound variables are
defined having a stem in common with some compound variables which
already exist, then the new compound variables will not be deleted
on return.
NOTE: As in standard REXX, the order in which the symbols are named can
have an effect. For example, if i=5 then
procedure expose i a.i
will expose i and the compound symbol a.5, but
procedure expose a.i i
will expose the compound symbol a.I and i. This is because the
names are processed from left to right, and in the latter case the
symbol i is not visible when the name a.i is encountered.
The PROCEDURE command will almost invariably be at the beginning of a
function or procedure. It may be used in the middle rather than at the
beginning, but this is not recommended. In fact the ANSI standard
states that PROCEDURE must be the first instruction of a subroutine, if
it is present. In any case, an error will result if it is used within
an INTERPRET, or a DO, or some other control structure.
LOCAL: If OPTIONS 'EXPOSE' (qv) is in effect then the PROCEDURE
instruction will be allowed at the start of a program which is
called as an external subroutine or function. This allows
variables from the caller (which would normally be hidden) to be
exposed. The instruction does not have to be the first in the
program but it must not be placed inside any control structure (so
it could, for example, be preceded by an OPTIONS 'EXPOSE'
instruction).
Example: an improved version of the above factorial program
parse arg x
say x"!="fact(x)
exit
fact: procedure /* now we get a different p each time */
parse arg p
if p<3 then return p
return fact(p-1) * p
NOTE: The special variable SIGL must be explicitly exposed if its current
value is needed within the procedure. It is set by the CALL
instruction or the function call before any PROCEDURE instruction
is encountered.
SIGNAL [VALUE] name | SIGNAL ON|OFF condition [NAME label]
1. SIGNAL [VALUE] name
In this form, the SIGNAL instruction is a primitive form of `goto'.
Using it to control program flow in this manner is strongly discouraged.
When this command is encountered interpretation jumps to the named label
(SIGNAL labels work just like procedure labels - but SIGNAL never invokes
another rexx program).
If the VALUE keyword is present, or if the name does not start with a
symbol or a string constant, then the name is treated as an expression
which must evaluate to the name of a label (irrespective of case).
All current DO and SELECT structures within the current procedure are
terminated by the SIGNAL instruction before the jump is taken.
When the SIGNAL instruction is executed, the variable SIGL is set to hold
the number of the line at the time of the jump. This can be used in
error analysis - as in:
if something_is_wrong then signal error
...
error: say "Something is wrong at line" sigl
or it can be used to type out long texts or help - as in:
<lots of argument checking>
if something_is_wrong then signal help /*
This is a paragraph of help. It is enclosed in comments, so
the interpreter ignores it. However the help routine will
use the sourceline function to type it out on to the screen.
*/
...
help: do i=sigl+1 while sourceline(i)~="*/"
say sourceline(i)
end
The SIGNAL VALUE construction is useful for calling procedures with
variable names. This can be done as follows:
/* procname is set to the name of a procedure */
call jumpto procname,arguments
...
jumpto: parse arg jumpname
signal value jumpname
...
When the named procedure is called, its first argument will be its name,
and the subsequent arguments will be those supplied by the caller.
The DO and SELECT structures in the calling program are protected from
the SIGNAL instruction, since the latter is encountered within procedure
`jumpto'.
2. SIGNAL ON condition [NAME symbol]
SIGNAL OFF condition
These instructions maintain exception handlers for the following
contitions:
SYNTAX: Any syntax error (for example "Bad arithmetic conversion" or
"Unexpected ',' or ')'") which occurs during interpretation.
NOVALUE: A variable name is used which has no value.
NOTE: This condition is not raised during interpretation of
sub-names in compound variables. Hence, if `foo' has no
value, then "a=foo+1" will cause a novalue error but
"a=abc.foo" will not cause an error unless ABC.'FOO' has
no value. Also, the builtin function VALUE() will never
raise the NOVALUE condition.
HALT: The user has attempted to halt the program, for example by
typing Control-C. Signals SIGHUP and SIGTERM also raise the
HALT condition.
FAILURE: A command to the environment returned a "failure" code.
Usually this means a negative return code, but see the
section on commands to the environment.
ERROR: A command to the environment returned an "error" code.
This usually means a non-zero return code. Note that if
"failures" are not being trapped, then "error" will catch
failures also.
NOTREADY: A function from the REXX I/O model (see the separate section)
was unsuccessful because, for example, an input function
encountered an end-of-file condition.
(These are the same conditions as for CALL ON, with the two extra
conditions SYNTAX and NOVALUE).
The SIGNAL ON instruction turns on condition handling. Whenever the
specified condition occurs, a SIGNAL is made to a handler. If the NAME
keyword is specified, then the following symbol is taken as the name of
the handler. Otherwise the handler has the same name as the condition.
At this point, RC holds the number of the error which caused the jump
(except in the case of NOTREADY) and SIGL holds the line number in
which the error occurred. The routine in which the SIGNAL ON
instruction was encountered becomes the current routine; all internal
routines which became active since then are terminated. All
DO/SELECT/IF control structures within the current routine are also
terminated. The SIGNAL ON instruction is then cancelled, and another
SIGNAL ON instruction will be necessary to reinstate handling of this
particular condition.
At any time after control is passed to the handler, and before the
handler causes a return from the current subroutine, the CONDITION()
builtin function may be used to retrieve information about the
condition which was trapped.
A SIGNAL OFF instructions cancels condition handling for a particular
condition. If handling is turned off for ERROR, FAILURE, NOTREADY or
NOVALUE, then the condition will be ignored whenever it occurs. If
handling is turned off for HALT or SYNTAX, then the program will halt
when the condition occurs.
Condition handling persists from the point of the SIGNAL ON instruction
until the current function returns, or until a SIGNAL OFF instruction
is executed. If an external routine is called, condition handling will
be turned off temporarily until the external routine finishes or turns
condition handling on.
The status of condition handling is saved across function calls. If a
subroutine uses a "SIGNAL ON/OFF" or "CALL ON/OFF" instruction, the
condition handling within the current routine will be unaffected.
NOTE: The SIGNAL ON SYNTAX command does not trap fatal system errors or
the error which is caused when EXIT or RETURN returns a non-integer
to the UNIX environment (this is because the latter is, in effect,
raised by the environment rather than by the interpreter itself).
TRACE [symbol]
TRACE "string"
TRACE VALUE expression
The symbol, string constant or expression is evaluated (the VALUE keyword
may be omitted if the expression does not start with a symbol or a string
constant). It must evaluate to a word consisting of zero or more
question marks, followed by an optional letter, followed by an optional
string of characters. Each question mark at the start of the string
toggles the `interactive tracing' mode (see below), and the following
letter, if any, is translated to upper case and must be one of the
following:
A (All): all clauses are traced before execution
C (Commands): all commands to the environment are traced before
execution, together with the actual string passed to
the environment. If the command results in a non-zero
return code, then the return code is traced after
execution.
E (Error): Any command to the environment resulting in an error
(i.e. non-zero return code) is traced after execution,
together with the return code
F (Failure): Any command to the environment resulting in failure
(i.e. negative return code) is traced after execution,
together with the return code
I (Intermediates): All clauses are traced before execution, and all
calculations are traced, including intermediate values
evaluated during the calculation. Assignments made by
PARSE instructions are also traced.
L (Labels): All labels passed during execution are traced
N (Normal): the default setting - same as F.
O (Off): Nothing is traced, and interactive tracing is also
switched off.
R (Results): All clauses are traced before execution, and the results
from all calculations are traced. Assignments made by
PARSE instructions are also traced.
If no setting is specified or if the setting is an empty string, then
interactive tracing is turned off and tracing is set to "N".
When clauses are being traced (i.e. A, R or I), when an INTERPRET command
is traced, the actual string being interpreted is also traced. When an
END command is traced, the source statement to which the END corresponds
is also traced.
A program may be made to trace itself during execution by signalling
it with SIGQUIT (on the Suns this can be done by pressing "control \").
When this signal is received, the tracing mode switches to "?i". If
a SIGQUIT is received whilst in interactive tracing mode and if an
interruption has already been received but not handled, the program
exits immediately (as is the case when SIGQUIT is not handled). This
feature exists mainly to stop the interpreter in case of a bug.
A program may be made to trace itself when execution starts by using the
"-t" commandline flag (see the invocation section for details).
Interactive tracing
In interactive trace mode, all TRACE instructions passed in the program
are ignored and the interpreter will pause after tracing each clause,
label, command or return code (as appropriate for the trace setting).
The interpreter prompts for input with the string ">trace>".
If an empty line is entered (without spaces), execution of the
program continues normally until the next event which is traced.
If a line of REXX is entered, then that line is interpreted with
tracing set to "E". If the line calls a program, then TRACE
instructions in that program are ignored. If the line itself uses the
TRACE instruction, then the trace setting is altered accordingly and
execution of the program will continue after the input line has been
interpreted.
If the input line does not contain a TRACE instruction, then when it
has been interpreted the prompt will reappear for more input.
If an error occurs during interpretation of the input line, a message
is displayed and the prompt reappears (unless the command executed a
TRACE instruction). The error does not cause the program to exit, and
no signalling takes place (unless the error occurred in a program which
was called by the input line and which contains its own SIGNAL ON xxx
command).
Commands to the environment within the string will not set the
variable RC, but will have non-zero return codes traced.
All condition traps are turned off during interpretation of the
string.
It is possible to make the interpreter change tracing and also prompt
for more input by using the built-in TRACE function rather than the
TRACE instruction, for example:
call trace r
sets the `results' tracing mode (whilst keeping interactive mode) without
continuing execution of the program.
The interactive tracing mode is useful for the following purposes (and
others):
- single-stepping through a program (use trace ?a)
- setting breakpoints (use trace ?l and put a label at the breakpoint)
- examining or changing variables during execution.
The input line is interpreted in exactly the same way as with the
INTERPRET command, and so the same restrictions apply (e.g. DO and END
instructions etc must be matched properly).
BUG:The following also applies, however:
- some of the source information is lost, so any PARSE SOURCE
instruction in the line will have the calling method and the calling
name replaced by "TRACE" (this does not apply to PARSE SOURCE
instructions within programs that may be called by the input line).
If the input line transfers control by a SIGNAL instruction, then control
is immediately transferred to the target instruction and it is executed
before tracing resumes. If the input line contains a RETURN or EXIT
instruction, then execution returns to the caller and continues to the
end of the current statement. The return may cause a change in the
tracing mode, since this is saved across function calls. However, if
interactive tracing is still in effect, then tracing will resume at the
next instruction.
NOTE:If the interpreter has a controlling terminal (that is, "/dev/tty"
can be opened when the interpreter initialises), then the trace
prompt will be written to the terminal, and input will be read from
the terminal. Otherwise, stderr and stdin are used respectively.
If an error occurs during a command which was typed in interactive
trace mode, then the error message will be written to the terminal.
However, all normal input and output use stdin and stdout, while
trace output is written to the requested file (see OPTIONS). In
particular, if tracing has been redirected, then no trace output
will appear on the terminal. Therefore it is not a good idea to
redirect tracing when interactive tracing will be used.
BUG: Interactive tracing is not recursive, i.e. if, during interactive
tracing, a line is entered such as:
trace i;say a+b
then the tracing of "say a+b" (and other statements following the
TRACE instruction) will not be interactive, even though the
interactive tracing mode is (in theory) still in operation.
TRACE output
Each line of trace output is preceded by three characters which identify
the type of trace output. Any clause or command traced will be indented
according to its logical depth of nesting. Results (or intermediate
values) will be indented a further two spaces, and have leading and
trailing quotes added. The line numbers of source statements and labels
are displayed before the three-character prefix. An interpreted
instruction or a command about to be executed will be displayed without
a line number.
The three-character prefixes are:
+++ A trace message (an error message, or the return code from a command)
*-* A source statement or label (exactly as it appears in the source).
*,* A source statement which is continued from the previous line.
*~* The result of evaluating an expression which is either a command to
be passed to the environment or the parameter of an INTERPRET
instruction.
>>> The result of an expression displayed in "trace r", or the value
assigned to a variable during parsing or during update of the
control variable of a repetitive DO loop.
>.> The value `assigned' to a placeholder (dot) during parsing.
The following prefixes are used during TRACE I:
>V> The contents of a variable
>L> a literal (that is, a constant symbol or number, an uninitialised
variable, or a string/hex/binary constant)
>F> The result of applying a function
>P> The result of applying a prefix operator
>O> The result of applying a (binary) operator
>C> The name of a compound variable (after substitution and before use).
The trace setting is saved across function calls, so that if tracing is
switched on or off during a function, the previous setting is restored
when the function returns. This means that:
- if a function is known to work, then "trace off" may be placed at
the start. When a program is being traced, tracing is switched off
when the function is entered, and back on when the function returns.
- if a function is known not to work, then a trace instruction placed
at the start of the function will switch tracing on only for the
duration of the function call.
OPTIONS expression
The expression is evaluated and broken into blank-delimited words.
Each word is examined to see if it is recognised as a valid interpreter
option for this implementation. Any word which is not recognised is
skipped over, since it probably applies to some other implementation.
In REXX/imc, the case of the options is not significant, and options
may be abbreviated. The minimum abbreviation for each option is shown
in uppercase. Options which require an '=' are only recognised if the
'=' sign is present and followed by a valid string.
REXX/imc currently recognises the following options (options starting
"no" are listed under their opposites):
EXPose This option makes the PROCEDURE EXPOSE instruction
NOEXPose legal at the beginning of a program which is called
as an external subroutine or function, so that it
can gain access to the variables of the caller. The
NOEXPose option restores the standard behaviour in
which PROCEDURE will cause an error when written at
the beginning of a program. See also the PROCEDURE
instruction.
SETRC This option causes the I/O operations linein,
NOSETRC charin, lineout, charout, parse pull and parse
linein to set the RC special variable as they did in
earlier versions of REXX/imc. If the NOTREADY
condition is not being trapped then an I/O operation
which sets RC to a nonzero value will instead
cause an ERROR condition to be raised, if that
is being trapped. Option NOSETRC restores the
behaviour of I/O operations to the documented
behaviour.
SIGPipe Usually the interpreter terminates silently when it
NOSIGPipe receives a SIGPIPE signal. This occurs when a
program tries to write data down a pipe with no
process to read it: for example, the command
rexx -s "do forever; say hello; end" | head -1
will echo one line of output before the "head"
process terminates, and the Rexx program will then
receive a SIGPIPE and terminate.
Using the SIGPipe option will make the interpreter
trap this signal and continue running. In this
case the program should take care to detect error
conditions from LINEOUT, CHAROUT and other I/O
functions to avoid wasting resources.
Using the NOSIGPipe option will restore the
behaviour of terminating when a SIGPIPE signal is
received.
TRACEfile=filespec If "filespec" represents a filename which can be
opened for writing, then an information message is
written to the standard output and all trace output
is redirected to the named file. Otherwise an error
message is written to the standard error and tracing
remains unchanged. Instead of a regular file the
filespec can be "stdout" to send trace output to
the standard output or "stderr" to send it to the
standard error.
ADDRESS [VALUE] [environment] | ADDRESS environment command
When the REXX interpreter finds a program statement which is not an
instruction (as listed above), then it evaluates the whole statement as
an expression (if it can), and issues the resulting string to the
current environment as a command.
The first form of the ADDRESS instruction stated above changes the
environment (until the next ADDRESS instruction). If the environment
name is given, it may be a symbol (which is translated to upper case,
but not substituted by its value) or a string constant, or a string
expression preceded by the keyword VALUE. The VALUE may be omitted if
the expression does not start with a symbol or a string constant. The
current environment is changed to the given string.
If no environment name follows the ADDRESS instruction, then the previous
environment is made current. For example:
address unix /* "UNIX" is current */
address "MY_ENV" /* "MY_ENV" is current */
address /* "UNIX" is current */
address /* "MY_ENV" is current */
The second form of the ADDRESS instruction given above executes a command
in a given environment without changing the current environment. The
environment name must be a symbol or string constant, and the command may
be any string expression. So, if the following line is appended to the
previous example:
address command "ls -al"
the command "ls -al" is executed in environment "COMMAND", while the
current environment is still "MY_ENV".
Whenever a command is executed, the special variable RC is set to the
return code given by the command. If this return code is non-zero,
then the command will also cause a FAILURE or ERROR condition to be
raised. These conditions are ignored unless trapped by CALL ON or
SIGNAL ON.
Two environments are built in to REXX/imc:
ADDRESS UNIX
Each command sent to the "UNIX" environment is executed in a separate
Bourne shell. Note that this involves considerable overhead, and
moreover no command can make a permanent change to the environment (e.g.
"set" and "export" will have no effect). However, it does allow the
flexible syntax of the Bourne shell to be used, including piping, I/O
redirection, and filename expansion.
In this environment, any command which returns a code of 1 will raise
the FAILURE condition, as well as any command which returns a negative
return code. This is because the Bourne shell always returns 1 when
it fails to find the requested command.
ADDRESS COMMAND
Each command sent to the "COMMAND" environment is tokenised and executed
by a primitive shell which is built into the interpreter (in shell.c).
This makes for quicker execution of each command, but note that at
present the only "meta-characters" which are supported are quotes. That
is, enclosing a string in quotes passes it verbatim (i.e. untokenised)
as a parameter to a command. In particular, piping, file redirection
and filename expansion are not supported. Nor does this shell have any
builtin commands (such as cd, set), with the exception of "hash" (see
later). For speed of execution, each time a command is executed its
path is remembered in a hash table. The hash table statistics may be
obtained with the "hash" builtin command, which is similar to that of
the Bourne shell (and bash). The command "hash name1 [name2 ...]" will
search for each of the given names and add the results to the hash
table, but if any of the names is "-r" then the hash table will be
cleared. The names are examined from left to right, so "hash cat -r
ls" will result in just "/bin/ls" in the hash table. The hash table is
also cleared whenever putenv() or value(,,"ENVIRONMENT") is used to
change PATH. The command "hash" will print out the list of hash table
entries. "hits" represents the number of times a command has been
looked up in the table, and "cost" represents the amount of work which
was initially carried out in searching along the path for the command.
A plus-sign in column 1 indicates that the entry was placed in the same
hash bucket as the previous entry; the commands within hash buckets are
arranged in alphabetical order. The hash buckets are listed in no
particular order.
In this environment, an unrecognised command produces return code -3.
Any command which produces a negative return code will raise the
FAILURE condition.
Other environments may be added by application programs.
If a command is sent to an unrecognised environment, then return code
-3 and a FAILURE condition results.
The environment when a program starts up is usually UNIX. The current
environment may be found by calling address(), and the environment at
startup may be found using "parse source".
Here is a simple shell program to demonstrate the use of commands:
do i
sayn i'>'
parse pull command
parse upper var command word .
if word='EXIT' then exit
command
if rc!=0 then say "The return code was" rc
end i
Each command is read from standard input. If the command 'Exit' is
received, the shell quits. Otherwise, the command is issued to a Bourne
Shell and the return code is checked.
Both the ADDRESS settings (that is, the current environment and the most
recent one) are saved across function calls.
NOTE: The program rxstack (in Oxford /mclab/imc/sun4/rxstack) may be
used to access the stack while executing a shell command. See
the stack section below for details.