UNB/ CS/ David Bremner/ teaching/ cs4613/ lectures/ lecture3/ snippet-025.rkt
#lang plait
#| BNF for the AE language:
   <AE> ::= <num>
          | { + <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)
		(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 second) (rec third))]
	[(s-exp-match? `(- ANY ANY) sx)
	 (Sub (rec second) (rec third))]
	[(s-exp-match? `(* ANY ANY) sx)
	 (Mul (rec second) (rec third))]
	[(s-exp-match? `(/ ANY ANY) sx)
	 (Div (rec second) (rec third))]
	[else (error 'parse-sx (to-string sx))])))

(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) (/ (eval l) (eval r))]))

(define (run sx)
  (eval (parse-sx sx)))

(test (run `3)  3)
(test (run `{+ 3 4})  7)
(test (run `{+ {- 3 4} 7})  6)