1

Patrick Hulsmeijer EcmaScript 3文法を使用して、ANTLRでJavaScriptインストルメンターを構築しています。

このコード行の解析に問題があります。

function(){}();

これは、関数式の直接呼び出しです。パーサーはステートメントを関数宣言として認識し、関数本体の後に括弧が見つかると失敗します。その理由は、関数式のあいまいさを避けるために、関数宣言が最も優先して認識されるためです。

これは、文法が関数宣言を認識する方法です。

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

それが有効なEcmaScriptステートメントであるかどうかさえわかりません。それは...ですか?
私はそれを書く方が正しいはずだと思います:

(function(){})();

これは実際にはパーサーによって適切に処理されます。
ちなみに、これは質問の核心ではありません。なぜなら、私はインストルメントするコードを制御できないからです。

私はプロダクションから排除functionDeclarationし、それをプロダクションに入れようとしました:sourceElementstatementstatementTail

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

ただし、ビルドエラーが発生します。

[致命的]ルールstatementTailには、alts 3,4から到達可能な再帰的なルール呼び出しのため、LL(*)以外の決定があります。左因数分解するか、構文述語を使用するか、 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 )
    ;

注:ASTの歩行中に必要になるため、異なるツリーノード(FUNCTIONDECLとFUNCTIONEXPR)を使用して元の書き換えルールを変更しました。

このあいまいさをどのように解決できますか?

4

1 に答える 1

2

sourceElementが'function'キーワードで始まる場合、パーサーはfunctionDeclarationを期待する権利があります。これは実際、 ECMAScript言語仕様からの次の制限を実装しています。

ExpressionStatementは、FunctionDeclarationであいまいになる可能性があるため、functionキーワードで開始できません。

したがって、問題のステートメントは上記の制限に従って無効ですが、実際には文法の生成によってあいまいではありません。関数識別子が省略されているため、functionDeclarationにすることはできません。構文のあいまいさを明らかにするステートメントは、

function f(){}(42)

ECMAScript仕様によれば、これはfunctionDeclarationであり、その後にexpressionStatementが続きます。

したがって、最善の方法は、このコードのプロバイダーに正しい構文を尋ねることです。あなたはとにかくそれを解析する必要があると言っていました、そしてそれはおそらくANTLRのバックトラックを使用して行うことができます。functionDeclarationで関数識別子が必須であることを確認し、ステートメントの前にfunctionDeclarationを試してもらいます。ただし、これが元のステートメントに役立つ場合でも、次の場合は失敗することに注意してください。

function f(){}()

ここでは、functionDeclarationを正常に完了することができますが、それに続く有効なステートメントがないためです。

于 2011-04-24T12:24:38.920 に答える