Compaq BASIC for OpenVMS
Alpha and VAX Systems
User Manual


Previous Contents Index

11.1.6.2 ECHO and NOECHO Functions

The NOECHO function disables echoing on a specified channel. Echoing is the process by which characters typed at the terminal keyboard appear on the screen.

If you specify channel #0 (your terminal) as the argument, the characters typed on the keyboard are still accepted as input; however, they do not appear on the screen.

The ECHO function enables echoing on a specified channel and cancels the effect of the NOECHO function on that channel.

If you do not use these functions, ECHO is the default. The following program shows a password routine in which the password does not echo:


Y% = NOECHO(0%) 
INPUT "PASSWORD"; pword$ 
IF pword$=="PLUGH" THEN PRINT "THAT IS CORRECT" 
END IF 
Y% = ECHO(0%) 
END 

Note that the Y% = ECHO(0%) statement is necessary to turn the echo back on. If this statement were not included, then all subsequent user inputs would not echo to the terminal screen.

11.1.6.3 INKEY$ Function

The INKEY$ function reads a single keystroke from a terminal opened on a specified channel and returns the typed character.

If you specify a channel that is not open, BASIC signals the error "I/O channel not open" (ERR=9). If a file or a device other than a terminal is open on the channel, BASIC signals the error "Illegal operation" (ERR=141).

Once you have specified a channel, BASIC allows you to specify an optional WAIT clause. A WAIT clause followed by no value tells BASIC to wait indefinitely for input to become available. A WAIT clause followed by a value from 1 to 255 tells BASIC to wait the specified number of seconds for input.


DECLARE STRING 
KEYSTROKE Inkey_Loop: WHILE 1%       KEYSTROKE = INKEY$(1%,WAIT) 
 
      SELECT KEYSTROKE 
          CASE '26'C 
               PRINT "Ctrl/Z to exit" 
               EXIT Inkey_Loop 
          CASE CR,LF,VT,FF,ESC 
               PRINT "Line terminator" 
          CASE "PF1" TO "PF4" 
               PRINT "P key" 
          CASE "E1" TO "E6" 
               PRINT "VT200 Function key" 
          CASE "KP0" TO "KP9" 
               PRINT "Application keypad key" 
          CASE < SP 
               PRINT "Control character" 
          CASE '127'C 
               PRINT "<DEL>" 
          CASE ELSE 
               PRINT "Character is "; KEYSTROKE 
       END SELECT 
NEXT 

11.2 User-Defined Functions

The DEF statement lets you create your own single-line or multiline functions.

In BASIC, a function name consists of the following:

Integer function names must end with a percent sign (%), and string function names must end with a dollar sign ($); therefore, the function name can have up to 31 characters. If the function name ends with neither a percent sign nor a dollar sign, the function returns a real number.

You can create user-defined functions using these function naming rules; however, it is recommended that you use explicit data typing when defining functions for new program development. See Chapter 13 for an example of an explicitly declared function. Note that the function name must start with FN only if the function is not explicitly declared, and a function reference lexically precedes the function definition.

DEF functions can be either single-line or multiline. Whether you use the single-line or multiline format for function definitions depends on the complexity of the function you create. In general, multiline DEF functions perform more complex functions than single-line DEF functions and are suitable for recursive operations.

If you want to pass values to a function, the function definition requires a formal parameter list. These formal parameters are the variables used to calculate the value returned by the function. When you invoke a function, you supply an actual parameter list; the values in the actual parameter list are copied into the formal parameter at this time. DEF functions allow up to 255 formal parameters. You can specify variables, constants, or array elements as formal parameters, but you cannot specify an entire array as a parameter to a DEF function.

11.2.1 Single-Line DEF Functions

In a single-line DEF, the function name, the formal parameter list, and the defining expression all appear on the same line. The defining expression specifies the calculations that the function performs. You can pass up to 255 arguments to this function through the formal parameter list. These parameters are variables local to the function definition, and each formal parameter can be preceded by a data type keyword.

The following example creates a function named fnratio. This function has two formal parameters: numer and denomin, whose ratio is returned as a REAL value.

When the function is invoked, BASIC does the following:

The PRINT statement then prints the returned value.


DEF REAL fnratio (numer, denomin) = numer / denomin 
PRINT fnratio(5.6, 7.8) 
END 

Output


 .717949 

Note that the actual parameters you supply must agree in number and data type with those in the formal parameter list; you must supply numeric values for numeric variables, and string values for string variables.

The defining expression for a single-line function definition can contain any constant, variable, BASIC built-in function, or any user-defined function except the function being defined. The following examples are valid function definitions:


DEF FN_A(X) = X^2 + 3 * X + 4 
DEF FN_B(X) = FN_A(X) / 2 + FN_A(X) 
DEF FN_C(X) = SQR(X+4) + 1 
DEF CUBE(X) = X ^ 3 

Note that the name of the last function defined does not begin with FN. This is valid as long as no reference to the function lexically precedes the function definition.

You can also define a function that has no formal parameters. The following function definition uses three BASIC built-in functions to return an integer corresponding to the day of the month:


DEF INTEGER fnday_number = VAL% (SEG$(DATE$(0%), 1%, 2%)) 

11.2.2 Multiline DEF Functions

The DEF statement can also define multiline functions. Multiline DEF functions are useful for expressing complicated functions. Note that multiline DEF functions do not have the equal sign and defining expression on the first line. Instead, this expression appears in the function block, assigned to the function name.

Note

If a multiline DEF function contains DATA statements, they are global to the program unit.

Multiline function definitions can contain any constant, variable, BASIC built-in function, or user-defined function. In BASIC, the function definition can contain a reference to the function you are defining. Therefore, a multiline DEF function can be recursive, or invoke itself; however, BASIC does not detect infinitely recursive DEF functions during compilation. If your program invokes an infinitely recursive DEF function, BASIC will eventually signal a fatal run-time error, typically the error "Access violation."

You can use either the END DEF or EXIT DEF statements to exit from a user-defined function. The EXIT DEF statement is equivalent to an unconditional transfer to the END DEF statement.

The following example shows a multiline DEF function that uses both the EXIT and END DEF statements. The defining expression of the function is in the ELSE clause. This assigns a value to the function if A is less than 10. The second set of output shows what happens when A is greater than 10; BASIC prints "OUT OF RANGE" and executes the EXIT DEF statement. The function returns zero because control is transferred to the END DEF statement before a value was assigned. In this way, this example tests the arguments before the function is evaluated.


DEF fn_discount(A) 
    IF A > 10 
    THEN 
       PRINT "OUT OF RANGE" 
       EXIT DEF 
    ELSE 
       fn_discount = A^A 
    END IF 
END DEF 
 
INPUT Z 
PRINT fn_discount(Z) 
END 

Output 1


? 4 
 256 

Output 2


? 12 
OUT OF RANGE 
 0 

If you do not explicitly declare the function with the DECLARE statement, the restrictions for naming a multiline DEF function are the same as those for the single-line DEF function; however, explicitly declaring a DEF function can make a program easier to read and understand. For instance, Example 1 concatenates two strings and Example 2 returns a number in a specified modulus.


DECLARE STRING FUNCTION concat (STRING, STRING) !Declare the function 
   .
   .
   .
DEF STRING concat (STRING Y, STRING Z) 
concat = Y + Z  !Define the function 
FNEND 
   .
   .
   .
new_string$ = concat(A$, B$) !Invoke the function 
   .
   .
   .
END 


DECLARE REAL FUNCTION mdlo (REAL, INTEGER) 
DEF mdlo( REAL  argument, INTEGER modulus ) 
  !Check for argument equal to zero 
 
  EXIT DEF IF argument = 0 
  !Check for modulus equal to zero, modulus equal to absolute 
  !value of argument, and modulus greater than absolute 
  !value of argument. 
 
  SELECT modulus 
  CASE = 0% 
      EXIT DEF 
  CASE > ABS( argument ) 
      EXIT DEF 
  CASE = ABS( argument ) 
      mdlo = argument 
      EXIT DEF 
  END SELECT 
 
  !If argument is negative, set flag negative% and set argument 
  !to its absolute value. 
  IF argument < 0 
     THEN argument = ABS( argument ) 
        negative%  = -1% 
  END IF 
  UNTIL argument < modulus 
        argument = argument - modulus 
 
        !If this calculation ever results in zero, mdlo returns zero 
        IF argument = modulus 
           THEN mdlo = 0 
           EXIT DEF 
        END IF 
  NEXT 
 
  !Argument now contains the right number, but the sign might be wrong. 
  !If the negative argument flag was set, make the result negative. 
 
  IF negative% 
     THEN mdlo = - argument 
     ELSE mdlo = argument 
  END IF 
 
END DEF 
 
INPUT "PLEASE INPUT THE VALUE AND THE MODULUS"; X,Y 
PRINT mdlo(X,Y) 
END 

Output


PLEASE INPUT THE VALUE AND THE MODULUS? 7, 5 
 2 

Because these functions are declared in DECLARE statements, the function names do not have to conform to the traditional BASIC rules for naming functions.

Recursion occurs when a function calls itself. The following example defines a recursive function that returns a number's factorial value:


DECLARE INTEGER FUNCTION factor ( INTEGER ) 
DEF INTEGER factor ( INTEGER F ) 
   IF F <= 0% 
      THEN factor = 1% 
      ELSE factor = factor(F - 1%) * F 
   END IF 
END DEF 
INPUT "INPUT N TO FIND N FACTORIAL"; N% 
PRINT "N! IS"; factor(N%) 
END 

Output


INPUT N TO FIND N FACTORIAL? 5 
N! IS 120 

Any variable accessed or declared in the DEF function and not in the formal parameter list is global to the program unit. When BASIC evaluates the user-defined function, these global variables contain the values last assigned to them in the surrounding program module.

To prevent confusion, variables declared in the formal parameter list should not appear elsewhere in the program. Note that if your function definition actually uses global variables, these variables cannot appear in the formal parameter list.

You cannot transfer control into a multiline DEF function except by invoking it. You should not transfer control out of a DEF function except by way of an EXIT DEF or END DEF statement. This means that:

A DEF function never changes the value of a parameter passed to it. Also, because formal parameters are local to the function definition, you cannot access the values of these variables from outside the DEF statement. These variable names are known only inside the DEF statement.

In the following example, the variable first is declared only in the function fn_sum. When BASIC sees the second PRINT statement, it assumes that first is a new variable that is not declared in the main program. If you try to run this example, BASIC signals the error "Explicit declaration of first required." If you do not specify the OPTION TYPE = EXPLICIT statement, BASIC assumes that first is a new variable and initializes it to zero.


OPTION TYPE = EXPLICIT 
DECLARE INTEGER A, B 
DEF fn_sum(INTEGER first, INTEGER second) = first + second 
A = 50 
B = 25 
PRINT fn_sum(A, B) 
PRINT first 
END 


Chapter 12
String Handling

This chapter defines dynamic and fixed-length strings and string virtual arrays, explains which you should choose for your application, and shows you how to use them.

12.1 Overview of Strings

A string is a sequence of ASCII characters. BASIC allows you to use the following types of strings:

Dynamic strings are strings whose length can change during program execution. The length of a dynamic string variable can change or not, depending on the statement used to modify it.

Fixed-length strings are strings whose length never changes. In other words, their length remains static. String constants are always fixed-length. String variables can be either fixed-length or dynamic. A string variable is fixed-length if it is named in a COMMON, MAP, or RECORD statement. If a string variable is not part of a map or common block, RECORD, or virtual array, it is a dynamic string. When a string variable is fixed-length, its length does not change, regardless of the statement you use to modify it. Table 12-1 provides more information about string modification.

Strings in virtual arrays have both fixed-length and dynamic attributes. String virtual arrays have a specified maximum length from 0 to 512 characters. During program execution, the length of an element in a string virtual array can change; however, the length is always from 0 to the maximum string size specified when the array was created. See Section 12.4 and Chapter 14 for more information about virtual arrays.

Table 12-1 String Modification
Statement Changes Made to
Fixed-Length Strings
Changes Made to
Dynamic Strings
LET Value Value and length
LSET Value Value
RSET Value Value
Terminal I/O
Statements 1
Value Value and length


1Terminal I/O statements include INPUT, INPUT LINE, LINPUT, MAT INPUT, and so on.

12.2 Using Dynamic Strings

Although dynamic strings are less efficient than fixed-length strings, they are often more flexible. For example, to concatenate strings, you can use the LET statement to assign the concatenated value to a dynamic string variable, without having to be concerned about BASIC truncating the string or adding trailing spaces to it. However, if the destination variable is fixed-length, you must make sure that it is long enough to receive the concatenated string, or BASIC truncates the new value to fit the destination string. Similarly, if you use LSET or RSET to concatenate strings, you must ensure that the destination variable is long enough to receive the data.

The LET, LSET, and RSET statements all operate on dynamic strings as well as fixed-length strings. The LET statement can change the length of a dynamic string; LSET and RSET do not. LSET and RSET are more efficient than LET when changing the value of a dynamic string. For more information about LSET and RSET, see Sections 12.5.2 and 12.5.3.

In the following example, the first line assigns the value "ABC" to A$, the second line assigns "XYZ" to B$, and the third line assigns six spaces to C$. These variables are dynamic strings. In the fourth line, LSET assigns A$ the value of A$ concatenated with B$. Because the LSET statement does not change the length of the destination string variable, only the first three characters of the expression A$ + B$ are assigned to A$. The fifth line uses LSET to assign C$ the value of A$ concatenated with B$. Because C$ already has a length of 6, this statement assigns the value "ABCXYZ" to it.


LET A$ = "ABC" 
LET B$ = "XYZ" 
LET C$ = "      " 
LSET A$ = A$ + B$ 
LSET C$ = A$ + B$ 
PRINT A$ 
PRINT C$ 
END 

Output


ABC 
ABCXYZ 

Like the LET statement, the INPUT, INPUT LINE, and LINPUT statements can change the length of a dynamic string, but they cannot change the length of a fixed-length string.

In this example, the first line assigns the null string to variable A$. The second line uses the LEN function to show that the null string has a length of zero. The third line uses the INPUT statement to assign a new value to A$, and the fourth and fifth lines print the new value and its length.


!Declare a dynamic string 
LET A$ = "" 
PRINT LEN(A$) 
INPUT A$ 
PRINT A$ 
PRINT LEN(A$) 
END 

Output


 0 
? THIS IS A TEST 
THIS IS A TEST 
 14 

You should not confuse the null string with a null character. A null character is one whose ASCII numeric code is zero. The null string is a string whose length is zero.

12.3 Using Fixed-Length Strings

It is generally more efficient to manipulate a fixed-length string than a dynamic string. Creating or modifying a dynamic string often causes BASIC to create new storage, and this increases processor overhead. Modifying fixed-length strings involves less overhead because BASIC manipulates existing storage using VAX character instructions.

If a string variable is part of a map or common block, or virtual array, a LET, INPUT, LINPUT, or INPUT LINE statement changes its value, but not its length. In the following example, the MAP statement in the first line explicitly assigns a length to each string variable. Because the LINPUT statements cannot change this length, BASIC truncates values to fit the address and city_state variables. Because the zip variable is longer than the assigned value, BASIC left-justifies the assigned value and pads it with spaces. The sixth line uses the compile-time constant HT (horizontal tab) to separate fields in the employee record.


MAP (FIELDS) STRING full_name = 10,                            & 
            address = 10,                                      & 
            city_state = 10,                                   & 
            zip = 10 
LINPUT "NAME"; full_name 
LINPUT "ADDRESS"; address 
LINPUT "CITY AND STATE"; city_state 
LINPUT "ZIP CODE"; zip 
EMPLOYEE_RECORD$ = full_name + HT + address + HT & 
                   + city_state + HT + zip 
PRINT EMPLOYEE_RECORD$ 
END 

Output


NAME? JOE SMITH 
ADDRESS? 66 GRANT AVENUE 
CITY AND STATE? NEW YORK NY 
ZIP? 01001 
 
JOE SMITH           66 GRANT A   NEW YORK N 01001 


Previous Next Contents Index