On this page:
Overview
Submitting
Testing
Fraud+
From Dupe+   to Fraud+
From Binary to Variadic Addition
Generalizing Let
Back-Referencing Let
8.14

Assignment 4: Let There Be (Many) Variables🔗

Due: Tuesday, October 29, 11:59PM EST

The goal of this assignment is to extend a compiler with binding forms and primitives that can take any number of arguments.

Overview🔗

For this assignment, you are given a fraud-plus.zip file on ELMS with a starter compiler similar to the Fraud language we studied in class.

Unlike Assignment 3, the following files have already been updated for you and should not be changed by you:
  • ast.rkt

  • parse.rkt

So you will only need to modify:
  • interp.rkt

  • interp-prim.rkt

  • compile.rkt

  • compile-ops.rkt

to correctly implement the new features. These features are described below.

Submitting🔗

Submit a zip file containing your work to Gradescope. Use make submit.zip from within the fraud-plus directory to create a zip file with the proper structure.

We will not use your ast.rkt or parse.rkt files. Part of Assignment 3 was learning to design your own structures, but part of Assignment 4 is learning to work within the constraints of an existing design!

Testing🔗

You can test your code in several ways:

Note that only a small number of tests are given to you, so you should write additional test cases.

Fraud+🔗

The Fraud+ language extends the Fraud language we studied in class with some new features:

From Dupe+ to Fraud+🔗

Implement the abs, unary -, and not operations and the cond and case forms from Assignment 3 by modifying interp.rkt, interp-prim.rkt, compile.rkt, and compile-ops.rkt. You can start from your previous code, but you will need to update it to work for the structures provided. What’s essentially left for you to do is to make sure to correctly signal an error ('err) when these constructs are applied to the wrong type of argument.

While you’re at it, implement the predicates integer? and boolean? for checking the type of an argument, modeled by the char? predicate that was covered in the lectures.

From Binary to Variadic Addition🔗

In Fraud, we implemented a binary operation for addition. However, Racket supports an arbitrary number of arguments for +. Your job is to extend the interpreter and compiler to behave similarly.

Generalizing Let🔗

The Fraud language has a let form that binds a single variable in the scope of some expression. This is a restriction of the more general form of let that binds any number of expressions. So, for example,

(let ((x 1) (y 2) (z 3))
  e)

simultaneously binds x, y, and z in the scope of e.

The syntax of a let expression allows any number of binders to occur, so (let () e) is valid syntax and is equivalent to e.

The binding of each variable is only in-scope within the body, not in the right-hand sides of any of the let. So, for example,

(let ((x 1) (y x)) 0)

is a syntax error because the occurrence of x is not bound.

Back-Referencing Let🔗

Similar to let, there is also let* that can also bind any number of expressions. The difference is that previous bindings are available in the right-hand sides of subsequent bindings. For example,

(let* ((x 1) (y 2) (z (add1 y)))
  e)

binds x to 1, y to 2, and z to 3 in the scope of e.

The syntax of a let* expression allows any number of binders to occur, so (let* () e) is valid syntax and is equivalent to e.

Unlike let,

(let* ((x 1) (y x)) 0)

is not a syntax error. However, bindings are only available forward, so

(let* ((x y) (y 1)) 0)

is a syntax error.

HINT: Think about what a lazy compiler writer would do.