Created
August 3, 2015 14:21
-
-
Save ha2ne2/5f1bd945d7719dbca5fe to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ;; scheme interpreter | |
| ;; PAIP p714より引用 | |
| ;; CL-USER> (scheme) | |
| ;; ==> (set! fact (lambda (n) (if (= n 0) 1 (* n (fact (- n 1)))))) | |
| ;; #<COMPILED-LEXICAL-CLOSURE (:INTERNAL INTERP) #x2100A5E22F> | |
| ;; ==> (fact 5) | |
| ;; 120 | |
| ;; ==> ((if (= 1 1) * +) 3 4) | |
| ;; 12 | |
| (defun interp (x &optional env) | |
| "Interpret (evaluate) the expression x in the envirionment env." | |
| (cond | |
| ((symbolp x) (get-var x env)) | |
| ((atom x) x) | |
| ((case (first x) | |
| (QUOTE (second x)) | |
| (BEGIN (last1 (mapcar #'(lambda (y) (interp y env)) | |
| (rest x)))) | |
| (SET! (set-var! (second x) (interp (third x) env) env)) | |
| (IF (if (interp (second x) env) | |
| (interp (third x) env) | |
| (interp (fourth x) env))) | |
| (LAMBDA (let ((parms (second x)) | |
| (code (maybe-add 'begin (rest2 x)))) | |
| #'(lambda (&rest args) | |
| (interp code (extend-env parms args env))))) | |
| (t ;; 手続き適用 | |
| (apply (interp (first x) env) | |
| (mapcar #'(lambda (v) (interp v env)) | |
| (rest x)))))))) | |
| (defun rest2 (x) | |
| "The rest of a list after the first TWO elements." | |
| (rest (rest x))) | |
| (defun set-var! (var val env) | |
| "Set a variable to a value, in the given or global environment." | |
| (if (assoc var env) | |
| (setf (second (assoc var env)) val) | |
| (set-global-var! var val)) | |
| val) | |
| (defun get-var (var env) | |
| "Get the value of a variable, from the given or global environment." | |
| (if (assoc var env) | |
| (second (assoc var env)) | |
| (get-global-var var))) | |
| (defun set-global-var! (var val) | |
| (setf (get var 'global-val) val)) | |
| (defun get-global-var (var) | |
| (let* ((default "unbound") | |
| (val (get var 'global-val default))) | |
| (if (eq val default) | |
| (error "Unbound scheme variable: ~a" var) | |
| val))) | |
| (defun extend-env (vars vals env) | |
| "Add some variables and values to an environment." | |
| (nconc (mapcar #'list vars vals) env)) | |
| (defparameter *scheme-procs* | |
| '(+ - * / = < > <= >= cons car cdr not append list read member | |
| (null? null) (eq? eq) (equal? equal) (eqv? eql) | |
| (write prin1) (display princ) (newline terpri))) | |
| (defun init-scheme-interp () | |
| "Initialize the scheme interpreter with some global variables." | |
| (mapc #'init-scheme-proc *scheme-procs*) | |
| (set-global-var! t t) | |
| (set-global-var! nil nil)) | |
| (defun init-scheme-proc (f) | |
| "Define a Scheme procedure as a corresponding CL function." | |
| (if (listp f) | |
| (set-global-var! (first f) (symbol-function (second f))) | |
| (set-global-var! f (symbol-function f)))) | |
| (defun maybe-add (op exps &optional if-nil) | |
| "For example, (maybe-add 'and exps t) returns | |
| t if exps is nil, exps if there is only one, | |
| and (and exp1 exp2...) if there are several exps." | |
| (cond ((null exps) if-nil) | |
| ((length=1 exps) (first exps)) | |
| (t (cons op exps)))) | |
| (defun length=1 (x) | |
| "Is x a list of length1?" | |
| (and (consp x) (null (cdr x)))) | |
| (defun last1 (list) | |
| "Return the last element (not last cons cell) of list" | |
| (first (last list))) | |
| (defun scheme (&optional x) | |
| "A Scheme read-eval-print loop (using interp)" | |
| (init-scheme-interp) | |
| (loop (format t "~&==> ") | |
| (print (interp (read) nil)))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment