c311 Assignment 14 -- Conditionals and Looping

Due Monday, April 22, at 9am

(with an automatic extension until Wednesday, April 24, at 9am)

Overview

In this project you will add five new forms (one expression and four statements) to the Java-like interpreter java1.ss. There is also one extra-credit portion.

The six new forms are:

Each of these will be discussed below.

Since this is your last assignment for the semester, after you've turned it in might be a good time to do those course evaluations (for Chris Haynes and your discussion section AI, either Vikram Subramaniam or Erik Hilsdale ).

Assignment

The ?: conditional expression

Java (like C) has a conditional expression as well as a conditional statement. The syntax of Java's expression is:

test-exp ? true-exp : false-exp
And its semantics is ``evaluate test-exp. If it turns out to be true, evaluate and return the value of true-exp, otherwise evaluate and return the value of false-exp''.

Add this functionality to our interpreter. Since we're all parenthesized over here (be glad we don't have you writing parsers for the non-parenthesized syntax), use

(? test-exp true-exp false-exp)
for your interpreters. For example:
> (run '((class Test (public)                         
           (method main (public static) (args)        
             (system.out.println (? (== 3 4) 5 6))))))
6       ; this is printed, not returned
>

The while loop

In Java, a while statement looks like:

while (test-exp) loop-stmt;
with the semantics: ``Evaluate test-exp. If it turns out to be true, execute the loop-stmt (which may be a block, of course) and start over. If test-exp turned out not to evaluate to true, do nothing and go on.''

Add this to the interpreter also. Use the syntax:

(while test-exp loop-stmt)
For example:
> (run '((class Test (public)                  
           (method main (public static) (args) 
             (var v 3)                         
             (while (< 0 v)                    
               (block                          
                 (system.out.println v)        
                 (set! v (- v 1)))))))))       
3
2
1
> 

The do-while loop

Java supports a variant of the while loop in which the loop-stmt gets evaluated before the test is checked:

do loop-stmt while (test-exp);
Its semantics is (are?): ``Execute loop-stmt, and then evaluate test-exp. If test-exp evaluates to true, start over, otherwise do nothing and go on.''

Add this to the interpreter, and use the syntax:

(do loop-stmt test-exp)
For example:
> (run '((class Test (public)                 
           (method main (public static) (args)
             (var v 3)                        
             (do (block                       
                   (system.out.println v)     
                   (set! v (- v 1)))          
               (< 0 v))))))                   
3
2
1
> (run '((class Test (public)
           (method main (public static) (args)
             (var v 0)
             (do (block
                   (system.out.println v)
                   (set! v (- v 1)))
               (< 0 v))))))
0       ; while would have printed nothing
> 

The for loop

For loops in Java look like:

for (init-stmt; test-exp; inc-stmt) loop-stmt;
With the semantics: ``Execute init-stmt. Then, evaluate test-exp, and if it evaluates to false, ignore the rest of the for statement and continue on with the program. If test-exp evaluates to true, though, execute loop-stmt, execute inc-stmt, and then go back and loop by checing test-exp again.''

Ah, if only that were the semantics. The problem (benefit, whatever) is that it is possible for init-stmt to include a variable declaration; if it does, then the scope of the variable is the entire for loop. While this is insanely useful, it complicates the statement considerably.

According to my reading of the Java specification, init-stmt can be a list of ``primitive'' statements (i.e., no blocks, no loops) or ONE (and only one) variable declaration form. For the purposes of this assignment, though, I would prefer to be less arbitrary, so for us init-stmt may be either a statement (of any type) or a variable declaration

(var id exp)

Also in Java, any of init-stmt, test-exp, or inc-stmt can be empty, but for this assignment you may assume none of them are.

So use the syntax:

(for (init-stmt test-exp inc-stmt) loop-stmt)
when you add for to your interpreter. Examples:
> (run '((class Test (public)
           (method main (public static) (args)
             (for ((var v 3) (< 0 v) (set! v (- v 1 )))
               (system.out.println v))))))
3
2
1
> (run '((class Test (public)
           (method main (public static) (args)
             (for ((var v 8) (< 0 v) (set! v (- v 1)))
               (block
                 (set! v (- v 2))
                 (system.out.println v)))))))
6
3
0
> (run '((class Test (public)
           (method main (public static) (args)
             (var v 3)
             (for ((system.out.println 88) (< 0 v) (set! v (- v 1)))
               (system.out.println v))))))
88
3
2
1
> (run '((class Test (public)
           (method main (public static) (args)
             (var v 3)
             (for ((var v 8) (< 0 v) (set! v (- v 1)))
               (block (set! v (- v 2))
                 (system.out.println v)))
             (system.out.println v)))))
6
3
0
3
> 

The break statement

Java provides a break statement to break out of loops:

break;
(Java also allows ``labeled'' breaks which permit some constrained goto-like behaviour, but that's too gross to discuss here). When a break statement is executed, control exits out of nearest enclosing while, do, or for loop (or switch statement in Java) as if the test-exp had just returned false.

Add break to the interpreter, using the syntax:

(break)
Not that you'd want to, but you shouldn't worry about breaks in the init-stmt or inc-stmt of for statments; Java disallows them, so you're free to do whatever you want if they come up.

Examples:

> (run '((class Test (public)
           (method main (public static) (args)
             (var v 3)
             (while (< 0 v)
               (if (== v 1)
                   (break)
                   (block
                     (system.out.println v)
                     (set! v (- v 1)))))))))
3
2
> (run '((class Test (public)
           (method main (public static) (args)
             (var v 5)
             (while (< 0 v)
               (block 
                 (for ((var v v) (< 0 v) (set! v (- v 2)))
                   (system.out.println v))
                 (system.out.println 999)
                 (set! v (- v 1))))))))
5
3
1
999
4
2
999
3
1
999
2
999
1
999
> (run '((class Test (public)
           (method main (public static) (args)
             (var v 5)
             (while (< 0 v)
               (block 
                 (for ((var v v) (< 0 v) (set! v (- v 2)))
                   (if (== v 3)
                       (break)
                       (system.out.println v)))
                 (system.out.println 999)
                 (set! v (- v 1))))))))
5
999
4
2
999
999
2
999
1
999
> 

Extra Credit: The continue statement

The continue statement,

continue;
is used to break out of computations but stay within the nearest enclosing loop. A continue statement in a while or do loop goes immediately to the evaluation of test-exp. A continue statement in a for loop goes immediately to the execution of the inc-stmt (which is followed by the evaluation of test-exp).

Add handling for the continue statement:

(continue)
to the interpreter. Examples:
> (run '((class Test (public)
           (method main (public static) (args)
             (var v 5)
             (while (< 0 v)
               (block
                 (set! v (- v 1))
                 (if (== v 3)
                     (continue)
                     (system.out.println v))
                 (system.out.println v)))))))
4
4
2
2
1
1
0
0
> (run '((class Test (public)
           (method main (public static) (args)
             (for ((var v 5) (< 0 v) (system.out.println v))
               (block
                 (set! v (- v 1))
                 (if (== v 3)
                     (continue)
                     (if (== v 1)
                         (break)
                         (system.out.println v)))
                 (system.out.println v)))))))
4
4
4
3
2
2
2
>

Analysis and Hints

Spend a bit of time to understand how the interpreter works without messing with it. Concentrate especially on eval-stmt and eval-exp, as you'll be doing most of your modifications there.

You might want to add the forms to the interpreter in the order I have assigned them. The first part, the ?: conditional, is almost a freebie. Use this one to get acquainted with the interpreter. Adding while and do loops is almost as easy, though you'll be playing with a different part of the interpreter.

The main complication with the for loop is the possibility of a variable declaration in init-stmt.

For break you'll have to modify your handling of while, do and for. I strongly suggest modifying these -- that is, writing the loops without the break capability and thoroughly testing them before adding break to the language. You should look at how the interpreter handles the return statement -- it might give you some ideas of how break might work.

continue can be solved in a number of ways, but all of them require a bit of continuation work.

Submission

Put the entire modified interpreter in a file and send it to

c311@lakshmi.cs.indiana.edu
with the subject line
14
Assuming you've saved your homework in the file ``asgn.ss'' in the current directory, one way to submit is with the command:
Mail -s "14" c311@lakshmi.cs.indiana.edu < asgn.ss


Back to the c311 page

ehilsdal@cs.indiana.edu