antlr4-遍历机制概念(三)

antlr4如何遍历树?

antlr4提供了2种树遍历方式。在默认情况下,antlr生成了一个解析树监听接口,它用内置的树遍历器响应事件触发。这个监听器正如SAX文档处理xml解析对象一样。SAX监听器接收通知事件,例如startDocument()和endDocumnet()。他们在监听器中仅仅被回调。

解析树监听器(Parse-Tree Listeners)

为了在遍历树的时候触发对监听器的调用,antlr的运行时包提供类ParseTreeWalker。

antlr生成了一个ParerTreeListener的子类,这个类会对每个语法规则指定一个enter和exit方法。当遍历器遇到节点规则assign时,会触发enterAssign()方法然后传递给他解析树节点的AssignConext。在遍历器访问了assign的所有子节点后,会触发exitAssign()方法。下面的树状图显示了ParseTreeWalker执行了深度优先的遍历:

接下来的图片显示了一个更完整的ParseTreeWalker调用:

解析树访问器(Parse-Tree Visitors)

有这样一种情形,就是我们想自己控制遍历方式,明确的调用方法去访问子节点。可选的 -visitor 命令让ANTLR生产了一个访问器接口,这个接口的每个规则都对应一个visit方法。下图是的访问器模式:

为了实例化一个遍历树,应用代码需要创建vistor的实现类并且调用visit()方法。

ParseTree tree = ...;//tree is result of parsing
MyVisitor v = new MyVisitor();
v.visit(tree);

antlr访问器支持编码调用visitStat()方法当遇到根节点的时候。visitStat()方法的时候将带着子节点参数调用visit()方法以便继续遍历。或者,visitMethod()也可以明确的调用visitAssian()方法,等等。

比较

监听器和遍历器的最大不同在于,监听方法并不为明确的嗲用方法区遍历他们的子节点负责。在另一方面,访问器必须明确的触发访问子节点,以便保持遍历的继续运行。

访问器控制了遍历的顺序,由于明确的调用了子节点,也控制的树是否会被 遍历。