如何使用Antlr实现函数调用,以便在定义之前就可以调用它?
一旦构建了AST,实现tree walker的最佳方式是什么,以便可以以任何顺序定义和调用函数 例如,这在PHP中是有效的:如何使用Antlr实现函数调用,以便在定义之前就可以调用它?,antlr,abstract-syntax-tree,function-call,Antlr,Abstract Syntax Tree,Function Call,一旦构建了AST,实现tree walker的最佳方式是什么,以便可以以任何顺序定义和调用函数 例如,这在PHP中是有效的: <?php f(); // function called before it’s defined function f() { print 3; } ?> 我猜一定有第二个过程,或者是一个树转换,但是我在这个主题上找不到任何有趣的东西。这个问题可能不是Antlr特有的,但是如果你能给我举一个Antlr的例子来说明如何做到这一点,那就更好了 是的,你
<?php
f(); // function called before it’s defined
function f() {
print 3;
}
?>
我猜一定有第二个过程,或者是一个树转换,但是我在这个主题上找不到任何有趣的东西。这个问题可能不是Antlr特有的,但是如果你能给我举一个Antlr的例子来说明如何做到这一点,那就更好了 是的,你是对的:这是在AST的多个过程中完成的 首先创建一个语法来构建源代码的AST,然后创建一个树语法,用于在树上迭代并发现所有定义的函数。然后,可以使用另一个树语法对脚本求值,该树语法从以前的树语法中获取已发现的函数 演示。 以来源为例:
<?php
f(); // function called before it’s defined
function f() {
g();
}
function g() {}
?>
并运行以下主类(D):
当然,这只是一个如何处理它的例子,而不是如何最好地完成它。我可以想象(当使用Java解释脚本时),您不会将声明的函数作为简单字符串存储在集合
中,而是作为映射
来轻松获取函数的根并在调用时对其求值
进一步阅读:
祝你好运
编辑
然后,秒数传递可以检查是否使用前面的树遍历器在其前面定义了所有函数:
tree grammar PHPMinValidateWalker;
options {
tokenVocab=PHPMin;
ASTLabelType=CommonTree;
}
@members {
java.util.Set<String> declared = new java.util.HashSet<String>();
}
validate
: script
;
script
: ^(SCRIPT atom*)
;
atom
: functionCall
| functionDecl
;
functionCall
: ^(F_CALL Identifier)
{
if(!declared.contains($Identifier.text)) {
throw new RuntimeException("no such function: " + $Identifier.text);
}
}
;
functionDecl
: ^(F_DECL Identifier functionBody)
;
functionBody
: ^(F_BODY functionCall*)
;
树语法PHPMinValidateWalker;
选择权{
tokenVocab=PHPMin;
ASTLabelType=CommonTree;
}
@成员{
声明的java.util.Set=new java.util.HashSet();
}
验证
:脚本
;
剧本
:^(脚本原子*)
;
原子
:函数调用
|函数DECL
;
函数调用
:^(F_呼叫标识符)
{
如果(!declared.contains($Identifier.text)){
抛出新的RuntimeException(“没有这样的函数:“+$Identifier.text”);
}
}
;
函数DECL
:^(F_DECL标识符函数体)
;
功能体
:^(F_BODY functionCall*)
;
使用测试:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "<?php \n" +
"f(); // function called before it’s defined \n" +
"function f() { \n" +
" g(); \n" +
" x(); \n" +
"} \n" +
"function g() {} \n" +
"?> \n";
// create a lexer and parser for the source
ANTLRStringStream in = new ANTLRStringStream(source);
PHPMinLexer lexer = new PHPMinLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PHPMinParser parser = new PHPMinParser(tokens);
PHPMinParser.parse_return returnValue = parser.parse();
CommonTree tree = (CommonTree)returnValue.getTree();
// create a tree walker to discover all declared functions
CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
nodes.setTokenStream(tokens);
PHPMinFunctionWalker functions = new PHPMinFunctionWalker(nodes);
functions.discover();
System.out.println("Declared functions: "+functions.declared);
// PHPMinValidateWalker
nodes = new CommonTreeNodeStream(tree);
nodes.setTokenStream(tokens);
PHPMinValidateWalker validator = new PHPMinValidateWalker(nodes);
validator.declared = functions.declared;
validator.validate();
}
}
import org.antlr.runtime.*;
导入org.antlr.runtime.tree.*;
导入org.antlr.stringtemplate.*;
公共班机{
公共静态void main(字符串[]args)引发异常{
字符串source=“\n”;
//为源代码创建词法分析器和解析器
AntlStringStream in=新的AntlStringStream(源);
PHPMinLexer=新的PHPMinLexer(in);
CommonTokenStream令牌=新的CommonTokenStream(lexer);
PHPMinParser=新的PHPMinParser(令牌);
PHPMinParser.parse_返回returnValue=parser.parse();
CommonTree=(CommonTree)returnValue.getTree();
//创建树遍历器以发现所有声明的函数
CommonTreeNodesTeam节点=新的CommonTreeNodesTeam(树);
nodes.setTokenStream(令牌);
PHPMinFunctionWalker函数=新的PHPMinFunctionWalker(节点);
函数discover();
System.out.println(“声明的函数:“+functions.Declared”);
//PHPMinValidateWalker
节点=新的CommonTreeNodeStream(树);
nodes.setTokenStream(令牌);
PHPMinValidateWalker验证器=新的PHPMinValidateWalker(节点);
validator.declared=functions.declared;
validator.validate();
}
}
生成异常,因为
x()
未在任何位置定义。从源代码中删除它将导致树漫游器不会产生任何异常。感谢mil提供的示例,即使它没有说明函数调用的第二步。。。然而,这个链接正是我所需要的——它甚至给我想要实现的东西起了一个名字:“forward function call”,这大大有助于找到更多的例子@塞巴斯蒂安,不客气。如果可以的话,一定要看一看:它处理所有这类事情,包括示例代码。好书。
// A
java -cp antlr-3.2.jar org.antlr.Tool PHPMin.g
// B
java -cp antlr-3.2.jar org.antlr.Tool PHPMinFunctionWalker.g
// C
javac -cp antlr-3.2.jar *.java
// D
java -cp .:antlr-3.2.jar Main // *nix
java -cp .;antlr-3.2.jar Main // Windows
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "<?php \n" +
"f(); // function called before it’s defined \n" +
"function f() { \n" +
" g(); \n" +
"} \n" +
"function g() {} \n" +
"?> \n";
// create a lexer and parser for the source
ANTLRStringStream in = new ANTLRStringStream(source);
PHPMinLexer lexer = new PHPMinLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PHPMinParser parser = new PHPMinParser(tokens);
PHPMinParser.parse_return returnValue = parser.parse();
CommonTree tree = (CommonTree)returnValue.getTree();
// create a tree walker to discover all declared functions
CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
nodes.setTokenStream(tokens);
PHPMinFunctionWalker functions = new PHPMinFunctionWalker(nodes);
functions.discover();
System.out.println("Declared functions: "+functions.declared);
}
}
Declared functions: [f, g]
tree grammar PHPMinValidateWalker;
options {
tokenVocab=PHPMin;
ASTLabelType=CommonTree;
}
@members {
java.util.Set<String> declared = new java.util.HashSet<String>();
}
validate
: script
;
script
: ^(SCRIPT atom*)
;
atom
: functionCall
| functionDecl
;
functionCall
: ^(F_CALL Identifier)
{
if(!declared.contains($Identifier.text)) {
throw new RuntimeException("no such function: " + $Identifier.text);
}
}
;
functionDecl
: ^(F_DECL Identifier functionBody)
;
functionBody
: ^(F_BODY functionCall*)
;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "<?php \n" +
"f(); // function called before it’s defined \n" +
"function f() { \n" +
" g(); \n" +
" x(); \n" +
"} \n" +
"function g() {} \n" +
"?> \n";
// create a lexer and parser for the source
ANTLRStringStream in = new ANTLRStringStream(source);
PHPMinLexer lexer = new PHPMinLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
PHPMinParser parser = new PHPMinParser(tokens);
PHPMinParser.parse_return returnValue = parser.parse();
CommonTree tree = (CommonTree)returnValue.getTree();
// create a tree walker to discover all declared functions
CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
nodes.setTokenStream(tokens);
PHPMinFunctionWalker functions = new PHPMinFunctionWalker(nodes);
functions.discover();
System.out.println("Declared functions: "+functions.declared);
// PHPMinValidateWalker
nodes = new CommonTreeNodeStream(tree);
nodes.setTokenStream(tokens);
PHPMinValidateWalker validator = new PHPMinValidateWalker(nodes);
validator.declared = functions.declared;
validator.validate();
}
}