Assignment 2



Due on Oct 2 before lecture.

Email your solutions to pdarga@umich.edu.



You can download MIT/GNU Scheme from here. Please use Scheme version 7.7.90.

(Note, we had previously suggested the latest Scheme version 7.7.90+. That seems to be incompatible with Scheme+. So please use the above older Scheme version 7.7.90.)

Or, you can log into a CAEN linux machine (such as loginlinux.engin.umich.edu) or a DCO linux machine (such as willow.eecs.umich.edu), and run scheme as follows:
% cd ~bchandra/490
% ./scheme


In this assignment you will modify an interpreter for the PostFix language as described in the Turbak text, Chapters 1-3. Your interpreter will mirror the small-step operational sematics rewrite rules on page 47 of the text. This assignment will also give you an opportunity to use the pattern-matching facilities of Scheme+.

Files Getting Started with PostFix

To get started with PostFix, we first must load the Scheme+ file and the PostFix support file into the interpreter.

(load "scheme+.scm")
(load "base.scm")
(load "postfix.scm")

After that, we can begin testing some simple PostFix programs with the supplied semantics.

(postfix 0 3) lambda (list) (...)
((postfix 0 3) '()) 3
((postfix 2 pop) '(4 5)) 5
((postfix 2 pop) '(4)) error "expected two arguments"
((postfix 0 pop) '()) "stuck: pop"

In general, to evaluate a PostFix program, apply it to a list of numbers with as many elements as the first argument to postfix.

Overview of the Interpreter

The interpreter closely follows the rewrite rules presented as part of the small-step operational semantics of PostFix. These rules are listed on page 47 of the Turbak text. Each rewrite rule transforms a configuration into another. In PostFix, a configuration is a tuple consisting of a list of commands and a stack. For example, the rule labeled [pop] takes a configuration with pop at the head of the command list and a value at the top of the stack, and returns a configuration with pop removed from the command list and the value at the top of the stack removed.

The interpreter makes use of a function small-step which, given a PostFix configuration, returns a new PostFix configuration representing the completion of one step of the PostFix computation. That is, given a configuration, it applies one of the rewrite rules and returns the rewritten configuration.

Datatypes for the PostFix Interpreter

The PostFix support file contains the declarations of several datatypes which are used in the interpreter. These datatypes define what configurations, commands, and stack values look like to the small-step interpreter.

Commands

As described in section 1.4.1 of the Turbak text, the commands in PostFix are:

The provided PostFix infrastructure converts PostFix syntax into a list of commands, where each command matches one of the following:

Stack Values

As stated in section 1.4.2 of the Turbak text: a value on the stack is either (1) an integer numeral or (2) an executable sequence. The provided infrastructure expects data matching one of the following:

Notice the difference between the constructors for stack data and commands: the stack data constructors begin with '$' while the commands begin with '@'.

Configurations

A configuration is simply a tuple containing a command list and a list of stack values: ($conf command-list stack).

How small-step works

The infrastructure calls small-step with a configuration, and expects it to return a configuration. The code assumes that the command list passed to small-step is non-null; that is, it has at least one command in it. The provided semantics uses Scheme+ pattern matching to get at that first command and the stack:

(define (small-step config)
  (match config
    (($conf (cons cmd rest-cmds) stack) ... )))

Notice that Scheme+ pattern matching was able to look not only inside the configuration, but also inside one of its elements, namely the command list. This facility will be useful for examining the state of the stack for some of the commands. In fact, the only way to inspect the type of values present on the stack is to use pattern matching.

Command Implementations

Now looking inside the ... in the above code from the semantics:

     (match cmd
       ((@num n)
	($conf rest-cmds (cons ($num n) stack)))
       ((@pop)
	(match stack
          ((cons _ rest-stk) ($conf rest-cmds rest-stk))
	  (_ (stuck "pop"))))
       ...)

The first example matches numeric literals, and simply returns a new configuration with the number removed from the command list and added to the top of the stack. Each clause looks roughly like this, matching a command name and returning a new configuration using $conf.

The second example above, @pop, performs a pattern match on the stack, ignores the top element, and returns the rest of the stack. This example highlights the use of stuck: if the pattern match fails, then no rewrite rule applies for this configuration in the operational semantics. Therefore, we cannot continue computation; we say we are stuck.

In the implementation of small-step, if no rewrite rule applies to the given configuration, the code calls stuck, passing it a string with the name of the command that failed. Every syntactically correct PostFix program does not cause a pattern match failure or otherwise cause an error; the interpreter instead calls stuck.


Warmup: Implement nget

All PostFix commands are implemented in the provided small-step, except for nget. Fill in the empty implementation of nget to complete the PostFix interpreter. Don't try PostText until you have nget working for PostFix! Implementing nget will help you understand the inner workings of the small-step interpreter.


Problem 1: PostText

One of the chief limitations of the PostFix language is that there is no way to name values. In this problem, we consider extending PostFix with a simple naming system. We will call the resulting language PostText. (This is adapted from a problem in the Turbak text.)

The grammar for PostText is the same as that for PostFix except that there are three new commands:

C ::= ...
	| I [Name]
	| def [Definition]
	| ref [Name-reference]

Here, I is an element of the syntactic domain Identifier, which includes all alphabetic names except for the PostText command names (pop, exec, def, etc.), which are treated as reserved words of the language.

The model of the PostText language extends the model of PostFix by including a current dictionary as well as a current stack. A dictionary is an object that maintains bindings between names and values. The commands inherited from PostFix have no effect on the dictionary. The informal behavior of the new commands is as follows:

I: I is a literal name that is similar to an immutable string literal in other languages. Executing this command simply pushes I on the stack. The Value domain must be extended to include identifiers in addition to numerals and executable sqeuences.

def: Let v1 be the top stack value and v2 be the next to top value. The def command pops both values off of the stack and updates the current dictionary to include a binding between v2 and v1. v2 should be a name, but v1 can be any value (including an executable sequence or name literal). It is an error if v2 is not a name.

ref: The ref command pops the top element vname off of the stack, where vname should be a name I. It looks up the value vval associated with I in the current dictionary and pushes vval on top of the stack. It is an error if there is no binding for I in the current dictionary or if vname is not a name.

Consider the following evaulations:

PostText program Result
((posttext 0 average (add 2 div) def 3 7 average ref exec) '()) 5
((posttext 0 a 3 def dbl (2 mul) def a ref dbl ref exec 4 dbl ref exec add) '()) 14
((posttext 0 a b def a ref 7 def b ref) '()) 7
((posttext 0 a 5 def a ref 7 def b ref) '()) "stuck: def"
((posttext 0 c 4 def d ref 1 add) '()) "stuck: ref"

In an SOS for PostText, the usual PostFix configuration space must be extended to include a dictionary object as a new state component:

CFPostText = Commands X Stack X Dictionary



Problem 1a:PostText Operational Semantics (4 Points)

Suppose that a dictionary is represented as a sequence of identifier/value pairs:

D ∈ Dictionary = (Identifier X Value)*
  1. Define the final configurations, input function, and output function for the PostText SOS.
  2. Give the rewrite rules for the I, def, and ref commands.



Problem 1b:Extend small-step for PostText (12 Points)

In this problem you will extended the provided small-step function for PostFix to handle PostText. Here is a brief list of hints to get you started:


Problem 2: Test Cases (4 Points)

As in assignment 1, supply a test suite along with your code. Your test suite should be appended to the end of your solution, and involve a series of applications of check to a quoted PostText program and its expected result. If the computation is supposed to get stuck on the given test case, supply the name of the command which gets stuck, appended to "stuck: ", as the expected value.
(check '((posttext 1 4 add) '(3)) 7)
(check '((posttext 0 1 2 pop swap) '()) "stuck: swap")



Summary



[Mail] [bchandra at umich dot edu]