[UMN logo]

CSCI 5106: Programming Languages
Spring 2006, University of Minnesota
Assignment 3
Comments on Grading


General Remarks

The assignment was graded out of 23. Problem 1 was graded out of 2 + 2 + 1 points, Problem 2 out of 1.5 + 1.5 + 1 + 1 points, Problem 3 out of 2 points, Problem 4 out of 5 points, Problem 5 out of 3 points and Problem 6 out of 3 points.

The average for this assignment was 16.42, the median was 17.25, the standard deviation was 4.56, and the highest score was 22.


Problem 1

This problem was to prepare you for the discussion on reasoning about programs and to bring out the value of structured control flow constructs.

In the first part of the problem we were looking for some expression of the fact that you would think of attaching properties to program points, showing that these actually held and then using these properties to conclude that the program did what you wanted it to. Note that simply writing down properties at program points is not good enough. It is also necessary to argue that these properties hold!

In the second part we were looking for some expression of the fact that noticing and reasoning about the two loops in the program (line 3 through line 15 and line 8 through line 13) is important and that some invariant property had to be observed What these invariant properties might be can be guessed from the discussion on page 68.

For the last part, the main observation in an answer I would write would be that in checking that a property holds at a particular point it is first of necessary to determine easily how exactly control can get to that point. This is easy to do with structured flow constructs but can become a nightmare with the gotos present in the RAM programs. Incidentally, there is an amusing article on this subject that contributes a ``come-from'' statement to programming languages. This paper appears in the Communications of the ACM, Volume 27, Number 4, April 1984, pages 394-395.


Problem 2

This was a straightforward problem. The point of this exercise was to recognize that, for the language in question, the overall flow diagram can be constructed by combining those for the simpler statements in a predetermined way. This is a consequence of the nested structure of statements and their single input-single output nature (some people mistakenly had two outputs from their if-then-else block -- remember these should merge before leaving the block). This is a very basic property and we had already covered it in some detail in class.

Gotos destroy the simple correspondence between abstract syntax and flow diagrams. A common mistake is to think that this is because an abstract syntax tree cannot be drawn for a program with gotos. This is not true. Thus

        goto n
  
corresponds to an operator (goto) with an argument (n) yielding the following abstract syntax tree
         goto
          |
          |
          n
  
The problem really is that flow diagrams can no longer be constructed by a simple composition of parts since the place where to go to may belong to the flow diagram for another part of the tree.


Problem 3

It should be clear how to do this problem. The main issue was recognizing the nature of selective evaluation and translating this into the logic of a flow diagram.


Problem 4

There are, of course, many different solutions to this one. I am not going to write out a complete solution to this one so as to give you another chance to work it out for yourself if you did not get it right. However, I will give you an idea of how to be systematic by using a different (and smaller) program

Thus consider the program

   l: <alpha>;
   if <E1> then goto m;
   <beta>;
   if <E2> then goto l;
   <delta>;
   m: <gamma>;
This code fragment has a loop back to the first statement from its midst that is at least one reason why it is not structured. Following the idea we used in class, we can somehow mark the path that leads to a loop back, proceed to the end of the code and then branch back from there if needed; the rationale for doing this is that then we can capture the structure using something like a repeat. Using a new variable called done to record which path we came to the end by, we can rewrite the above code as
   l: <alpha>;
   done = true;
   if <E1> then goto m;
   <beta>;
   if <E2> then done = false;
   else { <delta>;
          m: <gamma>;
        }
   if (done == false) then goto l;
But this is the same as
   repeat
       <alpha>;
       done = true;
       if <E1> then goto m;
       <beta>;
       if <E2> then done = false;
       else { <delta>;
              m: <gamma>;
            }
   until done;
This code is still not structured because it still has a goto. However, this is easy to remove: we make the conditional branch an if-then-else, copying portions of the code as needed to do this:
   repeat
       <alpha>;
       done = true;
       if <E1> then <gamma>;
       else { <beta>;
              if <E2> then done = false;
              else { <delta>; <gamma>; }
            }
   until done;
A common mistake in this kind of problem is assuming that atomic actions do not affect the tests in the program. This is not an acceptable assumption. If you think about this a little it means, for instance, that any program in which a statement is executed more than once never terminates.


Problem 5

Considering the abstract syntax tree of an or expression, the order of short-circuit evaluation is sort of 'depth-first'. For example, suppose we have an or expression like
         l1:or
          /  \
         /    \
      l2:or   l5:T
      /  \
     /    \
   l3:T   l4:e1
  
where e1 is some arbitrary or expression, and l1 through l5 are 'names' of the nodes. To decide the value of the top-level node l1, it's left child l2 has to be evaluated. Since l2 is yet another or node, the evaluation process recursively descends to its left child l3. Now a value T is found, the evaluation result of l2 can be decided as T, and so does that of l1.

Now suppose the set of rules are changed into

   <beta> or T   --->   T
   T or <beta>   --->   T
   F or F   --->  F
The evaluation order then becomes sort of 'breadth-first'. In the example above, evaluation of l5 should be considered even if we haven't finished evaluating l2. In this case, since l5 is a leaf T, the evaluation result of l1 can already be decided by applying the first rule even without doing any work on l2. Whether you choose to do this or not does not make a whole lot of difference in this particular example, but consider what the situation would be if the computation at l2 turned out to be nonterminating.

The bottomline, if you have appreciated the situation described above, is that the new set of rules when coupled with an outermost strategy calls for a parallel evaluation of the two parts of the or with the ability for each calculation to interrupt the other should it yield T as a result. This is essential because some computations can take infinitely long and, in this case, we would not provide a value for some expressions that do have a value as per our rules if we did otherwise. While it is possible to support such parallel computations, it clearly calls for a more sophisticated machinery than assumed within the framework discussed in class.

Some of you seemed to imply that the old set of rules under outermost evaluation corresponds to eager evaluation whereas the new set of rules under the same strategy is lazy. This is not accurate. Laziness is present in both cases: under the short-circuit evaluation, a right operand is evaluated only when necessary.


Problem 6

This question was the `tough' one in this assignment. The trick is to think recursively. The base cases are easy: if the expression is simply a number or a name, exactly one register is needed. What if the expression is of the form op(E1,E2)? Say you need m registers for evaluating E1 and n for evaluating E2. Now while evaluating E2 you need an extra register to remember the value of E1. Thus, you will need the larger of m and n+1 registers overall.

All this can be expressed in the form of a recursive function.


Last updated on March 3, 2006 by gopalan@cs.umn.edu and xqi@cs.umn.edu