0

私は単純な数式パーサーを持っており、自分で AST を構築したいと考えています (ast パーサーがないことを意味します)。ただし、すべてのノードは 2 つのオペランドしか保持できません。したがって、2+3+4 は次のようなツリーになります。

        +
       / \
      2   +
         / \
        3   4

問題は、文法に再帰を実行させることができないことです。ここでは、「追加」部分だけを示します。

add returns [Expression e]
  : op1=multiply { $e = $op1.e; Print.ln($op1.text); } 
    ( '+' op2=multiply   { $e = new AddOperator($op1.e, $op2.e); Print.ln($op1.e.getClass(), $op1.text, "+", $op2.e.getClass(), $op2.text); }
    | '-' op2=multiply   { $e = null; } // new MinusOperator    
    )*
  ;

しかし、一日の終わりには、次のような単一のツリーが生成されます。

     +
    / \
   2   4

問題がどこにあるかはわかっています。それは、「追加」がまったくまたは無限に発生する可能性があるためです(*)が、これを解決する方法がわかりません。私は次のようなことを考えました:

「追加」部分:

add returns [Expression e]
  : op1=multiply { $e = $op1.e; Print.ln($op1.text); } 
    ( '+' op2=(multiply|add)   { $e = new AddOperator($op1.e, $op2.e); Print.ln($op1.e.getClass(), $op1.text, "+", $op2.e.getClass(), $op2.text); }
    | '-' op2=multiply   { $e = null; } // new MinusOperator    
    )?
  ;

しかし、これにより再帰エラーが発生します。何か案は?

4

1 に答える 1

1

このソリューションをテストするための完全な文法はありませんが、これを置き換えることを検討してください (add問題の最初のルールから):

$e = new AddOperator($op1.e, $op2.e);

これとともに:

$e = new AddOperator($e, $op2.e);  //$e instead of $op1.e

このようにして、各反復はそれを置き換えるのではなく('+' multiply)*拡張します。e

それを正しくするために少し遊んでみる必要があるかもしれませんExpressionし、物事を管理し続けるためにルールに一時的なものが必要かもしれません. =のように、ループによって作成された最後の式が演算子の右側のどこかにあることを確認してください$e = new XYZ($e, $rhs.e);

于 2012-11-29T16:57:43.073 に答える