共计 5420 个字符,预计需要花费 14 分钟才能阅读完成。
CMPSC 461, HW11 MUL461 Part A
Due: April 22rd, 11:59PM
Set-up: For this assignment, edit a copy of mula.rkt, which is on the course website. In particular,
replace occurrences of “CHANGE” to complete the problems. Do not use any mutation (set!, set-mcar!,
etc.) anywhere in the assignment.
Overview: This project has to do with mul461 (a Made Up Language for CMPSC 461). mul461 programs
are written directly in Racket by using the constructors defined by the structs defined at the beginning of
mula.rkt. This is the definition of mul461’s syntax for Part A:
• If s is a Racket string, then (mul461-var s) is a mul461 expression (a variable use).
• If n is a Racket integer, then (mul461-int n) is a mul461 expression (an integer constant).
• If e1 and e2 are mul461 expressions, then (mul461-+ e1 e2) is a mul461 expression (an addition).
• If e1 and e2 are mul461 expressions, then (mul461– e1 e2) is a mul461 expression (a subtraction).
• If e1 and e2 are mul461 expressions, then (mul461-* e1 e2) is a mul461 expression (a multiplication).
• If b is a Racket boolean, then (mul461-bool b) is a mul461 expression (a boolean constant).
• If e1 and e2 are mul461 expressions, then (mul461-and e1 e2) is a mul461 expression. e1 and e2
should both evaluate to mul461-bool values.
• If e1 and e2 are mul461 expressions, then (mul461-or e1 e2) is a mul461 expression. e1 and e2
should both evaluate to mul461-bool values.
• If e is a mul461 expression that evaluates to a mul461-bool value, then (mul461-not e) is a mul461
expression.
• If e1 and e2 are mul461 expressions, then (mul461-< e1 e2) is a mul461 expression that evaluates
to a mul461-bool value if e1 and e2 evaluate to mul461-int values.
• If e1 and e2 are mul461 expressions, then (mul461-= e1 e2) is a mul461 expression that evaluates
to a mul461-bool value if e1 and e2 evaluate to mul461-int values.
• If e1, e2, and e3 are mul461 expressions, then (mul461-if e1 e2 e3) is a mul461 expression. It is a
condition where the result is e2 if e1 is a boolean constant of true else the result is e3. Only one of e2
and e3 is evaluated.
• If s is a Racket string and e1 and e2 are mul461 expressions, then (mul461-let s e1 e2) is a mul461
expression (a let expression where the value resulting from evaluating e1 is bound to s in the evaluation
of e2).
In Part A, A mul461 value is a mul461 integer constant, a or a mul461 boolean constant.
You should assume mul461 programs are syntactically correct (e.g., do not worry about wrong things like
(mul461-int “hi”) or (mul461-int (mul461-int 37)). But do not assume mul461 programs are free of
type errors like (mul461-+ (mul461-bool #t) (mul461-int 7)) or (mul461-not (mul461-int 3)).
Warning: What makes this assignment challenging is that you have to understand mul461 well and
debugging an interpreter is an acquired skill.
Turn-in Instructions: Turn in your modified mula.rkt to gradescope.
1
Problems:
- Implementing the mul461 Language: Write a mul461 interpreter, i.e., a Racket function eval-exp
that takes a mul461 expression e and either returns the mul461 value that e evaluates to under the
empty environment or calls Racket’s error if evaluation encounters a run-time mul461 type error or
unbound mul461 variable.
A mul461 expression is evaluated under an environment (for evaluating variables, as usual). In your
interpreter, use a Racket list of Racket pairs to represent this environment (which is initially empty)
so that you can use without modification the provided envlookup function. Here is a description of
the semantics of mul461 expressions:
• All values evaluate to themselves. For example, (eval-exp (mul461-int 17)) would return
(mul461-int 17), not 17.
• A variable evaluates to the value associated with it in the environment.(This case for var is done
for you.)
• An addition/subtraction/multiplication evaluates its subexpressions and, assuming they both
produce integers, produces the mul461-int n that is their sum/difference/product. (Note the
case for addition is done for you to get you pointed in the right direction.)
• An < or = comparison evaluates its subexpressions and, assuming they both produce integers,
produces the mul461-bool b that is the result of comparing the two integer values.
• An and/or evaluates its subexpressions and, assuming they both produce booleans, produces the
mul461-bool b that is their and/or boolean operation result.
• A not evaluates its subexpression and, assuming it produces a boolean, produces the mul461-bool
b that is the logical negation of its subexpression result.
• An if evaluates its first expression to a value v1. If it is a boolean, then if it is mul461-bool #t,
then if evaluates to its second subexpression, else it evaluates its third subexpression. Only one
of e2 and e3 should be evaluated. Do not evaluate both e2 and e3.
• A let expression evaluates its first expression to a value v. Then it evaluates the second expression
to a value, in an environment extended to map the name in the let expression to v. - Expanding the Language: mul461 is a small language, but we can write Racket functions that act
like mul461 macros so that users of these functions feel like mul461 is larger. The Racket functions
produce mul461 expressions that could then be put inside larger mul461 expressions or passed to
eval-exp. In implementing these Racket functions, do not use closure (which is used only internally
in eval-exp). Also do not use eval-exp (we are creating a program, not running it).
(a) Write a Racket function makelet* that takes a Racket list of Racket pairs’((s1 . e1) . . . (si
. ei)
. . . (sn . en)) and a final mul461 expression en+1. In each pair, assume si
is a Racket string and ei
is a mul461 expression. makelet* returns a mul461 expression whose value is en+1 evaluated in
an environment where each si
is a variable bound to the result of evaluating the corresponding ei
for 1 ≤ i ≤ n. The bindings are done sequentially, so that each ei
is evaluated in an environment
where s1 through si−1 have been previously bound to the values e1 through ei−1. - Using the Language: We can write mul461 expressions directly in Racket using the constructors
for the structs and (for convenience) the functions we wrote in the previous problem.
(a) Write a function makefactorial that gives a racket integer n, returns a mul461 expression that
is similar to n ∗ ((n − 1) ∗ (n − 2)… ∗ 1) using mul461 constructs. For example (makefactorial
3) should return this value:
(mul461- (mul461-int 3) (mul461- (mul461-int 2) (mul461-int 1))).