From 4530d977828ef03b64c9ff6efa643deaec59c094 Mon Sep 17 00:00:00 2001 From: David Van Horn Date: Wed, 10 Sep 2025 06:30:37 -0400 Subject: [PATCH 1/4] Revision of assign 3 and 4. Assignment 3 has been split into two assignments (3 & 4 now). The first does new primitives and cond. The second does case. This change updates the descriptions to reflect the new structure. --- www/assignments/3.scrbl | 204 ++++++++++++---------------------------- www/assignments/4.scrbl | 185 +++++++++--------------------------- 2 files changed, 104 insertions(+), 285 deletions(-) diff --git a/www/assignments/3.scrbl b/www/assignments/3.scrbl index a56cb4a4..8ca56172 100644 --- a/www/assignments/3.scrbl +++ b/www/assignments/3.scrbl @@ -8,17 +8,15 @@ The goal of this assignment is to extend the language developed in @secref{Dupe} with some simple unary numeric and boolean operations -and two forms of control flow expressions: @racket[cond]-expressions -and @racket[case]-expressions. +and a new form of control flow expressions: @racket[cond]-expressions. -@section[#:tag-prefix "a3-" #:style 'unnumbered]{Dupe+} +@section[#:tag "a3-dupe-plus" #:style 'unnumbered]{Dupe+} The Dupe+ language extends Dupe in the follow ways: @itemlist[ @item{adding new primitive operations,} -@item{adding @racket[cond], and} -@item{adding @racket[case].} +@item{adding @racket[cond].} ] @subsection[#:tag-prefix "a3-" #:style 'unnumbered]{Primitives} @@ -27,7 +25,7 @@ The following new primitves are included in Dupe+: @itemlist[ @item{@racket[(abs _e)]: compute the absolute value of @racket[_e],} -@item{@racket[(- _e)]: flips the sign of @racket[_e], i.e. compute @math{0-@racket[_e]}, and} +@item{@racket[(- _e)]: flip the sign of @racket[_e], i.e. compute @math{0-@racket[_e]}, and} @item{@racket[(not _e)]: compute the logical negation of @racket[_e]; note that the negation of @emph{any} value other than @racket[#f] is @racket[#f] and the negation of @racket[#f] is @racket[#t].} ] @@ -42,10 +40,10 @@ The following new conditional form is included in Dupe+: ] A @racket[cond] expression has any number of clauses @racket[[_e-pi -_e-ai] ...], followed by an ``else'' clause @racket[[else _en]]. For -the purposes of this assignment, we will assume every @racket[cond] -expression ends in an @racket[else] clause, even though this is not -true in general for Racket. The parser should reject any +_e-ai] ...], followed by an ``else'' clause @racket[[else _e-an]]. +For the purposes of this assignment, we will assume every +@racket[cond] expression ends in an @racket[else] clause, even though +this is not true in general for Racket. The parser will reject any @racket[cond]-expression that does not end in @racket[else]. @@ -56,43 +54,65 @@ does not evaluate to @racket[#f] is found, in which case, the corresponding expr @racket[cond] expression. If no such @racket[_e-pi] exists, the expression @racket[_e-an]'s value is the value of the @racket[cond]. -@subsection[#:tag-prefix "a3-" #:style 'unnumbered]{Case expressions} -The following new case form is included in Dupe+: +@section[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing Dupe+} -@racketblock[ -(case _ev - [(_d1 ...) _e1] - ... - [else _en]) -] +You must extend the interpreter and compiler to implement Dupe+. (The +parser for Dupe+ is given to you.) You are given a file +@tt{dupe-plus.zip} on ELMS with a starter compiler based on the +@secref{Dupe} language we studied in class. -The @racket[case] expression form is a mechanism for dispatching -between a number of possible expressions based on a value, much like -C's notion of a @tt{switch}-statement. +You may use any a86 instructions you'd like, however it is possible to +complete the assignment using @racket[Cmp], @racket[Je], @racket[Jg], +@racket[Jmp], @racket[Label], @racket[Mov], and @racket[Sub]. -The meaning of a @racket[case] expression is computed by evaluating -the expression @racket[_ev] and then proceeding in order through each -clause until one is found that has a datum @racket[_di] equal to -@racket[_ev]'s value. Once such a clause is found, the corresponding -expression @racket[_ei] is evaluated and its value is the value of the -@racket[case] expression. If no such clause exists, expression -@racket[_en] is evaluated and its value is the value of the -@racket[case] expression. +@section[#:tag-prefix "a3-" #:style 'unnumbered #:tag "parse"]{Parsing Dupe+} -Note that each clause consists of a parenthesized list of -@emph{datums}, which in the setting of Dupe means either integer or -boolean literals. +The AST type and parser for Dupe+ are given to you. -@section[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing Dupe+} +Here's the AST definition for the added primitives and @racket[cond]: -You must extend the parser, interpreter, and compiler to implement -Dupe+. You are given a file @tt{dupe-plus.zip} on ELMS with a starter -compiler based on the @secref{Dupe} language we studied in class. +@#reader scribble/comment-reader +(racketblock +;; type Expr = +;; ... +;; | (Cond [Listof CondClause] Expr) -You may use any a86 instructions you'd like, however it is possible to -complete the assignment using @racket[Cmp], @racket[Je], @racket[Jg], -@racket[Jmp], @racket[Label], @racket[Mov], and @racket[Sub]. +;; type CondClause = (Clause Expr Expr) + +;; type Op = +;; ... +;; | 'abs | '- | 'not + +(struct Cond (cs e) #:prefab) +(struct Clause (p b) #:prefab) +) + +There is one new kind of expression constructor: @racket[Cond]. A +@racket[Cond] AST node contains a list of cond-clauses and expression, +which the expression of the @racket[else] clause. Each cond-clause is +represented by a @racket[Clause] structure containing two expressions: +the left-hand-side of the clause which is used to determine whether +the right-hand-side is evaluated, and the right-hand-side expression. + +Here are some examples of how concrete expressions are parsed into +ASTs using this representation: + +@itemlist[ + +@item{@racket[(abs 1)] parses as @racket[(Prim1 'abs (Lit 1))],} + +@item{@racket[(not #t)] parses as @racket[(Prim1 'not (Lit #t))],} + +@item{@racket[(cond [else 5])] parses as @racket[(Cond '() (Lit 5))],} + +@item{@racket[(cond [(not #t) 3] [else 5])] parses as @racket[(Cond +(list (Clause (Prim1 'not (Lit #t)) (Lit 3))) (Lit 5))],} + +@item{@racket[(cond [(not #t) 3] [7 4] [else 5])] parses as +@racket[(Cond (list (Clause (Prim1 'not (Lit #t)) (Lit 3)) (Clause +(Lit 7) (Lit 4))) (Lit 5))],} +] @subsection[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing primitives} @@ -103,8 +123,7 @@ these using the limited a86 instruction set. To do this, you should: @itemlist[ -@item{Study @tt{ast.rkt} and the new forms of expression (i.e. new AST nodes) - then update the comment at the top describing what the grammmar should look like.} +@item{Study @tt{ast.rkt} to understand how these new forms of expression are represented.} @item{Study @tt{parse.rkt} and add support for parsing these expressions. (See @secref[#:tag-prefixes '("a3-")]{parse} for guidance.)} @@ -126,7 +145,6 @@ To do this, you should: @itemlist[ @item{Study @tt{ast.rkt} to add appropriate AST nodes.} -@item{Extend @tt{parse.rkt} to parse such expressions. (See @secref[#:tag-prefixes '("a3-")]{parse} for guidance.)} @item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[cond] expressions.} @item{Make examples of @racket[cond]-expressions and potential translations of them @@ -138,108 +156,6 @@ expressions based on your examples.} @item{Check your implementation by running the tests in @tt{test/all.rkt}.} ] -@section[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing case} - -Implement the @racket[case] expression form as described earlier. -To do this, you should: - -@itemlist[ -@item{Study @tt{ast.rkt} to add appropriate AST nodes.} -@item{Extend @tt{parse.rkt} to parse such expressions. (See @secref[#:tag-prefixes '("a3-")]{parse} for guidance.)} -@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[case] expressions.} - -@item{Make examples of @racket[case]-expressions and potential translations of them -to assembly.} - -@item{Update @tt{compile.rkt} to correctly compile @racket[case] expressions based on your examples.} - -@item{Check your implementation by running the tests in @tt{test/all.rkt}.} -] - -@section[#:tag-prefix "a3-" #:style 'unnumbered #:tag "parse"]{A Leg Up on Parsing} - -In the past, designing the AST type and structure definitions has -given students some grief. Getting stuck at this point means you -can't make any progress on the assignment and making a mistake at this -level can cause real trouble down the line for your compiler. - -For that reason, let us give you a strong hint for a potential design -of the ASTs and examples of how parsing could work. You are not -required to follow this design, but you certainly may. - -Here's a potential AST definition for the added primitives, -@racket[cond], and @racket[case]: - -@#reader scribble/comment-reader -(racketblock -;; type Expr = -;; ... -;; | (Cond [Listof CondClause] Expr) -;; | (Case Expr [Listof CaseClause] Expr) - -;; type CondClause = (Clause Expr Expr) -;; type CaseClause = (Clause [Listof Datum] Expr) - -;; type Datum = Integer | Boolean - -;; type Op = -;; ... -;; | 'abs | '- | 'not - -(struct Cond (cs e) #:prefab) -(struct Case (e cs el) #:prefab) -(struct Clause (p b) #:prefab) -) - -There are two new kinds of expression constructors: @racket[Cond] and -@racket[Case]. A @racket[Cond] AST node contains a list of -cond-clauses and expression, which the expression of the @racket[else] -clause. Each cond-clause is represented by a @racket[Clause] -structure containing two expressions: the left-hand-side of the -clause which is used to determine whether the right-hand-side is -evaluated, and the right-hand-side expression. - -The @racket[Case] AST node contains three things: an expression that -is the subject of the dispatch (i.e. the expression that is evaluated -to determine which clause should be taken), a list of case-clauses -(not to be confused with cond-clauses), and an @racket[else]-clause -expression. Each case-clause, like a cond-clause, consists of two -things. Hence we re-use the @racket[Clause] structure, but with -different types of elements. The first element is a list of -@emph{datums}, each being either an integer or a boolean. - -Now, we won't go so far as to @emph{give} you the code for -@racket[parse], but we can give you some examples: - -@itemlist[ - -@item{@racket[(abs 1)] parses as @racket[(Prim1 'abs (Lit 1))],} - -@item{@racket[(not #t)] parses as @racket[(Prim1 'not (Lit #t))],} - -@item{@racket[(cond [else 5])] parses as @racket[(Cond '() (Lit 5))],} - -@item{@racket[(cond [(not #t) 3] [else 5])] parses as @racket[(Cond -(list (Clause (Prim1 'not (Lit #t)) (Lit 3))) (Lit 5))],} - -@item{@racket[(cond [(not #t) 3] [7 4] [else 5])] parses as -@racket[(Cond (list (Clause (Prim1 'not (Lit #t)) (Lit 3)) (Clause -(Lit 7) (Lit 4))) (Lit 5))],} - -@item{@racket[(case (add1 3) [else 2])] parses as @racket[(Case (Prim1 -'add1 (Lit 3)) '() (Lit 2))].} - -@item{@racket[(case 4 [(4) 1] [else 2])] parses as @racket[(Case (Lit -4) (list (Clause (list 4) (Lit 1))) (Lit 2))],} - -@item{@racket[(case 4 [(4 5 6) 1] [else 2])] parses as @racket[(Case (Lit -4) (list (Clause (list 4 5 6) (Lit 1))) (Lit 2))], and} - -@item{@racket[(case 4 [(4 5 6) 1] [(#t #f) 7] [else 2])] parses as @racket[(Case (Lit -4) (list (Clause (list 4 5 6) (Lit 1)) (Clause (list #t #f) (Lit 7))) (Lit 2))].} -] - - @section[#:tag-prefix "a3-" #:style 'unnumbered]{Testing} You can test your code in several ways: diff --git a/www/assignments/4.scrbl b/www/assignments/4.scrbl index fa331721..179ae929 100644 --- a/www/assignments/4.scrbl +++ b/www/assignments/4.scrbl @@ -7,55 +7,23 @@ @bold{Due: @assign-deadline[4]} The goal of this assignment is to extend the language developed in -@secref{Dupe} with a new form of control flow expressions: +@secref{a3-dupe-plus} with another new form of control flow expressions: @racket[case]-expressions. -@section[#:tag-prefix "a4-" #:style 'unnumbered]{Dupe+} +@bold{Note:} you will need to carry forward all of the changes you +implemented for @secref{a3-dupe-plus}. -The Dupe+ language extends Dupe in the follow ways: +@section[#:tag-prefix "a4-" #:style 'unnumbered]{Dupe++} -@itemlist[ -@item{adding @racket[case].} -] - -@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Primitives} - -The following new primitves are included in Dupe+: +The Dupe++ language extends @secref{a3-dupe-plus} in the follow ways: @itemlist[ -@item{@racket[(abs _e)]: compute the absolute value of @racket[_e],} -@item{@racket[(- _e)]: flips the sign of @racket[_e], i.e. compute @math{0-@racket[_e]}, and} -@item{@racket[(not _e)]: compute the logical negation of @racket[_e]; note that the negation of @emph{any} value other than @racket[#f] is @racket[#f] and the negation of @racket[#f] is @racket[#t].} -] - -@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Conditional expressions} - -The following new conditional form is included in Dupe+: - -@racketblock[ -(cond [_e-p1 _e-a1] - ... - [else _e-an]) +@item{adding @racket[case].} ] -A @racket[cond] expression has any number of clauses @racket[[_e-pi -_e-ai] ...], followed by an ``else'' clause @racket[[else _en]]. For -the purposes of this assignment, we will assume every @racket[cond] -expression ends in an @racket[else] clause, even though this is not -true in general for Racket. The parser should reject any -@racket[cond]-expression that does not end in @racket[else]. - - -The meaning of a @racket[cond] expression is computed by evaluating -each expression @racket[_e-pi] in order until the first one that -does not evaluate to @racket[#f] is found, in which case, the corresponding expression -@racket[_e-ai] is evaluated and its value is the value of the -@racket[cond] expression. If no such @racket[_e-pi] exists, the -expression @racket[_e-an]'s value is the value of the @racket[cond]. - @subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Case expressions} -The following new case form is included in Dupe+: +The following new case form is included in Dupe++: @racketblock[ (case _ev @@ -81,79 +49,23 @@ Note that each clause consists of a parenthesized list of @emph{datums}, which in the setting of Dupe means either integer or boolean literals. -@section[#:tag-prefix "a4-" #:style 'unnumbered]{Implementing Dupe+} +For the purposes of this assignment, we will assume every +@racket[case] expression ends in an @racket[else] clause, even though +this is not true in general for Racket. The parser will reject any +@racket[case]-expression that does not end in @racket[else]. + -You must extend the parser, interpreter, and compiler to implement -Dupe+. You are given a file @tt{dupe-plus.zip} on ELMS with a starter +@section[#:tag-prefix "a4-" #:style 'unnumbered]{Implementing Dupe++} + +You must extend the interpreter and compiler to implement Dupe++. You +are given a file @tt{dupe-plus-plus.zip} on ELMS with a starter compiler based on the @secref{Dupe} language we studied in class. You may use any a86 instructions you'd like, however it is possible to complete the assignment using @racket[Cmp], @racket[Je], @racket[Jg], @racket[Jmp], @racket[Label], @racket[Mov], and @racket[Sub]. -@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Implementing primitives} - -Implement the primitives as described earlier. - -There are many ways to implement these at the assembly level. You should try implementing -these using the limited a86 instruction set. - -To do this, you should: -@itemlist[ -@item{Study @tt{ast.rkt} and the new forms of expression (i.e. new AST nodes) - then update the comment at the top describing what the grammmar should look like.} - -@item{Study @tt{parse.rkt} and add support for parsing these -expressions. (See @secref[#:tag-prefixes '("a4-")]{parse} for guidance.)} - -@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret these expressions.} - -@item{Make examples of these primitives and potential translations of them -to assembly.} - -@item{Update @tt{compile.rkt} to correctly compile these expressions.} - -@item{Check your implementation by running the tests in @tt{test/all.rkt}.} -] - -@section[#:tag-prefix "a4-" #:style 'unnumbered]{Implementing cond} - -Implement the @racket[cond] expression form as described earlier. -To do this, you should: - -@itemlist[ -@item{Study @tt{ast.rkt} to add appropriate AST nodes.} -@item{Extend @tt{parse.rkt} to parse such expressions. (See @secref[#:tag-prefixes '("a4-")]{parse} for guidance.)} -@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[cond] expressions.} - -@item{Make examples of @racket[cond]-expressions and potential translations of them -to assembly.} - -@item{Update @tt{compile.rkt} to correctly compile @racket[cond] -expressions based on your examples.} - -@item{Check your implementation by running the tests in @tt{test/all.rkt}.} -] - -@section[#:tag-prefix "a4-" #:style 'unnumbered]{Implementing case} - -Implement the @racket[case] expression form as described earlier. -To do this, you should: - -@itemlist[ -@item{Study @tt{ast.rkt} to add appropriate AST nodes.} -@item{Extend @tt{parse.rkt} to parse such expressions. (See @secref[#:tag-prefixes '("a4-")]{parse} for guidance.)} -@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[case] expressions.} - -@item{Make examples of @racket[case]-expressions and potential translations of them -to assembly.} - -@item{Update @tt{compile.rkt} to correctly compile @racket[case] expressions based on your examples.} - -@item{Check your implementation by running the tests in @tt{test/all.rkt}.} -] - -@section[#:tag-prefix "a4-" #:style 'unnumbered #:tag "parse"]{A Leg Up on Parsing} +@section[#:tag-prefix "a4-" #:style 'unnumbered #:tag "parse"]{Parsing Dupe++} In the past, designing the AST type and structure definitions has given students some grief. Getting stuck at this point means you @@ -171,58 +83,30 @@ Here's a potential AST definition for the added primitives, (racketblock ;; type Expr = ;; ... -;; | (Cond [Listof CondClause] Expr) ;; | (Case Expr [Listof CaseClause] Expr) -;; type CondClause = (Clause Expr Expr) ;; type CaseClause = (Clause [Listof Datum] Expr) ;; type Datum = Integer | Boolean -;; type Op = -;; ... -;; | 'abs | '- | 'not - -(struct Cond (cs e) #:prefab) (struct Case (e cs el) #:prefab) -(struct Clause (p b) #:prefab) ) -There are two new kinds of expression constructors: @racket[Cond] and -@racket[Case]. A @racket[Cond] AST node contains a list of -cond-clauses and expression, which the expression of the @racket[else] -clause. Each cond-clause is represented by a @racket[Clause] -structure containing two expressions: the left-hand-side of the -clause which is used to determine whether the right-hand-side is -evaluated, and the right-hand-side expression. - -The @racket[Case] AST node contains three things: an expression that -is the subject of the dispatch (i.e. the expression that is evaluated -to determine which clause should be taken), a list of case-clauses -(not to be confused with cond-clauses), and an @racket[else]-clause +There is one new kind of expression constructor: @racket[Case]. A +@racket[Case] AST node contains three things: an expression that is +the subject of the dispatch (i.e. the expression that is evaluated to +determine which clause should be taken), a list of case-clauses (not +to be confused with cond-clauses), and an @racket[else]-clause expression. Each case-clause, like a cond-clause, consists of two things. Hence we re-use the @racket[Clause] structure, but with different types of elements. The first element is a list of @emph{datums}, each being either an integer or a boolean. -Now, we won't go so far as to @emph{give} you the code for -@racket[parse], but we can give you some examples: +Here are some examples of how concrete expressions are parsed into +ASTs using this representation: @itemlist[ -@item{@racket[(abs 1)] parses as @racket[(Prim1 'abs (Lit 1))],} - -@item{@racket[(not #t)] parses as @racket[(Prim1 'not (Lit #t))],} - -@item{@racket[(cond [else 5])] parses as @racket[(Cond '() (Lit 5))],} - -@item{@racket[(cond [(not #t) 3] [else 5])] parses as @racket[(Cond -(list (Clause (Prim1 'not (Lit #t)) (Lit 3))) (Lit 5))],} - -@item{@racket[(cond [(not #t) 3] [7 4] [else 5])] parses as -@racket[(Cond (list (Clause (Prim1 'not (Lit #t)) (Lit 3)) (Clause -(Lit 7) (Lit 4))) (Lit 5))],} - @item{@racket[(case (add1 3) [else 2])] parses as @racket[(Case (Prim1 'add1 (Lit 3)) '() (Lit 2))].} @@ -237,6 +121,25 @@ Now, we won't go so far as to @emph{give} you the code for ] +@section[#:tag-prefix "a4-" #:style 'unnumbered]{Implementing case} + +Implement the @racket[case] expression form as described earlier. +To do this, you should: + +@itemlist[ +@item{Study @tt{ast.rkt} to understand how this new form of expression is represented.} + +@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[case] expressions.} + +@item{Make examples of @racket[case]-expressions and potential translations of them +to assembly.} + +@item{Update @tt{compile.rkt} to correctly compile @racket[case] expressions based on your examples.} + +@item{Check your implementation by running the tests in @tt{test/all.rkt}.} +] + + @section[#:tag-prefix "a4-" #:style 'unnumbered]{Testing} You can test your code in several ways: @@ -255,5 +158,5 @@ write additional test cases. @section[#:tag-prefix "a4-" #:style 'unnumbered]{Submitting} -To submit, use @tt{make} from within the @tt{dupe-plus} directory to +To submit, use @tt{make} from within the @tt{dupe-plus-plus} directory to create a zip file containing your work and submit it to Gradescope. From fecc31bb16197516982ea033678c684e755a0dab Mon Sep 17 00:00:00 2001 From: David Van Horn Date: Wed, 10 Sep 2025 06:36:35 -0400 Subject: [PATCH 2/4] Small tweaks to assign 4 write-up. --- www/assignments/4.scrbl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/www/assignments/4.scrbl b/www/assignments/4.scrbl index 179ae929..4babf9ef 100644 --- a/www/assignments/4.scrbl +++ b/www/assignments/4.scrbl @@ -129,13 +129,15 @@ To do this, you should: @itemlist[ @item{Study @tt{ast.rkt} to understand how this new form of expression is represented.} -@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[case] expressions.} +@item{Update @tt{interp.rkt} to correctly interpret @racket[case] expressions.} @item{Make examples of @racket[case]-expressions and potential translations of them to assembly.} @item{Update @tt{compile.rkt} to correctly compile @racket[case] expressions based on your examples.} +@item{Bring forward all the changes you made for @secref{a3-dupe-plus}.} + @item{Check your implementation by running the tests in @tt{test/all.rkt}.} ] From 49d0b5b4f7527ebd1651f78abbf46533ca8dd3c4 Mon Sep 17 00:00:00 2001 From: David Van Horn Date: Wed, 10 Sep 2025 11:17:20 -0400 Subject: [PATCH 3/4] YAKOHC. --- www/defns.rkt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/defns.rkt b/www/defns.rkt index 6a34d648..6c813a86 100644 --- a/www/defns.rkt +++ b/www/defns.rkt @@ -81,7 +81,7 @@ (itemlist (item "9:00am–12:00pm — Zhonqi") (item "12:00pm–3:00pm — Ben") - (item "3:00pm–6:00pm — Kalyan"))) + (item "3:30pm–6:30pm — Kalyan"))) (item "Thursday" (itemlist (item "10:00am–1:00pm — Zinat"))) From 16bd45c52fa72a6042a7f4d8f706ecda3a9b0c1a Mon Sep 17 00:00:00 2001 From: David Van Horn Date: Thu, 11 Sep 2025 08:35:26 -0400 Subject: [PATCH 4/4] Tweak to AST for Cond in assign 3 write-up. --- www/assignments/3.scrbl | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/www/assignments/3.scrbl b/www/assignments/3.scrbl index 8ca56172..cb5ffdf1 100644 --- a/www/assignments/3.scrbl +++ b/www/assignments/3.scrbl @@ -76,24 +76,20 @@ Here's the AST definition for the added primitives and @racket[cond]: (racketblock ;; type Expr = ;; ... -;; | (Cond [Listof CondClause] Expr) - -;; type CondClause = (Clause Expr Expr) +;; | (Cond [Listof Expr] [Listof Expr] Expr) ;; type Op = ;; ... ;; | 'abs | '- | 'not (struct Cond (cs e) #:prefab) -(struct Clause (p b) #:prefab) ) There is one new kind of expression constructor: @racket[Cond]. A -@racket[Cond] AST node contains a list of cond-clauses and expression, -which the expression of the @racket[else] clause. Each cond-clause is -represented by a @racket[Clause] structure containing two expressions: -the left-hand-side of the clause which is used to determine whether -the right-hand-side is evaluated, and the right-hand-side expression. +@racket[Cond] AST node contains three parts: two equal length lists of +expression and an expression. The two lists represent the clauses, +where the first list contains all of the left-hand-side parts of the +clauses and the other contains all of the right-hand-side parts. Here are some examples of how concrete expressions are parsed into ASTs using this representation: @@ -104,14 +100,14 @@ ASTs using this representation: @item{@racket[(not #t)] parses as @racket[(Prim1 'not (Lit #t))],} -@item{@racket[(cond [else 5])] parses as @racket[(Cond '() (Lit 5))],} +@item{@racket[(cond [else 5])] parses as @racket[(Cond '() '() (Lit 5))],} @item{@racket[(cond [(not #t) 3] [else 5])] parses as @racket[(Cond -(list (Clause (Prim1 'not (Lit #t)) (Lit 3))) (Lit 5))],} +(list (Prim1 'not (Lit #t))) (list (Lit 3)) (Lit 5))],} @item{@racket[(cond [(not #t) 3] [7 4] [else 5])] parses as -@racket[(Cond (list (Clause (Prim1 'not (Lit #t)) (Lit 3)) (Clause -(Lit 7) (Lit 4))) (Lit 5))],} +@racket[(Cond (list (Prim1 'not (Lit #t)) (Lit 7)) (list (Lit 3) +(Lit 4)) (Lit 5))],} ] @subsection[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing primitives}