func processTree(t)
case t.Type of
FOO: processFoo t
BAR: processBar t
end
// a post-order process
func processFoo(foo)
// visit children
for (i = 0; i < foo.ChildCount; ++i)
processTree(foo.GetChild(i))
// visit node
do_stuff(foo.getText())
// a pre-order process
func processBoo(bar)
// visit node
do_stuff(bar.getText())
// visit children
for (i = 0; i < foo.ChildCount; ++i)
processTree(foo.GetChild(i))
4条答案
按热度按时间oyxsuwqo1#
我通过修改Manuel Abadia's article结尾的例子来解决这个问题。
这是我的版本,我碰巧正在使用它来将解析后的代码转换为C#。具体步骤如下:
1.用你的输入示例化一个ANTLRStringStream或子类(可以是文件或字符串)。
1.示例化生成的lexer,传入该字符串流。
1.使用lexer示例化一个令牌流。
1.使用该标记流示例化解析器。
1.从解析器获取顶级值,并将其转换为
CommonTree
。1.遍历树:
要获取节点的文本,请使用
node.Text
。要获取节点的令牌名称,请使用node.Token.Text
。请注意,
node.Token.Text
只会在没有对应字符串的虚构令牌时给予令牌的实际名称。如果它是一个真实的的令牌,那么node.Token.Text
将返回它的字符串。例如,如果您的语法中有以下内容:
然后,您将从
node.Token.Text
的相应访问中获得"PROGRAM"
、"FUNCDEC"
、"=="
和"="
。您可以在下面看到我的示例的一部分,或者您可以浏览完整版本。
cvxl0en22#
通常,您使用递归遍历AST,并根据节点的类型执行不同的操作。如果您使用的是多态树节点(即树中不同节点的不同子类),则访问者模式中的双重分派可能是合适的;但是,使用Antlr通常不太方便。
在伪代码中,遍历通常看起来有点像这样:
处理的种类高度依赖于语言的语义。例如,当为JVM或CLR等堆栈机器生成代码时,处理结构为
(IF <predicate> <if-true> [<if-false>])
的IF
语句可能看起来有点像这样:一般来说,一切都是递归完成的,这取决于当前节点的类型等。
pb3s4cty3#
你应该考虑写一个TreeParser;它可以使解释树的工作简单得多。
对于ANTLR 2.x,请参见http://www.antlr2.org/doc/sor.html对于ANTLR 3.x,请参见http://www.antlr.org/wiki/display/ANTLR3/Tree+construction(基于Java的解析器和树解析器示例)
kuarbcqp4#
我做了类似的事情(但不是真的),最后得到了一个TreeParser。
我也建议买ANTLR的书。它比任何网络资源都更有价值。它可能没有所有的答案,但它肯定有助于与基础。