5. Control Statements

Control statements determine the order in which the UniScript program is executed.

5.1. The if-else Statement

The if-else statement is a conditional statement. It has the following syntax:

if (condition) {
    if statements
} else {
    else statements
}

The expression condition has to be a real scalar. The if statement will be executed if the condition is true. This means that the expression is not equal to 0. The else statement will be executed if the condition is false. else is optional.

if (condition) {
    if statements
}

If the if and else statements consist of only one statement, the braces are not necessary.

a = 1;
if (a == 1) print "a equal 1" else print "a not equal 1"

It is easier to read if you write the statements in separate lines:

a = 1
if (a == 1) {
    print "a equal 1"
} else {
    print "a not equal 1"
}

The following syntax is not allowed in UniScript and will result in a syntax error. The second brace will be interpreted as the end of the if-else statement.

a = 1;
if (a == 1)
{
    print "a equal 1";
}
    else
{
    print "a not equal 1";
}

As mentioned previously, the condition must be a real scalar. The expression string == "Hello" returns a real scalar if string is a scalar. The expression will return 1 if string holds the string "Hello". Otherwise, it will return 0. If string is a vector or a matrix of strings, the expression will return a real vector or a real matrix. For example, if string is a vector with the three elements ["Hello", "HELLO", "hello"], the expression will return a real vector with the elements [1, 0, 0]. To convert this vector to a real scalar you can use one of the UniScript functions all and any. The function all returns TRUE (1) if all elements of the input vector are not zero, otherwise the function returns the value 0. The any function returns 1 if at least one of the elements of the input vector is not zero, otherwise the function returns the value 0. If the argument of the function all or any is a real matrix, the matrix will be evaluated columnwise. In this case, the return value is a row vector. When the argument is a matrix and you use all or any twice, the return value is a scalar.

The following example will execute the if statements if all elements of the string variable have the value "Hello", no matter if string is a scalar, vector or matrix.

if (all(all(string == "Hello"))) {
    if statements
} else {
    else statement
}

The if-else statements can be used to make a decision out of multiple choices:

if (condition-1) {
    statements-1
} else if (condition-2) {
    statements-2
} else if (condition-3) {
    statements-3
} else {
    Statements-n
}

The conditions will be checked one after the other until one condition is true. After the statements are executed, the else-if chain is finished. If no condition is true, the last else case will be executed.

5.2. The for Statement

The for statement is used to iterate the overall elements of a vector. The general form of the for statement is

for (i in vector) {
    statements
}

If vector has the value [1, 3, 6, 4], then i takes the values 1, 3, 6, 4 one after the other. vector can also be a string vector or a complex vector.

The vector will only be evaluated once at the beginning of the for loop. The following example

a = [1,2,3]
for (i in a) {
    a = 0;
    printf("a = %d, i = %d\n", a, i);
}

generates the output

a = 0, i = 1
a = 0, i = 2
a = 0, i = 3

The following example will open two UniScript files:

svFilename = ["plot.ic", "alias.ic"];
svFilename = GetRootDirectory() + "script/" + ..
             svFilename;
for (ssName in svFilename) {
    EdCreate(ssName);
}

5.3. The while Statement

The while statement is used to execute one or more statements repeatedly. A while statement has the following syntax:

while (condition) {
    statements
}

The condition expression must be a real scalar. The statements will be executed as long the condition is true, i.e. a value not equal to 0.

while (1) {
    print "Hello"
}

would print the word "Hello" indefinitely, because the condition will never be 0. This loop can only be interrupted by pressing the ESCAPE key (ESC). The while(1) statement can also be interrupted by a break or return statement.

The following while loop will print the word "Hello" 10 times and then print the number 11.

i = 1;
while (i <= 10) {
    print "Hello";
    i = i + 1;
}
print i;

5.4. The break and continue Statement

The break statement is used to terminate within an iteration statement. break can be used in the statement body of a while or for loop.

Some programming languages have iteration statements which check the condition at the end of the loop (the repeat statement in Pascal or the do statement in C). In UniScript, the behavior of such control statements can be simulated with the break statement. The following example will print the string "Hello" 10 times and will then print the number 10.

i = 1;
while (1) {
    print "Hello";
    if (i == 10) break;
    i = i + 1;
}
print i;

The continue statement is used inside a while or for loop to skip over the rest of the statements and to continue with the next loop cycle immediately. The next example opens all files with the extension .ipw.

ssPath = "c:/uniplot/samples/";
svFiles = FindFiles(ssPath + "*.*");

for (ssName in ssPath + svFiles[;1]) {
    if (strupper(SplitPath(ssName)[4]) != ".IPW") {
        continue;
    }
    if (DocCreate(ssName) == 0) break;
}

The function call FindFiles(ssPath + "*.*") returns a string matrix of the files in the ssPath directory. The first column holds the file names, the second column the file size, and the third column holds the file attributes. In our example, we are only interested in the file names. The expression svFiles[;1] selects all elements of the first column.

The function SplitPath splits a complete file name into items: drive, path, name and extension. Therefore, the call SplitPath(ssName)[4] returns the extension of the file ssName. strupper converts its argument into upper case characters.

If the condition is true, i.e. the file does not have the extension ".ipw", the continue statement will be executed and the next file name will be evaluated. If the condition is false, the function DocCreate will load the file. If the file cannot be opened, DocCreate returns 0. The loop will be terminated because of the break statement.

If we had called the FindFiles function with the search pattern "*.ipw", we would have found all wanted files without using the for loop and the continue statement.

5.5. The try-except Statement

The try-except statement can be used to handle programming errors. It has the following syntax:

try {
    try statements
} except (condition) {
    except statements
}

In contrast to the if-else statement, the second block in the try-except statement is not optional. Every try block has exactly one except block. try-except statements can be nested.

Normally, only the try statement is executed. The condition and the except statement will only be executed in case of an error in the try statement. There are many reasons why a problem can occur while executing a statement.

Examples:

  • Not enough memory is available to execute the statement.
  • The user pressed the ESC key inside a try statement.
  • A vector element that does not exist was accessed.
  • An error occurs inside a function call within a try statement body.
  • The error function was called inside the function body.

1 and 2 are problems which the programmer cannot avoid but 3 and 4 are programming errors. In case 5 (call of the error function) an exception was created deliberately.

Example:

def GetTextFile(ssFileName)
{
    fp = fopen(ssFileName, "rt");
    ssText = fread(fp, "char");
    fclose(fp);
    return ssText;
}

The function fopen opens a file for reading, fread reads the file, and fclose closes the file. It is important to close the file as soon as possible, because the operating system only allows a limited number of simultaneous open files.

If you call GetTextFile("d:\\test.txt"), the function will return the contents of the file d:\test.txt as a string, if it exists, if all function calls are error free, if enough memory is available and if the user did not press the ESC key. If one of these exceptions occurs before the call of the function fclose, a so called resource loss will occur.

This problem can be solved by protecting the statements with a try-except statement.

def GetTextFile(ssFileName)
{
    fp = 0;
    try {
        fp = fopen(ssFileName, "rt");
        ssText = fread(fp, "char");
        if (isreal(ssText)) error();
        fclose(fp);
        return ssText;
    } except (1) {
        if (fp != 0) {
            fclose(fp);
        }
        MessageBox("File cannot be loaded!");
        return "";
    }
}

If an exception occurs inside the try body, the program branches into the except body to clean up the function. In our example, the open file will be closed and an error message will be displayed.

The keyword except is followed by a condition expression in parentheses. If the condition is false (0), the exception statements are not executed. If the condition is true (equal 1), the except statement is executed. With the function GetExceptionCode, the exception type can be received.

Example:

def TestException(a, b)
{
    try {
        i = 0;
        while (1) {
            x = a + b;
            i = i + 1;
        }
    } except (GetExceptionCode() == ICERR_INTERRUPT) {
        MessageBox(..
              sprintf("User Abort (i = %d", i"));
    }
}

If the function is called with the parameters "a" and 1.6 (TestException("a", 1.6)), an exception will occur and the exception condition will be evaluated.

GetExceptionCode() == ICERR_INTERRUPT, ICERR_OPERATOR_TYPE

GetExceptionCode returns an error code - in this case the error code with the name ICERR_OPERATOR_TYPE. Because the error code is not ICERR_INTERRUPT, the except statement will not be executed. The exception will only be handled if the user presses the ESC key to produce an ICERR_INTERRUPT exception. (UniScript error codes are listed in the file alias.ic.)

id-1192040