0. Announcements (On board & slide 1) Quiz 2 tomorrow night (5 to 7) xor (7 to 9) 4-270 xor 4-370 I. Course evaluation 10:05 to 10:20 (15 mins) II. Introduction, 5 mins., 10:20 to 10:25 Playing with interpreters -- This is why we make them -- Lots of experiments: name lookup, application, new syntax -- Today: improved efficiency (analyze) and control constructs III. Analyze Eval, 5 mins., 10:25 to 10:30 Basically a very, very simple compiler: examine the program before running it. When the program runs, we don't need the EXP argument, and we never call EVAL (i.e. dispatch) when the program runs. More sophisticated analysis, in conjunction with language changes, allows type checking and # of argument checking before the program runs. Builds on the idea of static vs. dynamic work -- do it statically once and then don't do it when you run. The analysis is a bit slower than when done dynamically, but it might not have to be done over and over again. At ANALYZE time we convert an expression (EXP) into a "bag of code" (i.e. a procedure) with one argument, the ENVIRONMENT. When we run, we just execute the "bags of code" by giving them an appropriate environment. III. Analyze Evaluator Code, 10 mins., 10:30 - 10:40 BOARD (define (eval exp env) ;; First call ANALYZE to build a bag of code from the original ;; EXPression, then call the bag of code with the ENVironment. ((analyze exp) env)) SLIDE 2 (define (eval exp env) ;; First call ANALYZE to build a bag of code from the original ;; EXPression, then call the bag of code with the ENVironment. ((analyze exp) env)) (define (analyze exp) (cond ((self-evaluating? exp) (analyze-self-evaluating exp)) ... ((variable? exp) (analyze-variable exp)) ((if? exp) (analyze-if exp)) ((lambda? exp) (analyze-lambda exp)) ((application? exp) (analyze-application exp)) (else ...))) BOARD (define (analyze-self-evaluating exp) (lambda (env) exp)) (define (analyze-variable exp) (lambda (env) (lookup-variable-value exp env))) SLIDE 3 (define (analyze-if exp) (let ((pproc (analyze (if-predicate exp))) (cproc (analyze (if-consequent exp))) (aproc (analyze (if-alternative exp)))) (lambda (env) (if (true? (pproc env)) (cproc env) (aproc env))))) (define (analyze-lambda exp) (let ((vars (lambda-parameters exp)) (bproc (analyze-sequence (lambda-body exp)))) (lambda (env) (make-procedure vars bproc env)))) SLIDE 4 (define (analyze-application exp) (let ((fproc (analyze (operator exp))) (aprocs (map analyze (operands exp)))) (lambda (env) (execute-application (fproc env) (map (lambda (aproc) (aproc env)) aprocs))))) (define (execute-application proc args) (cond ... ((compound-procedure? proc) ((procedure-body proc) (extend-environment (procedure-parameters proc) args (procedure-environment proc)))) ...)) IV. Exceptions, CATCH and OOPS, 5 mins., 10:40 - 10:45am Using the Analyze evaluator (or a compiler) we can catch some classes of errors before the program runs. But others (like divide by 0 or subscript out of range) can only be detected at runtime. We want programs: (a) Catch and handle dynamic errors (b) Not have a big performance penalty for doing so (c) Be structured so that the code is still readable SLIDE 5 (define (add-up l) (if (null? l) 0 (+ (car l) (add-up (cdr l))))) (define (average values) (CATCH Divide-by-Zero (divide (add-up values) (length values)) 0)) (define (divide x y) (if (zero? y) (oops divide-by-zero) (/ x y))) (average (list 10 20)) ==> 15 (average '()) ==> 0 V. Implementing CATCH and OOPS, 5 mins., 10:45am - 10:50am SLIDE 6 (define *labels* '()) (define (add-label name procedure) (set! *labels* (cons (list name procedure) *labels*))) (define (find-label name) (let ((entry (assq name *labels*))) (and entry (second entry)))) BOARD (define (analyze-catch exp) ;; (CATCH ) (let ((name (second exp)) (expr (analyze (third exp))) (error-exit (analyze (fourth exp))) (labels *labels*)) (lambda (env) (define (done) (set! labels *labels*) (error-exit env)) (add-label name done) (expr env)))) SLIDE 7 (define (analyze-oops exp) ;; (OOPS ) (let ((name (second exp))) (lambda (env) (let ((label (find-label name))) (if label (label) (error "No handler for error" name)))))) SLIDE 8 (catch george (oops george) 'george) ==> george (catch george (+ 2 3) 'george) ==> 5 (catch george (begin (oops george) (+ 2 3)) 'george) ==> 5 ; Should be GEORGE VI. Summary, 5 mins., 10:50am - 10:55am There are lots of games that can be played with evaluators. We have a bug to fix in our evaluator dealing with the flow of control. Next time we'll look at an evaluator for a "Java Parse Tree," called Java-In-Scheme.