Lisp解释器在python中引用

时间:2017-05-30 13:16:38

标签: python lisp interpreter

我想在python中编写一个lisp解释器。它适用于非递归表达式。但是,我发现在递归中引用它会让人感到困惑。

以下程序的说明:

  1. parse()函数解析用字符串写的lisp代码,用逗号和括号替换空格和括号,然后传递给python的eval()函数。

    < / LI>
  2. 符号和语法的字典包含原始程序。

  3. 评估以递归方式工作,语法模式可以更改环境字典。 (label =&gt;扩展当前词典,lambda =&gt;创建新词典)。 quote直接返回它背后的内容。对于一个过程,它通过在评估所有语句之后调用它们来工作。

  4. 就是这样。

    # -*- 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))

    它出了什么问题?

1 个答案:

答案 0 :(得分:2)

由于ff是一个程序,它会评估它的参数。在第一种情况下,它的参数(quote (((a b) c)))适用于它:

code => ['ff', ['quote', [[['a', 'b'], 'c']]]]
code => ['quote', [[['a', 'b'], 'c']]]
sval => ['ff', [[['a', 'b'], 'c']]]

第二次围绕它有参数(car s),其中s是一个绑定变量。

code => ['ff', ['car', 's']] ;; unevaluated expression
code => ['car', 's']
code => s
sval => ['car', [[['a', 'b'], 'c']]] ;; what apply gets for car

;; from this line, the quotation disappeared
sval => ['ff', [['a', 'b'], 'c']] ;; what apply gets for ff

据我所知,我在这里看不到任何错误。它完全符合预期。

其他地方可能还有一个错误。当您查看从一个到另一个递归的cond输出时:

code => ['cond', [['atom?', 's'], 's'], ['#t', ['ff', ['car', 's']]]]
code => ['cond', [[<function atom at 0x10efcad68>, [[['a', 'b'], 'c']]], 's'], ['#t', [COMPOND-PROCEDURE-#1, [['a', 'b'], 'c']]]]

除了环境之外,这些应该是相同的,因为它的代码相同。如果你看看你在eval_中做了什么,我看到你这样做:

`l[i] = eval_(l[i])`

这很糟糕,因为我包含你的AST。第二个你重新审视这个评估将不会是代码的符号,而是你前一次获得的值。您需要将运算符和操作数计算为其他值,然后应用它们。

我不是python程序员,但我想你正在寻找这样的东西:

operator = eval_(l[0], s)
operands = map(lambda e: eval_(e,s), l[1:])
return operator(*operands);

你可以在几个地方做到这一点,所以无论你在=处使用代码,都可能会发生变化。