Compaq BASIC for OpenVMS
Alpha and VAX Systems
User Manual


Previous Contents Index

20.1.5 Creating Local Copies

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 

Output


 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 

Output


 3 

20.1.6 Passing Arrays

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) 

20.3 Calling BASIC Subprograms from Other Languages

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.

Table 20-2 Run-Time Library Facilities
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

20.4.2 System Service Routines

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.

Table 20-3 System Services
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

20.4.3 System Routine Arguments

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.

Table 20-4 OpenVMS Usages
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


1Use the LOC function to pass the address of an AST routine to a system service. Specify BY VALUE for the passing mechanism.
2Although unsigned data structures are not directly supported in BASIC, you can substitute the signed equivalent provided you do not exceed the range of the signed data structure.
3The definition of the RECORD structures are included in the BASIC system definitions text library. See Section 20.4.4 for more information.

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