CSE305 Spring 2008
 Spring 2008 CSE305 Introduction to Programming Languages  
CSE305 Spring 2008 - Navigation Menus

Homework 3


Assigned: Monday March 24, 2008.
Due: on or before 11:59 PM on Monday April 7, 2008.


When doing this homework, first create a directory named HW3 somewhere in your home directory (e.g. as a subdirectory of a cse305 directory). Place your solution to each question in a file or set of files, as indicated, in the HW3 directory. When you're ready to submit, zip up the HW3 directory and its contents, and use the submit_cse305 command to submit your HW3.zip file. You can do this easily as follows. First, make sure your current directory is the directory that contains the HW3 directory. Next, issue the following command:

zip -r HW3 HW3
This will produce a file named HW3.zip which contains not only the HW3 directory, but also its contents.

It is very important that you pay close attention to the naming conventions for files and directories for you homework submissions in this course. Having uniform names for all student submissions makes grading submissions much easier. If you do not adhere to the naming conventions, grading of your work will be delayed, or it may simply be returned to you ungraded for you to correct the names.

For information on how to run the various programming language compilers/interpreters, click here. You will find resources for these languages on the course web site, under the "Resources" page. You might the following page, listing available CSE systems, helpful too: http://www-local.cse.buffalo.edu/Services/Data/Student/

Question: (100 points - 35 points each for C# and Prolog, 30 points for ML)

In this homework you will write the beginnings of a Scheme interpreter. You will build on what you do in this homework in your next homework. You must write your code in each of the following three languages: C# (use Mono), ML (use SML/NJ), and Prolog (use Sicstus). Put your C# solution in a file named hw3.cs, your ML solution in a file named hw3.ml, and your Prolog solution in a file named hw3.pl.

Your interactive Scheme interpreter must provide a read-eval-print loop (RELP) which prompts for an expression, evaluates the expression (if well formed), prints either the value of the expression (if it was well-formed) or an error message (if it was not well-formed), and loops back to prompt for another expression.

In each language, use "> " as the REPL prompt. In C#, your program should start up the REPL right away. In ML, name the main function in your program scheme, a function of type unit->unit. In Prolog, name the main predicate in your program scheme, a predicate of arity zero (i.e. taking zero arguments).

The REPL must be able to evaluate the following kinds of expressions:

  • integers - integers are interpreted in base 10
  • names - names are evaluated by looking them up in an environment, starting with the current environment, following static links, until the name is found. If it is not found, an error occurs. Names must consist of only letters, and cannot be either "define" or "exit".
  • (define <name> <expression>) is evaluated by first evaluating , and binding, in the current environment, the name to the that value. As discussed in class, binding a name to a value in an environment should work the way it does in ML: entering multiple bindings for a name in a given environment does not overwrite existing bindings, but new bindings must be found before older ones.

    The value of a define is the value assigned to the variable(i.e. the value of <expression>. If <expression> is not well-formed, the value of the define is Invalid (see below), and no binding takes place.

  • (exit) is evaluated by terminating the REPL. An exit does have a value (Invalid) but for practical purposes it doesn't matter (since the interpreter exits as a result or evaluating it).
If you wish to plan ahead for the next homework, here is a requirement you are not yet responsible for, but which you will need to implement eventually (along with some others):
  • arithmetic expressions - expressions involving +, -, * and / (integer division) of the typical scheme form, for example (+ x y).

Suggestion

Build up the appropriate abstractions first! For example, you will need an environment abstraction. You should also define a disjoint union of expression types. Because getting the types right in ML might be a bit challenging, here are some code snippets you can use.

Expression type (a disjoint union)

datatype Expression = Invalid of string | Number of int | Name of string | Define of string * Expression;

Expression to string conversion

fun expression2string(Invalid(msg)) = msg
  | expression2string(Number(x)) = Int.toString(x)
  | expression2string(Name(str)) = str
  | expression2string(Define(str,exp2)) = 
        str ^ " bound to value of " ^ expression2string(exp2);

Using String.tokens to parse input
Read basis library documentation for more information on String.tokens

fun space(#" ") = true
  | space(x) = false;

fun parse(str) = 
    let
	val tokens = String.tokens space str
    in
        (* DO YOUR PARSING HERE *)
    end;

Environment to string conversion
Assuming an environment is represented as a list of key-value tuples (an association list), this function returns a string representation given an environment.

fun environment2string([]) = ""
  | environment2string((k,v)::rest) = 
        "("^k^","^expression2string(v)^")"^environment2string(rest);

Name lookup in an environment

Assuming an environment is represented as a list of key-value tuples (an association list), this function returns SOME(value) if key-value is a pair in the environment, NONE otherwise.

fun lookup(str,[]) = NONE
  | lookup(str,(k,v)::rest) = 
      if (String.compare(str,k)=EQUAL) then SOME(v) else lookup(str,rest);

This page written an maintained by Carl Alphonce.
CSE305 Spring 2008

 

Page maintained by Carl Alphonce
tel: (716) 645-3180 x 115 • fax: (716) 645-3464 • e-mail: alphonce (at) cse dot buffalo dot edu