Previous | Contents | Index |
The STRING$ function creates a character string containing multiple occurrences of a single character. In the following example, 23 is the length of the returned string, and 30 is the ASCII value of the character that makes up the string. This value is treated modulo 256.
STRING$(23,30) |
The following example creates a 10-character string containing uppercase As, which have ASCII value 65:
out$ = STRING$(10%, 65%) PRINT out$ END |
AAAAAAAAAA |
Keep these considerations in mind when you use STRING$:
The SPACE$ function creates a character string containing spaces. In this example, 5 is the number of spaces in the string:
SPACE$(5) |
The following example creates a 9-character string which contains 3 spaces:
A$ = "ABC" B$ = "XYZ" PRINT A$ + SPACE$(3%) + B$ END |
ABC XYZ |
The TRM$ function removes trailing blanks and tabs from a string. The input string remains unchanged. In the following example, all trailing blanks that appear in the string expression "ABCDE " are removed once the TRM$ function is invoked:
A$ = "ABCDE " B$ = "XYZ" first$ = A$ + B$ second$ = TRM$(A$) + B$ PRINT first$ PRINT second$ END |
ABCDE XYZ ABCDEXYZ |
The TRM$ function is especially useful for extracting the nonblank
characters from a fixed-length string (for example, a COMMON or MAP, or
a parameter passed from a program written in another language).
12.6.8 EDIT$ Function
The EDIT$ function performs one or more string editing functions, depending on the value of an argument you supply. The input string remains unchanged. In the following example, stu_rec is a string expression and 32 determines the editing function performed:
EDIT$(stu_rec,32) |
Table 12-2 shows the action BASIC takes for a given value of the integer expression.
Value of Expression |
Effect |
---|---|
1 | Discards each character's parity bit (bit 7). Note that you should not use this value for characters in the DEC Multinational character set. |
2 | Discards all spaces and tabs. |
4 | Discards all carriage returns, line feeds, form feeds, deletes, escapes, and nulls. |
8 | Discards leading spaces and tabs. |
16 | Converts multiple spaces and tabs to a single space. |
32 | Converts lowercase letters to uppercase. |
64 | Converts left brackets ([) to left parentheses [(], and right brackets (]) to right parentheses [)]. |
128 | Discards trailing spaces and tabs. (Same as TRM$ function.) |
256 | Suppresses all editing for characters within quotation marks. If the string has only one quotation mark, BASIC suppresses all editing for the characters following the quotation mark. |
All values are additive; for example, by specifying 168, you can perform the following:
The following example requests an input string, discards all spaces and tabs, converts lowercase letters to uppercase, and converts brackets to parentheses:
LINPUT "PLEASE TYPE A STRING";input_string$ new_string$ = EDIT$(input_string$, 2% + 32% + 64%) PRINT new_string$ END |
PLEASE TYPE A STRING? 88 abc[TAB][5,5] 88ABC(5,5) |
Mapping a string storage area in more than one way lets you extract a substring from a string or concatenate strings. In the following example, the three MAP statements reference the same 108 bytes of data:
MAP (emprec) first_name$ = 10, & last_name$ = 20, & street_number$ = 6, & street$ = 15, & city$ = 20, & state$ = 2, & zip$ = 5, & wage_class$ = 2, & date_of_review$ = 8, & salary_ytd$ = 10, & tax_ytd$ = 10 MAP (emprec) full_name$ = 30, & address$ = 48, & salary_info$ = 30 MAP (emprec) employee_record$ = 108 |
You can move data into a map in different ways. For instance, you can use terminal input, arrays, and files. In the following example, the READ and DATA statements are used to move data into a map:
READ EMPLOYEE_RECORD$ DATA "WILLIAM DAVIDSON 2241 MADISON BLVD " & "SCRANTON PA14225A912/10/78$13,325.77$925.31" |
Because all the MAP statements in the previous example reference the same storage area (emprec), you can access parts of this area through the mapped variables as shown in the following examples:
PRINT full_name$ PRINT wage_class$ PRINT salary_ytd$ |
WILLIAM DAVIDSON A9 $13,325.77 |
PRINT last_name$ PRINT tax_ytd$ |
DAVIDSON $925.31 |
You can assign a new value to any of the mapped variables. The following example prompts the user for changed information by displaying a menu of topics. The user can then choose which topics need to be changed and then separately assign new values to each variable.
Loop_1: WHILE 1% = 1% INPUT "Changes? (please type YES or NO)"; CH$ EXIT Loop_1 IF CH$ = "NO" PRINT "1. FIRST NAME" PRINT "2. LAST NAME" PRINT "3. STREET NUMBER" PRINT "4. STREET" PRINT "5. CITY" PRINT "6. STATE" PRINT "7. ZIP" PRINT "8. WAGE CLASS" PRINT "9. DATE OF REVIEW" PRINT "10. SALARY YTD" PRINT "11. TAX YTD" INPUT "CHANGE NUMBER"; NUMBER% SELECT NUMBER% CASE 1% INPUT "FIRST NAME"; first_name$ CASE 2% INPUT "LAST NAME"; last_name$ CASE 3% INPUT "STREET NUMBER"; street_number$ CASE 4% INPUT "STREET"; street$ CASE 5% INPUT "CITY"; city$ CASE 6% INPUT "STATE"; state$ CASE 7% INPUT "ZIP CODE"; zip$ CASE 8% INPUT "WAGE CLASS"; wage_class$ CASE 9% INPUT "DATE OF REVIEW"; date_of_review$ CASE 10% INPUT "SALARY YTD"; salary_ytd$ CASE 11% INPUT "TAX YTD"; tax_ytd$ CASE ELSE PRINT "Invalid choice" END SELECT NEXT END |
Changes? (please type YES or NO)? YES 1. FIRST NAME 2. LAST NAME 3. STREET NUMBER 4. STREET 5. CITY 6. STATE 7. ZIP 8. WAGE CLASS 9. DATE OF REVIEW 10. SALARY YTD 11. TAX YTD CHANGE NUMBER? 10 SALARY YTD? 14,277.08 Changes? (please type YES or NO)? YES CHANGE NUMBER? 11 TAX YTD? 998.32 Changes? (please type YES or NO)? NO |
See Chapter 8 and the Compaq BASIC for OpenVMS Alpha and VAX Systems Reference Manual for more information about the MAP statement.
Program segmentation is the process of dividing a program into small, manageable routines and modules. In a segmented or modular program, each routine or module usually performs only one logical function. You can, therefore, design and implement a modular program faster than a nonsegmented program. Program modularity also simplifies debugging and testing, as well as program maintenance and transportability.
This chapter describes how to:
Subprograms processed by the BASIC compiler conform to the
OpenVMS Procedure Calling Standard. This standard prescribes how
arguments are passed, how values are returned, and how procedures
receive and return control. Because BASIC conforms to the
OpenVMS Procedure Calling Standard, a BASIC subprogram or main
program can call or be called by any procedure written in a language
that also conforms to this standard. For information about calling non
BASIC procedures, see Chapter 20.
13.1 BASIC Subprograms
BASIC has SUB, FUNCTION, and PICTURE subprograms. Each of these subprograms receives parameters and can modify parameters passed by reference or by descriptor. The differences between SUB, FUNCTION, and PICTURE subprograms are as follows:
All subprograms invoked by a BASIC program must have unique names. A BASIC program cannot have different subprograms with the same identifiers.
Subprograms can return a value to the calling program with parameters. You can use subprograms to separate routines that you commonly use. For example, you can use subprograms to perform file I/O operations, to sort data, or for table lookups.
You can also use subprograms to separate large programs into smaller, more manageable routines, or you can separate modules that are modified often. If all references to system-specific features are isolated, it is easier to transport the program to a different system. OpenVMS System Services and OpenVMS Run-Time Library routines are specific to OpenVMS systems; therefore, you should consider isolating references to them in subprograms. Chapter 20 describes how to access Run-Time Library routines and system services from BASIC.
You should also consider isolating complex processing algorithms that are used commonly. If complex processing routines are isolated, they can be shared by many programs while the complexity remains hidden from the main program logic. However, they can share data only if the following is true:
All DATA statements are local to a subprogram. Each time you call a subprogram, BASIC positions the data pointer at the beginning of the subprogram's data.
The data pointer in the main program is not affected by READ or RESTORE
statements in the subprogram (in contrast with the RESTORE # statement,
which resets record pointers to the first record in the file no matter
where it is executed). Chapter 6 contains more information about
the READ and RESTORE statements. For more information about the RESTORE
# statement, see Chapter 14.
13.1.1 SUB Subprograms
A SUB subprogram is a program module that can be separately compiled and that cannot return a value. A SUB subprogram is delimited by the SUB and END SUB statements. You may use the EXTERNAL statement to explicitly declare the SUB subprogram.
The END SUB statement does the following:
The EXIT SUB statement transfers control to the statement lexically following the statement that invoked the subprogram. It is equivalent to an unconditional branch to an END SUB statement.
The following SUB subprogram sorts two integers. If this SUB statement is invoked with actual parameter values that are already in sorted order, the EXIT SUB statement is executed and control returns to the calling program.
SUB sort_out (INTEGER X, INTEGER Y) DECLARE INTEGER temp IF X > Y THEN temp = X X = Y Y = temp ELSE EXIT SUB END IF END SUB |
A FUNCTION subprogram is a program module that returns a value and can be separately compiled. It must be delimited by the FUNCTION and END FUNCTION statements. You use the EXTERNAL statement to name and explicitly declare the data type of an external function.
The END FUNCTION statement does the following:
The EXIT FUNCTION statement immediately returns program control to the statement that invoked the function and optionally returns the function's return value. It is equivalent to an unconditional transfer to the END FUNCTION statement.
You can specify an expression with both the END FUNCTION and EXIT FUNCTION statements, which is another way of returning a function value. This expression must match the function data type, and it supersedes any function assignment. For more information, see the Compaq BASIC for OpenVMS Alpha and VAX Systems Reference Manual.
The following function returns the volume of a sphere of radius R. If this function is invoked with an actual parameter value less than or equal to zero, the function returns zero.
FUNCTION REAL Sphere_volume (REAL R) IF R <= 0 THEN Sphere_volume = 0.0 ELSE Sphere_volume = 4/3 * PI * R ** 3 END IF END FUNCTION |
The following example declares the FUNCTION subprogram and invokes it:
PROGRAM call_sphere EXTERNAL REAL FUNCTION SPHERE_VOLUME(REAL) PRINT SPHERE_VOLUME(5.925) END PROGRAM |
Note that this module is compiled separately from the FUNCTION subprogram. You can link these modules together to run the program from DCL level. To run the program in the VAX BASIC Environment, follow these steps:
See Chapter 2 for more information about the LOAD command and
linking and running multiple-unit programs.
13.2 Declaring Subprograms and Parameters
You declare a subprogram by naming it in an EXTERNAL statement in the calling program. You may also declare the data type of each parameter. If the subprogram is a function, the EXTERNAL statement also lets you specify the data type of the returned value.
The following statements are subprogram declarations using the EXTERNAL statement:
EXTERNAL SUB my_sub (LONG, STRING) EXTERNAL GFLOAT FUNCTION my_func (GFLOAT, LONG, GFLOAT) EXTERNAL REAL FUNCTION determinant (LONG DIM(,)) |
Note that the parameter lists contain only data type and dimension information; they cannot contain any format or actual parameters. When the external procedure is invoked, BASIC ensures that the actual parameter data type matches the data type specified in the EXTERNAL declaration. However, BASIC does not check to make sure that the parameters declared in the EXTERNAL statement match those in the external routine. You must ensure that these parameters match.
You can pass data of any BASIC data type to a BASIC subprogram, including RFAs and RECORDs. BASIC allows you to pass up to 255 parameters, separated by commas. The data can be any one of the following:
For passing constants, variables, functions, and array elements, name them in the argument list. For example:
CALL SUB01(var1, var2) CALL SUB02(Po_num%, Vouch, 66.67, Cust_list(5), FNA(B%)) |
However, when passing an entire array, you must use a special format. You specify the array name followed by commas enclosed in parentheses. The number of commas must be the number of array dimensions minus one. For example, array_name() is a one-dimensional array, array_name(,) is a two-dimensional array, array_name(,,) is a three-dimensional array, and so on.
The following example creates a three-dimensional array, loads the array with values, and passes the array to a subprogram as a parameter. The subprogram can access and change values in array elements, and these changes remain in effect when control returns to the main program.
PROGRAM fill_array OPTION TYPE = EXPLICIT DECLARE LONG I,J,K, three_d(10,10,10) EXTERNAL SUB example_sub (LONG DIM(,,)) FOR I = 0 TO 10 FOR J = 0 TO 10 FOR K = 0 TO 10 three_d(I,J,K) = I + J + K NEXT K NEXT J NEXT I CALL example_sub( three_d(,,)) END PROGRAM SUB example_sub( LONG X( , , )) . . . END SUB |
If you do not specify data types for parameters, the default data type is determined by:
The last specified parameter data type overrides all the other default data types, the defaults specified in the OPTION statement override any compilation qualifiers and system defaults, and so on. See Chapter 2 for more information about the OPTION statement and establishing data-type defaults.
When you know the length of a string or the dimensions of an array at
compile time, you can achieve optimum performance by passing them BY
REF. When you call programs written in other languages, the practice of
declaring subprograms and specifying the data types of parameters
becomes more important because other languages might not use the
BASIC default parameter-passing mechanisms. For more
information about calling subprograms written in other languages, see
Chapter 20.
13.3 Compiling Subprograms
A BASIC source file can contain multiple program units. When you compile such a file, BASIC produces a single object file containing the code from all the program units. You can then link this object file to create an executable image.
If the main program and subprograms are in separate source files, you can compile them separately from the DCL level. The following command causes BASIC to create MAIN.OBJ, SUB1.OBJ, and SUB2.OBJ by separating the file names with commas:
$ BASIC main,sub1,sub2 |
To link these programs, you must specify all object files as input to the OpenVMS Linker.
Alternatively, you can compile multiple modules into a single object file at the DCL command level by separating the file names with a plus sign (+) as follows:
$ BASIC main+sub1+sub2 |
The plus signs used to separate the file names instruct BASIC to create a single object file called MAIN.OBJ from the three source modules. To link this program, you specify only one input file to the linker. Note that in VAX BASIC, you cannot concatenate source files that do not contain line numbers.
In the VAX BASIC Environment, you can compile multiple program units with a resulting single object file by using the APPEND command followed by the COMPILE command. For more information about the APPEND and COMPILE commands, see Chapter 2.
When creating a multiple-unit program, follow these rules:
Note that in a multiple-unit program that contains line numbers, any comments or statements following an END, END SUB, or END FUNCTION statement become part of the preceding subprogram unless they begin on a numbered line. In a multiple-unit program that does not contain line numbers, however, any comments following an END, END SUB, or END FUNCTION statement become part of the following subprogram if one exists.
In the following example, the function Strip changes all brackets to parentheses in the string A$ or alpha, and strips all trailing spaces and tabs:
PROGRAM scan EXTERNAL STRING FUNCTION Strip (STRING) A$ = "USER$DISK:[BASIC.TRYOUTS]" B$ = Strip( A$ ) PRINT B$ END PROGRAM FUNCTION STRING Strip( STRING alpha ) IF (POS( alpha, "[", 1%)) > 0% THEN Strip = EDIT$(alpha, 128% +64%) ELSE Strip = EDIT$(alpha, 128%) END IF END FUNCTION |
Previous | Next | Contents | Index |