Control Flow Statements

FOR ... NEXT iteration statement


Syntax:

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

Parameters:

  • Data type: Number
    Counter 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.

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

Result:


 10
 9
 8
 7
 6
 5
 4
 3
 2
 1

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10

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

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 INTEGER | SINGLE | DOUBLE | SIZE_T ... NEXT iteration statement

BCX allows INTEGER, SINGLE, DOUBLE, and SIZE_T loop variable declarations. Using this option makes the variable local, in scope, to the loop. Variables used in defining a loop are local, in scope, 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
 
 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.


 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.

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.

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"

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 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:

BCX Console Sample Programs using GOSUB statement.

S107.bas, S134.bas,

EXIT statement

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


Syntax:

 EXIT CASE

 EXIT DO

 EXIT FOR

 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.

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.

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

Result:


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

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 AS STRING, Replacement$)
 
  SET rx = NOTHING
 
  FUNCTION = tmp$
 END FUNCTION
 

Result:


 ***123
 xyz***

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]
   ' more statements ..... 
 NEXT_EACH(LoopLocalVariable)

Do not DIM the LoopLocalVariable ... it is DIM'ed automatically. The name of the LoopLocalVariable must be provided as a parenthesis enclosed argument to the FOR_EACH and NEXT_EACH statements.

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(YY)
 NEXT_EACH(ZZ)
 
 PRINT
 PRINT "Displaying the STRING array one more time ..."
 PRINT
 
 FOR_EACH (HH, Strings$)
   PRINT "Cell No.", HH,  " Value = ", Strings$[HH]
 NEXT_EACH(HH)

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(iter)
 
 FOR_EACH (iter, Dict)
   IF Dict [iter, 1] = "Key 5" THEN PRINT "Found: ", Dict [iter, 2] : PRINT
 NEXT_EACH(iter)
 
 PRINT "Here are the complete contents" : PRINT
 
 FOR_EACH (iter, Dict)
   PRINT Dict [iter, 1] , "  ",  Dict [iter, 2]
 NEXT_EACH(iter)
 
 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 . . .