我一直在使用ANTLR提供的ECMAScript语法,目的是识别JavaScript全局变量。生成了一个AST,我现在想知道过滤掉全局变量声明的基本方法是什么。
我有兴趣在我的AST中查找所有最外层的“variableDeclaration”标记;但实际的操作方法却让我望而却步。这是我到目前为止的设置代码:
String input = "var a, b; var c;";
CharStream cs = new ANTLRStringStream(input);
JavaScriptLexer lexer = new JavaScriptLexer(cs);
CommonTokenStream tokens = new CommonTokenStream();
tokens.setTokenSource(lexer);
JavaScriptParser parser = new JavaScriptParser(tokens);
program_return programReturn = parser.program();
作为ANTLR的新手,任何人都可以提供任何指针吗?
答案 0 :(得分:3)
我猜你正在使用this grammar。
虽然该语法表明创建了适当的AST,但事实并非如此。它使用一些内联运算符从分析树中排除某些标记,但它从不为树创建任何根,从而产生完全平坦的分析树。由此,你无法以合理的方式获得所有全球变量。
您需要稍微调整语法:
在语法文件顶部的options { ... }
下添加以下内容:
tokens
{
VARIABLE;
FUNCTION;
}
现在用以下规则替换以下规则:functionDeclaration
,functionExpression
和variableDeclaration
:
functionDeclaration
: 'function' LT* Identifier LT* formalParameterList LT* functionBody
-> ^(FUNCTION Identifier formalParameterList functionBody)
;
functionExpression
: 'function' LT* Identifier? LT* formalParameterList LT* functionBody
-> ^(FUNCTION Identifier? formalParameterList functionBody)
;
variableDeclaration
: Identifier LT* initialiser?
-> ^(VARIABLE Identifier initialiser?)
;
现在生成一个更合适的树。如果您现在解析源:
var a = 1; function foo() { var b = 2; } var c = 3;
生成以下树:
你现在所要做的就是迭代树根的子节点,当你偶然发现VARIABLE
令牌时,你知道它是一个“全局”,因为所有其他变量都在{{1节点。
以下是如何做到这一点:
FUNCTION
产生以下输出:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
public class Main {
public static void main(String[] args) throws Exception {
String source = "var a = 1; function foo() { var b = 2; } var c = 3;";
ANTLRStringStream in = new ANTLRStringStream(source);
JavaScriptLexer lexer = new JavaScriptLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JavaScriptParser parser = new JavaScriptParser(tokens);
JavaScriptParser.program_return returnValue = parser.program();
CommonTree tree = (CommonTree)returnValue.getTree();
for(Object o : tree.getChildren()) {
CommonTree child = (CommonTree)o;
if(child.getType() == JavaScriptParser.VARIABLE) {
System.out.println("Found a global var: "+child.getChild(0));
}
}
}
}