2

相互左再帰についてさらに別の質問をして申し訳ありません。私の状況は私の状況に固有のもののように感じます。または、少なくとも他の人の文法に関連付けるのに十分なことがわかりません。私はコンプサイエンスの世界に少し慣れていないので(私のターゲット言語である Java と現在は ANTLR4 を独学で学んでいます)、可能であれば、CS の主要な用語ではなく、一般的な用語で物事を説明してください。

私は代数とシンボリック導関数を必要とするプログラムを書いています。もちろん、それには解析とツリーの操作が必要ですが、ANTLR4 は直接左再帰をサポートしていると思っていたので、まだ心配するつもりはありませんが、どうやらそれはどういうわけかではありません。出力では、私のメソッド[式]が相互に再帰的に残されていることを教え続けており、明らかにそれは許可されていません...? 私の質問:

1)誰かが左再帰/相互左再帰と直接左再帰の違いを説明できますか?

2) 私の文法でこの再帰的な煩わしさを引き起こしている原因と、それを修正する方法を説明してください。そして、これが話題になっているかどうかはわかりません:

3) 代替案や代替案のラベリング (#label 表記のことだと思います) について人々は言います。それは何のためにあるのです?

grammar MathProcessor;
@header {package utils;}
END: ';';
EQUALS: '=';
SIN: 'sin(';
COS: 'cos(';
TAN: 'tan(';
SEC: 'sec(';
CSC: 'csc(';
COT: 'cot(';
LN: 'ln(';
EPOW: 'pow(';
RPAREN: '(';
LPAREN: ')';
EXP: '^';
MULT: '*';
DIV: '/';
ADD: '+';
SUBT: '-';
VAR: ('a'..'z'|'A'..'Z');
INT: ('0'..'9')+;
mathobj: ((equation|expression) END) EOF;
equation: (expression '=' expression);

expression: 
((RPAREN|SIN|COS|TAN|SEC|CSC|COT|LN|EPOW) expression (RPAREN)) #parenOps
| (expression EXP expression) #exponent
| (expression (MULT|DIV) expression) #multiplyDivide 
| (expression (ADD|SUBT) expression) #addSubtract
| (VAR|INT) #varInt
;
4

1 に答える 1

5

文法内の不要な括弧のいくつかのケースを単純に削除した場合、文法は実際に ANTLR 4 で機能します。左再帰除去アルゴリズムは、次の例に示す直接左再帰でのみ機能します。

a
  : B
  | a B  // the reference to 'a' here is direct left recursion
  ;

他のタイプの再帰の主なものは間接左再帰で、通常は 2 つの別個の規則を使用して示されます。

a
  : B
  | c
  ;

c
  : a B // the reference back to 'a' is indirect left recursion
  ;

あなたの文法の場合、ANTLR は(...)無名サブルールとして扱われているため、次のようなコードは間接左再帰と判断されます。例から括弧を削除すると、最初のケースのように動作します。

a
  : B
  | (a B)
  ;

最後の質問に答えるために、#label構文は、その代替の生成された解析ツリー クラスを変更します。たとえば、プレーンExpressionContextオブジェクトを生成するのではなく、式3VarIntContext. これにより、自動生成されたリスナーとビジターでルール内のさまざまな選択肢を区別できます。

于 2014-02-19T12:08:25.607 に答える