【发布时间】:2017-05-30 13:16:38
【问题描述】:
我想用python写一个lisp解释器。它适用于非递归表达式。但是,我发现在递归中引用令人困惑。
以下程序的描述:
以字符串形式编写的lisp代码在
parse()函数中通过用逗号和括号替换空格和括号进行解析,并传递给python的eval()函数。符号和语法字典包含原始过程。
评估以递归方式进行,其中语法模式能够更改环境字典。 (
label=> 扩展当前字典,lambda=> 创建一个新字典)。quote直接返回其背后的内容。至于过程,它通过在评估其所有语句后调用它们来工作。
就是这样。
# -*- coding:utf-8 -*-
import re
def parse(s):
l = re.sub(r'\s+', ', ', (' '+s.lower()+' ').replace('(', '[').replace(')', ']'))[2:-2]
return eval(re.sub(r'(?P<symbol>[\w#%\\/^*+_\|~<>?!:-]+)', lambda m : '"%s"' % m.group('symbol'), l))
def cons(a, d):
if atom(d):
return (a, d)
return (lambda *args : list(args))(a, *d)
def car(s):
return s[0]
def cdr(s):
if len(s) == 1:
return []
return s[1:]
def atom(s):
return not isinstance(s, list)
def eq(s, t):
return s == t
def cond(l, d):
for [p, e] in cdr(l):
if eval_(p, d):
return eval_(e, d)
class lambda_object:
count = 0
def __init__(self, l, d):
self.dic = d
self.li = l[1]
self.ex = l[2]
lambda_object.count += 1
self.serial = lambda_object.count
def __call__(self, *args):
for i in range(len(self.li)):
self.dic[self.li[i]] = args[i]
return eval_(self.ex, self.dic)
def __str__(self):
return 'COMPOND-PROCEDURE-#%d' % self.serial
__repr__ = __str__
def label(l, d):
d[l[1]] = eval_(l[2])
def quote(l, d):
return l[1]
symbol_s = {'cons':cons, 'car':car, 'cdr':cdr, 'atom?':atom, 'eq?':eq, '#t':True, '#f':False}
syntax_s = {'cond':cond, 'lambda':lambda_object, 'quote':quote, 'label':label}
def eval_(l, s=symbol_s):
print 'code =>', l
if atom(l):
return symbol_s[l]
#if not atom(l[0]):
# l[0] = eval_(l[0])
if l[0] in syntax_s:
return syntax_s[l[0]](l, s)
else:
编辑:
根据答案,以下几行不正确:
for i in range(len(l))[1:]:
l[i] = eval_(l[i])
print 'sval =>', l
if isinstance(l[0], str):
l[0] = s[l[0]]
return l[0](*l[1:])
他们应该是:
operator = eval_(l[0], s)
operands = map(lambda e: eval_(e,s), l[1:])
print 'sval =>', operator, '<<', operands
return operator(*operands)
这就是程序。
运行时:
code = '''
(label ff
(lambda (s)
(cond
((atom? s) s)
(#t (ff (car s))))))
'''
print eval_(parse(code))
print symbol_s
print eval_(parse("(ff (quote (((a b) c))))"))
它产生某种东西:
code => ['label', 'ff', ['lambda', ['s'], ['cond', [['atom?', 's'], 's'], ['#t', ['ff', ['car', 's']]]]]]
code => ['lambda', ['s'], ['cond', [['atom?', 's'], 's'], ['#t', ['ff', ['car', 's']]]]]
None
{'cons': <function cons at 0x10efcaf98>, 'ff': COMPOND-PROCEDURE-#1, 'eq?': <function eq at 0x10efcaf28>, 'car': <function car at 0x10efca978>, '#f': False, 'atom?': <function atom at 0x10efcad68>, 'cdr': <function cdr at 0x10efcab38>, '#t': True}
code => ['ff', ['quote', [[['a', 'b'], 'c']]]]
code => ['quote', [[['a', 'b'], 'c']]]
sval => ['ff', [[['a', 'b'], 'c']]]
code => ['cond', [['atom?', 's'], 's'], ['#t', ['ff', ['car', 's']]]]
code => ['atom?', 's']
code => s
sval => ['atom?', [[['a', 'b'], 'c']]]
code => #t
code => ['ff', ['car', 's']]
code => ['car', 's']
code => s
sval => ['car', [[['a', 'b'], 'c']]]
;; from this line, the quotation disappeared
sval => ['ff', [['a', 'b'], 'c']]
code => ['cond', [[<function atom at 0x10efcad68>, [[['a', 'b'], 'c']]], 's'], ['#t', [COMPOND-PROCEDURE-#1, [['a', 'b'], 'c']]]]
code => [<function atom at 0x10efcad68>, [[['a', 'b'], 'c']]]
code => [[['a', 'b'], 'c']]
code => [['a', 'b'], 'c']
code => ['a', 'b']
code => b
Traceback (most recent call last):
File "slisp.py", line 113, in <module>
print eval_(parse("(ff (quote (((a b) c))))"))
...
File "slisp.py", line 66, in eval_
return symbol_s[l]
KeyError: 'b'
我知道有问题,但我不知道如何解决它。
在评估(ff (quote (((a b) c)))) 时,它会在下一次不带引号的递归中更改为(ff ((a b) c))。
这有什么问题?
【问题讨论】:
-
虽然您的解释器可以工作,但我认为这有点令人困惑。你应该看看像Peter Norvig's 这样的解释器。您可能还想阅读一下more about quotes first。
-
Lisp 表达式是由上下文无关文法描述的,正则表达式的解析力不够强大。
-
嗯,这还不是一个严重的问题......它在这个程序中工作。
-
@ChristianDean 我已经阅读了这两个网站。但是我仍然无法弄清楚它有什么问题。
标签: python lisp interpreter