CS 536 Homework 2: Rudimentary Interpreters

Due: September 20, hardcopy in class and electronic via turnin (asgmt name hwk2)


Repeating the warning I gave in class: solutions to homework problems are often available in texts, on the web, etc. The point of the assignments is for you to think them through so you see the questions that come up in building languages. Do not look at solutions to these problems, even for hints. If you need help, post to the board or send me email. If I find you've consulted sources beyond those posted on the CS536 web site, I will follow WPI's honesty policy and recommend an F for the course.

Testing and What to Turn In

Turn in two separate files for this assignment: one containing your code (called hwk2.scm) and the other containing your tests (called tests.scm). The quality of your test suite is worth a significant portion of your grade. Write your tests using the test and test/exn functions in the PLAI language levels. I will run your tests against each other's code: you get points for bugs you find in others' code and lose points for bugs that others' tests find in your code. Due to this, pay attention to the concrete syntax and function contracts, as mistakes in these would cause your work to fail against others' test suites.

For consistency of testing for errors using test/exn (when I cross run your test suites), make sure your error messages include the following phrase for each kind of error:

The Assignment

Extend the parser and interpreter for the F1WAE language discussed in class (and the text) with the language features described below. The text can be of great assistance in this part of the assignment; it provides the beginnings of a parser, an abstract syntax datatype and an interpreter. Your interpreter should have eager application semantics.

As part of the assignment, implement the function parse, which consumes an expression in the language’s concrete syntax and returns the abstract syntax representation of that expression, as well as the function interp, which consumes an abstract syntax expression (as returned by the parse function) and returns a (Scheme) number. Include a contract for every function.

Features to Implement

Binary arithmetic operators

In place of having separate abstract syntax forms for + and -, define a single form for all binary arithmetic operators. Parse these into a binop datatype variant that includes a symbol for the operation to perform as well as the two arguments. Define a table that maps operator names (symbols) to actual functions (Scheme procedures) that perform the corresponding operation. Having a single form like this, accompanied by a table, makes your language easier to extend: once you have modified your parser and interpreter once to support binary operators, you won't need to touch either one to add any number of new ones. To demonstrate this, define multiplication and division (using * and / to represent them in the language's concrete syntax).

Multi-armed with

This feature lets you introduce multiple identifiers in a single with statement. Each identifier bound by the with expression is bound only in the body of the with. Zero or more identifiers can be bound by each with expression. If there are multiple bindings of the same identifier in a single with expression’s bindings list, your interpreter should halt with an error message. An example:

{with {{x 2}
       {y 3}}
  {with {{z {+ x y}}}
    {+ x z}}

will evaluate to 7, while

{with {{x 2}
       {x 3}}
{+ x 2}}

will halt with an error message.

Conditionals

To save the trouble of having to add boolean values and operators over them, create a restricted conditional construct if0 with syntax

   {if0 F1WAE F1WAE F1WAE} 
An if0 expression has three parts:

Evaluation should signal an error for non-numeric test values.


Back to the Assignments page