Mercurial > octave-nkf
diff doc/interpreter/stmt.txi @ 3294:bfe1573bd2ae
[project @ 1999-10-19 10:06:07 by jwe]
author | jwe |
---|---|
date | Tue, 19 Oct 1999 10:08:42 +0000 |
parents | |
children | abdd5ed1bb4e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/interpreter/stmt.txi Tue Oct 19 10:08:42 1999 +0000 @@ -0,0 +1,802 @@ +@c Copyright (C) 1996, 1997 John W. Eaton +@c This is part of the Octave manual. +@c For copying conditions, see the file gpl.texi. + +@node Statements, Functions and Scripts, Evaluation, Top +@chapter Statements +@cindex statements + +Statements may be a simple constant expression or a complicated list of +nested loops and conditional statements. + +@dfn{Control statements} such as @code{if}, @code{while}, and so on +control the flow of execution in Octave programs. All the control +statements start with special keywords such as @code{if} and +@code{while}, to distinguish them from simple expressions. +Many control statements contain other statements; for example, the +@code{if} statement contains another statement which may or may not be +executed. + +@cindex @code{end} statement +Each control statement has a corresponding @dfn{end} statement that +marks the end of the end of the control statement. For example, the +keyword @code{endif} marks the end of an @code{if} statement, and +@code{endwhile} marks the end of a @code{while} statement. You can use +the keyword @code{end} anywhere a more specific end keyword is expected, +but using the more specific keywords is preferred because if you use +them, Octave is able to provide better diagnostics for mismatched or +missing end tokens. + +The list of statements contained between keywords like @code{if} or +@code{while} and the corresponding end statement is called the +@dfn{body} of a control statement. + +@menu +* The if Statement:: +* The switch Statement:: +* The while Statement:: +* The for Statement:: +* The break Statement:: +* The continue Statement:: +* The unwind_protect Statement:: +* The try Statement:: +* Continuation Lines:: +@end menu + +@node The if Statement, The switch Statement, Statements, Statements +@section The @code{if} Statement +@cindex @code{if} statement +@cindex @code{else} statement +@cindex @code{elseif} statement +@cindex @code{endif} statement + +The @code{if} statement is Octave's decision-making statement. There +are three basic forms of an @code{if} statement. In its simplest form, +it looks like this: + +@example +@group +if (@var{condition}) + @var{then-body} +endif +@end group +@end example + +@noindent +@var{condition} is an expression that controls what the rest of the +statement will do. The @var{then-body} is executed only if +@var{condition} is true. + +The condition in an @code{if} statement is considered true if its value +is non-zero, and false if its value is zero. If the value of the +conditional expression in an @code{if} statement is a vector or a +matrix, it is considered true only if @emph{all} of the elements are +non-zero. + +The second form of an if statement looks like this: + +@example +@group +if (@var{condition}) + @var{then-body} +else + @var{else-body} +endif +@end group +@end example + +@noindent +If @var{condition} is true, @var{then-body} is executed; otherwise, +@var{else-body} is executed. + +Here is an example: + +@example +@group +if (rem (x, 2) == 0) + printf ("x is even\n"); +else + printf ("x is odd\n"); +endif +@end group +@end example + +In this example, if the expression @code{rem (x, 2) == 0} is true (that +is, the value of @code{x} is divisible by 2), then the first +@code{printf} statement is evaluated, otherwise the second @code{printf} +statement is evaluated. + +The third and most general form of the @code{if} statement allows +multiple decisions to be combined in a single statement. It looks like +this: + +@example +@group +if (@var{condition}) + @var{then-body} +elseif (@var{condition}) + @var{elseif-body} +else + @var{else-body} +endif +@end group +@end example + +@noindent +Any number of @code{elseif} clauses may appear. Each condition is +tested in turn, and if one is found to be true, its corresponding +@var{body} is executed. If none of the conditions are true and the +@code{else} clause is present, its body is executed. Only one +@code{else} clause may appear, and it must be the last part of the +statement. + +In the following example, if the first condition is true (that is, the +value of @code{x} is divisible by 2), then the first @code{printf} +statement is executed. If it is false, then the second condition is +tested, and if it is true (that is, the value of @code{x} is divisible +by 3), then the second @code{printf} statement is executed. Otherwise, +the third @code{printf} statement is performed. + +@example +@group +if (rem (x, 2) == 0) + printf ("x is even\n"); +elseif (rem (x, 3) == 0) + printf ("x is odd and divisible by 3\n"); +else + printf ("x is odd\n"); +endif +@end group +@end example + +Note that the @code{elseif} keyword must not be spelled @code{else if}, +as is allowed in Fortran. If it is, the space between the @code{else} +and @code{if} will tell Octave to treat this as a new @code{if} +statement within another @code{if} statement's @code{else} clause. For +example, if you write + +@example +@group +if (@var{c1}) + @var{body-1} +else if (@var{c2}) + @var{body-2} +endif +@end group +@end example + +@noindent +Octave will expect additional input to complete the first @code{if} +statement. If you are using Octave interactively, it will continue to +prompt you for additional input. If Octave is reading this input from a +file, it may complain about missing or mismatched @code{end} statements, +or, if you have not used the more specific @code{end} statements +(@code{endif}, @code{endfor}, etc.), it may simply produce incorrect +results, without producing any warning messages. + +It is much easier to see the error if we rewrite the statements above +like this, + +@example +@group +if (@var{c1}) + @var{body-1} +else + if (@var{c2}) + @var{body-2} + endif +@end group +@end example + +@noindent +using the indentation to show how Octave groups the statements. +@xref{Functions and Scripts}. + +@defvr {Built-in Variable} warn_assign_as_truth_value +If the value of @code{warn_assign_as_truth_value} is nonzero, a +warning is issued for statements like + +@example +if (s = t) + ... +@end example + +@noindent +since such statements are not common, and it is likely that the intent +was to write + +@example +if (s == t) + ... +@end example + +@noindent +instead. + +There are times when it is useful to write code that contains +assignments within the condition of a @code{while} or @code{if} +statement. For example, statements like + +@example +while (c = getc()) + ... +@end example + +@noindent +are common in C programming. + +It is possible to avoid all warnings about such statements by setting +@code{warn_assign_as_truth_value} to 0, but that may also +let real errors like + +@example +if (x = 1) # intended to test (x == 1)! + ... +@end example + +@noindent +slip by. + +In such cases, it is possible suppress errors for specific statements by +writing them with an extra set of parentheses. For example, writing the +previous example as + +@example +while ((c = getc())) + ... +@end example + +@noindent +will prevent the warning from being printed for this statement, while +allowing Octave to warn about other assignments used in conditional +contexts. + +The default value of @code{warn_assign_as_truth_value} is 1. +@end defvr + +@node The switch Statement, The while Statement, The if Statement, Statements +@section The @code{switch} Statement +@cindex @code{switch} statement +@cindex @code{case} statement +@cindex @code{otherwise} statement +@cindex @code{endswitch} statement + +The @code{switch} statement was introduced in Octave 2.0.5. It should +be considered experimental, and details of the implementation may change +slightly in future versions of Octave. If you have comments or would +like to share your experiences in trying to use this new command in real +programs, please send them to +@email{octave-maintainers@@bevo.che.wisc.edu}. (But if you think you've +found a bug, please report it to @email{bug-octave@@bevo.che.wisc.edu}. + +The general form of the @code{switch} statement is + +@example +@group +switch @var{expression} + case @var{label} + @var{command_list} + case @var{label} + @var{command_list} + @dots{} + + otherwise + @var{command_list} +endswitch +@end group +@end example + +@itemize @bullet +@item +The identifiers @code{switch}, @code{case}, @code{otherwise}, and +@code{endswitch} are now keywords. + +@item +The @var{label} may be any expression. + +@item +Duplicate @var{label} values are not detected. The @var{command_list} +corresponding to the first match will be executed. + +@item +You must have at least one @code{case @var{label} @var{command_list}} +clause. + +@item +The @code{otherwise @var{command_list}} clause is optional. + +@item +As with all other specific @code{end} keywords, @code{endswitch} may be +replaced by @code{end}, but you can get better diagnostics if you use +the specific forms. + +@item +Cases are exclusive, so they don't `fall through' as do the cases +in the switch statement of the C language. + +@item +The @var{command_list} elements are not optional. Making the list +optional would have meant requiring a separator between the label and +the command list. Otherwise, things like + +@example +@group +switch (foo) + case (1) -2 + @dots{} +@end group +@end example + +@noindent +would produce surprising results, as would + +@example +@group +switch (foo) + case (1) + case (2) + doit (); + @dots{} +@end group +@end example + +@noindent +particularly for C programmers. + +@item +The implementation is simple-minded and currently offers no real +performance improvement over an equivalent @code{if} block, even if all +the labels are integer constants. Perhaps a future variation on this +could detect all constant integer labels and improve performance by +using a jump table. +@end itemize + +@defvr {Built-in Variable} warn_variable_switch_label +If the value of this variable is nonzero, Octave will print a warning if +a switch label is not a constant or constant expression +@end defvr + +@node The while Statement, The for Statement, The switch Statement, Statements +@section The @code{while} Statement +@cindex @code{while} statement +@cindex @code{endwhile} statement +@cindex loop +@cindex body of a loop + +In programming, a @dfn{loop} means a part of a program that is (or at least can +be) executed two or more times in succession. + +The @code{while} statement is the simplest looping statement in Octave. +It repeatedly executes a statement as long as a condition is true. As +with the condition in an @code{if} statement, the condition in a +@code{while} statement is considered true if its value is non-zero, and +false if its value is zero. If the value of the conditional expression +in a @code{while} statement is a vector or a matrix, it is considered +true only if @emph{all} of the elements are non-zero. + +Octave's @code{while} statement looks like this: + +@example +@group +while (@var{condition}) + @var{body} +endwhile +@end group +@end example + +@noindent +Here @var{body} is a statement or list of statements that we call the +@dfn{body} of the loop, and @var{condition} is an expression that +controls how long the loop keeps running. + +The first thing the @code{while} statement does is test @var{condition}. +If @var{condition} is true, it executes the statement @var{body}. After +@var{body} has been executed, @var{condition} is tested again, and if it +is still true, @var{body} is executed again. This process repeats until +@var{condition} is no longer true. If @var{condition} is initially +false, the body of the loop is never executed. + +This example creates a variable @code{fib} that contains the first ten +elements of the Fibonacci sequence. + +@example +@group +fib = ones (1, 10); +i = 3; +while (i <= 10) + fib (i) = fib (i-1) + fib (i-2); + i++; +endwhile +@end group +@end example + +@noindent +Here the body of the loop contains two statements. + +The loop works like this: first, the value of @code{i} is set to 3. +Then, the @code{while} tests whether @code{i} is less than or equal to +10. This is the case when @code{i} equals 3, so the value of the +@code{i}-th element of @code{fib} is set to the sum of the previous two +values in the sequence. Then the @code{i++} increments the value of +@code{i} and the loop repeats. The loop terminates when @code{i} +reaches 11. + +A newline is not required between the condition and the +body; but using one makes the program clearer unless the body is very +simple. + +@xref{The if Statement} for a description of the variable +@code{warn_assign_as_truth_value}. + +@node The for Statement, The break Statement, The while Statement, Statements +@section The @code{for} Statement +@cindex @code{for} statement +@cindex @code{endfor} statement + +The @code{for} statement makes it more convenient to count iterations of a +loop. The general form of the @code{for} statement looks like this: + +@example +@group +for @var{var} = @var{expression} + @var{body} +endfor +@end group +@end example + +@noindent +where @var{body} stands for any statement or list of statements, +@var{expression} is any valid expression, and @var{var} may take several +forms. Usually it is a simple variable name or an indexed variable. If +the value of @var{expression} is a structure, @var{var} may also be a +list. @xref{Looping Over Structure Elements}, below. + +The assignment expression in the @code{for} statement works a bit +differently than Octave's normal assignment statement. Instead of +assigning the complete result of the expression, it assigns each column +of the expression to @var{var} in turn. If @var{expression} is a range, +a row vector, or a scalar, the value of @var{var} will be a scalar each +time the loop body is executed. If @var{var} is a column vector or a +matrix, @var{var} will be a column vector each time the loop body is +executed. + +The following example shows another way to create a vector containing +the first ten elements of the Fibonacci sequence, this time using the +@code{for} statement: + +@example +@group +fib = ones (1, 10); +for i = 3:10 + fib (i) = fib (i-1) + fib (i-2); +endfor +@end group +@end example + +@noindent +This code works by first evaluating the expression @code{3:10}, to +produce a range of values from 3 to 10 inclusive. Then the variable +@code{i} is assigned the first element of the range and the body of the +loop is executed once. When the end of the loop body is reached, the +next value in the range is assigned to the variable @code{i}, and the +loop body is executed again. This process continues until there are no +more elements to assign. + +Although it is possible to rewrite all @code{for} loops as @code{while} +loops, the Octave language has both statements because often a +@code{for} loop is both less work to type and more natural to think of. +Counting the number of iterations is very common in loops and it can be +easier to think of this counting as part of looping rather than as +something to do inside the loop. + +@menu +* Looping Over Structure Elements:: +@end menu + +@node Looping Over Structure Elements, , The for Statement, The for Statement +@subsection Looping Over Structure Elements +@cindex structure elements, looping over +@cindex looping over structure elements + +A special form of the @code{for} statement allows you to loop over all +the elements of a structure: + +@example +@group +for [ @var{val}, @var{key} ] = @var{expression} + @var{body} +endfor +@end group +@end example + +@noindent +In this form of the @code{for} statement, the value of @var{expression} +must be a structure. If it is, @var{key} and @var{val} are set to the +name of the element and the corresponding value in turn, until there are +no more elements. For example, + +@example +@group +x.a = 1 +x.b = [1, 2; 3, 4] +x.c = "string" +for [val, key] = x + key + val +endfor + + @print{} key = a + @print{} val = 1 + @print{} key = b + @print{} val = + @print{} + @print{} 1 2 + @print{} 3 4 + @print{} + @print{} key = c + @print{} val = string +@end group +@end example + +The elements are not accessed in any particular order. If you need to +cycle through the list in a particular way, you will have to use the +function @code{struct_elements} and sort the list yourself. + +The @var{key} variable may also be omitted. If it is, the brackets are +also optional. This is useful for cycling through the values of all the +structure elements when the names of the elements do not need to be +known. + +@node The break Statement, The continue Statement, The for Statement, Statements +@section The @code{break} Statement +@cindex @code{break} statement + +The @code{break} statement jumps out of the innermost @code{for} or +@code{while} loop that encloses it. The @code{break} statement may only +be used within the body of a loop. The following example finds the +smallest divisor of a given integer, and also identifies prime numbers: + +@example +@group +num = 103; +div = 2; +while (div*div <= num) + if (rem (num, div) == 0) + break; + endif + div++; +endwhile +if (rem (num, div) == 0) + printf ("Smallest divisor of %d is %d\n", num, div) +else + printf ("%d is prime\n", num); +endif +@end group +@end example + +When the remainder is zero in the first @code{while} statement, Octave +immediately @dfn{breaks out} of the loop. This means that Octave +proceeds immediately to the statement following the loop and continues +processing. (This is very different from the @code{exit} statement +which stops the entire Octave program.) + +Here is another program equivalent to the previous one. It illustrates +how the @var{condition} of a @code{while} statement could just as well +be replaced with a @code{break} inside an @code{if}: + +@example +@group +num = 103; +div = 2; +while (1) + if (rem (num, div) == 0) + printf ("Smallest divisor of %d is %d\n", num, div); + break; + endif + div++; + if (div*div > num) + printf ("%d is prime\n", num); + break; + endif +endwhile +@end group +@end example + +@node The continue Statement, The unwind_protect Statement, The break Statement, Statements +@section The @code{continue} Statement +@cindex @code{continue} statement + +The @code{continue} statement, like @code{break}, is used only inside +@code{for} or @code{while} loops. It skips over the rest of the loop +body, causing the next cycle around the loop to begin immediately. +Contrast this with @code{break}, which jumps out of the loop altogether. +Here is an example: + +@example +@group +# print elements of a vector of random +# integers that are even. + +# first, create a row vector of 10 random +# integers with values between 0 and 100: + +vec = round (rand (1, 10) * 100); + +# print what we're interested in: + +for x = vec + if (rem (x, 2) != 0) + continue; + endif + printf ("%d\n", x); +endfor +@end group +@end example + +If one of the elements of @var{vec} is an odd number, this example skips +the print statement for that element, and continues back to the first +statement in the loop. + +This is not a practical example of the @code{continue} statement, but it +should give you a clear understanding of how it works. Normally, one +would probably write the loop like this: + +@example +@group +for x = vec + if (rem (x, 2) == 0) + printf ("%d\n", x); + endif +endfor +@end group +@end example + +@node The unwind_protect Statement, The try Statement, The continue Statement, Statements +@section The @code{unwind_protect} Statement +@cindex @code{unwind_protect} statement +@cindex @code{unwind_protect_cleanup} +@cindex @code{end_unwind_protect} + +Octave supports a limited form of exception handling modelled after the +unwind-protect form of Lisp. + +The general form of an @code{unwind_protect} block looks like this: + +@example +@group +unwind_protect + @var{body} +unwind_protect_cleanup + @var{cleanup} +end_unwind_protect +@end group +@end example + +@noindent +Where @var{body} and @var{cleanup} are both optional and may contain any +Octave expressions or commands. The statements in @var{cleanup} are +guaranteed to be executed regardless of how control exits @var{body}. + +This is useful to protect temporary changes to global variables from +possible errors. For example, the following code will always restore +the original value of the built-in variable @code{do_fortran_indexing} +even if an error occurs while performing the indexing operation. + +@example +@group +save_do_fortran_indexing = do_fortran_indexing; +unwind_protect + do_fortran_indexing = 1; + elt = a (idx) +unwind_protect_cleanup + do_fortran_indexing = save_do_fortran_indexing; +end_unwind_protect +@end group +@end example + +Without @code{unwind_protect}, the value of @var{do_fortran_indexing} +would not be restored if an error occurs while performing the indexing +operation because evaluation would stop at the point of the error and +the statement to restore the value would not be executed. + +@node The try Statement, Continuation Lines, The unwind_protect Statement, Statements +@section The @code{try} Statement +@cindex @code{try} statement +@cindex @code{catch} +@cindex @code{end_try_catch} + +In addition to unwind_protect, Octave supports another limited form of +exception handling. + +The general form of a @code{try} block looks like this: + +@example +@group +try + @var{body} +catch + @var{cleanup} +end_try_catch +@end group +@end example + +Where @var{body} and @var{cleanup} are both optional and may contain any +Octave expressions or commands. The statements in @var{cleanup} are +only executed if an error occurs in @var{body}. + +No warnings or error messages are printed while @var{body} is +executing. If an error does occur during the execution of @var{body}, +@var{cleanup} can access the text of the message that would have been +printed in the builtin constant @code{__error_text__}. This is the same +as @code{eval (@var{try}, @var{catch})} (which may now also use +@code{__error_text__}) but it is more efficient since the commands do +not need to be parsed each time the @var{try} and @var{catch} statements +are evaluated. @xref{Error Handling}, for more information about the +@code{__error_text__} variable. + +Octave's @var{try} block is a very limited variation on the Lisp +condition-case form (limited because it cannot handle different classes +of errors separately). Perhaps at some point Octave can have some sort +of classification of errors and try-catch can be improved to be as +powerful as condition-case in Lisp. + +@cindex continuation lines +@cindex @code{...} continuation marker +@cindex @code{\} continuation marker + +@node Continuation Lines, , The try Statement, Statements +@section Continuation Lines + +In the Octave language, most statements end with a newline character and +you must tell Octave to ignore the newline character in order to +continue a statement from one line to the next. Lines that end with the +characters @code{...} or @code{\} are joined with the following line +before they are divided into tokens by Octave's parser. For example, +the lines + +@example +@group +x = long_variable_name ... + + longer_variable_name \ + - 42 +@end group +@end example + +@noindent +form a single statement. The backslash character on the second line +above is interpreted a continuation character, @emph{not} as a division +operator. + +For continuation lines that do not occur inside string constants, +whitespace and comments may appear between the continuation marker and +the newline character. For example, the statement + +@example +@group +x = long_variable_name ... # comment one + + longer_variable_name \ # comment two + - 42 # last comment +@end group +@end example + +@noindent +is equivalent to the one shown above. Inside string constants, the +continuation marker must appear at the end of the line just before the +newline character. + +Input that occurs inside parentheses can be continued to the next line +without having to use a continuation marker. For example, it is +possible to write statements like + +@example +@group +if (fine_dining_destination == on_a_boat + || fine_dining_destination == on_a_train) + suess (i, will, not, eat, them, sam, i, am, i, + will, not, eat, green, eggs, and, ham); +endif +@end group +@end example + +@noindent +without having to add to the clutter with continuation markers.