70 lines
2.1 KiB
Racket
70 lines
2.1 KiB
Racket
#lang plait
|
|
|
|
(define minutes-spent 60)
|
|
|
|
#| BNF for the AE language:
|
|
ae: NUMBER
|
|
| { ae + ae }
|
|
| { ae - ae }
|
|
| { ae * ae }
|
|
| { ae / ae }
|
|
|#
|
|
|
|
;; AE abstract syntax trees
|
|
(define-type AE
|
|
[Num (val : Number)]
|
|
[Add (l : AE) (r : AE)]
|
|
[Sub (l : AE) (r : AE)]
|
|
[Mul (l : AE) (r : AE)]
|
|
[Div (l : AE) (r : AE)])
|
|
|
|
;; to convert s-expressions into AEs
|
|
(define (parse-sx sx)
|
|
(let ([rec (lambda (fn sx)
|
|
(parse-sx (fn (s-exp->list sx))))])
|
|
(cond
|
|
[(s-exp-match? `NUMBER sx)
|
|
(Num (s-exp->number sx))]
|
|
[(s-exp-match? `(ANY + ANY) sx)
|
|
(Add (rec first sx) (rec third sx))]
|
|
[(s-exp-match? `(ANY - ANY) sx)
|
|
(Sub (rec first sx) (rec third sx))]
|
|
[(s-exp-match? `(ANY * ANY) sx)
|
|
(Mul (rec first sx) (rec third sx))]
|
|
[(s-exp-match? `(ANY / ANY) sx)
|
|
(Div (rec first sx) (rec third sx))]
|
|
[else (error 'parse-sx (to-string sx))])))
|
|
|
|
;; consumes an AE and computes the corresponding number
|
|
(define (eval expr)
|
|
(type-case AE expr
|
|
[(Num n) n]
|
|
[(Add l r) (+ (eval l) (eval r))]
|
|
[(Sub l r) (- (eval l) (eval r))]
|
|
[(Mul l r) (* (eval l) (eval r))]
|
|
[(Div l r) (if (equal? 0 (eval r))
|
|
(cond
|
|
[(< 0 (eval l)) +inf.0]
|
|
[(> 0 (eval l)) -inf.0]
|
|
[else +nan.0])
|
|
(/ (eval l) (eval r)))]))
|
|
|
|
;; evaluate an AE program contained in an s-expr
|
|
(define (run sx)
|
|
(eval (parse-sx sx)))
|
|
|
|
;; Basic Parser tests
|
|
(test (run `3) 3) ; Evalutate number by itself
|
|
(test (run `{3 + 4}) 7) ; Evaluate two positive integers addition
|
|
(test (run `{{3 - 4} + 7}) 6) ; Evaluate subtraction and addition
|
|
(test (run `{8 * 9}) 72) ; Evaluate multiplication
|
|
(test (run `{8 / 2}) 4) ; Evaluate division
|
|
|
|
;; Divide by zero tests
|
|
(test (run `{-8 / 0}) -inf.0) ; Negative divide by zero
|
|
(test (run `{8 / {5 - 5}}) +inf.0) ; Positive divide by zero
|
|
(test (run `{1 / {1 / 0}}) 0.0) ; Divide by positive infinity
|
|
(test (run `{0 / 0}) +nan.0) ; Special 0/0 case
|
|
|
|
;; Parser Errors
|
|
(test/exn (run `{+ 1 1}) "parse") ; Parse error |