EECS 321 Programming Languages: Homework 6

Due: Friday, February 17th, 2012, noon

Part 1 – Mutable Structs

Add struct and get forms for records, and also add a set form that modifies the value of a record field:

  <RCFAE> = <number>
          | {+ <RCFAE> <RCFAE>}
          | {- <RCFAE> <RCFAE>}
          | {fun {<id>} <RCFAE>}
          | {<RCFAE> <RCFAE>}             ;; function application
          | <id>
          | {with {<id> <RCFAE>} <RCFAE>} ;; shorthand for fun & app
          | {struct {<id> <RCFAE>} ...}
          | {get <RCFAE> <id>}
          | {set <RCFAE> <id> <RCFAE>}
          | {seqn <RCFAE> <RCFAE>}

A struct form allocates a new record. A get form accesses from the record produced by the sub-expression the value of the field named by the identifier. A set form changes within the record produced by the first sub-expression the value of the field named by the identifer; the value of the second sub-expression determines the field's new value, and the origianl (now clobbered) value must be the result of the set expression.

Each of struct, get, and set evaluate all of their sub-expressions before doing the corresponding operations.

Also extend parse and define the usual interp-expr, which takes an expression and interprets it with an empty initial deferred substitution and empty initial store, and returns either a number, 'procedure, or 'struct (without returning the store).

Your implementation must not use mutation at the PLAI level.

Some examples (these are just a few to think about; this does not constitute anything near a comprehensive test suite):

  (test/exn (interp-expr (parse '{struct {z {get {struct {z 0}} y}}})
            "no such field")

  (test (interp-expr (parse '{{fun {r}
                                {get r x}}
                              {struct {x 1}}}))

  (test (interp-expr (parse '{{fun {r}
                                  {set r x 5}
                                  {get r x}}}
                              {struct {x 1}}}))

  (test (interp-expr (parse `{set {struct {x 42}} x 2}))

  (test (interp-expr (parse '{{{{{fun {g}
                                   {fun {s}
                                     {fun {r1}
                                       {fun {r2}
                                         {+ {get r1 b}
                                              {{s r1} {g r2}}
                                              {+ {seqn
                                                   {{s r2} {g r1}}
                                                   {get r1 b}}
                                                 {get r2 b}}}}}}}}
                                 {fun {r} {get r a}}}            ; g
                                {fun {r} {fun {v} {set r b v}}}} ; s
                               {struct {a 0} {b 2}}}             ; r1
                              {struct {a 3} {b 4}}}))            ; r2

Part 2 – Eliminating old bindings

If you used the same strategy we did in class for implementing the store, this program:

{with {b {struct {x 1}}}
  {with {f {fun {f}
             {seqn {set b x 2}
                   {f f}}}}
    {f f}}}
will (eventually) consume all of the memory available because the store grows without bound. Adjust your implementation so that the store's size is proportional only to the number of struct expressions that were evaluated, not to the number of set operations.

To help you experiment with your interpreter, use this function:

;; size : any -> number
;; computes a (very rough!) approximate to
;; the size a PLAI object takes in memory
(define (size s)
    [(struct? s)
     (size (struct->vector s))]
    [(vector? s)
     (for/fold ([tot 0])
               ([ele (in-vector s)])
       (+ tot (size ele)))]
    [(pair? s)
     (+ 1 (size (car s)) (size (cdr s)))]
    [else 1]))
Something like this:
;; interp : RCFAE DefrdSub Store -> Value*Store
(define (interp a-rcfae ds store)
  (printf "size ~s\n" (size store))
  (type-case RCFAE a-rcfae

Part 3 – Errors

There are five different kinds of errors that can occur (at runtime) in this language and for each error in the input program, your interpreter must signal an error that includes one of the following phrases:

free identifier
application expected procedure
numeric operation expected number
record operation expected record
unknown field

Part N – Handin instructions

Provide a definition of interp-expr : RCFAE -> number or 'procedure or 'struct, as above.

Provide a definition of parse : sexpression -> RCFAE, as usual (no extra n-ary functions this time, but do include with as a parser transformation)

Last update: Friday, February 17th, 2012