Last active
February 22, 2022 10:40
-
-
Save ytaki0801/58d7e71f7b43b0800ec87799dd44a5ca to your computer and use it in GitHub Desktop.
A Pure LISP Interpreter in Pseudocode-style Python 3
This file contains 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
#### | |
#### ev.py: A Pure LISP Interpreter | |
#### in Pseudocode-style Python 3 | |
#### | |
#### (C) 2022 TAKIZAWA Yozo | |
#### This code is licensed under CC0. | |
#### https://creativecommons.org/publicdomain/zero/1.0/ | |
#### | |
#### <examples> | |
#### | |
#### S> (((lambda (u) (u u)) (lambda (u) (lambda (a b) (if (eq a (quote ())) b ((u u) (cdr a) (cons (car a) b)))))) (quote (a b c d e)) (quote ())) | |
#### (e d c b a) | |
#### S> (((lambda (u) (u u)) (lambda (u) (lambda (a b) (if (eq a (quote ())) b (cons (car a) ((u u) (cdr a) b)))))) (quote (a b c)) (quote (x y z))) | |
#### (a b c x y z) | |
def cons(x, y): | |
return [x] + y | |
def car(x): | |
return x[0] | |
def cdr(x): | |
return x[1:] | |
def atom(x): | |
c = isinstance(x, str) | |
return c or x == [] | |
def eq(x, y): | |
if atom(x) and atom(y): | |
return x == y | |
else: | |
return False | |
builtins = {'cons': cons, | |
'car' : car, | |
'cdr' : cdr, | |
'atom': atom, | |
'eq' : eq} | |
def slex(s): | |
global tokens | |
s = s.replace('(', ' ( ') | |
s = s.replace(')', ' ) ') | |
s = s.split(' ') | |
tokens = [] | |
while s: | |
if car(s) != '': | |
tokens = tokens + [car(s)] | |
s = cdr(s) | |
def get_token(): | |
global tp | |
tp = tp + 1 | |
return tokens[tp - 1] | |
def slist(): | |
t = get_token() | |
if t == ')': | |
return [] | |
elif t == '(': | |
h = slist() | |
return cons(h, slist()) | |
else: | |
return cons(t, slist()) | |
def sread(): | |
t = get_token() | |
if t == '(': | |
return slist() | |
else: | |
return t | |
def swrite(s): | |
if atom(s): | |
print(s, end='') | |
else: | |
print('(', end='') | |
swrite(car(s)) | |
s = cdr(s) | |
while s: | |
print(' ', end='') | |
swrite(car(s)) | |
s = cdr(s) | |
print(')', end='') | |
def quote_syntax(s): | |
return s[1] | |
def if_syntax(s, e): | |
if ev(s[1], e): | |
return ev(s[2], e) | |
else: | |
return ev(s[3], e) | |
def lambda_syntax(s, e): | |
return s + [e] | |
def apply_function(s, e): | |
f = ev(car(s), e) | |
a = [] | |
s = cdr(s) | |
while s: | |
a = a + [ev(car(s), e)] | |
s = cdr(s) | |
if callable(f): | |
return f(*a) | |
else: | |
va = dict(zip(f[1], a)) | |
e1 = dict(**f[3], **va) | |
return ev(f[2], e1) | |
def ev(s, e): | |
if atom(s): | |
if s in builtins: | |
return builtins[s] | |
else: | |
return e[s] | |
elif car(s) == 'quote': | |
return quote_syntax(s) | |
elif car(s) == 'if': | |
return if_syntax(s, e) | |
elif car(s) == 'lambda': | |
return lambda_syntax(s, e) | |
else: | |
return apply_function(s, e) | |
while True: | |
tokens, tp = [], 0 | |
print('S> ', end='') | |
s = input().rstrip() | |
if s == 'exit': | |
break | |
else: | |
slex(s) | |
swrite(ev(sread(), {})) | |
print() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment