;; 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 S0) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) ;; Here is the code written (almost) entirely in lecture, ;; including the S0 parser. (require "student-extras.rkt") (require "scanner.rkt") (provide (all-defined-out)) #| Expr ::= Num | Paren | BinOp | Ifnz Paren ::= | Expr | (note: these “|”s are literal -- not BNF “or”s) BinOp ::= ? Op Expr Expr Ifnz ::= ( Expr ) !0 Expr : Expr Op ::= ad | su | mu |# ; An Expr is: ; - a number ; - (make-paren [Expr]) ; - (make-binop [Op] [Expr] [Expr]) ; - (make-ifnz [Expr] [Expr] [Expr]) (define OPS (list "ad" "su" "mu")) ; An Op is: (one-of OPS) (define-struct binop (op left right)) (define-struct paren (e)) (define-struct ifnz (cond nz-branch z-branch)) ; Examples of Expr: 34 (make-paren 34) (make-binop "ad" 3 4) (make-binop "ad" (make-paren 34) (make-binop "mu" 3 4)) (make-ifnz 3 7 9) (make-ifnz (make-paren 1) (make-binop "ad" (make-paren 34) (make-binop "mu" 3 4)) (make-ifnz 0 7 9)) ; parse! : (scanner OR string) -> Expr ; given a scanner, consume one S0 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: scanner *or* string. [(number? (peek s)) (pop! s)] [(string=? "|" (peek s)) (let* {[_ (pop! s)] [the-inside-expr (parse! s)] [_ (pop! s)] ; the closing-pipe } (make-paren the-inside-expr))] [(string=? "?" (peek s)) (let* {[question-mark (pop! s)] [_ (if (not (member? (peek s) OPS)) (error 'parse "Unknown op ~v" (peek s)) 'keep-on-going)] [op (pop! s)] [lefty (parse! s)] [righty (parse! s)] } (make-binop op lefty righty))] [(string=? "(" (peek s)) (let* {[_ (pop! s)] ; throw away the opening "(" [the-cond (parse! s)] [_ (pop! s)] ; discard ")" [_ (pop! s)] ; discard "!" [_ (pop! s)] ; discard "0" [the-nz-branch (parse! s)] [_ (pop! s)] ; throw away the ":" [the-z-branch (parse! s)] } (make-ifnz the-cond the-nz-branch the-z-branch))] [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 S0, 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))]} (cond [(string=? "ad" the-op) (+ left-val right-val)] [(string=? "su" the-op) (- left-val right-val)] [(string=? "mu" the-op) (* left-val right-val)] [else (error 'eval "unimplemented operator " the-op)]))] [(ifnz? e) (if (not (zero? (eval (ifnz-cond e)))) (eval (ifnz-nz-branch e)) (eval (ifnz-z-branch e)))] [else (error 'eval "unknown type of expr: " (expr->string e))])) ; 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 "?" (binop-op e) " " (expr->string (binop-left e)) " " (expr->string (binop-right e)) )] [(ifnz? e) (string-append "(" (expr->string (ifnz-cond e)) ") " "!0 " (expr->string (ifnz-nz-branch e)) " : " (expr->string (ifnz-z-branch e)) )] [else (error 'expr->string "unknown type of expr: " e)]))