1

我正在使用Patrick Hulsmeijer EcmaScript 3 语法构建一个带有 ANTLR 的 JavaScript 工具。

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

function(){}();

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

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

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

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

(function(){})();

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

我试图functionDeclarationsourceElement生产中消除并将其投入生产:statementstatementTail

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

但是会出现构建错误:

[致命] 规则statementTail具有非 LL(*) 决策,因为可以从 alts 3,4 访问递归规则调用。通过左分解或使用语法谓词或使用 backtrack=true选项来解决。
|---> : 变量声明

因为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 时需要它。

我该如何解决这种歧义?

4

1 回答 1

2

当 sourceElement 以 'function' 关键字开头时,解析器期望一个 functionDeclaration 是正确的。这实际上实现了ECMAScript 语言规范中的以下限制:

ExpressionStatement 不能以 function 关键字开头,因为这可能使其与 FunctionDeclaration 不明确。

因此,根据上述限制,所讨论的语句是无效的,尽管实际上它在语法的产生中并不模棱两可:因为它省略了函数标识符,所以它不能是函数声明。暴露句法歧义的声明将是

function f(){}(42)

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

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

function f(){}()

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

于 2011-04-24T12:24:38.920 回答