我正在使用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
作为后代,这会导致歧义。解析器无法在functionDeclaration
和functionExpression
中进行选择,因为它们几乎相同:
functionDeclaration
: FUNCTION name=Identifier formalParameterList functionBody
-> ^( FUNCTIONDECL $name formalParameterList functionBody )
;
functionExpression
: FUNCTION name=Identifier? formalParameterList functionBody
-> ^( FUNCTIONEXPR $name? formalParameterList functionBody )
;
注意:我使用不同的树节点(FUNCTIONDECL和FUNCTIONEXPR)修改了原始重写规则,因为我在走AST时需要它。
如何解决这种歧义?
答案 0 :(得分:2)
当sourceElement以'function'关键字开头时,解析器正确期望functionDeclaration。实际上,这实现了ECMAScript Language Specification:
的以下限制ExpressionStatement无法启动 使用function关键字因为那个 可能会使它变得模棱两可 FunctionDeclaration。
因此,根据上述限制,所讨论的语句是无效的,但实际上语法的产生并不含糊:因为它省略了函数标识符,所以它不能是函数声明。揭露句法歧义的陈述将是
function f(){}(42)
根据ECMAScript规范是一个functionDeclaration,后跟一个expressionStatement。
因此,最好的办法是向此代码的提供者询问正确的语法。你说你无论如何都需要解析它,这可能是用ANTLR的回溯来完成的。确保函数标识符在functionDeclaration中是必需的,并让它在语句之前尝试使用functionDeclaration。但要注意,即使这对原始语句有帮助,它也会失败
function f(){}()
因为这里的functionDeclaration可以成功完成,但是后面没有有效的语句。