[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP BASIC for OpenVMS
User Manual


Previous Contents Index

8.1.3 Accessing RECORD Components

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:

  • A RECORD contains more than one component with the same name
  • The GROUP is an array

The rules for using elliptical references are as follows:

  • You must always specify the RECORD instance, that is, the name of the declared variable.
  • You must always specify any dimensioned group.
  • You may omit any other intermediate component names.
  • You must specify the final component name.

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

Output


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.


Chapter 9
Program Control

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 control the execution of a single statement.
  • Loops or decision blocks control the execution of a block of statements.
  • Branching statements such as GOTO and ON GOTO pass control to statements or local subroutines.
  • The EXIT and ITERATE statements explicitly control loops or decision blocks.
  • The SLEEP, WAIT, STOP and END control statements suspend or halt the execution of your entire program.

9.1 Statement Modifiers

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)

9.1.2 UNLESS Modifier

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

9.1.3 FOR Modifier

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%

9.1.4 UNTIL Modifier

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

9.1.5 WHILE Modifier

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

9.1.6 Nesting Modifiers

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

Output


C = 15

9.2 Loops

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:

  1. Evaluates the starting value and assigns it to the control variable.
  2. Evaluates the ending value and the step value and assigns these results to temporary storage locations.
  3. Tests whether the ending value has been exceeded. If the ending value has already been exceeded, HP BASIC executes the statement following the NEXT statement. If the ending value has not been exceeded, HP BASIC executes the statements in the loop.
  4. Adds the step value to the control variable and transfers control to the FOR statement, which tests whether the ending value has been exceeded. Steps 3 and 4 are repeated until the ending value is exceeded.

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."

Output


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

Output


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