Presentation is loading. Please wait.

Presentation is loading. Please wait.

The Metacircular Evaluator

Similar presentations


Presentation on theme: "The Metacircular Evaluator"— Presentation transcript:

1 The Metacircular Evaluator
Chapter 4 Section 4.1 We will not cover every little detail in the lectures, so you MUST read Section 4.1 in full.

2 Compiler vs. Interpreter
The Programmer The Computer Transformation Command Processing Unit T Program in High Level Language Program in Low Level Machine Language

3 C A Compiler Inputs High Level Machine Level Program Program
The Compiler turns the high level program instructions to Instructions understood by the machine. CPU Outputs

4 I An Interpreter Inputs High Level Program CPU Outputs
The Interpreter is a machine level program, which interprets and executes the high level program line after line…

5 The Metacircular Evaluator
Inputs Scheme Program ME CPU It might seem circular to think about evaluating Scheme programs in Scheme, but the idea is since we have throughout the course used Scheme as our way of describing processes, and the evaluator is a process, then its only natural that we describe it too using Scheme. Outputs The Metacircular Evaluator is an Interpreter for Scheme on a machine whose machine language is Scheme.

6 The Environment Evaluation Model
To evaluate a combination (a compound expression other than a special form), evaluate the subexpressions and then apply the value of the operator subexpression to the values of the operand subexpressions. To apply a compound procedure to a set of arguments, evaluate the body of the procedure in a new environment. To construct this environment, extend the environment part of the procedure object by a frame in which the formal parameters of the procedure are bound to the arguments to which the procedure is applied.

7 The Eval/Apply Cycle

8 The Meta-Circular Evaluator: Eval
(define (eval exp env) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value exp env)) ((quoted? exp) (text-of-quotation exp)) ((assignment? exp) (eval-assignment exp env)) ((definition? exp) (eval-definition exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (make-procedure (lambda-parameters exp) (lambda-body exp) env)) ((begin? exp) (eval-sequence (begin-actions exp) env)) ((cond? exp) (eval (cond->if exp) env)) ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env))) (else (error "Unknown expression type -- EVAL" exp)))) Special forms This is a top down, modular piece of software, built correctly with many layers of abstraction. However, since you havn’t built an interpreter before, we will not start directly a top down review of the process but rather first give a simplified example. Note that the use of a high level description in the main eval loop allows easy modification For possible changes to the language, but also makes it harder to add new constructs since they must Be added by changing this main eveal loop.

9 The Meta-Circular Evaluator: Apply
(define (apply procedure arguments) (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) (eval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) arguments (procedure-environment procedure)))) (else (error "Unknown procedure type" procedure))))

10 Plan of Our Presentation
We will begin with a simple variant of the interpreter. In describing it we will break many of the abstraction layers and levels trying to give you a feel of what is really going on. This variant is similar to the MCE we will eventually construct, but not identical. We start by extending a simple “calculator” like evaluator to allow saving values in variables…I.e. have an environment.

11 Start Simple: Names Extend a “calculator” to store intermediate results as named values (define x (+ 4 5)) store result as x (+ x 2) use that result Store bindings between names and values in a table

12 (define (definition? exp) (tag-check exp 'define)) (define (eval exp)
(define (definition? exp) (tag-check exp 'define)) (define (eval exp) (cond ((number? exp) exp) ((symbol? exp) (lookup exp)) ((sum? exp) (eval-sum exp)) ((definition? exp) (eval-definition exp)) (else (error "unknown expression " exp)))) (define environment (make-frame nil nil)) (define (lookup name) (lookup-variable-value name environment)) (define (eval-definition exp) (let ((name (cadr exp)) (defined-to-be (eval (caddr exp)))) (add-binding-to-frame! name defined-to-be environment) ‘undefined))

13 The Environment Representation
Note: we are assuming an environment Consisting of a single frame frame x y 4 5 list of variables list of values

14 (define (make-frame variables values)
(cons variables values)) (define (lookup-variable-value var frame) (define (scan vars vals) (cond ((null? vars) (error "Unbound variable" var)) ((eq? var (car vars) (car vals)) (else (scan (cdr vars) (cdr vals))))) (let ((vars (car frame)) (vals (cdr frame))) (scan vars vals))) (define (add-binding-to-frame! var val frame) (set-car! frame (cons var (car frame))) (set-cdr! frame (cons val (cdr frame))))

15 Evaluation Example (define x (+ 4 5)) (+ x 2)
(eval '(define x (+ 4 5))) (eval '(+ 4 5)) (eval 4) ==> 4 (eval 5) ==> 5 ==> 9 names values ==> undefined (eval '(+ x 2)) (eval 'x) ==> 9 (eval 2) ==> 2 ==> 11 x 9

16 Things to observe Use scheme function symbol? to check for a name
the reader converts sequences of characters like "x" to symbols in the parse tree Can use any implementation of the environment,in particular we could use put and get from previous lectures. eval-definition recursively calls eval on the second subtree but not on the first one eval-definition returns a special undefined value

17 Conditionals and If Extend the calculator to handle conditionals and if: (if (> y 6) (+ y 2) 15) > an operation that returns a boolean if an operation that evaluates the first subexp, checks if value is true or false

18 (define (greater? exp) (tag-check exp ’>))
(define (greater? exp) (tag-check exp ’>)) (define (if? exp) (tag-check exp 'if)) (define (eval exp) (cond ((number? exp) exp) ((symbol? exp) (lookup exp)) ((sum? exp) (eval-sum exp)) ((greater? exp) (eval-greater exp)) ((definition? exp) (eval-definition exp)) ((if? exp) (eval-if exp)) (else (error "unknown expression " exp)))) (define (eval-greater exp) (> (eval (cadr exp)) (eval (caddr exp))))

19 (if (true? (eval (if-predicate exp))) (eval (if-consequent exp))
(define (eval-if exp) (if (true? (eval (if-predicate exp))) (eval (if-consequent exp)) (eval (if-alternative exp)))) (define (if-predicate exp) (cadr exp)) (define (if-consequent exp) (caddr exp)) (define (if-alternative exp) (if (not (null? (cdddr exp))) (cadddr exp) 'false)) (define (true? x) (not (eq? x #f))) (define (false? x) (eq? x #f)) (eval '(define y 9)) (eval '(if (> y 6) (+ y 2) 15))

20 We are just walking through a tree …
if 6 y > 2 + 15 (eval ) 6 y > Then (eval ) or (eval ) 2 y >

21 Evaluation of (eval '(if (> y 6) (+ y 2) 15)) (eval '(> y 6))
==> 11

22 Things to observe eval-greater is just like eval-sum from page 1
recursively call eval on both argument expressions call scheme > to compute the value eval-if does not call eval on all argument expressions: call eval on the predicate call eval on the consequent or on the alternative but not both

23 Store operators in the environment
Want to add lots of operators but keep eval short Operations like + and > are similar evaluate all the argument subexpressions perform the operation on the resulting values Call this standard pattern an application Implement a single case in eval for all applications Approach: eval the first subexpression of an application put a name in the environment for each operation put a value if that name is a procedure apply the procedure to the operands

24 (define (application? exp) (pair? exp)) (define (eval exp) (cond
(define (application? exp) (pair? exp)) (define (eval exp) (cond ((number? exp) exp) ((symbol? exp) (lookup exp)) ((definition? exp) (eval-definition exp)) ((if? exp) (eval-if exp)) ((application? exp) (apply (eval (car exp)) (map eval (cdr exp)))) (else (error "unknown expression " exp)))) ;; rename scheme’s apply so we can reuse the name (define scheme-apply apply) (define (apply procedure arguments) (if (primitive-procedure? procedure) (apply-primitive-procedure procedure arguments) (error "operator not a procedure: " procedure))) (define (apply-primitive-procedure proc args) (scheme-apply (primitive-implementation proc) args))

25 (define prim-tag 'primitive) (define (make-primitive scheme-proc)
(define prim-tag 'primitive) (define (make-primitive scheme-proc) (list prim-tag scheme-proc)) (define (primitive-procedure? exp) (tag-check exp prim-tag)) (define (primitive-implementation prim) (cadr prim)) (define environment (make-frame nil nil)) (add-binding-to-frame! environment ’+ (make-primitive +)) (add-binding-to-frame! environment ’> (make-primitive >)) (add-binding-to-frame! environment 'true #t) (eval '(define z 9)) (eval '(+ 9 6)) (eval '(if true 10 15))

26 The Environment after first “define”
Name Value z 9 true #t > + symbol primitive scheme procedure > symbol primitive scheme procedure +

27 Evaluation of (+ 9 6) (eval '(+ 9 6))
(apply (eval +) (map eval '(9 6))) (apply '(primitive #[add]) (list (eval 9) (eval 6)) (apply '(primitive #[add]) '(9 6)) (scheme-apply (primitive-implementation '(primitive #[add])) '(9 6)) (scheme-apply #[add] '(9 6)) 15

28 Evaluation of (if true 10 15)
(eval '(if true 10 15)) (eval-if '(if true 10 15)) (if (true? (eval 'true)) ...) (if (true? (lookup 'true))) ...) (if (true? #t) ...) (eval 10) 10 Apply is never called!

29 Things to observe Applications must be last the case in eval
No tag check Applications evaluate all subexpressions Expressions that need special handling, like if, get their own case in eval

30 The Environment as an Explicit Parameter
Change from (eval '(+ 6 4)) to (eval '(+ 6 4) environment) All procedures that call eval have extra argument lookup and define use the environment from the argument No other change from earlier evaluator

31 The Environment as an Explicit Parameter (define (eval exp env) (cond
;This change is boring! Exactly the same functionality as #4. (define (eval exp env) (cond ((number? exp) exp) ((symbol? exp) (lookup exp env)) ((definition? exp) (eval-defininition exp env)) ((if? exp) (eval-if exp env)) ((application? exp) (apply (eval (car exp) env) (map (lambda (exp) (eval exp env)) (cdr exp)))) (else (error "unknown expression " exp)))) (define (lookup name env) (lookup-variable-value name env)) (define (eval-define exp env) (let ((name (cadr exp)) (defined-to-be (eval (caddr exp) env))) (add-binding-to-frame! name defined-to-be env) ‘undefined))

32 (define (eval-if exp env) (if (true? (eval (if-predicate exp) env))
(define (eval-if exp env) (if (true? (eval (if-predicate exp) env)) (eval (if-consequent exp) env) (eval (if-alternative exp) env)))

33 Defining New Procedures
Want to add new procedures For example, a scheme program: (define twice (lambda (x) (+ x x))) (twice 4) Strategy: Add a case for lambda to eval the value of lambda is a compound procedure Extend apply to handle compound procedures Implement environment model

34 (define (make-procedure parameters body env)
(define (lambda? exp) (tag-check exp 'lambda)) (define (eval exp env) (cond ((number? exp) exp) ((symbol? exp) (lookup exp env)) ((define? exp) (eval-define exp env)) ((if? exp) (eval-if exp env)) ((lambda? exp) (eval-lambda exp env)) ((application? exp) (apply (eval (car exp) env) (map (lambda (e) (eval e env)) (cdr exp)))) (else (error "unknown expression " exp)))) (define (eval-lambda exp env) (make-procedure (lambda-parameters exp) (lambda-body exp) env)) (define (lambda-parameters exp) (cadr exp)) (define (lambda-body exp) (cddr exp)) (define (make-procedure parameters body env) (list 'procedure parameters body env))

35 (define (apply procedure arguments)
(define (apply procedure arguments) (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) (eval-sequence (procedure-body procedure) (extend-environment (procedure-parameters procedure) arguments (procedure-env procedure)))) (else (error "Unknown procedure type -- APPLY" procedure)))) (define (compound-procedure? exp) (tag-check exp ‘procedure)) (define (procedure-parameters compound) (cadr compound)) (define (procedure-body compound) (caddr compound)) (define (procedure-env compound) (cadddr compound))

36 (define (eval-sequence exps env)
(cond ((last-exp? exps) (eval (first-exp exps) env)) (else (eval (first-exp exps) env) (eval-sequence (rest-exps exps) env)))) (define (last-exp? seq) (null? (cdr seq))) (define (first-exp seq) (car seq)) (define (rest-exps seq) (cdr seq))

37 How the Environment Works
manipulation 3. How the Environment Works E2 x: plus: (procedure ...) E1 Abstractly – in our environment diagrams: Concretely – our implementation (as in SICP) list of values enclosing- environment list of variables frame x plus 10 E2 procedure

38 Extending the Environment
plus: (procedure ...) E3 x: 4 y: 5 Abstractly (extend-environment '(x y) (list 4 5) E2) Concretely E2 list of values list of variables frame x y 4 E3 5 E1

39 (define (extend-environment vars vals base-env)
(if (= (length vars) (length vals)) (cons (make-frame vars vals) base-env) (if (< (length vars) (length vals)) (error "Too many arguments supplied" vars vals) (error "Too few arguments supplied" vars vals))))

40 "Scanning" the environment
Look for a variable in the environment... Look for a variable in a frame... loop through the list of vars and list of vals in parallel detect if the variable is found in the frame If not found in frame (out of variables in the frame), look in enclosing environment

41 (define (lookup-variable-value var env)
(define (env-loop env) (define (scan vars vals) (cond ((null? vars) (env-loop (enclosing-environment env))) ((eq? var (car vars)) (car vals)) (else (scan (cdr vars) (cdr vals))))) (if (eq? env the-empty-environment) (error "Unbound variable" var) (let ((frame (first-frame env))) (scan (frame-variables frame) (frame-values frame))))) (env-loop env)) (define (enclosing-environment env) (cdr env)) (define (frame-variables frame) (car frame)) (define (frame-values frame) (cdr frame))

42 (define (define-variable! var val env)
(let ((frame (first-frame env))) (define (scan vars vals) (cond ((null? vars) (add-binding-to-frame! var val frame)) ((eq? var (car vars)) (set-car! vals val)) (else (scan (cdr vars) (cdr vals))))) (scan (frame-variables frame) (frame-values frame)))) (define (eval-definition exp env) (let ((name (cadr exp)) (defined-to-be (eval (caddr exp) env))) (define-variable! name defined-to-be env) ‘undefined))


Download ppt "The Metacircular Evaluator"

Similar presentations


Ads by Google