Due: Friday, September 18th, 2009 9:40am
Start with the F1WAE interpreter, and extend the implementation to support multiple or zero arguments to a function, and multiple or zero arguments in a function call:
<FunDef> = {deffun {<id> <id>*} <F1WAE>} <F1WAE> = <number> | {+ <F1WAE> <F1WAE>} | {- <F1WAE> <F1WAE>} | {with {<id> <F1WAE>} <F1WAE>} | <id> | {<id> <F1WAE>*}
Since you must change the F1WAE datatype, and since different people may change it in different ways, you must provide a parse function this time, which accepts a quoted expression and produces an F1WAE value. For parsing, assume that any symbol other than '+, '-, or 'with can be a function name for a function call. Also, you must provide a parse-defn function that takes one (quoted) deffun form and produces a FunDef value.
At run-time, a new error is now possible: function application with the wrong number of arguments. Your interp function should detect the mismatch and report an error that includes the words "wrong arity".
Some examples:
(test (interp (parse '{f 1 2}) (list (parse-defn '{deffun {f x y} {+ x y}}))) 3) (test (interp (parse '{+ {f} {f}}) (list (parse-defn '{deffun {f} 5}))) 10) (test/exn (interp (parse '{f 1}) (list (parse-defn '{deffun {f x y} {+ x y}}))) "wrong arity")
A function would be ill-defined if two of its argument <id>s were the same. To prevent this problem, your parse-defn function should detect this problem and reports a "bad syntax" error. For example, (parse-defn '{deffun {f x x} x}) should report a "bad syntax" error, while (parse-defn '{deffun {f x y} x}) should produce a FunDef value.
Remember that the PLAI language provides the following useful function:
Extend your interpreter to support the construction of records with named fields, and to support field selection from a record:
<F1WAE> = ... | {rec {<id> <F1WAE>}*} | {get <F1WAE> <id>}
Your revised parse should check that each <id> is distinct in a rec expression.
Adding records means that the language now has two kinds of values: numbers and records. At run-time, an error may occur because a record is misused as a number, a number is supplied to get, or a record supplied to get does not have the named field. Your error message for the last case should include the words "no such field", otherwise you can make up your own error messages (or just let primitive error checking handle problems, such as trying to add a record to a number).
Extend parse to support rec and get expressions.
Since records are now values, the result of interp can be a record instead of a number. For homework purposes, we don't want to nail down the representation of a record result, because there are many choices. The examples below therefore use interp-expr, which is a wrapper on interp that just a number if interp produces a number, but it returns the symbol 'record if interp produces a record value.
Examples:
(test (interp-expr (parse '{rec {a 10} {b {+ 1 2}}}) empty) 'record) (test (interp-expr (parse '{get {rec {a 10} {b {+ 1 2}}} b}) empty) 3) (test (interp-expr (parse '{get {rec {a 10}} b}) empty)) "no such field") (test (interp-expr (parse '{g {rec {a 0} {c 12} {b 7}}}) (list (parse-defn '{deffun {g r} {get r c}}))) 12) (test (interp-expr (parse '{get {rec {r {rec {z 0}}}} r}) empty) 'record) (test (interp-expr (parse '{get {get {rec {r {rec {z 0}}}} r} z}) empty) 0)
Last update: Thursday, December 3rd, 2009mflatt@cs.utah.edu |