Previous | Contents | Index |
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 |
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 |
.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%)) |
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.
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 |
? 4 256 |
? 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 |
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 |
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 |
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.
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 |
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 |
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 |
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 |
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 |