ControlFlow.md 16 KB

Control Flow Statements

FOR ... NEXT statement


 Syntax:

 FOR Counter = StartNumber TO EndNumber [ STEP StepNumber% ]
 Statements
 [ EXIT FOR ]
 NEXT

 Parameters:

  • Counter Integer variable or array.
  • StartNumber Integer, single or double variable or literal number.
  • EndNumber Integer, single or double variable or literal number.
  • StepNumber Integer variable or literal number.

Here is an easy to follow example that shows how BCX handles positive and negative STEP values(step up and step down).


 CLS

 DIM i, j, k, q

 j = 10
 k =  1
 q = -1

 FOR i = j TO k STEP q
   PRINT i
 NEXT

 PRINT

 j =  1
 k = 10
 q =  1

 FOR i = j TO k STEP q
   PRINT i
 NEXT

 KEYPRESS

To start the next iteration of a NEXT early in control loops see the description of the ITERATE function.

FOR INTEGER | SINGLE | DOUBLE ... NEXT statement

BCX allows INTEGER, SINGLE, and DOUBLE loop variable declarations. Using this option makes the variable LOCAL to the loop. Variables used in defining a loop are LOCAL to the loop and cannot be accessed from outside the loop. Here is an example.


 DIM I = 100, J = 200

 FOR DOUBLE I = 1.1 TO 18.7 STEP 1.1
   FOR INTEGER J = 1 TO 10 STEP 5
     ? USING$("#.##",I), " .....", J
   NEXT
 NEXT

 ? : ? : ? I , " ....." , J

Result:


 1.10 ..... 1
 1.10 ..... 6
 2.20 ..... 1
 2.20 ..... 6
 3.30 ..... 1
 3.30 ..... 6
 4.40 ..... 1
 4.40 ..... 6
 5.50 ..... 1
 5.50 ..... 6
 6.60 ..... 1
 6.60 ..... 6
 7.70 ..... 1
 7.70 ..... 6
 8.80 ..... 1
 8.80 ..... 6
 9.90 ..... 1
 9.90 ..... 6
 11.00 ..... 1
 11.00 ..... 6
 12.10 ..... 1
 12.10 ..... 6
 13.20 ..... 1
 13.20 ..... 6
 14.30 ..... 1
 14.30 ..... 6
 15.40 ..... 1
 15.40 ..... 6
 16.50 ..... 1
 16.50 ..... 6
 17.60 ..... 1
 17.60 ..... 6
 18.70 ..... 1
 18.70 ..... 6

 100 ..... 200

Note well ! Using floating point numbers for the start and end value of a FOR ... NEXT loop can cause problems. The basis of the difficulty is that some floating point numbers will be rounded up or down because they can not be represented, with absolute accuracy, bit for bit. One specific problem in a FOR ... NEXT loop is that this rounding of the floating point numbers, and more specifically that the rounding up of the accumulated value, may push beyond the end value causing the loop to end prematurely as in the following example.


 DIM I = 100, J = 200

 FOR DOUBLE I = 9.9 TO 18.7 STEP 1.1
   FOR INTEGER J = 1 TO 10 STEP 5
     ? USING$("#.##",I), " .....", J
   NEXT
 NEXT

 ? : ? : ? I , " ....." , J

Result:


 9.90 ..... 1
 9.90 ..... 6
 11.00 ..... 1
 11.00 ..... 6
 12.10 ..... 1
 12.10 ..... 6
 13.20 ..... 1
 13.20 ..... 6
 14.30 ..... 1
 14.30 ..... 6
 15.40 ..... 1
 15.40 ..... 6
 16.50 ..... 1
 16.50 ..... 6
 17.60 ..... 1
 17.60 ..... 6

 100 ..... 200

The problem is not simply the number of steps. For example, in the example above the start value is different but the end value and STEP are the same as in the previous example which works as expected. The upward rounding problem can be guarded against by adding one-half of the STEP value to the end value. To apply this correction in the example above, the line


 FOR DOUBLE I = 9.9 TO 18.7 STEP 1.1

would be changed to


 FOR DOUBLE I = 9.9 TO 19.25 STEP 1.1

To start the next iteration of a NEXT early in control loops see the description of the ITERATE function.

WHILE ... WEND statement


 Syntax:

 [ DO ] WHILE expression ' "DO" is optional
  EXIT LOOP  OR EXIT DO
 WEND

To start the next iteration of a WEND early in control loops see the description of the ITERATE function.

DO [UNTIL] ... LOOP [UNTIL] [WHILE] statement


 Syntax 1:

 DO
  Statements
 IF Condition THEN
  EXIT LOOP | EXIT DO
 END IF
  More Statements
 LOOP

or


 Syntax 2:

 DO UNTIL Condition
  Statements
 LOOP

or


 Syntax 3:

 DO
  Statements
 LOOP UNTIL Condition

or


Syntax 4:

 DO
   Statements
 LOOP WHILE Condition

Remarks: See ITERATE to start the next iteration of a LOOP early in control loops.

IF...THEN...ELSE...ELSEIF...END IF [ENDIF] statements


 Syntax 1:

 IF Expression THEN
  Statement
 END IF

 Syntax 2:

 IF  Expression1 THEN
  Statements
 ELSEIF Expression THEN
  Statements
 ELSE
  Statements
 END IF

SELECT CASE statement


 Syntax:

 SELECT CASE  Expression
  CASE  Expression1
   your code here
  CASE Expression2
    ... ' CASE Expression is tested for equality against all
    ... ' SELECT CASE expression and executes the instructions
    ... ' following if CASE found TRUE.
  CASE  Expression N
    your code here
  CASE ELSE
    your default code here
 END SELECT

Remarks:

CASE statements allow the following common construct:


 CASE 1 TO 10

which will capture the flow if the CASE is any number between 1 and 10.

Also allowed are less than greater than comparisons like


 CASE > 5 AND < 9

The OR operator also may be used, for example,


 CASE < 4 OR > 9

The NOT operator may be used as well, for example,


 CASE <> "BCX"

When a conditional operator(AND or OR) is used, scalar operators(= or < or > etc.) preceding the test expression must be used.


 CASE = "Selector" OR = "Selectee"

The following line is not valid and will cause an error.


 CASE "Selector" OR "Selectee"

However, in the example above, the OR can be replaced with a comma to form a valid CASE test statement.


 CASE "Selector", "Selectee"

Arrays, functions and variations of variables that contain the dereferencing operator(->) may be used as arguments to the CASE statement, for example,


 CASE A[1] TO A[9]
 
 CASE foo->f,foo->g
 
 CASE Funcfoo(A[foo->f],"nada"), foo->g
 
 CASE > foo->f AND < Funfoo(A[1])

Example 1:


 DIM Choose$
 
 Choose$ = "SelectOR"
 
 SELECT CASE Choose$
  CASE = "SelectOR" OR = "SelectXOR"
  PRINT "Selected"
 END SELECT

Example 2:


SELECT CASE

variants:


 DIM i

 INPUT "Enter a number: ", i

 SELECT CASE i
   CASE 1
    PRINT "1"

   CASE 2 TO 4
    PRINT "2 TO 4"

   CASE 5
    PRINT "5"

   CASE >5 AND <9
    PRINT ">5 AND <9"

   CASE 9
    PRINT "9"
 END SELECT

BCX translates the above SELECT CASE block as:


  while(1)
 {
 if(i==1)
   {
     printf("%s\n","1");
     break;
   }
 if(i>=2&&i<=4)
   {
     printf("%s\n","2 TO 4");
     break;
   }
 if(i==5)
   {
     printf("%s\n","5");
     break;
   }
 if(i>5&&i<9)
   {
     printf("%s\n",">5 AND <9");
     break;
   }
 if(i==9)
   {
     printf("%s\n","9");
   }
 break;
 }
SELECT CASE BAND

may be used. This statement suppresses breaks between CASE statements and performs a binary AND on all CASE statements. Here is an example.


 SELECT CASE BAND Style
 CASE WS_CHILD : CONCAT(StyleString$,"WS_CHILD,")
 CASE WS_VISIBLE : CONCAT(StyleString$,"WS_VISIBLE,")
 CASE WS_TABSTOP : CONCAT(StyleString$,"WS_TABSTOP")
 END SELECT

Here is an another example using

SELECT CASE BAND:

A status code is returned in lParam from which, depending on the bits set, the messages can be determined. This is how it would normally be written:


 ' IF lParam BAND CE_BREAK THEN err$=err$ + "CE_BREAK "
 ' IF lParam BAND CE_FRAME THEN err$=err$ + "CE_FRAME "
 ' IF lParam BAND CE_IOE THEN err$=err$ + "CE_IOE "
 ' IF lParam BAND CE_MODE THEN err$=err$ + "CE_MODE "
 ' IF lParam BAND CE_OVERRUN THEN err$=err$ + "CE_OVERRUN "
 ' IF lParam BAND CE_RXOVER THEN err$=err$ + "CE_RXOVER "
 ' IF lParam BAND CE_RXPARITY THEN err$=err$ + "CE_RXPARITY "
 ' IF lParam BAND CE_TXFULL THEN err$=err$ + "CE_TXFULL"

Here is a similar solution using


SELECT CASE BAND.

Note well that breaks are suppressed when using the


SELECT CASE BAND,

otherwise the flow would exit after the first match.


 SELECT CASE BAND lParam
 CASE CE_BREAK : CONCAT(err$,"CE_BREAK ")
 CASE CE_FRAME : CONCAT(err$,"CE_FRAME ")
 CASE CE_IOE : CONCAT(err$,"CE_IOE ")
 CASE CE_MODE : CONCAT(err$,"CE_MODE ")
 CASE CE_OVERRUN : CONCAT(err$,"CE_OVERRUN ")
 CASE CE_RXOVER : CONCAT(err$,"CE_RXOVER ")
 CASE CE_RXPARITY : CONCAT(err$,"CE_RXPARITY ")
 CASE CE_TXFULL : CONCAT(err$,"CE_TXFULL")
 END SELECT

GOTO statement

Purpose: Redirects program flow to a label.


 Syntax:

 GOTO Label

Remarks: A note about labels.

  • Labels must be appended with a colon(:).
  • Labels are not case sensitive.
  • Labels must appear on their own line.

BCX Console Sample Programs using GOTO function.

S01.bas, S134.bas

GOSUB ... RETURN statement

Purpose: GOSUB redirects program flow to a label. The flow continues from the label until a RETURN statement is encountered and the flow is returned to the line following the GOSUB Label statement.


 Syntax:

 GOSUB Label

 Label:
  Statements
 RETURN

Remarks: A note about labels.

  • Labels must be appended with a colon(:).
  • Labels are not case sensitive.
  • Labels must appear on their own line.

BCX Console Sample Programs using GOSUB statement.

S104.bas, S107.bas, S134.bas,

EXIT statement

Purpose: Causes EXIT of a DO...LOOP, FOR...NEXT, SELECT ... END SELECT, REPEAT... END REPEAT loop, or FUNCTION or SUB


 Syntax:

 EXIT CASE

 EXIT DO

 EXIT FOR

 EXIT IF

 EXIT LOOP

 EXIT REPEAT

 EXIT SELECT

 EXIT WHILE

The EXIT statements above translate to C code break;

The EXIT statements below translate to C code return;


 EXIT FUNCTION

 EXIT SUB

Please note well that, unlike some BASIC dialects, the BCX implementation of EXIT will not allow a nested EXIT as in the following example where an attempt is made to EXIT the DO LOOP from a CASE in the SELECT CASE structure.


 DIM int1%

 DO

   int1++

   SELECT CASE int1%

     CASE 1

     CASE 2
      EXIT DO ' This does not work.
              ' The SELECT...END SELECT structure
              ' is exited, not the DO ... LOOP.
   END SELECT

   IF int1% > 2 THEN
     PRINT "Did not EXIT DO"
     EXIT LOOP
   END IF

 LOOP

The only way to jump from a nested flow control structure is to use a GOTO


 DIM int1%

 DO

    int1++

    SELECT CASE int1%

       CASE 1

       CASE 2
       PRINT "Jumping out of DO...LOOP"
       GOTO jmp1

    END SELECT

    IF int1% > 2 THEN
       PRINT "Did not EXIT DO"
       EXIT LOOP
    END IF

 LOOP

jmp1:

END statement

Purpose: Immediately terminates a running program


 Syntax:

  END

REPEAT ... END REPEAT statement

Purpose: REPEAT / END REPEAT blocks allow you to create loops without the need of a loop variable. BCX translates these to "C" style for/next loops that instead use TEMPORARY variables that are LOCAL TO THE LOOP.

Example:


 CLS

 REPEAT 2
   REPEAT 5
     PRINT "Here is an example of nested REPEATS"
   END REPEAT
 END REPEAT

 PRINT

 DIM Iterations

 INPUT "Type a number, press ENTER ", Iterations

 REPEAT(Iterations+1+((Iterations+1)*2))
   PRINT "Calculated Expressions Allowed in REPEAT/END REPEAT"
 END REPEAT

To count backwards, the argument must begin with a minus sign. The "add a minus sign" rule is the same rule that BCX has always used in FOR/NEXT statements that contain a negative STEP clause. "add a minus sign" is the only way that BCX can detect and respond to the logic flow at compile time.

Examples :


 REPEAT -10
 REPEAT -A
 REPEAT -(A*2+100)

See ITERATE to start the next iteration of a END REPEAT early in control loops.

EXIT REPEAT immediately breaks the flow out of a REPEAT block.

BCX_REPEAT variable

The BCX_REPEAT variable automatically keeps count of how many times REPEAT has been executed within a REPEAT ... END REPEAT block.

Example:


  REPEAT 2
  PRINT BCX_REPEAT
   REPEAT 5
    PRINT "... ", BCX_REPEAT
   END REPEAT
 END REPEAT

Here's another sample.


  DIM a
  a = -10

 REPEAT -ABS(a)
  PRINT BCX_REPEAT
  IF BCX_REPEAT = 5 THEN EXIT REPEAT
 END REPEAT

WITH ... END WITH statement

Purpose: WITH ... END WITH allows repeated reference to be made to an user defined type object or structure.


 Syntax:

 WITH UserDefinedTypeObject
   [ statements ]
 END WITH

Example 1:


 TYPE QWERTY
  DIM a
  DIM b!
  DIM c$ [80]
  DIM q AS RECT
 END TYPE

 GLOBAL MyType [10,10,10] AS QWERTY

 WITH MyType[2,3,4]
 .a = 1
 .b! = 2.345
 .c$ = "Hello world from a poly-dimensional udt!"
 WITH .q
 .left = 100
 .right = 200
 .top = 150
 .bottom = 300
 END WITH
 PRINT .a
 PRINT .b!
 PRINT UCASE$(.c$)
 END WITH

Example 2:


 TYPE Foo
 One AS LONG
 Two AS LONG
 Three AS LONG
 END TYPE

 DIM MyArray AS Foo

 WITH MyArray
 .One = 1
 .Two = 2
 .Three= 3
 PRINT .One
 PRINT .Two
 PRINT .Three
 END WITH