[an error occurred while processing this directive]
HP OpenVMS Systems Documentation |
HP BASIC for OpenVMS
|
Previous | Contents | Index |
To access a particular elementary component within a RECORD that contains other groups, you use the name of the declared RECORD instance, the group name (or group names, if groups are nested), and the elementary component name, each separated by double colons (::).
In the following example, the PRINT statement displays the Rig component in the Specifications group in the variable named My_yacht. The RECORD instance name qualifies the group name and the group name qualifies the elementary RECORD component. The elementary component name, qualified by all intermediate group names and by the RECORD instance name, is called a fully qualified component. The full qualification of a component is called a component path name.
DECLARE Yacht My_yacht . . . PRINT My_yacht::Specifications::Rig |
Because it is cumbersome to specify the entire component path name, BASIC allows elliptical references to RECORD components. GROUP names are optional in the component path name unless:
The rules for using elliptical references are as follows:
The following example shows that using the complete component path name is valid but not required. The assignment statement uses the fully qualified component name; the PRINT statement uses an elliptical reference to the same component, omitting Extended_family and Nuclear_family GROUP names. Note that the Children GROUP name is required because the GROUP is an array; the elliptical reference to this component must include the desired array element, in this case the second element of the Children array.
! RECORD templates: RECORD Family GROUP Extended_family STRING Grandfather(1) = 30 ! Two-element fixed-length string STRING Grandmother(1) = 30 ! arrays for the names of maternal ! and paternal grandparents. GROUP Nuclear_family STRING Father = 30 ! Fixed-length strings for the names STRING Mother = 30 ! of parents. GROUP Children (10) ! An 11-element array for the names and ! gender of children. STRING Kid = 10 STRING Gender = 1 END GROUP Children END GROUP Nuclear_family END GROUP Extended_family END RECORD ! Declarations DECLARE Family My_family ! Program logic starts here. My_family::Extended_family::Nuclear_family::Children(1)::Kid = "Johnny" PRINT My_family::Children(1)::Kid END |
Johnny |
! RECORD Templates. RECORD Test INTEGER Test_integers(2) ! 3-element array of integers. GROUP Group_1 ! Single GROUP containing: REAL My_number ! a real number and STRING Group_1_string ! a 16-character (default) string END GROUP GROUP Group_2(5) ! A 6-element GROUP, each element containing: INTEGER My_number ! an integer and DECIMAL Group_2_decimal ! a DECIMAL number. END GROUP END RECORD ! Declarations DECLARE Test Array_of_test(10) ! Create an 11-element array of type Test... DECLARE Test Single_test ! ...and a separate single instance of type ! Test. |
The minimal reference to the string Group_1_string in RECORD instance Array_of_test is as follows:
Array_of_test(i)::Group_1_string |
In this case, i is the subscript for array Array_of_test. Because the RECORD instance is itself an array, the reference must include a specific array element.
Because Single_test is not an array, the minimal reference to string Group_1_string in RECORD instance Single_test is as follows:
Single_test::Group_1_string |
The minimal reference for the REAL variable My_number in GROUP Group_1 in RECORD instance Array_of_test is as follows:
Array_of_test(i)::Group_1::My_number |
Here, i is the subscript for array Array_of_test. The minimal reference to the REAL variable My_number in RECORD instance Single_test is as follows:
Single_test::Group_1::My_number |
Because there is a variable named My_number in groups Group_1 and Group_2, you must specify either Group_1::My_number or Group_2(i)::My_number. In this case, extra component names are required to resolve an otherwise ambiguous reference.
The minimal reference to the DECIMAL variable Group_2_decimal in RECORD instances Array_of_test and Single_test are the fully qualified references. In the following examples, i is the subscript for array Array_of_test and j is an index into the group array Group_2. Even though Group_2_decimal is a unique component name within RECORD instance Single_test, the element of array Group_2 must be specified. In this case, the extra components must be specified because each element of GROUP Group_2 contains a component named Group_2_decimal.
Array_of_test(i)::Group_2(j)::Group_2_decimal Single_test::Group_2(j)::Group_2_decimal |
You can assign all the values from one RECORD instance to another RECORD instance, as long as the RECORD instances are identical except for names.
In the following example, RECORD instances First_test1, Second_test1, and the individual elements of array Array_of_test1 have the same form: an array of four groups, each of which contains a 10-byte string variable, followed by a REAL variable, followed by an INTEGER variable. Any of these RECORD instances can be assigned to one another.
!RECORD Templates RECORD Test1 GROUP Group_1(4) STRING My_string_1 = 10 REAL My_real_1 INTEGER My_integer_1 END GROUP END RECORD RECORD Test2 GROUP Group_2 STRING My_string_2 = 10 REAL My_real_2 INTEGER My_integer_2 END GROUP END RECORD RECORD Test3 STRING My_string_3 = 10 REAL My_real_3 INTEGER My_integer_3 END RECORD !Declarations DECLARE Test1 First_test1, & Second_test1, & Array_of_test1(3) DECLARE Test2 First_test2 DECLARE Test3 First_test3, & Array_of_test3(10) !Program logic starts here ! A single RECORD instance is assigned to another single instance First_test1 = Second_test1 ! An array element is assigned to a single instance Second_test1 = Array_of_test1(2) ! And vice versa Array_of_test1(2) = Second_test1 |
Further, you can assign values from single RECORD instances to groups contained in other instances.
In the following example, Array_of_test1 and First_test1 do not have the same form because Array_of_test1 is an array of RECORD Test1 and First_test1 is a single instance of RECORD Test1. Therefore, First_test1 and Array_of_test1 cannot be assigned to one another.
! A single instance is assigned to one group Array_of_test1(3)::Group_1(2) = First_test1 ! An array element is assigned a value from ! a group contained in another array instance Array_of_test3(5) = Array_of_test1(3)::Group_1(3) |
The examples shown in this chapter explain the mechanics of using data structures. See Chapter 12 for more information about using data structures as parameters. See Chapter 13 for more information about using data structures for file input and output.
This chapter describes the HP BASIC control statements.
HP BASIC normally executes statements sequentially. Control statements let you change this sequence of execution. HP BASIC control statements can alter the sequence of program execution at several levels:
Statement modifiers are control structures that operate on a single statement. Statement modifiers let you execute a statement conditionally or create a loop. The following are BASIC statement modifiers:
IF
UNLESS
FOR
UNTIL
WHILE
A statement modifier affects only the statement immediately preceding
it. You can modify only executable statements; declarative statements
cannot be modified.
9.1.1 IF Modifier
The IF modifier tests a conditional expression. If the conditional expression is true, HP BASIC executes the statement. If it is false, HP BASIC does not execute the modified statement but continues execution at the next program statement. The following is an example of a statement using the IF modifier:
PRINT A IF (A < 5) |
The UNLESS modifier tests a conditional expression. HP BASIC executes the modified statement only if the conditional expression is false.
PRINT A UNLESS (A < 5) |
This is equivalent to the following:
PRINT A IF A >= 5 |
The FOR modifier creates a loop on a single line. The following is an example of a loop created using the FOR modifier:
A = A + 1 FOR I% = 1% TO 10% |
The UNTIL modifier, like the FOR modifier, creates a single-line loop. However, instead of using a formal loop variable, you specify the terminating condition with a conditional expression. The modified statement executes repeatedly as long as the condition is false. For example:
B = B + 1 UNTIL (A - B) < 0.0001 |
The WHILE modifier repeats a statement as long as a conditional expression is true. Like the UNTIL and FOR modifiers, the WHILE modifier lets you create single-line loops. In the following example, HP BASIC replaces the value of A with A/2, as long as the absolute value of A is greater than one-tenth. Note that you can inadvertently create an infinite loop if the terminating condition is never reached.
A = A / 2 WHILE ABS(A) > 0.1 |
If you append more than one modifier to a statement, you are nesting modifiers. HP BASIC evaluates nested modifiers from right to left. If the test of the rightmost modifier fails, control passes to the next statement, not to the preceding modifier on the same line.
In the following example, HP BASIC first tests the rightmost modifier of the first PRINT statement. Because this condition is false, HP BASIC executes the following PRINT statement and tests the rightmost modifier. Because this condition is met, HP BASIC tests the leftmost modifier of the same PRINT statement. This condition, however, is not met. Therefore, HP BASIC executes the following PRINT statement. Because both conditions are met in the third PRINT statement, HP BASIC prints the value of C.
A = 5 B = 10 C = 15 PRINT "A =";A IF A = 5 UNLESS C = 15 PRINT "B =";B UNLESS C = 15 IF B = 10 PRINT "C =";C IF B = 10 UNLESS C = 5 END |
C = 15 |
Loops allow you to repeat the execution of a set of statements. This set of statements is called a loop block. There are three types of HP BASIC program loops:
FOR...NEXT
WHILE...NEXT
UNTIL...NEXT
Note that these types of loops can be nested, that is, lexically
located one inside another.
9.2.1 FOR...NEXT Loops
In a FOR...NEXT loop, you specify a loop control variable (the loop index) that determines the number of loop iterations. This number must be a scalar (unsubscripted) variable. When HP BASIC begins execution of a FOR...NEXT loop, the starting and ending values of the loop control variable are known.
The FOR statement assigns the control variable a starting value and an ending value. You can use the optional STEP clause to specify the amount to be added to the loop control variable after each loop iteration.
When a FOR loop block executes, the HP BASIC compiler performs the following steps:
Note that HP BASIC performs the test before the loop executes. When the control variable exceeds the ending value, HP BASIC exits the loop, and then subtracts the step value from the control variable. This means that after loop execution, the value of the control variable is the value last used in the loop, not the value that caused loop termination.
Example 9-1 assigns the values 1 to 10 to consecutive array elements 1 to 10 of New_array, and Example 9-2 assigns consecutive multiples of 2 to the odd-numbered elements of New_array.
Example 9-1 Assigning Values to Consecutive Array Elements |
---|
FOR I% = 1% TO 10% New_array(I%) = I% NEXT I% |
Example 9-2 Assigning Consecutive Multiples to Odd-Numbered Elements of Array |
---|
FOR I% = 1% TO 10% STEP 2 New_array(I%) = I% + 1% NEXT I% |
Note that the starting, ending, and step values can be run-time expressions. You can have HP BASIC calculate these values when the program runs, as opposed to using a constant value. For instance, the following example assigns sales information to array Sales_data. The number of iterations depends on the value of the variable Days_in_month, which represents the number of days in that particular month.
FOR I% = 1% TO Days_in_month Sales_data(I%) = Quantity_sold NEXT I% |
Because the starting, ending, and step values can be numeric expressions, they are not evaluated until the program runs. This means that you can have a FOR...NEXT loop that does not execute. The following example prompts the user for the starting, ending, and step values for a loop, and then tries to execute that loop. The loop executes zero times because it is impossible to go from 0 to 5 using a step value of -1.
counter% = 0% INPUT "Start"; start% INPUT "Finish"; finish% INPUT "Step value"; step_val% FOR I% = start% TO finish% STEP step_val% counter% = counter% + 1% NEXT I% PRINT "This loop executed"; counter%; "times." |
Start? 0 Finish? 5 Step value? -1 This loop executed 0 times. |
Whenever possible, you should use integer variables to control the execution of FOR...NEXT loops because some decimal fractions cannot be represented exactly in a binary computer, and the calculation of floating-point control variables is subject to this inherent imprecision.
In the following example, the first loop uses an integer control variable while the second uses a floating-point control variable. The first loop executes 100 times and the second 99 times. After the ninety-ninth iteration of the second loop, the internal representation of the value of Floating_point_variable exceeds 10 and BASIC exits the loop. Because the first loop uses integer values to control execution, HP BASIC does not exit the loop until Integer_variable equals 100.
Loop_count_1 = 0% Loop_count_2 = 0% FOR Integer_variable = 1% to 100% STEP 1% Loop_count_1 = Loop_count_1 + 1% NEXT Integer_variable FOR Floating_point_variable = 0.1 to 10 STEP 0.1 Loop_count_2 = Loop_count_2 + 1% NEXT Floating_point_variable PRINT "Integer loop count:"; Loop_count_1 PRINT "Integer loop end :"; Integer_variable PRINT "Real loop count: "; Loop_count_2 PRINT "Real loop end: "; Floating_point_variable |
Integer loop count: 100 Integer loop end: 100 Real loop count: 99 Real loop end: 9.9 |
Although it is not recommended programming practice, you can assign a
value to a FOR...NEXT loop's control variable while in the loop. This
affects the number of times a loop executes. For example, assigning a
value that exceeds the ending value of a loop will cause the loop's
execution to end as soon as HP BASIC performs the termination test
in the FOR statement. Assigning values to ending or step variables,
however, has no effect at all on the loop's execution.
9.2.2 WHILE...NEXT Loops
A WHILE...NEXT statement uses a conditional expression to control loop execution; the loop is executed as long as a given condition is true. A WHILE...NEXT loop is useful when you do not know how many loop iterations are required.
In the following example, the first statement instructs the user to input data and then type DONE when finished. After the user enters the first piece of input, HP BASIC executes the WHILE...NEXT loop. If the first input value is not "DONE", the loop executes and prompts the user for another input value. Once the user enters this input value, the WHILE...NEXT loop once again checks to see if this value corresponds to "DONE". The loop will continue executing until the user types "DONE" in response to the prompt.
INPUT 'Type "DONE" when finished'; Answer WHILE (Answer <> "DONE") . . . INPUT "More data"; Answer NEXT |
Note that the NEXT statement in the WHILE...NEXT and UNTIL...NEXT loops does not increment a control variable; your program must change a variable in the conditional expression or the loop will execute indefinitely.
The evaluation of the conditional expression determines whether the loop executes. The test is performed (that is, the conditional expression is evaluated) before the first iteration; if the value is false (0), the loop does not execute.
It can be useful to intentionally create an infinite loop by coding a
WHILE...NEXT loop whose conditional expression is always true. When
doing this you must take care to provide a way out of the loop. You can
do this with an EXIT statement or by trapping a run-time error. See
Chapter 15 for more information about trapping run-time errors.
9.2.3 UNTIL...NEXT Loops
The UNTIL...NEXT loop performs like a WHILE...NEXT loop, except that the logical sense of the conditional expression is reversed; that is, the UNTIL...NEXT loop executes until a given condition is true.
An UNTIL...NEXT loop executes repeatedly for as long as the conditional expression is false. Note that in UNTIL...NEXT loops, the NEXT statement does not increment a control variable. You must explicitly change a variable in the conditional expression or the loop will execute indefinitely.
It is possible to code the WHILE...NEXT loop with a UNTIL...NEXT loop, as shown in the following example. These loops are equivalent except for the logical sense of the termination test (WHILE Answer <> "DONE" as opposed to UNTIL Answer = "DONE").
INPUT 'Type "DONE" when finished.'; Answer UNTIL (Answer = "DONE") . . . INPUT "More data"; Answer NEXT |
Previous | Next | Contents | Index |