280 likes | 439 Views
Metacircular Evaluation. SICP Chapter 4 Mark Boady. Metacircular Evaluator. An interpreter built for a language using the same language as it is interpreting. We will be looking at a Scheme interpreter written in scheme Read Chapter 4 of SICP for a more detailed look at this interpreter
E N D
Metacircular Evaluation SICP Chapter 4 Mark Boady
Metacircular Evaluator • An interpreter built for a language using the same language as it is interpreting. • We will be looking at a Scheme interpreter written in scheme • Read Chapter 4 of SICP for a more detailed look at this interpreter • Why? • Extending an interpreted language • Debuggers
Jikes RVM • A Java Research Virtual Machine written in Java • The RVM runs on the JVM • Used For Research in: • Garbage Collection • Dynamic Parallelization • Machine Learning for dynamic compilation • Dynamic Typing • Distributed VM
Scheme Metacircular Evaluator • Eval • Takes an expression and an Environment • Environment = Variable Names and Values • Returns the result of evaluating the expression • Apply • Takes a Procedure and a list of arguments • Produces an expression for eval • (+ (* 4 5) 6)
Eval Definition (define (evalexpenv) (cond ((self-evaluating? exp) exp) ((variable? exp) (lookup-variable-value expenv)) ((quoted? exp) (text-of-quotation exp)) ((assignment? exp) (eval-assignment expenv)) ((definition? exp) (eval-definition expenv)) ((if? exp) (eval-if expenv)) ((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))))
(define (bevalexpenv) (cond ((boolean? exp) exp) ((conjunct? exp) (beval-and expenv)) ((disjunct? exp) (beval-or expenv)) ((negate? exp) (beval-not expenv)) ((variable? exp) ... ; You'll need to supply your own function that takes a frame, returns the assoc. value (else (error "beval: illegal syntax")))))
Apply Definition (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 -- APPLY" procedure))))
What do eval and apply do? • Eval • Takes the expression and determines what the expression is • Passes the work to a helper function that evaluates the specific type • For procedures, pass control to apply • Apply • Determine the type of procedure • Add to the environment • Pass control to Eval
Concept • We want to eval (+ 4 5) • ((application? exp) (apply (eval (operator exp) env) (list-of-values (operands exp) env))) • List-of-values evaluates the inputs to the procedure • Apply performs the actual procedure • With a primitive (like +) the underlying language handles it • With a custom procedure, we need to pass back to eval
Basic Example • (eval ‘(+ a 5) ‘((a 10) (b 7)) • Evaluate the expression a+5 with the variables a=10, b=7 • Eval starts with a procedure and sees it is an apply • Eval evaluates the inputs to the procedure • Looks up variable values in this case • Apply is asked to handle with (+ 10 5) • Apply can determine 10+5=15 using the underlying system
Details • Getting the arguments of a Procedure • (apply (eval (operator exp) env) (list-of-values (operands exp) env))) • (define (list-of-values expsenv) (if (no-operands? exps) '() (cons (eval (first-operand exps) env) (list-of-values (rest-operands exps) env))))
If Statements • (define (eval-if expenv) (if (true? (eval (if-predicate exp) env)) (eval (if-consequent exp) env) (eval (if-alternative exp) env))) • Only Evaluate based on the true case • (define (true? X) (not (eq? x false))) • (define (if-alternative exp) • (if (not (null? (cdddrexp))) (cadddrexp) 'false))
Evaluating Sequences • (define (eval-sequence expsenv) (cond ((last-exp? exps) (eval (first-expexps) env)) (else (eval (first-expexps) env) (eval-sequence (rest-expsexps) env)))) • Evaluate the sequence of expressions in a procedure body
Assigning Variables • (define (eval-assignment expenv) (set-variable-value! (assignment-variable exp) (eval (assignment-value exp) env) env) 'ok) • set-variable-value! Bounds a value to a name
Expressions • Basic functionality is implemented directly • Assignment • (define (assignment? exp) (tagged-list? exp 'set!)) (define (assignment-variable exp) (cadrexp)) (define (assignment-value exp) (caddrexp)) • Derived Expressions • Some functionality is implemented using existing functionality • Cond can be transformed into if statements • Let statements can be transformed in lambda expressions
Derived Expressions • Let expressions are derived expressions, because • (let ((<var1> <exp1>) ... (<varn> <expn>)) <body>) • is equivalent to • ((lambda (<var1> ... <varn>) <body>) <exp1> ...<expn>)
Derived Expressions • (let ((a 4) (b 6)) (+ a b)) • Value 10 • ( (lambda (a b) (+ a b)) 4 6) • Value 10 • Wecanwrite a commandthatwilltranslate a let to a lambda. • Let eval handle the lambda commandusingexistingtools.
Environment • (lookup-variable-value <var> <env>) • returns the value that is bound to the symbol <var> in the environment <env>, or signals an error if the variable is unbound. • (extend-environment <variables> <values> <base-env>) • returns a new environment, consisting of a new frame in which the symbols in the list <variables> are bound to the corresponding elements in the list <values>, where the enclosing environment is the environment <base-env>.
Environment • (define-variable! <var> <value> <env>) • adds to the first frame in the environment <env> a new binding that associates the variable <var> with the value <value>. • (set-variable-value! <var> <value> <env>) • changes the binding of the variable <var> in the environment <env> so that the variable is now bound to the value <value>, or signals an error if the variable is unbound.
Environments • There are multiple scopes in the environment • We make changes to the most recent • Example: • Initial memory: ( ( (a b) (5 7) ) ) • A new function is called with inputs b=6, c=7 • We push a new set of variables into the environment • New Memory: ( ( (b c) (6 7) ) ( (a b) (5 7) ) ) • When the function call is over we remove it from the environment • New Memory: ( ( (a b) (5 7) ) )
Environments (define (lookup-variable-value varenv) (define (env-loop env) (define (scan varsvals) (cond ((null? vars) (env-loop (enclosing-environment env))) ((eq? var (car vars)) (car vals)) (else (scan (cdrvars) (cdrvals))))) (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))
Environments (define (lookup-variable-value varenv) (env-loop env) ) (define (env-loop env) (if (eq? env the-empty-environment) (error "Unbound variable" var) (let ((frame (first-frame env))) (scan (frame-variables frame) (frame-values frame)) )) ) (define (scan varsvals) (cond ((null? vars) (env-loop (enclosing-environment env))) ((eq? var (car vars)) (car vals)) (else (scan (cdrvars) (cdrvals))) ) )
Primitives (define primitive-procedures (list (list 'car car) (list 'cdrcdr) (list 'cons cons) (list 'null? null?) (list '- -) (list '+ +) )) (define (apply-primitive-procedure procargs) (apply-in-underlying-scheme (primitive-implementation proc) args))
Running the Evaluator • Load the File • (load "ch4-mcevalM.scm") • Initialize the Global Environment • (define the-global-environment (setup-environment)) • Initialize the Evaluator • (driver-loop) • We can now execute code!
Running (load "ch4-mcevalM.scm") (define the-global-environment (setup-environment)) (driver-loop) ;;; M-Eval input: (define (append x y) (if (null? x) y (cons (car x) (append (cdr x) y)))) ;;; M-Eval value: ok ;;; M-Eval input: (append '(a b c) '(d e f)) ;;; M-Eval value: (a b c d e f)
Driver Loop (define input-prompt ";;; M-Eval input:") (define output-prompt ";;; M-Eval value:") (define (driver-loop) (prompt-for-input input-prompt) (let ((input (read))) (let ((output (eval input the-global-environment))) (announce-output output-prompt) (user-print output))) (driver-loop)) (define (prompt-for-input string) (newline) (newline) (display string) (newline))
Environments (define (setup-environment) (let ((initial-env (extend-environment (primitive-procedure-names) (primitive-procedure-objects) the-empty-environment))) (define-variable! 'true true initial-env) (define-variable! 'false false initial-env) initial-env))