Control Flow Statements
FOR ... NEXT statement
Syntax: FOR Counter = StartNumber TO EndNumber [ STEP StepNumber% ] Statements [ EXIT FOR ] NEXT Parameters:
|
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
|
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.
BCX Console Sample Programs using 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: A note about labels.
BCX Console Sample Programs using GOSUB statement.
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