# 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:

- The letters FN
- From 1 to 28 letters, digits, underscores, or periods
- An optional percent sign or dollar sign

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:

- Copies the values 5.6 and 7.8 into the formal parameters numer and denomin
- Evaluates the expression to the right of the equal sign
- Returns the value to the statement that invoked the function (the PRINT statement)

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:

- DATE$(0) returns a date string in the form dd-Mmm-yy.
- The SEG$ function strips out of this value the characters starting at character position 1 up to and including the character at position 2 (the day number).
- The VAL% function converts this resulting numeric string to an integer. In this way, fnday_number returns the day of the month as an integer.

    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:

- If the DEF function contains an ON ERROR GOTO, GOTO, ON GOTO, GOSUB, ON GOSUB, or RESUME statement, that statement's target line number must also be in that DEF function.
- An ON ERROR GO BACK statement can transfer control out of a DEF function; however, a RESUME statement in an error handler outside the DEF function cannot transfer control back into the DEF function.
- If the DEF function contains a handler, and was invoked from a protected region, an EXIT HANDLER statement causes control to be transferred to the specified handler for that protected region. However, if the DEF function contains a handler but was not invoked from a protected region, an EXIT HANDLER statement causes control to be transferred to the default error handler.
- A subroutine cannot be shared by more than one DEF function; however, if you rewrite the subroutine as a DEF function with no parameters, other function definitions can share it.

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
- Fixed-length strings
- String virtual arrays

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