V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
tioover
V2EX  ›  分享创造

新手,写了个简单的Lisp 解释器

  •  
  •   tioover ·
    tioover · 2013-09-01 01:23:21 +08:00 · 5960 次点击
    这是一个创建于 4103 天前的主题,其中的信息可能已经有所发展或是发生改变。
    https://github.com/tioover/schepy/tree/master

    其实我Scheme 不怎么会,SICP 才正在看第二章,不过有一天心血来潮想要写一个解释器,于是照着[一个知乎上的回答]( http://www.zhihu.com/question/20115358/answer/15350593 )开始写了。写完了要测试,连运行多条表达式都不会,然后才找到begin 给解释器加上。几秒前我才发现这篇文章( http://www.googies.info/articles/lispy.html )

    本来是很简单的东西,但是我水平挺臭写了四天,不包括测试用例一共四百多行。原本以为最难的部分是函数,像作用域啊,递归啊什么的,但是没想到(或者说果然),在求值器删删改改了以后,函数这一块反而一两个小时就弄好了。

    ## 已知问题

    有些打算慢慢在这几天解决,有些打算边学边在今明年解决,有些可能永远也不会解决了(Python 最大递归深度……)。

    * 我连标准都还没看过。
    * 仅仅是个玩具,大量功能缺失:向量、尾递归优化、符号、eval、元编程。
    * 很多语法糖不能使用,而且只能严格按照S-表达式,比如说只能用 (cons x y) 定义序对,(define foobar (lambda ...)) 定义函数。
    * 参数只能用列表的形式:(lambda (a b c) ...)
    * 错误信息不完善,有些地方还忘了写异常(这里记一下:函数的参数个数。)
    * 如果在上下文中找不到,那就会直接在Python 中eval,可以弄出各种诡异的东西,需要用正则表达式判断类型再eval。
    * 为了获取链表的长度(len(li)),会多一次对链表的遍历。
    * Python 的最大递归深度限制。
    * 重写求值器以后忘了写处理符号的部分了。因为符号的类型已经写好了所以很好弄。
    第 1 条附言  ·  2013-09-01 17:44:50 +08:00
    附一副图XD 因为用的是Python 3 所以Unicode 不在话下。

    第 2 条附言  ·  2013-09-05 02:50:05 +08:00
    好激动,我做到了,尾递归优化~~~~ Python 的最大递归深度限制你看看你

    8 条回复    1970-01-01 08:00:00 +08:00
    felix021
        1
    felix021  
       2013-09-01 02:13:09 +08:00
    赞。。我就是为了解释器去看SICP的,现在看到3.3.5了,好艰辛……
    cxe2v
        2
    cxe2v  
       2013-09-01 09:27:12 +08:00
    牛逼,都能写解释器了就不能叫新手了,绝对是老手
    tioover
        3
    tioover  
    OP
       2013-09-01 17:36:50 +08:00
    昨天今天解决了一些问题:
    * define 惰性求值。
    * 符号,eval,判断类型
    * 一些错误提示
    * 之前字符串里面如果有空格会出错,现在修复了,不过词法分析器现在用了一些正则表达式。
    * 一些语法糖,可以直接用define 来定义函数了,不需要define lambda。也可以用(a . b) 定义序对了。
    JackLinMaker
        4
    JackLinMaker  
       2013-09-02 10:04:00 +08:00
    改天我写个ruby的:)
    yuelang85
        5
    yuelang85  
       2013-09-02 10:05:19 +08:00
    cool
    gadmyth
        6
    gadmyth  
       2013-09-02 13:06:48 +08:00
    Lisp还支持变量为unicode的,不知楼主是否支持
    tioover
        7
    tioover  
    OP
       2013-09-03 01:05:23 +08:00
    搞错define 的语法了,还以为函数定义函数名要单独写一个原子(define foobar (x) ()),结果不用,已经修复了。还有对于define 要惰性求值也是因此而起的误解(SICP 习题1.5)

    今天开了个dev 分支,新功能都写在里面,没问题了再合并,刚刚支持了词法闭包……其实就是在定义函数的时候复制一部分环境呗。

    明天打算试试看尾递归优化。
    tioover
        8
    tioover  
    OP
       2013-09-05 19:20:13 +08:00
    尾递归原本只是对函数体归约的思路,不过 提醒了我蹦跳床函数,这个东西专门把尾递归栈转化成循环,不错。

    昨天把尾递归给弄好了,今天迷迷糊糊的已经忘了昨天的思路了,但是测试了一下工作正常,尾递归计算过程中内存占用也比较稳定,那就好了。

    不过效率令人发指,和racket 比较了一下,差了人家百倍吧,还是递归空转的效率,不过也就是一个练习用的东西。

    嗯,总之作为一个练习项目差不多是完成了的,之后是修修补补了吧,有空把里面的递归都变成循环,毕竟Python 不提倡递归。

    打算SICP 大成以后用C 写一个,最好能编译……
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   908 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 20:15 · PVG 04:15 · LAX 12:15 · JFK 15:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.