;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname T0) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) #| ;; A T0 implementation. @see http://www.radford.edu/itec380/2018fall-ibarland/Homeworks/Project/T0.html @author ibarland @version 2018-Nov-17 @original-at http://www.radford.edu/itec380/2018fall-ibarland/Homeworks/Project/T0.rkt @license CC-BY -- share/adapt this file freely, but include attribution, thx. https://creativecommons.org/licenses/by/4.0/ https://creativecommons.org/licenses/by/4.0/legalcode Including a link to the *original* file satisifies "appropriate attribution". |# (require "student-extras.rkt") (require "scanner.rkt") (provide (all-defined-out)) #| Expr ::= Num | Paren | BinOp | parity Paren ::= < Expr > BinOp ::= # Expr Op Expr # parity ::= even? Expr dope Expr nope Expr dawg Op ::= boii | boi | boiii |# ; An Expr is: ; - a number ; - (make-paren [Expr]) ; - (make-binop [Op] [Expr] [Expr]) ; - (make-parity [Expr] [Expr] [Expr]) (define OPS (list "boii" "boi" "boiii")) ; An Op is: (one-of OPS) (define-struct binop (left op right)) (define-struct paren (e)) (define-struct parity (test even-ans odd-ans)) ; Examples of Expr: 34 (make-paren 34) (make-binop 3 "boii" 4) (make-binop (make-paren 34) "boii" (make-binop 3 "boiii" 4)) (make-parity 3 7 9) (make-parity (make-paren 1) (make-binop (make-paren 34) "boii" (make-binop 3 "boiii" 4)) (make-parity 0 7 9)) ; parse! : (scanner OR string) -> Expr ; given a scanner, consume one T0 expression off the front of it ; and ; return the corresponding parse-tree. ; (define (parse! s) ; We use recursive-descent parsing. (cond [(string? s) (parse! (create-scanner s))] ; overload for convenience: handle scanner *or* string. [(number? (peek s)) (pop! s)] [(string=? "<" (peek s)) (let* {[_ (pop! s)] ; consume the "<" from front of `s` [the-inside-expr (parse! s)] [_ (pop! s)] ; the closing-bracket } (make-paren the-inside-expr))] [(string=? "#" (peek s)) (let* {[open-hash (pop! s)] [lefty (parse! s)] [_ (if (not (member? (peek s) OPS)) (error 'parse "Unknown op " (peek s)) 'keep-on-going)] [op (pop! s)] [righty (parse! s)] [close-hash (pop! s)] } (make-binop lefty op righty))] [(string=? "even" (peek s)) (let* {[_ (pop! s)] ; throw away the opening "even" [_ (pop! s)] ; throw away the opening "?" [the-test (parse! s)] [_ (pop! s)] ; discard "dope" [the-even-ans (parse! s)] [_ (pop! s)] ; throw away the "nope" [the-odd-ans (parse! s)] [_ (pop! s)] ; throw away "dawg" } (make-parity the-test the-even-ans the-odd-ans))] [else (error 'parse! (format "syntax error -- something has gone awry! Seeing ~v" (peek s)))])) ; eval : Expr -> Num ; Return the value which this Expr evaluates to. ; In T0, the only type of value is a Num. ; (define (eval e) (cond [(number? e) e] [(paren? e) (eval (paren-e e))] [(binop? e) (let* {[the-op (binop-op e)] [left-val (eval (binop-left e))] [right-val (eval (binop-right e))] } (eval-binop the-op left-val right-val))] [(parity? e) (if (even? (eval (parity-test e))) (eval (parity-even-ans e)) (eval (parity-odd-ans e)))] [else (error 'eval "unknown type of expr: " (expr->string e))])) ; eval-binop : op num num -> num ; Implement the binary operators. (define (eval-binop op l r) (cond [(string=? op "boii") (+ l r)] [(string=? op "boi") (- l r)] [(string=? op "boiii") (* l r)] [else (error 'eval "Unimplemented op " op)] )) (check-expect (eval-binop "boii" 3 2) 5) (check-expect (eval-binop "boi" 3 2) 1) (check-expect (eval-binop "boiii" 3 2) 6) ; expr->string : Expr -> string ; Return a string-representation of `e`. ; (define (expr->string e) (cond [(number? e) (number->string (if (integer? e) e (exact->inexact e)))] [(paren? e) (string-append "<" (expr->string (paren-e e)) ">")] [(binop? e) (string-append "#" (expr->string (binop-left e)) " " (binop-op e) " " (expr->string (binop-right e)) "#" )] [(parity? e) (string-append "even? " (expr->string (parity-test e)) " dope " (expr->string (parity-even-ans e)) " nope " (expr->string (parity-odd-ans e)) " dawg" )] [else (error 'expr->string "unknown type of expr: " e)]))