1 目录
本系列旨在学习各种parser思路及技巧,分为以下几个部分
- 清晨入古寺—-论世间parser为何物
- 初日照高林—-初探First集,Follow集
- 曲径通幽处—-预测分析表的构建 [本篇]
- 禅房花木深—-实现LL(1) parser
- 山光悦鸟性—-递归下降的两种实现
- 潭影空人心—-浅谈recursive ascent parser(SLR,LALR(1))
- 万籁此俱寂—-parser combinator(从ohm.js源码说起)
- 但余钟磬音—-反思与总结
2 什么是预测分析表
预测分析表是在语法分析中用于进行预测分析的数据结构,龙书上有比较详细的定义,在这里就举一个栗子来说明:
假定有如下文法:
S -> F
S -> (S + F)
F -> a
它的预测分析表长这个样:
非终结符/终结符 | ( | ) | a | + | $ |
---|---|---|---|---|---|
S | S -> (S + F) | - | S -> F | - | - |
F | - | - | F -> a | - | - |
假如这时我们要解析一个字符串”(a + a)”
- 读入”(“
- 查询预测分析表
- 根据预测分析表结果,进入相应的产生式(也可称展开产生式)
- 这里有两种等价的方式实现匹配
4.1 使用程序的调用栈递归进行预测分析,当程序正常结束且输入完全匹配时,语法分析成功
4.2 使用栈数据结构来非递归的预测分析,当栈为空且完全匹配时,语法分析成功
Tip:这里有同学可能会问,为啥总是能用非递归来模拟递归?
其实在Forthan的年代,人们还木有意识到递归对于程序的用处,第一个倡导编程语言应该实现递归的就是大名鼎鼎的Dijkstra ,随着Dijkstra的论文发表,在 那之后的语言比如ALGOL 60便使用了call stack这个概念来实现递归,不过据说在forthan的年代(也就是50年代早期)IBM的机器还没有堆栈实现,并且机器很小,估计用了递归效率也够呛,不过递归的威力早在Church提出lambda calculus以及 Church encoding就已经显现出来了。
3 为什么需要预测分析表
其实你也可以不用实现预测分析表,预测分析表的本质就是对当前字符进行分支判断吗,只不过这分支比较多,然后你懂的代码写出来都是if-else,嵌套if-else,这一点都不优雅:(,据说优雅的程序员能找到女朋友:),所以我们需要预测分析表来驱动预测语义分析(这部分龙书语法分析部分讲的挺细)
4 实现预测分析表
1 | /** |