如何使用Antlr实现函数调用,以便在定义之前就可以调用它?
一旦构建了 AST,实现树遍历器以便可以按任意顺序定义和调用函数的最佳方法是什么?
例如,这在 PHP 中是有效的:
<?php
f(); // function called before it’s defined
function f() {
print 3;
}
?>
我猜想一定有第二遍,或者树转换,但我找不到关于这个主题的任何有趣的东西。这个问题可能不是 Antlr 特有的问题,但如果你能给我一个 Antlr 示例来说明如何完成此操作,那就更好了!
Once the AST is built, what is the best way implement the tree walker so that functions can be defined and called in whatever order?
For example, this is valid in PHP:
<?php
f(); // function called before it’s defined
function f() {
print 3;
}
?>
I’m guessing that somehow there must be a second pass, or a tree transformation, but I can’t find anything interesting on this subject. The problem is probably not an Antlr-specific one, but if you could point me to an Antlr example of how this is done, even better!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,你是对的:这是通过多次 AST 完成的。
首先创建一个语法来构建源的 AST,然后创建一个树语法,用于迭代树并发现所有定义的函数。然后,您可以使用另一个树语法来评估脚本,该语法从先前的树语法中获取发现的函数。
一个演示。
获取源代码:
将其解析为以下 AST:
使用(组合)语法
:然后发现声明的函数使用从以下树语法生成的“tree-walker”:
要测试所有内容,请创建词法分析器和解析器 (A),生成“tree-walker”(B),编译所有源文件 (C):
并运行以下主类 (D):
产生以下输出:
当然,这只是如何处理它的示例,而不是如何最好地完成它的示例。我可以想象(当使用 Java 解释脚本时),您不会将声明的函数存储为
Set
中的简单字符串,而是存储为Map;
轻松获取函数的根并在调用时对其求值。进一步阅读: http://www.antlr.org/wiki/ display/ANTLR3/Simple+tree-based+interpeter
祝你好运!
编辑
然后,秒数传递可以使用前面的树遍历器检查是否所有函数都在其之前定义:
使用测试:
产生异常,因为
x()
未定义任何地方。从源中删除它将导致树遍历器不会产生异常。Yes, you are right: this is done in more than one pass over the AST.
You first create a grammar that builds a AST of the source, then you create a tree grammar that is used to iterate over the tree and discovers all defined function. You could then evaluate the script using another tree grammar that takes the discovered functions from the previous tree grammar.
A demo.
Take the source:
which is parsed into the following AST:
using the (combined) grammar:
Then discover the declared functions using a "tree-walker" generated from the following tree grammar:
To test it all, create a lexer and parser (A), generate the "tree-walker" (B), compile all source files (C):
and run the following main class (D):
which produces the following output:
Of course, this is just an example of how to approach it, not of how it is best done. I can imagine (when using Java to interpret the script), you wouldn't store the declared functions as simple Strings in a
Set<String>
, but rather as aMap<String, CommonTree>
to easily get the root of a function and evaluate it when called.Further reading: http://www.antlr.org/wiki/display/ANTLR3/Simple+tree-based+interpeter
Good luck!
EDIT
The seconds pass could then check if all functions are defined ahead of it using the previous tree-walker:
Using the test:
produces an exception since
x()
is not define anywhere. Removing it from the source will cause the tree-walker to produce no exception.