5

shift\reduce 競合を GLR メソッドで強制的に解決するにはどうすればよいですか?
右シフト演算子とそれ自体のテンプレート引数の 2 つの閉じ山かっこの間の競合をパーサーに解決させたいとします。1 つの ">>" トークンにマージせずに、レクサーに 2 つの連続する ">" 記号を個別のトークンとして渡すようにします。次に、これらのルールを文法に入れます。

operator_name:  
     "operator" ">"  
   | "operator" ">" ">"  
;  

これを shift\reduce 競合にしたい。左結合で ">" のトークン宣言がある場合、これは競合しません。そのため、token precedence\associativity 宣言を削除する必要がありますが、競合するルールごとにコンテキストの優先順位を指定して手動で解決したくない他の多くの競合が発生します。それで、トークンを宣言している間に shift\reduce 競合を強制する方法はありますか?

4

2 に答える 2

2

operator_name のルールでコンテキスト依存の優先順位を使用するとうまくいくと思います。

更新された標準で指定されている C++ 文法は、実際には文法を変更して、>> トークンを 2 つの開いているテンプレート宣言を閉じるものとして受け入れます。標準的な動作を得るために、それに従うことをお勧めします。たとえば、「x > > y」が「x >> y」として解析されないように注意する必要があります。また、「foo<bar<2 >> 1>>」が無効であることも確認する必要があります。 bar<(2 >> 1)>>" が有効です。

于 2012-02-01T17:05:20.693 に答える
1

私は同様のシナリオで Yacc (Bison に類似) で作業しました。

標準文法は、「構文による構文解析」と呼ばれることがあります。

このケースは、「セマンティクスによる構文解析」のようなものと呼ばれることもあります。

例:

...
// shift operator example
if ((x >> 2) == 0)
...
// consecutive template closing tag example
List<String, List<String>> MyList =
...

覚えておいてください、私たちの心はコンパイラのように機能します。人間の心はこれをコンパイルできますが、以前の文法ではできません。うーん。人間の心がこのコードをどのようにコンパイルするか見てみましょう。

ご存知のように、連続する ">" および ">" トークンの前の "x" は、式または左辺値を示します。心は、「式の後、2 つの連続する大なり記号は、1 つのシフト演算子トークンになるべきである」と考えます。

また、「文字列」トークンについては、「型識別子の後の 2 つの連続する大なり記号は、2 つの連続するテンプレート終了タグ トークンになる必要があります」。

このケースは、通常の演算子の優先順位、シフトまたは削減、または単なる文法では処理できないと思いますが、パーサー自体が提供するいくつかの機能を使用 (「ハッキング」) します。

あなたの例の文法規則に誤りはありません。「演算子」記号は、あなたが言及した2つのケースを混同しないようにします。注意すべき部分は、シフト演算子が使用されている文法と、連続したテンプレートの終了タグが使用されている部分です。

operator_expr_example:  
  lvalue "<<"  lvalue |  
  lvalue ">>"  lvalue |
  lvalue "&&"  lvalue |
;  

template_params:  
  identifier |
  template_declaration_example |
  array_declaration |
  other_type_declaration 
;  

template_declaration_example:  
  identifier "<"  template_params ">"
;  

乾杯。

于 2012-02-01T17:18:33.030 に答える