; http://www.radford.edu/itec380/2008fall/Homeworks/Hw06/hw06.html ; Ian Barland, 2008.Nov.27 ; Run this program in language-level 'Module', ; *not* 'Advanced Student'. ; These two lines make a module which exports everything ; (in Java terms: a package where everything is public). ; #lang scheme (provide (all-defined-out)) (require "scanner.ss") ; scanner.ss must be in the same dir as this file. ;;;;;;;;;;; language M0 ;;;;;;;;;;;;;; ; An Expr is one of: ; - a number ; - (make-sum Expr Expr) ; - (make-prod Expr Expr) ; - (make-ifZero Expr Expr Expr) (define-struct sum (e1 e2) #:transparent) (define-struct prod (e1 e2) #:transparent) (define-struct ifZero (cond then else) #:transparent) ; ; The keyword 'transparent' makes structs with 'public' fields; ; in particular check-expect can inspect these structs. ; parse!: ( scanner -> expr) ; Return (our internal, parse-tree representation of) the first M0 expr ; at the front of the scanner. ; Side effect: Consumes tokens from scnr corresponding exactly ; to the returned expr. ; (define (parse! scnr) (cond [(number? (peek scnr)) (pop! scnr)] [(string=? (peek scnr) "(") (let* {[open-paren (pop! scnr)] ; Pop off the "(" we just peeked at. Ignore it. [subexpr1 (parse! scnr)] ; Read an *entire* expr, even if deeply nested! [operator (pop! scnr)] [subexpr2 (parse! scnr)] [closing-paren (pop! scnr)]} (begin (when (not (string=? closing-paren ")")) (error 'parse! "Expected ')', got: ~v." closing-paren)) (cond [(string=? operator "+") (make-sum subexpr1 subexpr2)] [(string=? operator "*") (make-prod subexpr1 subexpr2)] [else (error 'parse! "Unexpected operator ~v" operator)])))] [(string=? (peek scnr) "ifZero") (let* {[open-ifZero (pop! scnr)] ; Pop off the "ifZero" we just peeked at. Ignore it. [open-paren (pop! scnr)] ; There *must* be a '(' after 'ifZero'. [subexpr1 (parse! scnr)] [comma1 (pop! scnr)] ; There *must* be a comma after the 1st expr. [subexpr2 (parse! scnr)] [comma2 (pop! scnr)] ; There *must* be a comma after the 2nd expr. [subexpr3 (parse! scnr)] [closing-paren (pop! scnr)] ; Pop off the trailing close-paren. } (make-ifZero subexpr1 subexpr2 subexpr3))] [else (error 'parse! "Unrecognized expr: ~v." (peek scnr))])) ; parse-string: (-> string expr) ; Convert the given string representing exactly *one* single Expr ; into our internal format (structs). ; ;; Since S-Expressions are (in Scheme) more natural for representing ;; the input, this function is merely a wrapper for 'parse', which ;; takes in an S-expression. ;; You don't need to modify this function; ;; only update 'parse' so that it handles all the types of Exprs. ;; (define (parse-string str) (parse! (create-scanner str))) ; expr->string : (-> expr string) (a.k.a. toString) ; Return a human-readable version of our internal representaiton of Exprs. ; ;; You don't need to modify this function; ;; only update 'expr->tokens' so that it handles all the types of Exprs. ;; (define (expr->string e) (cond [(number? e) (number->string e)] [(sum? e) (string-append " (" (expr->string (sum-e1 e)) "+" (expr->string (sum-e2 e)) ")" )] [(prod? e) (string-append " (" (expr->string (prod-e1 e)) "*" (expr->string (prod-e2 e)) ")" )] [(ifZero? e) (string-append "ifZero" "(" (expr->string (ifZero-cond e)) ", " (expr->string (ifZero-then e)) ", " (expr->string (ifZero-else e)) ")")] [else (error 'expr->string "unknown internal format: ~v" e)] )) ; eval : (-> expr val) ; Evaluate the given expr. ; (define (eval e) (cond [(number? e) e] [(sum? e) (+ (eval (sum-e1 e)) (eval (sum-e2 e)))] [(prod? e) (* (eval (prod-e1 e)) (eval (prod-e2 e)))] [(ifZero? e) (if (= (eval (ifZero-cond e)) 0) (eval (ifZero-then e)) (eval (ifZero-else e)))] [else (error 'eval "fell off cond with expr: ~v." e)])) ;;;;;;;;;;;;;;;;;;; TEST CASES: M0 ;;;;;;;;;;;;;;;; ;;; The following is used by 'hw07-test-helpers.ss': (define tests ; Each entry in the list is either ; [str val] (where val is the result of interpreting the string str), or ; [str val expr] (as above, but expr is the internal (struct) representation). `{["7" 7 7] ["(3 + 4)" 7 ,(make-sum 3 4)] ["(3*4)" 12 ,(make-prod 3 4)] ["((3+4) + ( 3 * 4 ))" 19] ["ifZero( 0, 1, 2)" 1 ,(make-ifZero 0 1 2)] ["ifZero (1, 1, 2)" 2 ,(make-ifZero 1 1 2)] ["ifZero( (3+ -3), 1, 2)" 1 ,(make-ifZero (make-sum 3 -3) 1 2)] ["ifZero( (ifZero( ifZero(0,1,2), 3, 4) + -3), 1, 2)" 2 ,(make-ifZero (make-sum (make-ifZero (make-ifZero 0 1 2) 3 4) -3) 1 2)] })