Ruby 能否用 Ruby 改写这个 Python 的 Lisp 解释器

chenge · 2013年04月09日 · 最后由 skandhas 回复于 2016年07月04日 · 6104 次阅读

如何使用 Python 编写一个 Lisp 解释器

http://www.googies.info/articles/lispy.html

感觉是个不错的学习项目,没太看懂怎么用,python 不够熟悉。

补充:

代码来自谷歌的高人,Peter Norvig。 自顶向下地解释了 lisp 解释器。解释器分两部分,parse 和 run。 代码不长,但有些复杂,不是一下子能看懂。

代码分三部分:env, eval, parse, 比较复杂的是前两个部分,盒中盒的结构。

快用 @luikore 的 rsec!

看了一下这个 似乎没实现什么复杂的功能。 反正先了解

  1. 解释器基本流程就是(可能说错): 字符串读入,交给词法分析 (lex/scanner),语法分析 (parser) 然后求值 (eval) 输出
  2. 然后 lisp 的话 s-expression 分 atom 和括号扩起来的 list,

对应这个例子里面,从 repl 开始 raw_input 得到用户输入类似 ruby 的 gets parse 里处理 tokenize 方法返回的 tokens,int 类型的转为 int,其他的都归为 symbol(字符串表示) read_from 这里就是 atom 直接返回,list 返回数组 最后交给 eval,数组第一个参数就是 if define lambda 这些 分情况处理就好了 还有个 Env 环境,这里用了个 dict 存变量赋值

rsec 是个 ruby 实现的 parser combinator library 是这么说来着吧(其实没用过)

可以用了。from lispy import *, 就可以了。 #3 楼 @krazy 我看有空的话用 Ruby 改写一下。

#6 楼 @WolfLee 这个没 cons 吧

#1 楼 @krazy #2 楼 @chenge

嗯... 我的 rsec 自带了例子,84 行 (含空行和注释) ruby 实现的 scheme 解释器... https://github.com/luikore/rsec/blob/master/examples/scheme.rb

就是能跑 hello world 和处理 curry 的程度,很多基本函数都没加

#8 楼 @luikore 有个问题一直没明白。 rsec 文档里面说它是一个 parser generator 项目里面说是一个 parser combinator library 感觉这俩还是有区别的...是吧 求科普?

#9 楼 @krazy

parser generator 含义广泛,一种是静态的例如 bison 和 antlr, 编译生成源文件并且只用生成一次。另一种是动态的,例如 boost::spirit, 在运行时生成 parser. treetop 可以当静态的用也可以当动态的用。

parser combinator 是一种 parser generator, 区别是用组合的方式,而不是专门的语法定义... 像 haskell 的 parsec 就是 parser combinator.

@luikore 编译原理这边有啥 0 基础的入门指引推荐的? 大概水平是扫过一眼 编程语言实现模式 用 c 写过中缀表达式 parser 的

#12 楼 @jasl 龙书 / 可变目标 C 编译器?厚的书都是 0 基础 看看前言就知道哪些章节可以跳着读

现在应用一般都用 LALR / GLR 或者 PEG 的 generator. 感觉关于 LL 的章节可以不用看太认真... PEG 其实和递归下降解析器构造是可以对应上的,就是加了缓存而已。

代码来自谷歌的高人,Peter Norvig。 自顶向下地解释了 lisp 解释器。解释器分两部分,parse 和 run。 代码不长,但有些复杂,不是一下子能看懂。

可以看看 treetop 和 parslet

#10 楼 @luikore 话说 bison 和 antlr 都不支持 ruby 吧。。。。

#16 楼 @lostleaf antlr 有 ruby target 的,就是极其挫...

#17 楼 @luikore 大概是由于不是原作者开发的。。。

#13 楼 @luikore 话说 antlr 是不是 LL 的,它所说的 LL(*) 和 packrat 解析到底有什么区别?这个一直没有弄明白

还有就是比如想使用 antlr 或者说用 peg parser generator 来实现一个 wikitext/markdown 这种上下文相关的语法是不是就不太合适,这种一般是用什么方案?看到好多似乎是直接手写来处理的(还不太明白,所以不知道怎么问)

我感觉问题和帖子跑题太远了..... 谢 LZ 宝地,谢@luikore ~

#19 楼 @krazy

antlr 接受的是 CFG 的子集,而 packrat parser 接受的是 PEG CFG 和 PEG 的区别是,CFG 的选择支是无序的,PEG 的选择支是有序的。

packrat 可以无限 lookahead. LL, LR, GLR 都只支持定长 lookahead, LL(3) 就表示最多 lookahead 3 个 token. 不过这个长度在 antlr 里是可以配置/检测的,所以叫 LL(*).

缩进敏感语法可以用 lexer 插入伪 token: indentdedent 来解决。python 语法里的缩进就是这么预处理后交给 antlr 的。手写语法有一些好处,例如可以加入特殊的规则,优化性能,可以更自由的自定义错误报告之类的。官方 java 的语法就是手写的。但是对比较复杂的语法来说手写还是容易出错的,ruby 和 python 就没用手写法。


LL, LR, GLR 里面的第一个 L 都是废话 (left to right), 最后一个字母区别了 Leftmost derivation 和 Rightmost derivation.

LL 和 packrat parser 都不支持 left recursion (称作 ambiguity ignored, 也有一些实现改写了算法加入有限支持的).

LR 可以辨认的语法范围比 LL 大,支持 left recursion. GLR (generalized LR) 通过平行构造多个语法树,最终可以多消除一些歧义 (称作 ambiguity embraced). lookahead LR 的缩略写法是 LALR, 和 LL(k) 的写法略有区别。

#20 楼 @luikore peg 的选择原则和 haskell 的模式匹配规则倒是好像...然后 CFG 比较像是 Prolog CFG 可以用 BNF/EBNF 表示,相应的 PEG 是不是有一个 PEG-notation? 还有总觉得 CFG 是输入 chomsky 层级的一个概念,不知道 PEG 这个是怎么混进去的 我觉得我得去看看那个 PEG 的 paper 了

还有就是不同的解析方法似乎又总可以通过扩展做一些它不应该做得到事情,比如正则表达式..

#21 楼 @krazy 是的,PEG 的 notation 和 EBNF 最主要的区别就是用 / 而不是 |, 不过一般正则表达式的库里 | 是和 PEG 的 / 意思相同的。

chenge Ruby 学习汇集,请推荐内容 提及了此话题。 07月04日 11:35
skandhas ScmRb : Scheme Interpreter In Ruby 提及了此话题。 07月04日 11:35
需要 登录 后方可回复, 如果你还没有账号请 注册新账号