4.9 Control structures
Within the EXPERIMENT
section flow control structures can be
used. These are REPEAT
, WHILE
, UNTIL
, FOR
and
FOREVER
loops and IF-ELSE
and UNLESS-ELSE
constructs. (Please note: all of these keywords have to be spelt in
upper case letters!).
Most flow control construct keywords are followed by a condition and all
are then followed by a block of statements. Such a block of statements
has to be enclosed in curly braces ({
and }
) and may
contain as many statements as needed (and still fit into the computers
memory).
• REPEAT loops | ||
• WHILE loops | ||
• UNTIL loops | ||
• FOR loops | ||
• FOREVER loops | ||
• NEXT statement | ||
• BREAK statement | ||
• IF-ELSE constructs | ||
• UNLESS-ELSE constructs |
4.9.1 REPEAT loops
The most simple construct is the REPEAT
loop. What is needed
following the keyword REPEAT
is a number and a block with
commands. The number should be an integer number (or an expression
resulting in an integer). The following block of statements will now be
repeated as many times as specified by the number (or
expression). Here's an example:
I = 0; SUM = 0; REPEAT 100 { I = I + 1; SUM = SUM + I; } |
This snippet will calculate the sum of all integers between 1 and 100
(of course, there are more elegant ways to do this, but it's just an
example). After the initialization of the two variables `I
' and
`SUM
' the REPEAT
loop starts with 100 as the number of
repetitions. Now, in curly braces, i.e. between `{
' and
`}
', follow the statements to be executed in the loop.
Please note: If the number of repetitions of the loop is a variable or an expression the variable or expression will be evaluated just once at the very start, i.e. once before the loop is executed, so if you change the value of the variable (or the variables involved in the expression) within the loop the number of repetitions won't change.
4.9.2 WHILE loops
Nearly as simple a construct is the WHILE
loop, but instead of a
simple number following the keyword a condition is needed. Usually, this
will be a comparison between two numbers, but also a simple number will
suffice - if its value is non-zero it will be interpreted as TRUE. Of
course, the keyword and the condition have to be followed by a block of
statements.
Again, an example:
I = 1; Fact = 1; WHILE I <= 6 { Fact = Fact * I; I = I + 1; } |
This snippet (that also could have been written using a REPEAT
loop) calculates the factorial of 6. After initializing the variables
I
and Fact
it is tested in the loop condition if I
is still not larger that 6. If this is true, the following block of
statements is executed.
Here is now an example for using simple numbers in a condition, using the fact that a non-zero value is always interpreted as TRUE:
I = 6; Fact = 1; WHILE I { Fact *= I; I -= 1; } |
This example does exactly the same as the previous one, i.e. it
calculates the factorial of 6. But the difference is that we start with
`I' set to 6 and than decrement it successively. Thus we can use
`I
' in the loops condition by simply checking if it still is
non-zero and thus the condition still TRUE and repeating the loop as
long as it is.
Sometimes, you may want to check not for the truth but for the falsehood
of an expression. In this case you have to prepend the expression with
an exclamation mark, `!
', or the equivalent logical not
operator, `NOT
', to reverse the meaning of a test (or use an
UNTIL
loop, see below).
If you want to check for combinations of expressions you can use the
logical AND
, OR
or XOR
(exclusive or)
operators. Here is a list of these operators and their meaning:
NOT
or!
not: negates truth of an expression AND
or&
and: true if both left and right hand side expressions are true OR
or|
or: true if at least one of the left and right hand side expressions is true XOR
or~
exclusive or: true if either left or right hand side expression is true (but not both)
Please note: For both the logical or operator (`OR
'
or `|
') and the logical and operator (`AND
' or
`&
') the expressions are always only evaluated as far as
necessary to determine the final result. Thus for the condition
A == 0 OR B != 3 |
only the first part, A == 0
, is tested when A
is 0
because in this case the result is already known to be true and does not
depend on the second comparison. The same holds for expressions like
A != 0 AND lockin_phase( ) > 90.0 |
If A
equals 0
the value of the whole expression is
already known to be false even though the lock-ins phase may be less
then 90 degrees. Thus no call of the function
lockin_phase()
will be done.
Thus the sequence in conditions containing the logical "or" and "and" operator is important.
To make it more clear please understand that the code (please read about
the IF
and ELSE
constructs below for more details)
IF A == 0 OR B != 3 { do_something( ); } |
is treated as if you would have written
IF A == 0 { do_something( ); } ELSE IF B != 3 { do_something( ); } |
In the same way
IF A != 0 AND lockin_phase( ) > 90 { do_something( ); } |
is logically equivalent to
IF A != 0 { IF lockin_phase( ) > 90 { do_something( ); } } |
All comparison operators can also be used with strings. The test
for equality has its usual meaning (but take care, in the comparison
lower and upper case characters are treated as different). The
comparison for larger or smaller than is based on the ASCII values of the
characters of the string, not the lengths of the strings. For example,
the comparison of the strings "ON"
and "OFF"
will result
in "ON"
being larger than "OFF"
because for the first
characters where the strings differ, 'N'
and 'F'
,
'N'
has a higher ASCII value than 'F'
.
4.9.3 UNTIL loops
Directly related to the WHILE
loop is the UNTIL
loop. The
only difference is that, instead of repeating the loop until the
condition becomes false, the UNTIL
loop is repeated until the
loop condition becomes true. Thus, the second example for calculating
the factorial of 6 also could have been written as
I = 6; Fact = 1; UNTIL I == 0 { Fact *= I; I -= 1; } |
4.9.4 FOR loops
Before the start of a WHILE
loop one usually has to initialize a
loop variable and within the statement block one has to update it. In
many cases (for example in both the examples for the WHILE
loop
above) it's much simpler to use a FOR
loop instead, because
setting the loop variable as well as updating it is automatically done
in its condition part. Here's an example that does exactly the same as
the first of the two examples for WHILE
loops:
Fact = 1; FOR I = 1 : 6 { Fact *= I; } |
At the very start of the FOR
loop the loop variable `I
'
is set to 1 and the loop body is run using this value. When the of the
loops body is reached`I
' is automatically incremented by 1 and
then it's tested if it is still less or equal to 6. If this is
TRUE
the loop is repeated with the new value of `I
'.
Take care: You can change `I
' also within the loop, but you
only should do this if you really mean it and know what you're doing!
But you can also reproduce the second version of the factorial
calculation using a FOR
loop. Here it is:
Fact = 1; FOR I = 6 : 1 : -1 { Fact *= I; } |
Now `I
' starts of with the value 6 and the third value in the
FOR
loop condition part is the value to be used for incrementing
`I
'. In this case it is -1, so `I
' actually will be
decremented until it is smaller than 1 (the second value in the
FOR
loop condition). As you see, FOR
loop variables can
not only be incremented by 1 but by any value (integer or floating point
ones). And, of course, the loop variable doesn't have to be an integer!
Please note that after the end of a FOR
loop the loop variable
does not has the value it had in the last run through the loop but that
it has been incremented (or decremented) one more time. I.e. after the
end of the loop
FOR I = 1 : 9 : 2 { do_something( ); } |
the loop variable I
has the value 11
and not 9
.
Please also note that the end and increment value os evaluated only at the start of the loop. Thus if you would have
End = 10; Incr = 1; FOR I = 1 : End : Incr { End = 20; Incr = 2; } |
the changes done to the variables End
and Incr
don't
have any effect on when the loop ends or on how the loop variable
is incremented, it will still stop when the loop variable I
reaches 10 and I
will continue to be incremented by 1. You
will have to use a WHILE
loop if you want to change the
end of a loop or the increment from within a loop.
4.9.5 FOREVER loops
There are situations where one wants to have the program running as long
as the STOP
button doesn't get pressed. While something like this
can be realized by using i.e. a REPEAT
loop with a huge number
of repeats, this would take extremely long when testing the script before
the EXPERIMENT
is started. In these cases a FOREVER
loop is
more convenient because the content of the loop is only tested once, so
the experiment can start much faster. For obvious reasons, a
FOREVER
loop doesn't have a loop condition and the loop block
starts directly after the FOREVER
keyword.
There is a disadvantage of using a
FOREVER
loop: becausefsc2
can't determine in advance when theFOREVER
loop is going to be terminated it is not possible to test the loop thoroughly in the test run, i.e. before the experiment is started. Instead, in the test run aFOREVER
loop is just run once to do a plausibility check, but further tests are not feasible. Thus, it can not be guaranteed that the experiment will run without errors. Therefore the use ofFOREVER
loops should be restricted to preliminary experiments, e.g. when trying to figure out the optimum parameters for an experiment, unless you're quite sure you know what you are doing.
4.9.6 NEXT statement
Sometimes under certain conditions one doesn't want to execute all
remaining statements of a WHILE
, UNTIL
, REPEAT
or
FOR
loop but to go back to the test of the loop condition
immediately. Whenever the keyword NEXT
is encountered in a loop
all the remaining statements are skipped and the program jumps directly
back to the test of the loop condition.
4.9.7 BREAK statement
There also may be situations where one doesn't want to continue with a
loop until the loop condition becomes satisfied but where one has to
exit the loop immediately. For this purpose the keyword BREAK
is
to be used. If it is found as the next statement to be executed in a
loop the program immediately jumps to the first statement following the
loops block.
4.9.8 IF-ELSE constructs
Finally, there is the IF-ELSE
construct, functioning as in most
other programming languages. In the simplest case you just have the
IF
part to execute instructions only under certain conditions.
In this case you start with the IF
keyword, followed by the
condition that has to be met in order to run the following code and
then the set of statements to be enclosed in curly braces. Here's a
simple example:
IF x < 0 { x *= -1.0; } |
Here the variable x
is multiplied by -1.0
only if
x
is negative, i.e. it basically just sets x
to its
absolute value (there's also the built-in function abs()
for calculating the absolute value of variable which probably is a lot
faster).
By using the ELSE
statement you can specify an alternative with
statements to be executed if the IF
condition is not being met.
Also the block of alternative statements must be enclosed in curly
braces:
IF x >= 0 { x = 1.0; } ELSE { x = 0.0; } |
But things can also get more complex - you may follow the ELSE
directly by another IF
. Let's assume that you need to set
x
to 1 if it's larger than 1, to 0 if it belongs to the interval
[0, 1] and to -1 if it's smaller than 0. Then you could use:
IF x > 1.0 { x = 1.0; // x is larger than 1 } ELSE IF x >= 0.0 { x = 0.0; // x must be element of [0, 1] } ELSE { x = -1.0; // otherwise x is less than 0 } |
4.9.9 UNLESS-ELSE constructs
UNLESS
is identical to IF
with the only exception that the
condition is not tested for truth but for falsehood, i.e. while in an
IF
construct the following block of statements is executed when
the condition is true, in UNLESS
constructs the block is only
executed when the condition test fails. Of course, also with the
UNLESS
an alternative can be specified with an ELSE
block.
As already mentioned for
FOREVER
loops alsoIF-ELSE
andUNLESS-ELSE
constructs introduce some problems for testing anEDL
script before the real experiment is done. This happens when the condition to be tested depends either on user input (e.g. tests if the user pressed a button etc.) or on the results of a measurement itself. In these cases the flow of control of the program can not be known in advance and thus a thorough test is impossible. Thus it can happen that the test run of the experiment succeeds but the actual experiment stops with an error that could not be anticipated.
This document was generated by Jens Thoms Toerring on September 6, 2017 using texi2html 1.82.