Created
August 31, 2015 13:49
-
-
Save mdaisuke/bb8f6858d3599b911e10 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
def tokenize(chars): | |
"Convert a string of characters into a list of tokens." | |
return chars.replace('(', ' ( ').replace(')', ' ) ').split() | |
def parse(program): | |
"Read a Scheme expression from a string" | |
return read_from_tokens(tokenize(program)) | |
def read_from_tokens(tokens): | |
"Read an expression from a sequence EOF of 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)) | |
tokens.pop(0) | |
return L | |
elif ')' == token: | |
raise SyntaxError('unexpected )') | |
else: | |
return atom(token) | |
def atom(token): | |
"Numbers become numbers; every other token is a symbol" | |
try: return int(token) | |
except ValueError: | |
try: return float(token) | |
except ValueError: | |
return Symbol(token) | |
Symbol = str | |
List = list | |
Number = (int, float) | |
Env = dict | |
def standard_env(): | |
"An environment with some Scheme standard procedures." | |
import math, operator as op | |
env = Env() | |
env.update(vars(math)) | |
env.update({ | |
'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, | |
'>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq, | |
'abs': abs, | |
'append': op.add, | |
'apply': apply, | |
'begin': lambda *x: x[-1], | |
'car': lambda x: x[0], | |
'cdr': lambda x: x[1:], | |
'cons': lambda x,y: [x] + y, | |
'eq?': op.is_, | |
'equal?': op.eq, | |
'length': len, | |
'list': lambda *x: list(x), | |
'list?': lambda x: isinstance(x, list), | |
'map': map, | |
'max': max, | |
'min': min, | |
'not': op.not_, | |
'null?': lambda x: x == [], | |
'number?': lambda x: isinstance(x, Number), | |
'round': round, | |
'symbol?': lambda x: isinstance(x, Symbol), | |
}) | |
return env | |
global_env = standard_env() | |
def eval(x, env=global_env): | |
"Evaluate an expression in an environment" | |
if isinstance(x, Symbol): | |
return env[x] | |
elif not isinstance(x, List): | |
return x | |
elif x[0] == 'quote': | |
(_, exp) = x | |
return exp | |
elif x[0] == 'if': | |
(_, text, conseq, alt) = x | |
exp = (conseq if eval(test, env) else alt) | |
return eval(exp, env) | |
elif x[0] == 'define': | |
(_, var, exp) = x | |
env[var] = eval(exp, env) | |
else: | |
proc = eval(x[0], env) | |
args = [eval(arg, env) for arg in x[1:]] | |
return proc(*args) | |
def repl(prompt='lis.py> '): | |
"A prompt-read-eval-print loop." | |
while True: | |
val = eval(parse(raw_input(prompt))) | |
if val is not None: | |
print(schemestr(val)) | |
def schemestr(exp): | |
"Convert a Python object back into a Scheme-readable string." | |
if isinstance(exp, list): | |
return '(' + ' '.join(map(schemestr, exp)) + ')' | |
else: | |
return str(exp) | |
program = "(begin (define r 10) (* pi (* r r)))" | |
print(eval(parse(program))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment