.. highlightlang:: us .. _control-statements: Control Statements ================== Control statements determine the order in which the UniScript program is executed. .. index:: if, else, print .. _if: .. _else: .. _the-if-else-statement: The if-else Statement --------------------- The :keyword:`if`-:keyword:`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 :keyword:`if` statement will be executed if the condition is true. This means that the expression is not equal to 0. The :keyword:`else` statement will be executed if the condition is false. :keyword:`else` is optional. :: if (condition) { if statements } If the :keyword:`if` and :keyword:`else` statements consist of only one statement, the braces are not necessary. :: a = 1; if (a == 1) print "a equals 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 equals 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 :keyword:`if`-:keyword:`else` statement. :: a = 1; if (a == 1) { print "a equals 1"; } else { print "a not equal 1"; } However using :ref:`continuation-line` one can write: :: a = 1; if (a == 1) { print "a equals 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 :ref:`all` and :ref:`any`. The function :ref:`all` returns TRUE (1) if all elements of the input vector are not zero, otherwise the function returns the value 0. The :ref:`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 :ref:`all` or :ref:`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 :ref:`all` or :ref:`any` twice, the return value is a scalar. The following example will execute the :keyword:`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 :keyword:`if`-:keyword:`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 :keyword:`else`-:keyword:`if` chain is finished. If no condition is true, the last :keyword:`else` case will be executed. .. index:: for, in, printf .. _for: .. _in: .. _the-for-statement: The for Statement ----------------- The :keyword:`for` statement is used to iterate the overall elements of a vector. The general form of the :keyword:`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 :keyword:`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); } .. index:: while .. _while: .. _the-while-statement: The while Statement ------------------- The :keyword:`while` statement is used to execute one or more statements repeatedly. A :keyword:`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 :keyword:`break` or :keyword:`return` statement. The following :keyword:`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; .. index:: break, continue, loops .. _break: .. _continue: .. _the-break-and-continue-statement: The break and continue Statement -------------------------------- The :keyword:`break` statement is used to terminate within an iteration statement. :keyword:`break` can be used in the statement body of a :keyword:`while` or :keyword:`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 :keyword:`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; .. index:: continue The :keyword:`continue` statement is used inside a :keyword:`while` or :keyword:`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 :file:`.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 :ref:`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``. :ref:`strupper` converts its argument into upper case characters. If the condition is true, i.e. the file does not have the extension :file:`".ipw"`, the :keyword:`continue` statement will be executed and the next file name will be evaluated. If the condition is false, the function :ref:`DocCreate` will load the file. If the file cannot be opened, :ref:`DocCreate` returns 0. The loop will be terminated because of the :keyword:`break` statement. If we had called the :ref:`FindFiles` function with the search pattern :file:`"*.ipw"`, we would have found all wanted files without using the :keyword:`for` loop and the :keyword:`continue` statement. .. index:: try, except .. _try: .. _except: .. _the-try-except-statement: The try-except Statement ------------------------ The :keyword:`try`-:keyword:`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 :keyword:`if`-:keyword:`else` statement, the second block in the :keyword:`try`-:keyword:`except` statement is not optional. Every :keyword:`try` block has exactly one :keyword:`except` block. :keyword:`try`-:keyword:`except` statements can be nested. Normally, only the :keyword:`try` statement is executed. The condition and the :keyword:`except` statement will only be executed in case of an error in the :keyword:`try` statement. There are many reasons why a problem can occur while executing a statement. .. index:: ESC-Key, error, exception **Examples**: * Not enough memory is available to execute the statement. * The user pressed the ESC key inside a :keyword:`try` statement. * A vector element that does not exist was accessed. * An error occurs inside a function call within a :keyword:`try` statement body. * The :ref:`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 :ref:`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 :ref:`fopen` opens a file for reading, :ref:`fread` reads the file, and :ref:`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 :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 :ref:`fclose`, a so called resource loss will occur. This problem can be solved by protecting the statements with a :keyword:`try`-:keyword:`except` statement. .. index:: fopen, fclose, fread, MessageBox, isreal, error :: 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 :keyword:`try` body, the program branches into the :keyword:`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 :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 :keyword:`except` statement is executed. With the function :ref:`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. .. index:: ICERR_INTERRUPT :: GetExceptionCode() == ICERR_INTERRUPT, ICERR_OPERATOR_TYPE :ref:`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 :keyword:`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 :file:`alias.ic`.) :sub:`id-1192040`