如何用ANTLR解析JavaScript函数表达式调用?

时间:2011-04-20 10:44:38

标签: javascript parsing antlr function-calls

我正在使用Patrick Hulsmeijer EcmaScript 3 grammar使用ANTLR构建JavaScript工具器。

我在解析这行代码时遇到问题:

function(){}();

这是函数表达式的直接调用。 解析器将语句识别为函数声明,然后在函数体后面找到括号时失败。原因是函数声明以最优先的方式被识别,以避免与函数表达式的歧义。

这是语法识别函数声明的方式:

sourceElement
options
{
    k = 1 ;
}
    : { input.LA(1) == FUNCTION }? functionDeclaration
    | statement
    ;

我甚至不确定它是否是有效的EcmaScript语句。是吗?
我认为写起来应该更正确:

(function(){})();

实际上解析器处理得很好 顺便说一下,这不是问题的核心,因为我无法控制代码。

我尝试从functionDeclaration制作中删除sourceElement并将其放入 statement statementTail制作中:

statementTail
    : variableStatement
    | emptyStatement
    | expressionStatement
    | functionDeclaration
    | ifStatement
    | ...
    ;

但是出现了构建错误:

  

[致命]规则statementTail有   由于递归而导致的非LL(*)决策   从alts可以访问的规则调用   3,4。通过左因子或   使用句法谓词或使用   backtrack=true选项。
  | ---> :variableStatement

因为variableStatement制作包含functionExpression作为后代,这会导致歧义。解析器无法在functionDeclarationfunctionExpression中进行选择,因为它们几乎相同:

functionDeclaration
    : FUNCTION name=Identifier formalParameterList functionBody
    -> ^( FUNCTIONDECL $name formalParameterList functionBody )
    ;

functionExpression
    : FUNCTION name=Identifier? formalParameterList functionBody
    -> ^( FUNCTIONEXPR $name? formalParameterList functionBody )
    ;

注意:我使用不同的树节点(FUNCTIONDECL和FUNCTIONEXPR)修改了原始重写规则,因为我在走AST时需要它。

如何解决这种歧义?

1 个答案:

答案 0 :(得分:2)

当sourceElement以'function'关键字开头时,解析器正确期望functionDeclaration。实际上,这实现了ECMAScript Language Specification

的以下限制
  

ExpressionStatement无法启动   使用function关键字因为那个   可能会使它变得模棱两可   FunctionDeclaration。

因此,根据上述限制,所讨论的语句是无效的,但实际上语法的产生并不含糊:因为它省略了函数标识符,所以它不能是函数声明。揭露句法歧义的陈述将是

function f(){}(42)

根据ECMAScript规范是一个functionDeclaration,后跟一个expressionStatement。

因此,最好的办法是向此代码的提供者询问正确的语法。你说你无论如何都需要解析它,这可能是用ANTLR的回溯来完成的。确保函数标识符在functionDeclaration中是必需的,并让它在语句之前尝试使用functionDeclaration。但要注意,即使这对原始语句有帮助,它也会失败

function f(){}()

因为这里的functionDeclaration可以成功完成,但是后面没有有效的语句。