Early checks
The Rexx Parser is able to detect at parse time
certain errors that other processors are only able to detect at
execution time. Since the detection is done at parse time, the parser is
able to reach dead code, like branches that cannot be taken, or code
after a EXIT
or RETURN
instructions, and also
procedures and ::ROUTINES
that will never be called.
We have attempted to mimick the behaviour of the ooRexx interpreter, even when this behaviour is obviously erroneous; please refer to the Bugs section for details.
If .False Then Say Length(a,b) -- Dead branch, too many arguments
Exit
-- Unreachable code
Guard On -- GUARD is only valid inside a method
::Method NeverCalled -- Method never calles
Signal NonExistent -- This label does not exist
Early checking is controlled by the earlycheck
entry of
the options passed to the Rexx.Parser class. The value
associated with earlycheck
has to be an array of uppercase
strings chosen between "BIFS"
, "GUARD"
and
"SIGNAL"
. The effect of specifiying these options is
described below.
BIFS
When the earlychecks
array has an item equal to
"BIFS"
, built-in function calls, procedural calls to
built-in functions, and CALL ON
instructions whose trapname
is a built-in function are checked against the built-in function
definition. Namely,
If the number of arguments passed to the function is greater
than the maximum arguments allowed, a SYNTAX
error is
raised. In most cases, the error raised is 40.4,
"Too many arguments in invocation of &1; maximum expected is &2"
,
but in some few cases 88.922 is raised instead
("Too many arguments in invocation; &1 expected"
: this
is due to an anomaly in the ooRexx interpreter, by
which BEEP, DIRECTORY and FILESPEC are handled as external functions,
even when they are defined to be BIFs; their error handling is also
different from the other BIFs).
Say ChangeStr(a,b,c,d,e) -- Too many arguments in invocation of CHANGESTR; maximum expected is 3
If the number of arguments passed to the function is smaller
than the minimum number of required arguments, a SYNTAX
error is raised. In most cases, the error raised is 40.3,
"Not enough arguments in invocation of &1; minimum expected is &2"
,
although for some few BIFs, 88.901 is raised instead
("Missing argument; argument &1 is required"
).
Say Left("String") -- Not enough arguments in invocation of LEFT; minumum expected is 2
If there are enough arguments but some of the required arguments are
missing, a SYNTAX
error is raised. In most cases, the error
raised is 40.5,
"Missing argument in invocation of &1; argument &2 is required"
,
although for some few BIFs, 88.901 is raised instead.
x = ChangsStr(,'b','c') -- Missing argument in invocation of CHANGESTR; argument 1 is required
When the BIF has a one-letter argument (that is, an argument of which
only the first letter is examined) and the corresponding parmeter is a
string literal, this string literal is checked. BIFs checked this way
are ARG
, CONDITION
, DATATYPE
,
DATE
, FILESPEC
, LINES
,
RXQUEUE
, STREAM
, STRIP
,
TIME
, TRACE
and VERIFY
. The
message for the TRACE
BIF is special. Some of the other
BIFs raise a 40.904 SYNTAX
error,
&1 argument &2 must be one of &3; found "&4"
,
while still others raise a 93.915,
Method option must be one of "&1"; found "&2"
,
which is a bug. DATE
and
TIME
do not check that literal dates and times are in the
required format.
Var = "*"
Call Trace Var -- "Var" is a variable; not checked
Call Trace "*" -- TRACE request letter must be one of "ACEFILNOR"; found "*"
When the BIF expects a whole number, literal strings, numbers, and
prefix expressions consisting of any number of "-" and "+" signs
followed by a number are checked. Checking is done using the
DATATYPE(x,"Internal")
BIF.
Say WordPos(a,string,0) -- Invalid position argument specified; found "0".
When the BIF expects a number (i.e., it may be whole or not), literal
strings, numbers, and prefix expressions consisting of any number of "-"
and "+" signs followed by a number are checked. Checking is done using
the DATATYPE(x,"Number")
BIF. This applies to the following
BIFs: ABS
, FORMAT
, MAX
,
MIN
, SIGN
, TRUNC
.
Call Abs -+- "- 12" -- result = 12
In the case of XRANGE
, literal arguments are checked to
ensure that they are either a single character in length, or one of the
allowed POSIX classes.
Call XRange "42" -- XRANGE argument 1 must be a character class name or a single character; found "42"
In the case of D2C
and D2X
, the first
argument, which is a whole number, may not have more digits than "the
current setting of NUMERIC DIGITS", which is an execution-time value. In
this case, the parser only checks that the supplied constant value is a
number (DATATYPE(x,"Number")
) containing no blanks, no
dots, and no "E" exponential mark, and, if the second argument is
omitted, that the supplied constant is not negative.
Call D2C -1 -- Length must be specified to convert a negative value
Pad characters are checked that they have exactly one character in
length, and separators to see that they are the null string or a single
character. Some combinations of separators are not valid in the
TIME
BIF, depending on the options chosen; this is not
checked.
Call Left 'a',12,'ww' -- LEFT argument 3 must be a single character; found "ww".
Call Date ,'20/04/25', 'E', '**' -- DATE argument 4 must be a single non-alphanumeric
-- character or the null string; found "**"
STREAM
and RXQUEUE
are not early-checked at
this time.
GUARD
GUARD
instructions are only allowed in the body of a
method. The ooRexx interpreter raises a SYNTAX condition (code 99.911:
"GUARD can only be issued in an object method invocation"
)
when it attempts to execute a GUARD
instruction in
a code body which is not a method body. When the
earlychecks
array contains an item whose value is
"GUARD"
, the Rexx Parser will exit with a 99.911 error code
whenever a GUARD
instruction is found in a non-method code
body.
::Routine R
Say "Exiting..."
Exit
Guard On -- GUARD can only be issued in an object method invocation
Signal
When a SIGNAL
instruction targets a labelname
which is not dynamically evaluated (i.e., when the label is a string or
a symbol taken as a constant), it is easy to check whether a branchable
label exists with the corresponding name. If the such a label does not
exist, a 16.1 SYNTAX
error is raised
('Label "&1" not found.'
).
Signal NoNo -- Label "NONO" not found
Bugs
In the process of writing the code for the early check Parser feature, we have uncovered a number of ooRexx bugs. We are listing them here for reference.
- https://sourceforge.net/p/oorexx/bugs/2006/.
- https://sourceforge.net/p/oorexx/bugs/2007/.
- https://sourceforge.net/p/oorexx/bugs/2008/.
- https://sourceforge.net/p/oorexx/bugs/2009/.
- https://sourceforge.net/p/oorexx/bugs/2010/.
- https://sourceforge.net/p/oorexx/bugs/2011/.
- https://sourceforge.net/p/oorexx/bugs/2012/.
- https://sourceforge.net/p/oorexx/bugs/2014/.
- https://sourceforge.net/p/oorexx/bugs/2015/.
- https://sourceforge.net/p/oorexx/bugs/2016/.