1

我一直在使用 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 的新手,任何人都可以提供任何指示吗?

4

1 回答 1

3

我猜你正在使用这个语法

尽管该语法表明创建了正确的 AST,但事实并非如此。它使用一些内联运算符从解析树中排除某些标记,但它从不为树创建任何根,从而产生一个完全平坦的解析树。由此,您无法以合理的方式获得所有全局变量。

您需要稍微调整语法:

options { ... }在语法文件顶部的下方添加以下内容:

tokens
{
  VARIABLE;
  FUNCTION;
}

现在替换以下规则:functionDeclarationfunctionExpressionvariableDeclaration用这些:

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标记时,您知道它是一个“全局”,因为所有其他变量都将位于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));
            }
        }
    }
}

产生以下输出:

Found a global var: a
Found a global var: c
于 2010-09-27T14:45:25.997 回答