1

私はこの問題の回避策をすでに知っていますが、少なくとも1つの理由から、この1つのアプローチを実際に使用したいと思います。それは機能するはずです。

これは、TerenceParrによる「TheDefinitiveANTLR Reference」から抜粋したルールです(本はANTLR3用です)。

expr : (INT -> INT) ('+' i=INT -> ^('+' $expr $i) )*;

INTが続かない場合+、結果はINT(単一ノード)になります。そうである場合、サブツリーは最初INT(と呼ばれる$expr)を左ブランチとして構築されます。

同様のルールを作成したいのですが、カスタムアクションを使用します。

mult_expr : (pow_expr -> pow_expr ) 
            (op=MUL exr=pow_expr 
              -> { new BinExpr($op,$mult_expr.tree,$exr.tree) })*; 

ANTLRはそのようなルールを受け入れますが、入力(たとえば)「5 * 3」でパーサーを実行すると、「行1:1に'*'5でEOFがありません」というエラーが表示されます。

質問:カスタム書き換えアクションでバックリファレンスを使用する方法は?

4

2 に答える 2

1

文法ファイルでこれを行うのではなく、独自に作成してCommonTreeAdaptor、カスタムノードの作成をこれに移動することをお勧めします。CommonTreeAdaptor詳細については、以下を参照してください:ANTLR3ASTの拡張

マイナス記号(バイナリまたは単項演算子)など、複数の意味を持つ可能性のある演算子の場合は、パーサールールで次のように単項演算子を書き直してください。

grammar X;

...

tokens { U_SUB; } 

add_expr
 : mult_expr ((SUB | ADD)^ mult_expr)*
 ;

...

unary_expr
 : SUB atom -> ^(U_SUB atom)
 | atom
 ;

...

そして、の実装で、次のCommonTreeAdaptorようなことを行います。

@Override
public Object create(Token t) {
  ...
  switch(t.getType()) {
    case X.SUB   : /* return a binary-tree */
    ...
    case X.U_SUB : /* return an unary-tree */
  }
  ...
}
于 2012-08-20T10:12:23.633 に答える
1

私は執拗な男であり、カスタムノードを1つのステップで使用するというこのアイデアは、私を悩ませていました... ;-)

だから、私はしました。重要なポイントは次のとおりです。

  • 「メイン」ルールの最後に置くEOF!

  • トークンにラベルを付けるときは、グループ化するのではなく、トークンの横にラベルを配置します(op='*'|op='/')op=('*'|'/')

文法規則を使用してすぐにカスタムノードを作成するこのアプローチが良いアイデアかどうかはわかりませんが、これで問題の問題が解決するので、これを解決策としてマークします。

そして、記録として、最も興味深いルールは次のようになります。

mult_expr : (exl=pow_expr -> $exl ) 
        ((op=MUL|op=IDIV|op=RDIV|op=MOD) exr=pow_expr 
        -> { new BinaryExpression($op,$exl.tree,$exr.tree) })*; 
于 2012-08-22T16:22:19.897 に答える