1

私はちょうど何か頭痛に遭遇しました..

サンプルステートメントがあるように、ステートメントをさまざまな関数に分割しようとしています

start
 n turnTo 's'.
 n terminate.
end

両方のステートメントは「n」で始まります、現在私は書いています

statement 
    :
    (turnTo_statment|terminate_statment)*
    ;

turnTo_statment
    :
    variable 'turnTo' '\'' value '\'' '.'
    ;

terminate_statment
    :
    variable 'terminate' '.'
    ;

ただし、レクサーが実行されている場合、両方のサブステートメントが同じもの'n'で始まるため、どちらがどちらであるかを判別できません。コンパイラーは、ルールを使用する別の選択肢があります。次の文字列がコンパイラが使用する最初のルールと一致しない場合、一致しないエラーが自動的にスローされます。

'x turnTo y'に出会った場合、ANTLRを識別して伝えるにはどうすればよいですか?'x turnTo y'に出会った場合、ルールturnTo_statmentを使用します。次に、ルールterminate_statmentを使用します。

つまり、antlrにこれを行う関数はありますか。

statement 
    :
    ((if statement contain_keywords 'turnTO') -> turnTo_statment
    |
    (if statement contain_keywords 'terminate') ->terminate_statment)*
    ;

ありがとう..

4

2 に答える 2

3

まず、パーサー ルールで「リテラル」を使用しないでください。ANTLR で多くの経験がなければ、これはトラブルに巻き込まれます。実際のレクサー ルールを作成します。

TURNTO: 'turnTo';

ここで、おそらく ANTLR wiki のチュートリアルを読み、ダウンロード可能なサンプルを調べて、それらを理解していることを確認する必要があります。文法言語は簡単に学べるので、良い文法を書くのは簡単に思えますが、実際にはかなりの知識が必要です。ただし、最初に認識すべきことは、レクサーはパーサーの知識を持っていないということです。つまり、入力ストリームをトークン化し、それらのトークンをパーサーに渡すだけなので、レクサー パターンがあいまいになることはありません。パーサー ルールは、潜在的な違いを処理できます。

ANTLR はおそらく LL(1) に変換せずに文法を処理できます。ANTLR は LL(k) を処理することができ、通常はあなたの助けなしに k が何であるかを解決します。これはあなたの文法全体ですか?ただし、とにかく factor を残すことが常に最善です。

statement: var ( TURNTO {etc} | TERMINATE DOT )
于 2012-12-10T04:35:21.927 に答える
2

あなたの文法はLL(1)文法ではありません(お気づきのようにfirst(turnTo_statment) = first(terminate_statment))。ただし、左因数分解により、LL(1)文法に変換できます。

statement -> var_stmt statement
var_stmt -> variable turnto_stmt | variable terminate_stmt
turnto_stmt -> "turnTo" value
terminate_stmt -> "terminate."

ANTLRについてはよくわかりませんが、これはこの種の競合に対処するための従来の方法です。

于 2012-12-09T13:02:37.890 に答える