Created
October 4, 2010 21:21
-
-
Save cametan001/610454 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
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| ### Env クラス | |
| class Env(dict): | |
| "環境: ペア{'var':val} の dict で、外部環境(outer)を持つ。" | |
| def __init__(self, parms = (), args = (), outer = None): | |
| self.update(zip(parms, args)) | |
| self.outer = outer | |
| def find(self, var): | |
| "var が現れる一番内側の Env を見つける" | |
| return self if var in self else self.outer.find(var) | |
| ### グローバル環境 | |
| def add_globals(env): | |
| "環境に Scheme 標準の手続きのいくつか追加する" | |
| import math, operator as op | |
| env.update(vars(math)) # sin, sqrt, ... | |
| env.update( | |
| {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_, | |
| '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, | |
| 'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x, y: [x] + y, | |
| 'car':lambda x: x[0], 'cdr':lambda x:x[1:], 'append':op.add, | |
| 'list':lambda *x:list(x), 'list?':lambda x:isa(x, list), | |
| 'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)}) | |
| return env | |
| global_env = add_globals(Env()) | |
| ### 実行: eval | |
| def interpret(x, env = global_env): | |
| "環境の中で式を評価する。" | |
| if isa(x, Symbol): # 変数参照 | |
| return env.find(x)[x] | |
| elif not isa(x, list): # 定数リテラル | |
| return x | |
| elif x[0] == 'quote': # (quote exp) | |
| (_, exp) = x | |
| return exp | |
| elif x[0] == 'if': # (if test conseq alt) | |
| (_, test, conseq, alt) = x | |
| return interpret((conseq if interpret(test, env) else alt), env) | |
| elif x[0] == 'define': # (define var exp) | |
| (_, var, exp) = x | |
| env[var] = interpret(exp, env) | |
| elif x[0] == 'lambda': # (lambda (var*) exp) | |
| (_, vars, exp) = x | |
| return lambda *args: interpret(exp, Env(vars, args, env)) | |
| elif x[0] == 'begin': # (begin exp*) | |
| for exp in x[1:]: | |
| val = interpret(exp, env) | |
| return val | |
| else: # (proc exp*) | |
| exps = [interpret(exp, env) for exp in x] | |
| proc = exps.pop(0) | |
| return proc(*exps) | |
| isa = isinstance | |
| Symbol = str | |
| ### 構文解析: read と parse | |
| def read(s): | |
| "文字列から Scheme 式を読み込む。" | |
| return read_from(tokenize(s)) | |
| parse = read | |
| def tokenize(s): | |
| "文字列をトークンのリストに変換する。" | |
| return s.replace('(', ' ( ').replace(')', ' ) ').split() | |
| def read_from(tokens): | |
| "トークンの列から式を読み込む。" | |
| if len(tokens) == 0: | |
| raise SyntaxError('unexpected EOF while reading') | |
| token = tokens.pop(0) | |
| if '(' == token: | |
| L = [] | |
| while tokens[0] != ')': | |
| L.append(read_from(tokens)) | |
| tokens.pop(0) # pop off ')' | |
| return L | |
| elif ')' == token: | |
| raise SyntaxError('unexpected )') | |
| else: | |
| return atom(token) | |
| def atom(token): | |
| "数は数にし、それ以外のトークンはシンボルにする。" | |
| try: return int (token) | |
| except ValueError: | |
| try: return float(token) | |
| except ValueError: | |
| return Symbol(token) | |
| def to_string(exp): | |
| "Python オブジェクトを Lisp の読める文字列に戻す。" | |
| return '('+' '.join(map(to_string, exp))+')' if isa(exp, list) else str(exp) | |
| def repl(prompt='lis.py> '): | |
| "read-eval-print-loop のプロンプト" | |
| while True: | |
| val = interpret(parse(raw_input(prompt))) | |
| if val is not None: print to_string(val) | |
| repl() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment