Previous | Contents | Index |
If a parameter is an expression, function, or virtual array element, then it is not possible to pass the parameter's address. In these cases, BASIC makes a local copy of the parameter's value and passes this local copy by reference.
You can force BASIC to make a local copy of any parameter by enclosing the parameter in parentheses. Forcing BASIC to make a local copy is a useful technique because you make it impossible for the subprogram to modify the actual parameter. In the following example, when variable A is printed in the main program, the value is zero because the variable A is not modifiable by the subprogram:
DECLARE LONG A CALL SUB1 ((A)) PRINT A END SUB SUB1 (LONG B) B = 3 END SUB |
0 |
By removing the extra parentheses from A, you allow the subprogram to modify the parameter.
DECLARE LONG A CALL SUB1 (A) PRINT A END SUB SUB1 (LONG B) B = 3 END SUB |
3 |
In Alpha BASIC, if a subprogram or function declares an array in its
parameter list, the calling program must pass an array. Passing a null
parameter instead would cause the program to fail with a memory access
violation.
20.2 Calling External Routines
Most of the steps of calling external routines are the same whether you
are calling an external routine written in BASIC, an external
routine written in some other language, a system service, or a OpenVMS
Run-Time Library routine. The following sections outline the procedure
for calling non BASIC external routines. For information about calling
BASIC routines, see Chapter 13.
20.2.1 Determining the Type of Call
Before you call an external routine, you must determine whether the
call to the routine should be a function call or a procedure call. You
should call a routine as a function if it returns any type of value. If
the routine does not return a value, you should call it as a procedure.
20.2.2 Declaring an External Routine and Its Arguments
To call an external routine or system routine you need to declare it as an external procedure or function and to declare the names, data types, and passing mechanisms for the arguments. Arguments can be either required or optional.
You should include the following information in a routine declaration:
When you declare an external routine, use the EXTERNAL statement. This allows you to specify the data types and parameter-passing mechanisms only once.
In the following example, the EXTERNAL statement declares cobsub as an external subprogram with two parameters---a LONG integer and a string both passed by reference:
EXTERNAL SUB cobsub (LONG BY REF, STRING BY REF) |
With the EXTERNAL statement, BASIC allows you to specify that particular parameters do not have to conform to specific data types and that all parameters past a certain point are optional. A parameter declared as ANY indicates that any data type can appear in the parameter position. In the following example, the EXTERNAL statement declares a SUB subprogram named allocate. This subprogram has three parameters: one LONG integer, and two that can be of any BASIC data type.
EXTERNAL SUB allocate(LONG, ANY,) |
A parameter declared as OPTIONAL indicates that all following parameters are optional. You can have both required and optional parameters. The required parameters, however, must appear before the OPTIONAL keyword because all parameters following it are considered optional.
In the following example, the EXTERNAL statement declares the Run-Time Library routine LIB$LOOKUP_KEY. The keyword OPTIONAL is specified to indicate that the last three parameters can be optional.
EXTERNAL LONG FUNCTION LIB$LOOKUP_KEY(STRING, LONG, OPTIONAL LONG, STRING, INTEGER) |
For more information about using the EXTERNAL statement, see the
Compaq BASIC for OpenVMS Alpha and VAX Systems Reference Manual.
20.2.3 Calling the Routine
Once you have declared an external routine, you can invoke it. To invoke a procedure, you use the CALL statement. To invoke a function, you use the function name in an expression. You must specify the name of the routine being invoked and all parameters required for that routine. Make sure the data types and passing mechanisms for the actual parameters you are passing match those you declared earlier, and those declared in the routine.
If you do not want to specify a value for a required parameter, you can pass a null argument by inserting a comma as a placeholder in the argument list. If you are passing a parameter using a mechanism other than the default passing mechanism for that data type, you must specify the passing mechanism in the CALL statement or the function invocation.
The following example shows you how to call the external subprogram allocate declared in Section 20.2.2. When allocate is called, it is called as a procedure. The first parameter must always be a valid LONG INTEGER value; the second and third parameters can be of any valid BASIC data type.
EXTERNAL SUB allocate(LONG, ANY,) . . . CALL allocate (entity%, a$, 1%) |
This next example shows you how to call the Run-Time Library routine LIB$LOOKUP_KEY declared in Section 20.2.2. When the routine LIB$LOOKUP_KEY is called, it is invoked as a function. The first two parameters are required; all remaining parameters are optional.
EXTERNAL LONG FUNCTION LIB$LOOKUP_KEY(STRING, LONG, OPTIONAL LONG, STRING, INTEGER) . . . ret_status% = LIB$LOOKUP_KEY(value$, point%) |
Note that if the actual parameter's data type in the CALL statement does not match that specified in the EXTERNAL statement, BASIC reports the compile-time informational message "Mode for parameter of routine changed to match declaration." This tells you that BASIC has made a local copy of the value of the parameter, and that this local copy has the data type specified in the EXTERNAL declaration. BASIC warns you of this because the change means that the parameter can no longer be modified by the subprogram. If BASIC cannot convert the data type, BASIC signals the error "Mode for parameter of routine not as declared."
The routine being called receives control, executes, and then returns control to the calling routine at the next statement after the CALL statement or function invocation.
BASIC provides the built-in function LOC to allow you to access the address of a named external function. This is especially useful when passing the address of a callback or AST routine to an external subprogram. In the following example, the address of the function compare is passed to the subprogram come_back_now using the LOC function:
EXTERNAL LONG FUNCTION compare (LONG, LONG) EXTERNAL SUB come_back_now (LONG BY VALUE) CALL come_back_now (LOC(compare) BY VALUE) |
When you call a BASIC subprogram from another language, there are some additional considerations that you should be aware of. For example, although BASIC conforms to the OpenVMS Calling Standard, you should specify explicit passing mechanisms when calling a routine written in another language. The default passing mechanisms of BASIC may not match what the procedure expects. In the following section, FORTRAN refers to VAX FORTRAN and Compaq Fortran.
FORTRAN passes and receives numeric data by reference; only the default parameter-passing mechanisms are required for passing numeric data back and forth between FORTRAN and BASIC programs.
Both BASIC and FORTRAN pass strings by descriptor. However, FORTRAN subprograms cannot change the length of strings passed to them. Therefore, if you pass a string to a FORTRAN subprogram, you must make sure that the string is long enough to receive the result. You do this in one of two ways:
Because the length of the returned string does not change, it is either padded with spaces or truncated.
To pass an array to a FORTRAN subprogram, you must specify BY REF.
Note that FORTRAN arrays are one-based, while BASIC arrays are zero-based by default. For example, in FORTRAN the array Two_D(5,3) represents a 5 by 3 matrix, while in BASIC the array Two_d(5,3) represents a 6 by 4 matrix. You can adjust your array bounds in BASIC by using the keyword TO when defining the array bounds. For more information about array bounds, see Chapter 7.
When passing two-dimensional arrays as parameters, keep in mind that FORTRAN addresses array elements in column major order, while BASIC refers to array elements in row major order. That is, FORTRAN arrays are of the form Fortran_array(column,row), while BASIC array elements are addressed as Basic_array(row,column). The FORTRAN array Grid(x,y) is therefore referred to as GRID(y,x) in BASIC. You should reverse references to array elements when passing arrays between BASIC and FORTRAN program modules. You can do this in one of two ways:
Example 20-1 shows a BASIC program that passes a two-dimensional array to a FORTRAN subprogram. The FORTRAN subprogram is shown in Example 20-2.
Example 20-1 BASIC Main Program |
---|
PROGRAM call_fortran ! The BASIC main program prints the array before ! calling the subroutine EXTERNAL SUB forsub (WORD DIM(,) BY REF) DIM WORD array_x(1 TO 10, 1 TO 5) FOR column = 1 TO 5 FOR row = 1 TO 10 array_x(row,column)=(10*row + column) PRINT array_x(row,column); NEXT row PRINT NEXT column PRINT CALL forsub(array_x(,) BY REF) END PROGRAM |
Example 20-2 FORTRAN Subprogram |
---|
C The FORTRAN subprogram receives C and then prints the same array SUBROUTINE forsub(f_array) INTEGER*2 f_array(5,10) DO 20 row = 1,5 TYPE *, (f_array(row,column), column = 1,10) 20 CONTINUE RETURN END |
You can pass only the data types that BASIC and FORTRAN have in
common. You cannot pass a complex number from a FORTRAN program to a
BASIC program, because BASIC does not support complex
numbers. However, you can pass a complex number as two floating-point
numbers and treat them independently in the BASIC program.
20.4 Calling System Routines
The steps for calling system routines are the same as those for calling
any external routine. However, when calling system routines, you need
to provide additional information, which is discussed in the following
sections.
20.4.1 OpenVMS Run-Time Library Routines
The OpenVMS Run-Time Library routines are grouped according to the types of tasks they perform. The routines in each group have a prefix that identifies them as members of a particular OpenVMS Run-Time Library facility. Table 20-2 lists all the language-independent Run-Time Library facility prefixes and the types of tasks each facility performs.
Facility Prefix | Types of Tasks Performed |
---|---|
DTK$ | DECtalk routines that are used to control the DECtalk device |
LIB$ | General purpose routines that obtain records from devices, manipulate strings, convert data types for I/O, allocate resources, obtain system information, signal exceptions, establish condition handlers, enable detection of hardware exceptions, and process cross-reference data |
MTH$ | Mathematics routines that perform arithmetic, algebraic, and trigonometric calculations |
OTS$ | Language-independent support routines that perform tasks such as data type conversions as part of a compiler's generated code |
PPL$ | Parallel processing routines that help you implement concurrent programs on single-CPU and multiprocessor systems |
SMG$ | Screen management routines that are used in designing, composing, and keeping track of complex images on a video screen |
STR$ | String manipulation routines that perform such tasks as searching for substrings, concatenating strings, and prefixing and appending strings |
System services are system routines that perform a variety of tasks such as controlling processes, communicating among processes, and coordinating I/O.
Unlike the OpenVMS Run-Time Library routines, which are divided into groups by facility, all system services share the same facility prefix (SYS$). However, these services are logically divided into groups that perform similar tasks. Table 20-3 describes these groups.
Group | Types of Tasks Performed |
---|---|
AST | Allows processes to control the handling of ASTs |
Change Mode | Changes the access mode of particular routines |
Condition Handling | Designates condition handlers for special purposes |
Event Flag | Clears, sets, reads, and waits for event flags, and associates with event flag clusters |
Information | Returns information about the system, queues, jobs, processes, locks, and devices |
Input/Output | Performs I/O directly, without going through RMS |
Lock Management | Enables processes to coordinate access to shareable system resources |
Logical Names | Provides methods of accessing and maintaining pairs of character string logical names and equivalence names |
Memory Management | Increases or decreases available virtual memory, controls paging and swapping, and creates and accesses shareable files of code or data |
Process Control | Creates, deletes, and controls execution of processes |
Security | Enhances the security of OpenVMS systems |
Time and Timing | Schedules events, and obtains and formats binary time values |
All of the system routine arguments are described in terms of the following information:
OpenVMS usages are data structures that are layered on the standard OpenVMS data types. For example, the OpenVMS usage mask_longword signifies an unsigned longword integer that is used as a bit mask, and the OpenVMS usage floating_point represents any OpenVMS floating-point data type. Table 20-4 lists all the OpenVMS usages and the BASIC statements you need to implement them.
OpenVMS Usage | BASIC Implementation |
---|---|
access_bit_names | Not applicable (NA) |
access_mode | BYTE (signed) |
address | LONG |
address_range |
LONG address_range (1)
or RECORD address_range LONG beginning_address LONG ending_address END RECORD |
arg_list | NA |
ast_procedure | EXTERNAL LONG FUNCTION ast_proc 1 |
boolean | LONG |
byte_signed | BYTE |
byte_unsigned | BYTE 2 |
channel | WORD |
char_string | STRING |
complex_number |
RECORD complex
REAL real_part REAL imaginary_part END RECORD |
cond_value | LONG |
context | LONG |
date_time | QUAD |
device_name | STRING |
ef_cluster_name | STRING |
ef_number | LONG |
exit_handler_block |
RECORD EHCB
LONG flink LONG handler_addr BYTE arg_count BYTE FILL(3) LONG status_value_addr END RECORD |
fab | NA |
file_protection | LONG |
floating_point |
SINGLE
DOUBLE GFLOAT HFLOAT SFLOAT TFLOAT XFLOAT |
function_code |
RECORD function-code
WORD major-function WORD subfunction END RECORD |
identifier | LONG |
io_status_block |
RECORD iosb
WORD iosb_field(1 to 4) END RECORD |
item_list_2 |
RECORD item_list_two
GROUP item(15) VARIANT CASE WORD comp_length WORD code LONG comp_address CASE LONG terminator END VARIANT END GROUP END RECORD |
item_list_3 |
RECORD item_list_3
GROUP item (15) VARIANT CASE WORD buf_len WORD code LONG buffer_address LONG length_address CASE LONG terminator END VARIANT END GROUP END RECORD |
item_list_pair |
RECORD item_list_pair
GROUP item(15) VARIANT CASE LONG code LONG item_value CASE LONG terminator END VARIANT END GROUP END RECORD item_list_pair |
item_quota_list |
RECORD item_quota_list
GROUP quota(n) VARIANT CASE BYTE quota_name LONG item_value CASE BYTE list_end END VARIANT END GROUP END RECORD |
lock_id | LONG |
lock_status_block | NA |
lock_value_block | NA |
logical_name | STRING |
longword_signed | LONG |
longword_unsigned | LONG 2 |
mask_byte | BYTE |
mask_longword | LONG |
mask_quadword | QUAD |
mask_word | WORD |
null_arg | A null argument is indicated by a comma used as a placekeeper in the argument list. |
octaword_signed | BASIC$OCTAWORD 3 |
octaword_unsigned | BASIC$OCTAWORD 3 |
page_protection | LONG |
procedure | EXTERNAL LONG FUNCTION proc |
process_id | LONG |
process_name | STRING |
quadword_signed | QUAD |
quadword_unsigned | QUAD 2 |
rights_holder | QUAD |
rights_id | LONG |
rab | NA |
section_id | QUAD |
section_name | STRING |
system_access_id | QUAD |
time_name | STRING |
uic | LONG |
user_arg | LONG |
varying_arg | Dependent upon application. |
vector_byte_signed | BYTE array(n) |
vector_byte_unsigned | BYTE array(n) 2 |
vector_longword_signed | LONG array(n) |
vector_longword_unsigned | LONG array(n) 2 |
vector_quadword_signed | NA |
vector_quadword_unsigned | NA |
vector_word_signed | WORD array(n) |
vector_word_unsigned | WORD array(n) 2 |
word_signed | WORD |
word_unsigned | WORD 2 |
If a system routine argument is optional, it will be indicated in the format section of the routine description in one of the following ways:
[,optional-argument]
,[optional-argument]
Previous | Next | Contents | Index |