为什么要构建AST walker而不是让节点负责自己的输出?

时间:2011-06-15 20:50:32

标签: parsing compiler-construction

给定AST,使Walker类遍历树并执行输出的原因是什么,而不是给每个Node类一个compile()方法,让它负责自己的输出?

以下是一些例子:
Doctrine 2(ORM)使用SQLWalker遍历AST并从节点生成SQL Twig(模板语言)让节点输出自己的代码(这是一个if语句节点)。

3 个答案:

答案 0 :(得分:6)

使用单独的Walker进行代码生成可避免随着目标表示数量的增加,AST节点类数量出现组合爆炸。当Walker负责代码生成时,您可以通过更改Walker类将其重新定位到不同的表示形式。但是当AST节点本身负责编译时,每个单独的目标表示需要不同版本的每个节点。

答案 1 :(得分:1)

主要是因为旧文献和可用工具。尝试使用这两种方法,您可以轻松地发现AST遍历会产生非常缓慢且复杂的代码。而且,与立即语法分离的代码不再像它那样。这非常像支持两个同步的代码库,这总是一个坏主意。调试,维护变得困难。

当然,除非你有一个设计良好的状态机,否则在节点上处理语义也很困难。事实上,你永远不会比事后更好地遍历AST,因为它只是在节点上处理语义的一个特例。

您经常可以听到AST遍历允许为相同的语法实现多个语义。实际上,你永远不会想要这样,不仅因为它很少需要,而且还因为性能原因。坦率地说,为不同的语义编写单独的语法没有困难。两者设计在一起时,结果总是更好。

最后,在每个非平凡的任务中,获取语法解析是最简单的部分,使语义正确并快速处理动作是一个挑战。专注于AST正在向后推进任务。

答案 2 :(得分:0)

支持“内部AST助行器”没有的功能。

例如,有几种方法可以转换“分层”或“tre”结构, 比如“先走过树叶”,或“先走过树枝”。

或者,如果节点的兄弟节点有一个排序索引,并且您希望通过索引逐步“遍历”/“访问”它们,而不是逐步地。“/ p>

如果AST类或结构只适用于一种方法,则可能需要使用自定义“walker”/“visitor”的其他方法。