Whenever a SYNTAX condition is raised, an error number, and possibly a sub-error number as well, is associated with that instance of the condition being raised. Each one of the numerous reasons for SYNTAX being raised will produce a different combination of error/sub-error numbers. So, by checking the error/sub-error numbers, you can deduce exactly what went wrong in your script (ie, why the SYNTAX condition was raised).
As mentioned previously, the default handling for the SYNTAX condition is to display some information to the command prompt window, and then end the script right there. The information displayed includes the line number and the actual line in the script where the condition was raised, the error number and sub-error numbers, the name of the script, and finally a descriptive message that tells why the condition was raised.
The error/sub-error numbers are displayed after the word "ERROR". They are separated by a dot. For example, 40.28 will be displayed for a SYNTAX condition raised because you passed an unrecognized 'option' to TIME(). 40 is the error number, and 28 is the sub-error number.
For example, consider that you have the following REXX script named "myscript.rex" which passes TIME() some option that isn't one of the recognized ones:
newtime = TIME('b') EXITBecause we aren't trapping SYNTAX condition, REXX uses its default handling. So, the script will be aborted at the first line, with the following text displayed to the command prompt window:
1 +++ newtime = TIME('b') ERROR 40.28 in "myscript.rex" at line 1 TIME argument 1, option must start with one of "CEHJLMNORS"; found "B"But if you trap the SYNTAX condition, then such default handling doesn't happen (usually. The exception is with "fatal" SYNTAX errors discussed below). Instead, REXX calls your own SYNTAX handler. Your handler can use the CONDITION() built-in function's 'E' option to fetch the error and sub-error numbers associated with a given instance of that condition. CONDITION('E') will return the two numbers separated by a dot. For example, 40.28 will be returned for the above SYNTAX condition.
The error number can be thought of as a "general category number". And the sub-error number is a specific error within that category.
The ANSI REXX specification defines about 50 categories of errors. For example, all errors that have to do with bad arguments passed to some Function have an error (ie, category) number of 40. All errors that have to do with using a non-numeric value in a math expression have an error (category) number of 41. There are categories having to do with mistakes in your PARSE templates (ie, search strings and offsets), mistakes in specifying the expressions used in conditional instructions, mistakes in the names you choose for variables, etc. All of these raise the SYNTAX condition.
Each category may have one or more sub-errors associated with it. For example, the category of 40 has many sub-errors associated with it, since there are many different mistakes you can make in specifying arguments to functions. We saw above that passing an unrecognized 'option' to TIME() results in a category of 40 and a sub-error of 28. If you pass a 'position' to the CHARIN() built-in function that isn't actually a numeric value, then this also results in a SYNTAX condition with a error (category) number of 40, but a sub-error of 14.
Sometimes, REXX will not have enough information about the cause of the SYNTAX condition being raised in order to provide a sub-error number. In this case, only the category number is reported. Such a case may happen when you're calling a Function in a DLL/EXE, and it doesn't provide enough information about what went wrong. In this case, the Function may simply report a category number of 40 to indicate that something is wrong with your call to the Function. But without a sub-error, you are given no more information than that.
You can use the "PARSE SOURCE" and "SAY" REXX instructions, the SIGL variable, and the CONDITION() built-in function to duplicate the default handling for SYNTAX (or HALT) condition, as so:
/* Handler for SYNTAX that duplicates the default handling */ SYNTAX: linenum = SIGL PARSE SOURCE . . scriptname SAY " " SIGL "+++" SOURCELINE(linenum) SAY 'ERROR' CONDITION('E') 'in "'||scriptname||'" at line' linenum SAY CONDITION('D') RETURNBut Reginald's CONDITION() function offers an extra, more useful option. CONDITION('M') will open a message box with all of the above information plus a "Help" button to bring up an online help page for the error. This is analogous to what Reginald's MSGBOX option does for untrapped SYNTAX and HALT conditions. So, to display an error message to the user, you need do no more than:
/* Handler for SYNTAX that duplicates Reginald's MSGBOX OPTION */ SYNTAX: CALL CONDITION('M') RETURNThe following chart lists the ANSI error and sub-error numbers associated with the SYNTAX condition, and what is the meaning of each combination of error/sub-error number.
2 | Category: An error during script cleanup |
2.1 | An error during script cleanup |
3 | Category: An error during script initialization |
3.1 | An error during script initialization |
5 | Category: Memory allocation error |
5.1 | Memory allocation error |
6 | Category: There's an unmatched /* in a comment, or unmatched quote in a literal string |
6.1 | There's an unmatched /* in a comment |
6.2 | There's an unmatched single quote in a literal string |
6.3 | There's an unmatched double quote in a literal string |
7 | Category: There's an problem in a SELECT group |
7.1 | Missing the first WHEN in a SELECT group |
7.2 | There is some other keyword where a WHEN, OTHERWISE, or END is expected |
7.3 | None of the WHEN statements are true, and you failed to supply an OTHERWISE |
8 | Category: There's a THEN or ELSE keyword in an unexpected place |
8.1 | There's a THEN keyword without an IF or WHEN before it |
8.2 | There's an ELSE keyword without an IF/THEN before it |
9 | Category: There's a WHEN or OTHERWISE keyword in an unexpected place |
9.1 | There's a WHEN keyword without a SELECT before it |
9.2 | There's an OTHERWISE keyword without a SELECT before it |
10 | Category: There's an END keyword in an unexpected place, or a missing END where one is expected |
10.1 | There's an END keyword without a DO or SELECT before it |
10.2 | There's a variable name after END which doesn't match any variable being used with a DO instruction |
10.3 | There's a variable name after END which goes with a DO instruction that uses no variable |
10.4 | An END, belonging to a SELECT group, has some variable name after it |
10.5 | There's an END keyword immediately following a THEN keyword, without at least a NOP inbetween |
10.6 | There's an END keyword immediately following an ELSE keyword, without at least a NOP inbetween |
11 | Category: There's a problem with the file system. There may be a sub-error number too. If so, this is an operating system specific number which may give a more informative message when passed to UNIXERROR(). |
13 | Category: There's an invalid character in your REXX script |
13.1 | There's an invalid character in your REXX script |
14 | Category: There's an incomplete DO, SELECT, or IF/THEN instruction |
14.1 | There's a DO keyword without a matching END keyword after it |
14.2 | There's a SELECT keyword without a matching END keyword after it |
14.3 | There's a THEN keyword without another REXX instruction (or NOP) after it |
14.4 | There's an ELSE keyword without another REXX instruction (or NOP) after it |
15 | Category: There's a mistake with a string in hexadecimal or binary |
15.1 | There's a space in a hexadecimal string where no space is allowed |
15.2 | There's a space in a binary string where no space is allowed |
15.3 | You specified something other than the allowable characters of a to f, A to F, 0 to 9, or a space in a hexadecimal string |
15.4 | You specified something other than the allowable characters of 0, 1, or a space in a binary string |
16 | Category: You referenced a label that is not found within your script |
16.1 | You tried to SIGNAL to a label name that can't be found |
16.3 | You tried to SIGNAL to a label inside of a DO loop, SELECT group, or IF/THEN instruction. (Some interpreters do not allow this) |
16.3 | You tried to call a label that isn't a subroutine/function, but instead, is some label in a DO loop, SELECT group, or IF/THEN instruction. (Some interpreters do not allow this) |
17 | Category: There's an PROCEDURE keyword in an unexpected place |
17.1 | A PROCEDURE instruction wasn't the first instruction in a subroutine/function |
18 | Category: There's a missing THEN keyword |
18.1 | There is an IF keyword with no subsequent THEN |
18.2 | There is a WHEN keyword (in a SELECT group) with no subsequent THEN |
19 | Category: There's a missing string or variable name |
19.1 | There is no environment name after an ADDRESS keyword |
19.2 | There is no subroutine name after a CALL keyword |
19.3 | There is no label name after a NAME keyword |
19.4 | There is no label name after a SIGNAL keyword (to jump somewhere) |
19.5 | There is no string or variable name after a TRACE keyword |
19.6 | There is no variable name after a PARSE keyword |
20 | Category: There's a missing label name where one is expected |
20.1 | Found an illegal label name |
20.2 | Found something that wasn't a label name |
21 | Category: An instruction ended unexpectedly (ie, missing the remainder of the instruction) |
21.1 | An instruction ended unexpectedly |
22 | Category: An invalid literal string |
22.1 | An invalid literal string |
23 | Category: An invalid data string |
23.1 | An invalid data string |
24 | Category: An invalid trace setting |
24.1 | An invalid trace setting |
25 | Category: An invalid keyword found |
25.1 | An unrecognized keyword followed CALL ON |
25.2 | An unrecognized keyword followed CALL OFF |
25.3 | An unrecognized keyword followed SIGNAL ON |
25.4 | An unrecognized keyword followed SIGNAL OFF |
25.5 | An unrecognized keyword followed ADDRESS WITH |
25.6 | An unrecognized keyword followed INPUT |
25.7 | An unrecognized keyword followed OUTPUT |
25.8 | An unrecognized keyword followed APPEND |
25.9 | An unrecognized keyword followed REPLACE |
25.11 | An unrecognized keyword followed NUMERIC FORM |
25.12 | An unrecognized keyword followed PARSE |
25.13 | An unrecognized keyword followed UPPER |
25.14 | An unrecognized keyword followed ERROR |
25.15 | An unrecognized keyword followed NUMERIC |
25.16 | An unrecognized keyword followed FOREVER |
25.17 | An unrecognized keyword followed PROCEDURE |
26 | Category: An invalid whole number |
26.1 | The whole number is larger than the current NUMERIC DIGITS setting |
26.2 | The repetition count after DO is not a whole number |
26.3 | The value after FOR (in a DO instruction) is not a whole number |
26.4 | A position in a PARSE template is not a whole number |
26.5 | NUMERIC DIGITS setting is not a whole number |
26.6 | NUMERIC FUZZ setting is not a whole number |
26.7 | Number of instructions to skip in interactive trace is not a whole number |
26.8 | Tried to raise to a power that wasn't a whole number |
26.11 | Remainder of division exceeds NUMERIC DIGITS |
25.12 | Division result exceeds NUMERIC DIGITS |
27 | Category: An invalid DO instruction |
27.1 | An invalid keyword was used in a DO instruction |
28 | Category: An unexpected LEAVE or ITERATE |
28.1 | There is a LEAVE keyword outside of a loop |
28.2 | There is an ITERATE keyword outside of a loop |
28.3 | The variable name after a LEAVE keyword is not used with any DO instruction |
28.4 | The variable name after an ITERATE keyword is not used with any DO instruction |
29 | Category: An environment name is too long |
29.1 | An environment name is too long |
30 | Category: A variable name or literal string is too long |
30.1 | A variable name is too long |
30.2 | A literal string is too long |
31 | Category: A variable name starts with a '.' or number |
31.1 | A variable name consists of a number |
31.2 | A variable name starts with a number |
31.3 | A variable name starts with a '.' |
33 | Category: Invalid expression |
33.1 | NUMERIC DIGITS setting is greater than NUMERIC FUZZ setting |
33.2 | NUMERIC DIGITS setting is larger than maximum |
33.3 | NUMERIC FORM is not followed by either an 'E' or 'S' |
34 | Category: A conditional expression doesn't evaluate to 0 or 1 |
34.1 | The expression after IF doesn't evaluate to 0 or 1 |
34.2 | The expression after WHEN doesn't evaluate to 0 or 1 |
34.3 | The expression after WHILE doesn't evaluate to 0 or 1 |
34.4 | The expression after UNTIL doesn't evaluate to 0 or 1 |
34.5 | The expression before a boolean operator isn't a 0 or 1 |
34.6 | The expression after a boolean operator isn't a 0 or 1 |
35 | Category: Invalid expression is encountered |
35.1 | Invalid expression is encountered |
36 | Category: A closing parenthesis '(' is missing |
37 | Category: Unexpected closing parenthesis '(' or comma |
37.1 | Unexpected comma |
37.2 | Unexpected closing parenthesis '(' |
38 | Category: Invalid PARSE template |
38.1 | Invalid parse search string |
38.2 | Invalid parse position |
38.3 | Missing WITH keyword after PARSE VALUE |
40 | Category: Incorrect call to a subroutine/function |
40.1 | Generic error |
40.3 | You passed too few arguments |
40.4 | You passed too many arguments |
40.5 | A required arg is missing |
40.9 | A numeric arg exceeds the NUMERIC DIGITS setting |
40.11 | An arg is supposed to be numeric, but isn't |
40.12 | An arg is supposed to be a whole number, but isn't |
40.13 | An arg is supposed to be 0 or positive, but isn't |
40.14 | An arg is supposed to be positive, but isn't |
40.15 | A numeric arg is has more digits than it is supposed to have |
40.16 | A numeric whole number arg is has more digits than it is supposed to have |
40.17 | A numeric arg is not within a required range |
40.18 | A numeric arg representing a year is not within a required range |
40.19 | An arg is not in the expected format |
40.21 | A required arg has been omitted |
40.23 | An arg is supposed to consist of a single character, but has more |
40.24 | An arg is supposed to be expressed in binary, but isn't |
40.25 | An arg is supposed to be expressed in hexadecimal, but isn't |
40.26 | An arg is not a valid variable name |
40.27 | An arg is not a valid stream name |
40.28 | An unrecognized option |
40.29 | Conversion is not supported to the requested format |
40.31 | An arg to RANDOM() exceeds the maximum value |
40.32 | The args to RANDOM() exceed the maximum range |
40.33 | A numeric arg that is not supposed to be larger than another arg, is |
40.34 | The linenumber passed to SOURCELINE exceeds the number of lines in the script |
40.35 | An arg is supposed to be converted to a whole number, cannot be converted |
40.36 | An arg is supposed to be the name of an existing variable, but isn't |
40.37 | An arg is supposed to be the name of an environment, but isn't |
40.38 | An arg is not large enough to format |
40.39 | An arg whose value is that supposed to be either 0 or 1, isn't |
40.41 | An arg that represents a position in a stream, is beyond the end of the stream |
40.42 | Attempted to set the position on a TRANSIENT stream |
41 | Category: Bad math expression |
41.1 | A non-numeric value is to the left of a math operator |
41.2 | A non-numeric value is to the right of a math operator |
41.3 | A non-numeric value is used with a prefix operator such as '\' |
41.4 | The value of the expression of a TO keyword (in a DO instruction) is not numeric |
41.5 | The value of the expression of a BY keyword (in a DO instruction) is not numeric |
41.6 | The expression that represents the loop count in a DO instruction is not numeric |
41.7 | A numeric value in exponential format has too big an exponent |
42 | Category: Overflow/underflow in math result |
42.1 | Overflow in math result |
42.2 | Underflow in math result |
42.3 | Tried to divide by 0 |
43 | Category: A script you tried to run cannot be found |
43.1 | A script you tried to run cannot be found |
44 | Category: A function didn't return any value when it was supposed to |
44.1 | A function didn't return any value when it was supposed to |
45 | Category: A REXX script didn't return any value when it was supposed to |
45.1 | A REXX script didn't return any value when it was supposed to |
46 | Category: Invalid variable reference |
46.1 | There's a missing closing parenthesis in a variable name |
47 | Category: Label found in an unexpected place |
47.1 | There's a label found in an INTERPRET string |
47.2 | There's a duplicate label. Reginald-only, when the 'LABELCHECK' OPTION is on |
48 | Category: The operating system reported some problem |
48.1 | The operating system reported some problem |
49 | Category: REXX reported some internal problem |
49.1 | REXX reported some internal problem. Most likely a bug |
50 | Category: Encountered an unrecognized reserved keyword |
50.1 | Encountered an unrecognized reserved keyword |
51 | Category: Invalid function name |
51.1 | An unquoted function name erroneously ends with a dot |
52 | Category: A function/subroutine tried to return a value that has too many characters |
53 | Category: Invalid option |
53.1 | A variable name was supposed to appear after the STREAM keyword |
53.2 | A variable name was supposed to appear after the STEM keyword |
53.3 | The variable name after the STEM keyword was supposed to end with a dot |
54 | Category: Invalid use of STEM keyword |
54.1 | An count of lines does not follow STEM APPEND |
65 | Category: An untrapped SYNTAX condition occurred in a child script. OPTIONS 'TRAP' must be on. CONDITION('D') reports the script name, exact error, and line number. Reginald-only |
80 | Category: An error in an environment. Reginald-only |
80.5 | An environment had a problem when you tried to fetch the value of one of its variables |
80.5 | An environment tried to return a value that has too many characters |
Even if you have the SYNTAX condition trapped in your script, there are certain of the above errors that will cause REXX to do its default handling of displaying some information about the problem, and aborting your script. Why? Because there are just some SYNTAX problems which REXX considers insurmountable. For example, if there is a missing quote on some literal string, REXX can't be sure what is supposed to be part of a literal string and what is supposed to be your instructions. So, REXX simply aborts your script regardless of whether you have a SYNTAX handler. In practice, REXX does this only for errors you make in the actual notation of your script, so you should be able to track down and eliminate these SYNTAX errors before finalizing your script. Some interpreters, such as Reginald, will not even begin running the script if there is such a "fatal" SYNTAX error in the script. As soon as you attempt to run the script, it will abort with an error message. So, if your script runs at all, then you know that you have no such fatal SYNTAX errors in it, and all other SYNTAX errors that crop up while your script is running can be trapped by your own handler. (Reginald also offers a SYNTAX Checker that will report all fatal SYNTAX errors in a script).
The majority of SYNTAX errors that could crop up while your script is running, such as category 40, can be trapped by your SYNTAX handler.
If a SYNTAX condition is handled via SIGNAL ON, then the special variable RC will be set to the ANSI error number associated with why the SYNTAX condition was raised. The CONDITION() built-in function's 'E' option can return both the error and sub-error numbers, but RC is set to the error number only. Since some interpreters do not implement the 'E' option for CONDITION(), in this case, you'll have to make due with the RC variable, and perhaps the 'D' option only.
Note: The RC variable is created by REXX, which assigns it a value when a condition is raised. You should never name your own variable RC, but may reference this variable.