ON int_expr GOSUB target1 [, target2...] [ELSE statement]
10 start: INPUT 'Procedure (1=add, 2=del, 3=exit)': pro 20 ON pro GOSUB add, del, done ELSE PRINT 'Enter 1, 2 or 3' GOTO start add: PRINT 'Adding...' RETURN del: PRINT 'Deleting...' RETURN 30 done: PRINT 'Finished' END RNH Procedure (1=add, 2=del, 3=exit)? add Non-numeric input when number expected at START Procedure (1=add, 2=del, 3=exit)? 5 Enter 1, 2 or 3 Procedure (1=add, 2=del, 3=exit)? 1 Adding... Procedure (1=add, 2=del, 3=exit)? 3 Finished
Use ON..GOSUB when you want to jump to one of several subroutines depending on a condition you set up. ON..GOSUB jumps to one of the locations, executes the code at that location and then returns to the first statement after the ON..GOSUB.
ON..GOSUB transfers control to one of several subroutines depending on the value of an integer expression. The simplest version of ON..GOSUB is:
ON int_expr GOSUB target1, target2...
int_expr is an integer expression whose value determines where control is transferred. The targets begin subroutines. They can be ROUTINE statements, labels or line numbers. The subroutines are blocks of code. When INTOUCH branches to a subroutine, it executes the block of code until it reaches a RETURN or END ROUTINE statement. INTOUCH then returns to the statement following the ON..GOSUB.
When INTOUCH executes the ON GOSUB, it evaluates the integer expression. If the value is one, INTOUCH branches to the first target and executes the subroutine. If the integer is two, INTOUCH branches to the second subroutine, and so on.
int_expr must evaluate to an integer. If it does not, INTOUCH rounds the value and uses the resulting integer. The integer expression must yield an integer within the range of the target list. For example, if there are five targets in the list, the integer value must be in the range of 1 to 5. If the integer value is not in the range of the target list, and there is no ELSE clause, an exception is generated.
INTOUCH supports 128 targets for ON..GOSUB. More targets than 128 gives an "expression too complex" exception.
The ELSE option executes a statement if the integer value does not yield a target. ON GOSUB with the ELSE option looks like this:
ON int_expr GOSUB target1, target2... ELSE statement
ELSE must be followed by a statement. The ELSE is executed if the integer value exceeds the number of targets in the list, is 0 or is negative.
The previous example shows how ELSE is used.
DISPATCH str_expr . . . target --- --- block of code --- RETURN
10 INPUT 'Routine name', DEFAULT 'add': routine$ DISPATCH routine$ STOP 20 add: PRINT 'Adding information...' RETURN 30 change: PRINT 'Changing information...' RETURN 40 END RNH Routine name? add Adding information...
DISPATCH executes a routine that the program determines at run-time.
DISPATCH looks at the contents of the string expression (str_expr), searches for a routine with that name and GOSUBS to the routine.
str_expr is the name of the subroutine to execute.
ROUTINE routine_name --- --- block of code --- [REPEAT ROUTINE] --- [EXIT ROUTINE] END ROUTINE
10 get_username 20 END 12000 ROUTINE get_username INPUT PROMPT 'Username: ': uname$ IF _BACK or _EXIT THEN EXIT ROUTINE END ROUTINE RNH Username: Tester
ROUTINES are block-structured subroutines. They provide a convenient way to name a block of code. Routines can be edited as a complete unit, or partially edited by line number.
To execute a ROUTINE, use the GOSUB or DISPATCH statement or just the name of the routine. You CANNOT fall into a routine the way you can a subroutine that starts with a label.
EXIT ROUTINE
The EXIT ROUTINE statement enables you to exit from the executed routine.
The above example shows how EXIT ROUTINE can be used.
REPEAT ROUTINE
10 get_username 20 END 12000 ROUTINE get_username INPUT PROMPT 'Username: ': uname$ IF _BACK or _EXIT THEN EXIT ROUTINE IF uname$ = '' THEN REPEAT ROUTINE END ROUTINE RNH Username: Username: Sunny
The REPEAT ROUTINE statement enables you to repeat the entire routine execution. When INTOUCH executes the REPEAT ROUTINE statement, the routine is re-executed.
Exception handling routines intercept run-time exceptions and execute a block of code which handles them. If you do not have an exception handler, INTOUCH returns an exception message specifying what the exception was and where it occurred. INTOUCH stops program execution or tries the offending statement again.
There are two types of exception handlers: attached handlers and detached handlers.
When you have an attached handler, you use a WHEN EXCEPTION IN statement. WHEN EXCEPTION IN puts the handler (the block of code to execute) right after the block of code it protects.
You can also have a detached handler. For a detached handler, use the statement WHEN EXCEPTION USE. When an exception occurs in the protected block, WHEN EXCEPTION USE calls a handler routine located in some other part of the program. The same handler routine can be used by any number of WHEN EXCEPTION USE statements and can be placed anywhere in your program.
This section explains exception handlers. It also describes the handling statements--RETRY, CONTINUE and EXIT HANDLER.
The following functions are also related to exception handling:
For a full description of these functions, see Section A.2, Other Functions.
CAUSE EXCEPTION exception_number
10 DO INPUT 'Select a number between 1 and 10': no IF no < 1 OR no > 10 THEN CAUSE EXCEPTION 1001 REPEAT DO END DO 20 END RNH Select a number between 1 and 10? 8 Select a number between 1 and 10? 99 Illegal number at 10.2
Use CAUSE EXCEPTION when you need to generate an exception under specific conditions.
CAUSE EXCEPTION causes the specified exception to occur. exception_number can be any integer expression. When INTOUCH executes the CAUSE EXCEPTION statement, it generates the exception specified. See Section C.2, Exceptions for a list of exception messages.
WHEN EXCEPTION IN --- --- protected block --- USE --- --- handler --- END WHEN
10 INPUT 'Your name, please': name$ WHEN EXCEPTION IN INPUT 'How old are you': age USE PRINT 'Not a valid age' RETRY END WHEN PRINT PRINT NAME$; ' is'; age 20 END RNH Your name, please? Tester How old are you? 3x Not a valid age How old are you? 35 Tester is 35
Use WHEN EXCEPTION IN to catch run-time exceptions and resolve them within your program when you want the code, handling the exception, to be next to the code you are protecting.
WHEN EXCEPTION IN begins the protected block of code. Everything between the WHEN EXCEPTION IN and USE statements constitutes the section of code protected by the handler---the protected block.
USE begins the handler routine. Everything between the USE and the END WHEN statements constitutes the handler. If an exception occurs in the protected block, the handler code is executed. END WHEN ends the routine.
WHEN EXCEPTION USE handl_name --- --- protected block --- END WHEN . . . HANDLER handl_name --- --- handler --- END HANDLER
10 INPUT 'Enter total sales amount': tsales INPUT 'Enter number of sales': nsales WHEN EXCEPTION USE fix_average average = tsales/nsales END WHEN PRINT 'The average is:'; average 20 HANDLER fix_average average = 0 CONTINUE 30 END HANDLER 40 END RNH Enter total sales amount? 25.00 Enter number of sales? 0 The average is: 0
Use WHEN EXCEPTION USE to catch run-time exceptions and resolve them within a program when you need the same handler for several protected blocks, or when you want all the handlers in one place in your program.
WHEN EXCEPTION USE begins the protected block of code and specifies the HANDLER routine to use. handl_name is the name of the handler routine. The handler name must meet the specifications for variable names. The protected block is everything between the WHEN EXCEPTION USE and the END WHEN statements. If an exception occurs in this block of code, INTOUCH calls the handler specified. If the handler does not exist, an error is generated.
HANDLER begins the handler routine. Everything between the HANDLER and the END HANDLER constitutes the handler routine. END HANDLER returns control to the statement following the END WHEN. When the handler is called, this block of code is executed. In the example above, INTOUCH would normally return an exception when it tried to divide 25.00 by 0. The exception handler FIX_AVERAGE intercepts this exception and sets AVERAGE equal to 0.
The handler routine can occur before or after the protected block. For example:
10 HANDLER fix_average average = 0 <--- handler routine CONTINUE END HANDLER 20 INPUT 'Enter total sales amount': tsales INPUT 'Enter number of sales': nsales WHEN EXCEPTION USE fix_average average = tsales/nsales END WHEN 30 PRINT 'The average is'; average 40 END
One of the advantages of WHEN EXCEPTION USE is that the same handler routine can be called by any number of WHEN EXCEPTION USE statements. For example:
10 WHEN EXCEPTION USE numbers INPUT 'How old are you': age <--- first protected block END WHEN 20 INPUT 'Your name, please': name$ 30 WHEN EXCEPTION USE numbers INPUT 'Your birthdate': birth <--- second protected block END WHEN 40 PRINT name$; ' was born on'; birth 50 HANDLER numbers PRINT 'Enter numbers only, please.' <--- handler routine RETRY END HANDLER 60 END
USE --- --- RETRY --- END WHEN or HANDLER handl_name --- --- RETRY --- END HANDLER
10 INPUT 'Your name, please': name$ 20 WHEN EXCEPTION IN INPUT 'How old are you': age USE PRINT 'Not a valid age' RETRY END WHEN 30 PRINT PRINT name$; ' is'; age 40 END RNH Your name, please? Tester How old are you? 3x Not a valid age How old are you? 35 Tester is 35
Use RETRY after an exception to re-execute the statement that generated the exception.
RETRY can only be used in a HANDLER routine. RETRY causes INTOUCH to leave the handler and re-execute the statement that generated an exception.
USE --- --- CONTINUE --- END WHEN or HANDLER handl_name --- --- CONTINUE --- END HANDLER
10 INPUT 'Enter total sales amount': tsales INPUT 'Enter number of sales': nsales 20 WHEN EXCEPTION USE fix_average average = tsales / nsales END WHEN 30 PRINT 'The average is:'; average 40 HANDLER fix_average average = 0 CONTINUE END HANDLER 50 END RNH Enter total sales amount? 18.00 Enter number of sales? 0 The average is: 0
Use CONTINUE to continue normal program execution at the statement following the one that generated the exception.
CONTINUE causes INTOUCH to exit the exception handler and continue program execution at the first statement following the statement which generated the exception. CONTINUE can only be used in a HANDLER routine.
USE --- --- RESUME target --- END WHEN or HANDLER handl_name --- --- RESUME target --- END HANDLER
10 INPUT 'Enter total sales amount': tsales INPUT 'Enter number of sales': nsales 20 WHEN EXCEPTION USE fix_average average = tsales / nsales END WHEN 30 PRINT 'The average is:'; average 40 HANDLER fix_average average = 0 PRINT 'Invalid numbers. Try again.' RESUME 10 END HANDLER 50 END RNH Enter total sales amount? 75.00 Enter number of sales? 0 Invalid numbers. Try again. Enter total sales amount? 75.00 Enter number of sales? 3 The average is: 25
Use RESUME to resume normal program execution at the statement label that you specify.
RESUME causes INTOUCH to exit the exception handler and resume program execution at the target line specified. The target can be a line number or a label.
RESUME can only be used in a handler routine.
USE --- --- EXIT HANDLER --- END WHEN or HANDLER handl_name --- --- EXIT HANDLER --- END HANDLER
10 WHEN EXCEPTION USE mistake INPUT 'Enter your age': age END WHEN PRINT 'You are'; age; 'years old' 20 HANDLER mistake PRINT 'Oops...' DELAY 2 EXIT HANDLER END HANDLER 30 END RNH Enter your age? 3x Oops... Non-numeric input when number expected at 10.1 Enter your age? 35 You are 35 years old
Use EXIT HANDLER to exit a handler routine and pass the exception up to the next level of exception handling.
EXIT HANDLER exits the current HANDLER routine. If the current handler is nested within another handler, INTOUCH jumps to the outside handler and executes the code for that handler. If there is no other exception handler, control returns to the INTOUCH system. INTOUCH prints the exception message and takes whatever action it normally would.
EXIT HANDLER can only be used within an exception handler.
You can call routines written in other languages and run them from an INTOUCH program.
Callable routines are stored in libraries. The LIBRARY statement tells INTOUCH what library a routine is located in. You must use the LIBRARY statement to specify where routines are located before you call them in your program.
The CALL statement calls routines and executes them. You can call any routine in a shared VMS library and execute it. The CALL and LIBRARY statements make your programs more powerful, more versatile, and give you more programming options.
LIBRARY 'libr_name'
10 LIBRARY 'BASRTL' 20 PRINT 'Waiting 5 seconds...' 30 CALL BAS$SLEEP(5% BY VALUE) 40 END RNH Waiting 5 seconds...
You can use the LIBRARY statement to specify the libraries you will use in your program.
The LIBRARY statement specifies libraries from which you CALL routines. The routines can be written in any VMS language that supports the standard calling interface (FORTRAN, BASIC, COBOL, etc.).
libr_name is the file specification of a library. The library can be one of the VMS supplied libraries, or a user-defined library. You must name a library with the LIBRARY statement before you call a routine from it. The library name must be a string constant in quotes.
To create libraries for INTOUCH, you can refer to Appendix E, Creating Libraries for Use with INTOUCH.
CALL routine_name(arg [BY pass_mech], arg...)
10 LIBRARY 'BASRTL' 20 PRINT 'Waiting 5 seconds...' 30 CALL BAS$SLEEP(5% BY VALUE) 40 END RNH Waiting 5 seconds...
You can use the CALL statement to call and execute library routines. You can use these routines to perform procedures rather than writing the code yourself.
The library to which the routine belongs must have been specified in a LIBRARY statement.
routine_name is the name of the routine you are calling. Some routines take arguments. arg is an argument you are passing to or getting from the routine. If more than one argument is passed, separate the arguments with commas:
CALL routine_name(arg, arg, arg...)
Some routines have optional arguments--arguments which can be used, but do not have to be used. To pass an optional argument, include it in the appropriate place in the argument list. If you do not want to pass an optional argument, specify that no argument is to be used by typing two commas side by side at the appropriate place in the argument list.
For example, the routine LIB$GET_INPUT gets a record of ASCII text. Its argument list contains two optional arguments:
LIB$GET_INPUT(get-str.wt.dx [,prompt-str.rt.dx [,out-len.wwu.r]]) | | | string variable the a prompt string length of the input is assigned to string variable
To input a line without using a prompt string, your CALL statement would have the following format:
CALL routine_name(str_var,,num_var)
The double commas tell INTOUCH that the optional variable prompt-str is not used. For example:
10 LIBRARY 'LIBRTL' BUF$ = REPEAT$(' ', 200) CALL LIB$GET_INPUT(BUF$, , OUT_LEN%) PRINT 'You typed: ';BUF$[1:OUT_LEN%] 20 END
pass_mech refers to the mechanism by which values are passed to the routine. The default passing mechanism for reals and integers is by reference. The default passing mechanism for strings is by descriptor. Here is an explanation of the passing mechanisms available:
BY REF | By reference. This is the default passing mechanism for real and integer data. Arguments passed by reference can be changed by the routine they are passed to. |
BY VALUE | By value. Arguments passed by value cannot be changed by the routine they are passed to. |
BY DESC | By descriptor. This is the default passing mechanism for strings. By descriptor causes INTOUCH to use the argument's descriptor when passing the argument. Arguments passed by descriptor can be changed by the routine they are passed to. |
The system functions _REAL and _INTEGER can be used in conjunction with the library statements. These functions return resulting data associated with the CALL. (See Section A.1, System Functions for more information.)