4

ObjectiveC antlr v3 文法 ( http://www.antlr3.org/grammar/1212699960054/ObjectiveC2ansi.g ) を見ると、他の一般的な文法の多くは、条件を解決するためにこれと同様の構造を行っています。

conditional_expression : logical_or_expression 
  ('?' logical_or_expression ':' logical_or_expression)? ;

constant_expression : conditional_expression ;

logical_or_expression : logical_and_expression 
  ('||' logical_and_expression)* ;

logical_and_expression : inclusive_or_expression 
  ('&&' inclusive_or_expression)* ;

inclusive_or_expression : exclusive_or_expression 
  ('|' exclusive_or_expression)* ;

exclusive_or_expression : and_expression ('^' and_expression)* ;

and_expression : equality_expression ('&' equality_expression)* ;

equality_expression : relational_expression 
  (('!=' | '==') relational_expression)* ;

relational_expression : shift_expression
 (('<' | '>' | '<=' | '>=') shift_expression)* ;

shift_expression : additive_expression (('<<' | '>>') additive_expression)* ;

additive_expression : multiplicative_expression
  (('+' | '-') multiplicative_expression)* ;

multiplicative_expression : cast_expression 
  (('*' | '/' | '%') cast_expression)* ;

cast_expression : '(' type_name ')' cast_expression | unary_expression ;

unary_expression 
  : postfix_expression
  | '++' unary_expression
  | '--' unary_expression
  | unary_operator cast_expression
  | 'sizeof' ('(' type_name ')' | unary_expression) ;

unary_operator : '&' | '*' | '-' | '~' | '!' ;

あなたがそれを読むと、彼らがこの非常に長い 1 対 1 の条件付きチェーン from conditional_expressionto logical_or_expressionto logical_and_expressionto to をinclusive_or_expression行っていることに気付くでしょうexclusive_or_expression

さて、私はANTLRに関してはかなり素朴ですが、これは条件を解析する奇妙な方法だと思います。logical_or_expression の定義が他のすべての条件式タイプをひねるのは非常に複雑に思えます。結局のところ、論理の定義はビットごとの左シフトとどのような関係があるのORでしょうか?

おそらくより良い方法がありますか、またはこの方法が必要な特定の理由がありますか?

4

2 に答える 2

7

すでに述べたように、演算子の優先順位を適切に処理するには「チェーン」が必要です。それがなければ、次のような入力は次のよう1+2*3に解析されます。

     *
    / \
   +   3
  / \
 1   2

それ以外の:

  +
 / \
1   *
   / \
  2   3

ANTLR 4 は直接左再帰ルールをサポートしているため、次のようになります。

foo
 : foo '?' foo
 | TOKEN
 ;

したがって、間接的な左再帰規則ではありません。

foo
 : bar
 | TOKEN
 ;

bar
 : foo '?' foo
 ;

これらのルールを次のように書き換えることができます。

expression
 : '-' expression
 | '(' type_name ')' expression
 | expression ('*' | '/' | '%') expression
 | expression ('+' | '-') expression
 | expression ('<<' | '>>') expression
 | expression ('<' | '>' | '<=' | '>=') expression
 | expression ('!=' | '==') expression
 | expression '&' expression
 | expression '^' expression
 | expression '|' expression
 | expression '&&' expression
 | expression '||' expression
 | expression '?' expression ':' expression
 | IDENTIFIER
 | NUMBER
 ;

パーサーが に出くわした場合、expression最初に を探し、('*' | '/' | '%')そこにない場合は('+' | '-')などを探します。つまり、ルールの最初に配置された選択肢は、ルールの下位に配置された選択肢よりも優先されます。

以前の質問からわかりましたが、文法が完成したら、ANTLR v4 ツリーをたどる最良の方法は何ですか? 、リスナーを使用してツリーを「ウォーク」していること。expression先ほど示したようにルールを作成すると、enterExpression(...)exitExpression(...)メソッドで多くの手動検査を行って、どの選択肢が に一致したかを調べる必要がありますexpression。ここで「ラベル」が役に立ちます。expressionルールの各選択肢にラベルを付けるだけです。

expression
 : '-' expression                                  #unaryExpr
 | '(' type_name ')' expression                    #castExpr
 | expression ('*' | '/' | '%') expression         #multExpr
 | expression ('+' | '-') expression               #addExpr
 | expression ('<<' | '>>') expression             #...
 | expression ('<' | '>' | '<=' | '>=') expression 
 | expression ('!=' | '==') expression
 | expression '&' expression
 | expression '^' expression
 | expression '|' expression
 | expression '&&' expression
 | expression '||' expression
 | expression '?' expression ':' expression
 | IDENTIFIER
 | NUMBER
 ;

(1 つにラベルを付ける場合は、すべてにラベルを付ける必要があることに注意してください!)

そして、基本リスナー クラスには、すべての選択肢のenter- およびexitメソッドがあります。

public void enterUnaryExpr(...)
public void exitUnaryExpr(...)

public void enterCastExpr(...)
public void exitCastExpr(...)

public void enterMultExpr(...)
public void exitMultExpr(...)

...
于 2013-02-27T22:15:13.717 に答える
0

このようにするのには十分な理由があります: 演算子の優先順位です。論理 OR と左ビットごとのシフトの例を取り上げて、次のようなことを考えてください。

if (a << b || c)

Objective-C の優先順位規則では、「<<」が優先されるため、これを評価する正しい方法は次のとおりです。

(a << b) || c

パーサールールは、言及したチェーンを使用してこれを管理します。これは、「||」のルールが チェーンの上位にある場合、解析は || の部分式として a << b を正しく提供します。オペレーター。

Antl3 にはこれ以上の方法はありませんが、Antlr4 にはあります。Antlr4 では直接左の再帰規則を使用できるからです。この問題の非常に良い説明があるため、「決定的な Antlr4 リファレンス」を強くお勧めします。

于 2013-02-27T17:04:45.507 に答える