代码之家  ›  专栏  ›  技术社区  ›  Christopher Hunt

使用ANTLR识别JavaScript文件中的全局变量声明

  •  1
  • Christopher Hunt  · 技术社区  · 14 年前

    我一直在使用ANTLR提供的ECMAScript语法来识别JavaScript全局变量。生成了一个AST,我现在想知道过滤掉全局变量声明的基本方法是什么。

    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();
    

    1 回复  |  直到 14 年前
        1
  •  3
  •   Bart Kiers    14 年前

    我猜你在用 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;
    

    alt text

    你现在所要做的就是在你的树根的子树上迭代,当你偶然发现一个 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