Wednesday, August 15, 2012

AdaTutor - Operators and Control Constructs (2)

Control Constructs

You're almost ready to write your own Ada program in an Outside Assignment, but first we need to discuss the control constructs.

Ada encourages structured programming by providing control constructs such as

     block ifs with elsifs and else
     while loops
     for loops
     case statements

Ada also provides a goto statement, but it's seldom if ever needed.  That's because the constructs above handle the flow of control more clearly, making the program easier to read.  With the constructs above, we know how control reaches each statement. When gotos are used, there can be many paths to a statement, and we're not sure how control got there.

Let's look at the above control constructs, and the goto statement, one at a time.  Discussion of the declare statement and Ada "blocks" is postponed until we cover exception handlers.

The "IF" Block
    if A >= B and C = A + D then
       -----;
       -----;  (block of code)
       -----;
    end if;

In Ada, every if introduces a block of code that ends with end if;.  There are no exceptions; every if always has an end if;.  The condition is followed by then, and it can be any expression with a Boolean result.  The above example is valid if A, B, C, and D are suitably declared. Each statement in the block of code, including the last, has a semicolon.  Note that end if; is two reserved words, so there must be at least one space between them.  All Ada control constructs, including if blocks, can be nested to any depth.

In Pascal and C, if is designed to execute only one statement conditionally.  If there are several statements to be executed conditionally, they have to be enclosed with "begin ... end" in Pascal or braces in C, so they will be considered as one statement.  In Ada, however, if always starts a block of code, so "begin ... end" or braces aren't necessary. The end of the block is always marked by end if; even if there's just one statement in the block.

      if A >= B and C = A + D then
         -----;
         -----;
         -----;
      elsif G = H + P then
         -----;
      elsif Q > R or S <= T then
         -----;
         -----;
      else
         -----;
      end if;

The reserved words elsif and else are also available; note the unusual spelling of elsif.  In the above example, only one of the four blocks of code will be executed.  If A >= B and C = A + D is True, the first block of code will be executed and the remaining tests and blocks will be skipped.  Control will continue after the end if;.  If A >= B and C = A + D is False, then G = H + P will be tested.  If it's True, the second block, and only that block, will be executed; otherwise, Q > R or S <= T will be tested.  If that's True, the third block will be executed; otherwise the else block will be executed.  If all the tests are False and there's no else block, then no blocks are executed.

The above block of code is equivalent with the following code:

      if A >= B and C = A + D then
         -----;
         -----;
         -----;
      else
         if G = H + P then
            -----;
         else
            if Q > R or S <= T then
               -----;
               -----;
            else
               -----;
            end if;
         end if;
      end if;

Note that elsif is equivalent to else plus if ... end if;.  Although the two program segments above are equivalent, the first one is much clearer.  The example on first one doesn't require multiple end ifs at the bottom, and the indentation emphasizes that only one of the four blocks of code will be executed.

Question

    D, N : Integer := 1;
    ...
    if D = 0 then
       One;
    elsif N/D = 1 then
       Two;
    elsif D = 1 then
       Three;
    else
       Four;
    end if;
In this segment of code, which procedure(s) will be called?
  • Procedure One will be called.
  • Procedure Two will be called
  • Procedure Three will be called.
  • Procedure Four will be called.
  • Procedures Two and Three will be called.
"WHILE" Loops
    while I < 10 loop
      -----;
      -----;
      -----;
    end loop;

The while loop first evaluates the Boolean expression (I < 10 in this example).*  If it's False, the block of code isn't executed at all, and execution continues after the end loop;.  If it's True, the block of code is executed and then the Boolean condition is again evaluated.  If the condition is still True, the block is executed again and the Boolean expression is evaluated again, and so forth.  When the Boolean expression becomes False, the block of code is skipped and execution continues after the end loop;.

To create an "infinite loop," it isn't necessary to write while True loop ... end loop;.  We simply write loop ... end loop;, like this:

   loop
      -----;
      -----;
      -----;
   end loop;

An infinite loop might be useful in a device that continually does the same thing so long as power is applied.

Ada doesn't have a "repeat ... until" loop, with the test at the bottom.  However, we can create a loop that's equivalent to a "repeat ... until" loop by using what would otherwise be an infinite loop with an exit statement, to be covered very soon.

"FOR" Loops
   for Ix in 1 .. 10 loop      for Ix in reverse 1 .. 10 loop
     -----;                      -----;
     -----;                      -----;
   end loop;                   end loop;

Here are two sample for loops.  We need not declare the index (Ix in these examples) in the declarative region of the program; an index of a for loop declares itself.  In these examples, Ix comes into existence at the for statement and goes out of existence at end loop; the index isn't available outside the loop.  If the name Ix happens to appear in the declarative region, it's a different Ix.  Inside the loop Ix refers to the index; there the name Ix is said to hide any Ix that might be mentioned in the declarative region.

The index variable may not be modified.  In these examples, Ix may not appear on the left side of an assignment statement, etc.

In the first example above, the block of statements is executed ten times, with Ix equal to 1, then 2, then 3, etc., up to 10.  In the second example, Ix starts at 10 and counts down to 1.  Note that the range is still written 1 .. 10, but the keyword reverse precedes the range.

The index of a for loop can have any discrete type.  That means any integer or enumeration type.  It can't be of type Float.  For example, if we write

   type Rainbow_Color is (Red, Orange, Yellow, Green, Blue,
                          Indigo, Violet);
   type Traffic_Light_Color is (Red, Amber, Green);
then we can write for Ix in Red .. Blue loop,, and the compiler will know that Ix must be of type Rainbow_Color.  Similarly, the compiler will know that the type of Ix must be Traffic_Light_Color if we write for IX in Red .. Amber loop.  But the compiler can't handle for Ix in Red .. Green loop because of the ambiguity.  In this case we must specify the type.  For example, we could write either of these:
   for Ix in Rainbow_Color'(Red) .. Green loop
   for Ix in Rainbow_Color range Red .. Green loop

Because the index can have any discrete type, there's no STEP clause in Ada, as there is in Basic.  One might increment an Integer index by 2, but we couldn't add 2 to Red.  For uniformity, no STEP clause is available, even if the index type is Integer.

Ranges may contain expressions.  If A, B, C, and D are Integer variables, we can say for I in A + B .. C + D loop or for I in reverse A + B .. C + D loop.  In both cases the range is null if C + D is less than A + B.  That won't cause an error; the loop is simply skipped when the range is null.

Question

If we have
   type Rainbow_Color is (Red, Orange, Yellow, Green, Blue,
                          Indigo, Violet);
   J : Integer := 5; 
which one of these statements is illegal?
  1. for I in -J .. J loop
  2. for I in J .. Violet loop
  3. for I in Violet .. Red loop

< prev   next >

No comments: