CS 450 Homework 7
Modifying the Metacircular Evaluator

Carl Offner
Spring 2022

Due Monday, April 11, 5:00 PM


In this assignment we will add some features to s450 in order to learn about different methods of argument passing and get some simple experience with continuations.

There are two parts to this assignment. Part 1 is much longer than Part 2. However, they are completely independent, so you can do them in any order. You can even do Part 2 first.

I will collect two files: s450.scm will contain your Scheme code for this assignment. notes.txt will contain your design notes (what changes did you have to make to s450.scm to support this feature), alternatives you considered, problems you encountered, some indication of how you tested your code (but not complete test scripts!), and so on. Please do not leave notes.txt for the end. It is an important part of this assignment.


Please do not read the section of Chapter 4 that talks about delayed arguments. You will just get confused and end up writing code that is incorrect. What the book means by delayed evaluation in that section is not the same as what we mean in this assignment. You will not learn anything useful by reading that part of the book. In fact, I would suggest not reading the book at all for this assignment. I'm explaining everything you need to know in class. If you have a question, it's much better to ask me than to try to dig it out from the book.

Part 1: Various Methods of Argument Passing

In Scheme, and in s450, all arguments are passed by value. Other languages use other semantics:

We want to build all of these into s450, in an extensible way that allows for other argument semantics not yet imagined. To do so we extend the special form lambda, giving each formal argument an optional tag, so we get the following kind of syntax:

        (lambda (x
                 (delayed y)
                 (dynamic z)
                 (reference w))
          <body>)

The <body> is as usual a sequence of Scheme expression. These expressions can refer to the formal arguments x, y, z, w in the usual way, with no special syntax required to deal with the different methods of argument passing. (That is, if you just looked at the code in the body, you would have no way of knowing that w was a reference argument. That information is only contained in the formal argument list.)

Please note that the tags (delayed, dynamic, and reference) in the formal argument list are not procedure names or special form names. They are just tags, and they are used only in that one place. They are there simply to indicate how the corresponding actual arguments are handled at run-time at a procedure call site (that is, at a point in the program where a procedure is called).

I suggest that you not try to implement all these capabilities at once. Rather, implement them one at a time. Here is one way to go about it---it's the way I used myself:

  1. First, copy your hw6/s450.scm into your hw7 directory. Make sure this file is clean, well-organized, and well-commented. Feel free to rearrange it in any way you like. Try hard to make it as easy to understand as possible. This will of course help me when I read it, but—trust me on this—it will also pay off greatly for you in that it will make your job in this assignment much easier.
  2. Get in the practice of backing up your work.

    You can of course use a tool such as CVS to help you with this. But since you are in effect a one-person project, it's just as simple to do it by hand, like this:

Of course, you can implement these various features in any order you find convenient.

Here are the specific things you should do, and some hints for your design:


Part 2: Continuations

s450 has two flaws, each of which represents a failure to deal cleanly with abnormal control flow:

Repair those flaws now, using continuations to implement (exit) and (s450error args). While you're at it, see if you can have <EOF> at the s450 prompt return the user to the Scheme virtual machine. (Be careful: I don't mean the string "EOF". I mean what you get when you come to the end of a file. See the entry under eof-object? in R5RS.)

One important implementation detail: don't put a call to call/cc at the outermost scope. In other words, always bury it inside the body of some procedure. The reason for this is that we really don't have any control over what the Scheme interpreter is doing at the outermost scope, and different versions of Scheme will act differently. In particular, UMB Scheme doesn't seem to act very nicely about this in general. I don't think this is a bug. If you look at the examples of this mechanism in R5RS, you will see that all of them are inside a procedure body. And again, I suggest very strongly that you use the handout save_continuation.scm as a model for your code.