(with an automatic extension until Wednesday, April 24, at 9am)
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:
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 ).
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
>
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
>
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
>
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
>
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
>
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
>
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.
Put the entire modified interpreter in a file and send it to
c311@lakshmi.cs.indiana.eduwith the subject line
14Assuming 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