Control Flow Statements

FOR ... NEXT iteration statement

Purpose:

The FOR ... NEXT loop is a control flow statement that iterates a section of code repeatedly until the specified condition has been satisfied.

Syntax:

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

Parameters:

  • Data type: Number
    Counter Loop iterator variable or array identifier.
  • Data type: Number
    StartNumber Integer, single or double variable or literal number.
  • Data type: Number
    EndNumber Integer, single or double variable or literal number.
  • Data type: Number
    StepNumber Integer variable or literal number.

👉 BCX uses the C/C++ rule of evaluating StartNumber, EndNumber, and StepNumber arguments on each iteration of a FOR ... NEXT loop. This allows dynamic changes to the loop bounds or step values during the loop's execution. PureBasic, also, uses the C/C++ rule.

Microsoft GW-BASIC, QBASIC, and Visual Basic, as well as, FreeBASIC, VB, and PowerBASIC, evaluate, only once, the start, end, and step arguments in a FOR ... NEXT loop.

Example 1:

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

CLS

DIM AS INTEGER Counter, StartNumber, EndNumber, StepNumber

StartNumber = 1
EndNumber = 10
StepNumber = 1

FOR Counter = StartNumber TO EndNumber STEP StepNumber
  PRINT Counter
NEXT

PRINT

StartNumber = 10
EndNumber = 1
StepNumber = -1

FOR Counter = StartNumber TO EndNumber STEP StepNumber
  PRINT Counter
NEXT

PAUSE

Result:

1
2
3
4
5
6
7
8
9
10

10
9
8
7
6
5
4
3
2
1

Press any key to continue . . .

Remarks:

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

Example 2:

👉 Underflow possibilities exist when any unsigned number is used for the count in a FOR ... NEXT loop coded to terminate at zero (0). Here is an example that will create an underflow. Press Any Key To Quit !

DIM AS UINT TheCounter, TheCount, EndNumber

TheCount = 255
EndNumber = 0
FOR TheCounter = TheCount TO EndNumber STEP -1
  PRINT " Press Any Key To Quit !", TheCounter
  IF INKEY$ <> "" THEN
    EXIT FOR
  END IF
NEXT

FOR DataType ... NEXT iteration statement

Purpose:

BCX allows integrated loop iterator variable declarations. Using this option declares the loop iterator inline and makes the iterator variable local, in scope, to the loop.

Syntax 1:

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

Syntax 2:

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

Parameters:

  • Data type: DataType Number
    DataType Counter Loop iterator variable or array identifier prepended wih DataType. Most scalar data types are a valid DataType of Loop Iterator Variable. Valid types are SINGLE, DOUBLE, FLOAT, CHAR, SHORT, INTEGER, INT, LONG, LLONG, LONGLONG, BYTE, SBYTE, UBYTE, USHORT, UINT, UINT64, ULONG, ULONGLONG, UCHAR, INT8_T, INT16_T, INT32_T, INT64_T, SSIZE_T UINT8_T, UINT16_T, UINT32_T, UINT64_T, SIZE_T
  • Data type: Number
    StartNumber Integer, single or double variable or literal number.
  • Data type: Number
    EndNumber Integer, single or double variable or literal number.
  • Data type: Number
    StepNumber Integer variable or literal number.

👉 BCX uses the C/C++ rule of evaluating StartNumber, EndNumber, and StepNumber arguments on each iteration of a FOR ... NEXT loop. This allows dynamic changes to the loop bounds or step values during the loop's execution. PureBasic, also, uses the C/C++ rule. Microsoft GW-BASIC, QBASIC, and Visual Basic, as well as, FreeBASIC, VB, and PowerBASIC, evaluate, only once, the start, end, and step arguments in a FOR ... NEXT loop.

Example 1:

Here is the above Example 1:, the only difference being that the Loop iterator variable, Counter, is declared inline.

CLS

DIM AS INTEGER StartNumber, EndNumber, StepNumber

StartNumber = 1
EndNumber = 10
StepNumber = 1

FOR INTEGER Counter = StartNumber TO EndNumber STEP StepNumber
  PRINT Counter
NEXT

PRINT

StartNumber = 10
EndNumber = 1
StepNumber = -1

FOR INTEGER Counter = StartNumber TO EndNumber STEP StepNumber
  PRINT Counter
NEXT

PAUSE

Example 2:

Because a Loop iterator variable is local, in scope, to the loop, the same variable, in the case of the example below "Both", also can be used as a Global.

DIM Both = 100, J = 200

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

? : ? : ? Both , " ....." , J

PAUSE

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

Press any key to continue . . .

Remarks:

👉 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 cannot 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 2:

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 instance, 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.

FOR_EACH ... NEXT_EACH statement

Purpose:

FOR_EACH ... NEXT_EACH iterates statements for each member of a one-dimensional, statically dimensioned array.

Syntax:

FOR_EACH (LoopLocalVariable, NameOfOneDimensionalArray)
  PRINT " Value = ", NameOfOneDimensionalArray [LoopLocalVariable]
  [ EXIT_EACH ]
  ' more statements ..... 
NEXT_EACH

👉 Do not DIM the LoopLocalVariable ... it is DIM'ed automatically.

Example 1:

Here is an example showing a nested FOR_EACH loop:

DIM Numbers[3] AS SINGLE

Numbers[0]=0.000
Numbers[1]=1.111
Numbers[2]=2.222
           
DIM Strings[3] AS STRING

Strings$[0]="ZERO"
Strings$[1]="ONE"
Strings$[2]="TWO"

CLS
PRINT "Displaying the NUMERIC array ..."
PRINT

FOR_EACH (ZZ, Numbers)
  PRINT "Cell No.", ZZ, " Value = ", Numbers[ZZ]
  FOR_EACH (YY, Strings)
    PRINT "Now Showing a NESTED FOR_EACH LOOP: ", Strings[YY]
  NEXT_EACH
NEXT_EACH

PRINT
PRINT "Displaying the STRING array one more time ..."
PRINT

FOR_EACH (HH, Strings$)
  PRINT "Cell No.", HH,  " Value = ", Strings$[HH]
NEXT_EACH

Result:

Displaying the NUMERIC array ...

Cell No. 0 Value =  0
Now Showing a NESTED FOR_EACH LOOP: ZERO
Now Showing a NESTED FOR_EACH LOOP: ONE
Now Showing a NESTED FOR_EACH LOOP: TWO
Cell No. 1 Value =  1.111
Now Showing a NESTED FOR_EACH LOOP: ZERO
Now Showing a NESTED FOR_EACH LOOP: ONE
Now Showing a NESTED FOR_EACH LOOP: TWO
Cell No. 2 Value =  2.222
Now Showing a NESTED FOR_EACH LOOP: ZERO
Now Showing a NESTED FOR_EACH LOOP: ONE
Now Showing a NESTED FOR_EACH LOOP: TWO

Displaying the STRING array one more time ...

Cell No. 0 Value = ZERO
Cell No. 1 Value = ONE
Cell No. 2 Value = TWO

Example 2:

Here is an example using a two (2) dimensional string array to simulate a poor mans dictionary:

DIM Dict[10,10] AS STRING
CLS

FOR_EACH (iter, Dict)
  Dict [iter, 1] = "Key" + STR$(iter)
  Dict [iter, 2] = "Value" + STR$(iter)
NEXT_EACH

FOR_EACH (iter, Dict)
  IF Dict [iter, 1] = "Key 5" THEN PRINT "Found: ", Dict [iter, 2] : PRINT
NEXT_EACH

PRINT "Here are the complete contents" : PRINT

FOR_EACH (iter, Dict)
  PRINT Dict [iter, 1] , "  ",  Dict [iter, 2]
NEXT_EACH

PAUSE

Result:

Found: Value 5

Here are the complete contents

Key 0  Value 0
Key 1  Value 1
Key 2  Value 2
Key 3  Value 3
Key 4  Value 4
Key 5  Value 5
Key 6  Value 6
Key 7  Value 7
Key 8  Value 8
Key 9  Value 9

Press any key to continue . . .

XFOR ... XNEXT iteration statement

Syntax:

XFOR [StartParameters] [ WHILE ... UNTIL Condition] [ BY VariableChanges]
Statements
[ EXIT XFOR ]
XNEXT

Parameters:

  • StartParameters This can be any of the normal variables in a typical FOR ... NEXT loop and, as well, can be a pointer to a type or string.
  • Condition This can be any condition that applies to WHILE and UNTIL.
  • VariableChanges This parameter can increment and decrement variables and reassign pointers.

Remarks:

👉 With all of the parameters being optional, the following is legal and results in generation of a for ever loop

XFOR WHILE BY
PRINT "Type Ctrl C to stop this!"
XNEXT

Example 1:

Here is an example that uses XFOR ... XNEXT in the program which calculates and prints the combinations of a subset of items in a set.

DIM SetItemCount%
DIM SubSetItemCount%
DIM SubSetCount%
DIM start AS clock_t
DIM finish AS clock_t
DIM duration#

INPUT "Total number of items in set? ", SetItemCount%
INPUT "Number of items in one subset combination? ", SubSetItemCount%
PRINT

start = clock()
SubSetCount% = SubSets(SetItemCount%, SubSetItemCount%)
finish = clock()
duration# = ROUND((DOUBLE)(finish - start) / CLOCKS_PER_SEC, 2)

PRINT
PRINT "It took", duration#, " seconds to calculate that"
PRINT "there are", SubSetCount%, " combinations of", SubSetItemCount%, " item subsets in a set of", SetItemCount%, " items."


FUNCTION SubSets% (n%, k%)
  RAW buffer%[100]
  DIM i% = 0
  DIM j%
  DIM SSCnt%

  XFOR j = 0 WHILE j <= n BY j++
    buffer[j] = 0
  XNEXT

  WHILE i >= 0
    IF (buffer[i] < n + i - k + 1) THEN
      buffer[i]++
      IF (i = k - 1) THEN
        XFOR j = 0 WHILE j < k BY j++
          PRINT buffer[j];
        XNEXT
        PRINT
        SSCnt++
      ELSE
        buffer[++i] = buffer[i - 1]
      END IF
    ELSE
      i--
    END IF
  WEND
  FUNCTION = SSCnt%
END FUNCTION

Result:

Total number of items in set? 5
Number of items in one subset combination? 3

 1 2 3
 1 2 4
 1 2 5
 1 3 4
 1 3 5
 1 4 5
 2 3 4
 2 3 5
 2 4 5
 3 4 5

It took 0 seconds to calculate that
there are 10 combinations of 3 item subsets in a set of 5 items.

Example 2:

Here is a more complex example using XFOR ... XNEXT.

' Make a file of names.

OPEN "NAMES.TXT" FOR OUTPUT AS FPOUT
FPRINT FPOUT, "John G.";",";"Kemeny"
FPRINT FPOUT, "Thomas E.";",";"Kurtz"
FPRINT FPOUT, "Mary Kenneth";",";"Keller"
CLOSE

' Read in from file
' and display input.

TYPE tagLink
  DIM szFirst$
  DIM szLast$
  DIM ptNxt AS tagLink PTR
END TYPE

DIM pzNames AS tagLink PTR
DIM ptCurrent AS tagLink PTR
pzNames = (tagLink*)calloc(1, SIZEOF(tagLink))
OPEN "NAMES.TXT" FOR INPUT AS FPIN

XFOR ptCurrent = pzNames WHILE NOT EOF(FPIN) BY ptCurrent = ptCurrent->ptNxt = (tagLink*)calloc(1, SIZEOF(tagLink))
  FINPUT FPIN, ptCurrent->szFirst$, ptCurrent->szLast$
XNEXT

XFOR ptCurrent = pzNames WHILE ptCurrent BY ptCurrent = ptCurrent->ptNxt
  PRINT ptCurrent->szFirst$; " "; ptCurrent->szLast$
XNEXT
PAUSE

Result:

John G. Kemeny
Thomas E. Kurtz
Mary Kenneth Keller

Example 3:

And here is an even more complex example using XFOR ... XNEXT.

TYPE tagRECORD
  DIM sName[16] AS CHAR
  DIM iAge AS INT
  DIM ptPRV AS tagRECORD PTR
  DIM ptNXT AS tagRECORD PTR
END TYPE

DIM szBuf$
DIM ptHIGH AS tagRECORD PTR
DIM ptLOW AS tagRECORD PTR
DIM ptHead AS tagRECORD PTR

AddRec("Jim",  22)
AddRec("Jane", 23)
AddRec("Alex", 22)
AddRec("Mary", 24)
AddRec("John", 26)
AddRec("Steve",29)
AddRec("Sally",25)
AddRec("Zak",  21)
AddRec("Betty",29)
AddRec("Clive",26)
AddRec("Doris",28)
AddRec("Kelly",22)

sprintf(szBuf, "%12s%4s%3s", "Name", "", "Age")
PRINT szBuf$
  
XFOR INT i = 1,  tagRECORD PTR ptRL = ptLOW WHILE ptRL <> NULL BY i++, ptRL = ptRL->ptNXT
sprintf(szBuf, "%14s  %3i", ptRL->sName, ptRL->iAge)
PRINT szBuf$
XNEXT

PRINT
sprintf(szBuf, "%12s%4s%3s", "Name", "", "Age")
PRINT szBuf$; " "; szBuf$
XFOR INT i = 1, INT j = 12, tagRECORD PTR ptRL = ptLOW, tagRECORD PTR ptRH = ptHIGH  WHILE i < j BY i++, j--, ptRL = ptRL->ptNXT, ptRH = ptRH->ptPRV
sprintf(szBuf, "%14s  %3i %14s  %3i", ptRL->sName, ptRL->iAge, ptRH->sName, ptRH->iAge)
PRINT szBuf$
XNEXT

PAUSE

SUB AddRec (pszN$, iA AS INT)
  RAW ptTMP AS tagRECORD PTR
  ptTMP = (tagRECORD *)calloc(1,SIZEOF(tagRECORD))
  ptTMP->sName$ = pszN$
  ptTMP->iAge = iA

  IF ptHead = NULL THEN
    ptHIGH = ptLOW = ptHead = ptTMP
    EXIT SUB
  END IF
 
  RAW ptREC AS tagRECORD PTR
  XFOR ptREC = ptHead WHILE ptREC <> NULL AND ptREC->iAge < iA BY ptREC = ptREC->ptNXT
  XNEXT

  IF ptREC = NULL THEN
    ptHIGH->ptNXT = ptTMP
    ptHIGH->ptNXT->ptPRV = ptHIGH
    ptHIGH = ptTMP
    EXIT SUB
  END IF

  IF ptREC = ptHead THEN
    ptTMP->ptNXT = ptHead
    ptHead->ptPRV = ptTMP
    ptHead = ptLOW = ptTMP
  ELSE
    ptTMP->ptNXT = ptREC
    ptREC->ptPRV->ptNXT = ptTMP
    ptTMP->ptPRV = ptREC->ptPRV
    ptREC->ptPRV = ptTMP
  END IF
  
END SUB

Result:

       Name    Age
          Zak   21
        Kelly   22
         Alex   22
          Jim   22
         Jane   23
         Mary   24
        Sally   25
        Clive   26
         John   26
        Doris   28
        Betty   29
        Steve   29

       Name    Age         Name    Age
          Zak   21          Steve   29
        Kelly   22          Betty   29
         Alex   22          Doris   28
          Jim   22           John   26
         Jane   23          Clive   26
         Mary   24          Sally   25

WHILE ... WEND iteration statement

Syntax:

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

Example:

DIM RetStr$

RetStr$ = NumberToRoman$(3999)
?  RetStr$

RetStr$ = NumberToRoman$(0xF9F)
?  RetStr$

RetStr$ = NumberToRoman$(%07637)
?  RetStr$

RetStr$ = NumberToRoman$(0b111110011111)
?  RetStr$

FUNCTION NumberToRoman$ (NumberToConvert%)

  DIM FunctionReturnString$

  SET RomanNumerals[] AS PCHAR
    "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"
  END SET

  SET ArabicNumerals%[]
    1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1
  END SET

  DIM Counter%
  WHILE (NumberToConvert)
    WHILE (NumberToConvert / ArabicNumerals[Counter])
      CONCAT(FunctionReturnString$, RomanNumerals[Counter])
      NumberToConvert -= ArabicNumerals[Counter]
    WEND
    Counter++
  WEND
  FUNCTION = FunctionReturnString$
END FUNCTION

Result:

MMMCMXCIX
MMMCMXCIX
MMMCMXCIX
MMMCMXCIX

Remarks:

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

DO ... LOOP iteration statement

Syntax 1:

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

Example:

DIM a

DO
  a++
  IF a > 45 THEN
    EXIT LOOP
  END IF
  ?  a
LOOP

Result:

1
...
45

DO UNTIL ... LOOP iteration statement

Syntax 2:

DO UNTIL Condition
 Statements
LOOP

Example:

DIM a

DO UNTIL a > 45
  a++
  ?  a
LOOP

Result:

1
...
46

DO ... LOOP UNTIL iteration statement

Syntax 3:

DO
 Statements
LOOP UNTIL Condition

Example:

DIM a

DO
  a++
  ?  a
LOOP UNTIL a > 45

Result:

1
...
45

DO ... LOOP WHILE iteration statement

Syntax 4:

DO
  Statements
LOOP WHILE Condition

Example:

DIM a

DO
  a++
  ?  a
LOOP WHILE a < 45

Result:

1
...
45

Remarks:

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

ITERATE statement

Purpose:

ITERATE will start the next iteration of a loop early in control loops

Syntax 1:

ITERATE

Remarks:

ITERATE has the effect of jumping to the LOOP, WEND, NEXT or END REPEAT at the end of the currently executing block.

Example:

DIM A,B

CLS

PRINT "This will print Iterations 7 thru 10 of the outer loop"
PRINT "and will print the numbers 999 and 1000 from within"
PRINT "the inner loop. All 10,000 iterations still occur,"
PRINT "it's the ADDED LEVEL OF CONTROL within your loops that "
PRINT "ITERATE gives to you."

FOR B = 1 TO 10
 IF B < 7 THEN ITERATE
 PRINT
 PRINT "<Outer Loop> Iteration Number", B
 FOR A=1 TO 1000
  IF A < 999 THEN ITERATE
  PRINT ">Inner Loop< Iteration Number", A
 NEXT
NEXT

Result:

This will print Iterations 7 thru 10 of the outer loop
and will print the numbers 999 and 1000 from within
the inner loop. All 10,000 iterations still occur,
it's the ADDED LEVEL OF CONTROL within your loops that
ITERATE gives to you.

 Iteration Number 7
>Inner Loop< Iteration Number 999
>Inner Loop< Iteration Number 1000

 Iteration Number 8
>Inner Loop< Iteration Number 999
>Inner Loop< Iteration Number 1000

 Iteration Number 9
>Inner Loop< Iteration Number 999
>Inner Loop< Iteration Number 1000

 Iteration Number 10
>Inner Loop< Iteration Number 999
>Inner Loop< Iteration Number 1000

IF ... THEN ... ELSE ... ELSEIF ... END IF or ENDIF selection statements

Syntax 1:

IF Expression THEN
 Statement
END IF

Syntax 2:

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

Example:

DIM i

WHILE i < 10
 INCR i
 IF i = 5 THEN
  PRINT "Five"
 ELSEIF i = 7 THEN
  PRINT "Seven"
  EXIT WHILE
 END IF
WEND

PRINT "The final value of i =" ; i

PAUSE

Result:

Five
Seven
The final value of i = 7

Example:

👉 The IF ... THEN code above can be expressed as a single line but only with a modification. ELSEIF will not be parsed correctly when embedded in a single line conditional statement. ELSE IF, instead, must be used.

DIM i

WHILE i < 10
  INCR i
  IF i = 5 THEN PRINT "Five" ELSE IF i = 7 THEN PRINT "Seven" : EXIT WHILE
WEND

PRINT "The final value of i =" ; i

PAUSE

Result:

Five
Seven
The final value of i = 7

SELECT CASE selection 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.

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

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"

Also allowed are less than, greater than, comparisons like

CASE > 5 AND < 9

The OR operator also may be used for less than, greater than, comparisons, for example,

CASE < 4 OR > 9

The scalar not equal <> operator may be used as well, for example,

CASE <> "BCX"

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 "less than 1"

  CASE 1
  PRINT "1"

  CASE 2 TO 4
  PRINT "2 to 4 inclusive"

  CASE 5
  PRINT "5"

  CASE >5 AND <9
  PRINT "greater than 5 and less than 9"

  CASE 9
  PRINT "9"

  CASE >9
  PRINT "greater than 9"
END SELECT

SELECT CASE BAND also may be used. This statement performs a binary AND on all CASE statements.

👉 In the C code translation, breaks normally inserted between the CASE statements are suppressed when using SELECT CASE BAND, otherwise the flow would exit after the first match.

Example:

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

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"

Example:

Here is a similar solution using SELECT CASE BAND.

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 jump statement

Purpose:

GOTO redirects program flow to a label.

Syntax:

GOTO Label

Label:

Remarks:

BCX Console Sample Programs using the GOTO function.

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:

BCX Console Sample Programs using the GOSUB statement.

EXIT statement

Purpose:

Causes EXIT from a
DO ... LOOP,
FOR ... NEXT,
FOR_EACH ... NEXT_EACH,
REPEAT ... END REPEAT,
loop,
a
SELECT ... END SELECT,
construct,
or a FUNCTION or SUB.

Syntax:

EXIT CASE

EXIT DO

EXIT FOR

EXIT_EACH

EXIT LOOP

EXIT REPEAT

EXIT SELECT

EXIT WHILE

EXIT FUNCTION

EXIT SUB

When translated with the BCX -w flag, the following code generates a warning with the code generated exiting out of inner most FOR ... NEXT loop

DIM iW, iX, iY
FOR iW = 1 TO 2
  FOR iX = 1 TO 5
    iY = iX+1
    WHILE iY < 10
      PRINT iX;iY
      IF iY = iX THEN EXIT FOR
      iY++
      iY = IMOD(iY,10)
    WEND
  NEXT
  PRINT iX;iY
NEXT

When translated with the BCX -w flag, the following code generates a warning with code generated exiting out of the XFOR ... XNEXT loop

DIM iW, iX, iY
XFOR iW = 1 WHILE iW < 2 BY iW++
FOR iX = 1 TO 5
  FOR iY = 1 TO 5
    IF iY + iX + iW = 10 THEN EXIT XFOR
    PRINT iW;iX;iY
  NEXT
NEXT
XNEXT
PRINT iW;iX;iY

When translated with BCX, the following code will generate an error since there is no DO ... LOOP.

DIM iX, iY
FOR iX = 1 TO 5
  FOR iY = iX+1 TO 5
    PRINT iX;iY
    IF iY +iY > 7 THEN EXIT DO
  NEXT
NEXT

EXIT without a control named results in a warning message with the innermost loop named. The code generated results in the exiting of the innermost control loop.

EXIT NEST statement

Purpose:

Causes an EXIT out of the nest of current loop types to the positon in the code where a different loop type is encountered.

Syntax:

EXIT NEST

Example 1:

This example will EXIT from the nested DO loops when (w+x)*(y+z) > 20.

DIM w, x, y, z
w = 0

WHILE w < 10
  x = 0
  WHILE x < 5
    y = 0
    DO
      z = 0
      DO
        IF (w+x)*(y+z) > 20 THEN
        PRINT "Exit Nest"
        EXIT NEST
        END IF
        z++
        PRINT "z Pass"; z
      LOOP UNTIL z > 4
      y++
    LOOP UNTIL y > 4
    PRINT "w equals"; w
    x++
  WEND
  w++
WEND
PRINT "At end w equals"; w
PAUSE

EXIT SELECT statement

Purpose:

Causes an EXIT out of the SELECT ... END SELECT.

Syntax:

EXIT SELECT

Example 1:

Here is a general example of when one might need EXIT SELECT

SELECT CASE SomeCondition

  CASE Condition_1

  IF SomeFlagIsSet THEN
    EXIT SELECT
  ELSE
    Do_Condition_1_Thing() ' Only if SomeFlagIsSet = FALSE
  END IF

  CASE Condition_2
  Do_Condition_2_Thing()

  CASE Condition_3
  Do_Condition_3_Thing()

END SELECT

Example 2:

Here is an specific example using EXIT SELECT

$BCXVERSION "6.50"

DIM WajYaDoing$, SelexitFlag$, TheThing$, What$

SelexitFlag$ = "Selexit"
What$ = "One"
TheThing$ = ToBeDone$(What$)
PRINT WajYaDoing$
PRINT TheThing$
PRINT

SelexitFlag$ = "NoSelexit"
What$ = "One"
TheThing$ = ToBeDone$(What$)
PRINT WajYaDoing$
PRINT TheThing$
PRINT


FUNCTION ToBeDone$ (DoSomething$)

  DIM Retstr$

  SELECT CASE DoSomething$

  CASE "One"

    IF SelexitFlag$ = "Selexit" THEN
      WajYaDoing$ = "I'm Selexiting."
      Retstr$ = "See if I care ..."
      EXIT SELECT
    ELSE
      WajYaDoing$ = "I'm not Selexiting. "
      Retstr$ = "You had your chance. No whining. No excuses."
    END IF

  END SELECT

  FUNCTION = Retstr$

END FUNCTION

Result:

I'm Selexiting.
See if I care ...

I'm not Selexiting.
You had your chance. No whining. No excuses.

EXIT SUB statement

Purpose:

Subroutines can be prematurely exited by using the EXIT SUB statement.

Example:

JumpOut()

PRINT a$

SUB JumpOut ()
GLOBAL a$
a$ = "JumpOut"
 IF a$ = "JumpOut" THEN
  EXIT SUB
 END IF
 PRINT "Didn't get out. Too bad !"
END SUB

Result:

JumpOut

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

Result:

Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS
Here is an example of nested REPEATS

Type a number, press ENTER 3
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in REPEAT/END REPEAT
Calculated Expressions Allowed in 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.

Example:

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

Result:

 1
...  1
...  2
...  3
...  4
...  5
 2
...  1
...  2
...  3
...  4
...  5

Example:

Here's another sample.

DIM a
a = -10

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

Result:

 1
...  1
...  2
...  3
...  4
...  5
 2
...  1
...  2
...  3
...  4
...  5

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] AS CHAR
  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!"
  PRINT .a
  PRINT .b!
  PRINT UCASE$(.c$)
  WITH .q
    .left = 100
    .right = 200
    .top = 150
    .bottom = 300
    PRINT .left
    PRINT .top
    PRINT .right
    PRINT .bottom
  END WITH
END WITH

Result:

 1
 2.345
HELLO WORLD FROM A POLY-DIMENSIONAL UDT!
 100
 150
 200
 300

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

Result:

1
2
3

Example 3:

? Rx$("xyz123", "[a-z]", "*") ' replace letters 
? Rx$("xyz123", "[0-9]", "*") ' replace numbers 

'---------------------------------------------------------- 
FUNCTION Rx$ (MainStr AS STRING, Pattern$, Replacement$)
 '---------------------------------------------------------- 
 DIM rx AS OBJECT : rx = CREATEOBJECT("VBScript.RegExp")

 WITH rx
  .IgnoreCase = TRUE
  .global = TRUE
  .Pattern = Pattern$
 END WITH

 DIM tmp$ : tmp$ = rx.replace(MainStr, Replacement$)

 SET rx = NOTHING

 FUNCTION = tmp$
END FUNCTION

Result:

***123
xyz***