17

のドキュメントは次のようにParsec.Expr.buildExpressionParser述べています。

同じ優先順位のプレフィックス演算子とポストフィックス演算子は1回だけ発生します(つまり、-がプレフィックス否定の場合、-2は許可されません)。

実際、これは私を苦しめています。なぜなら、私が解析しようとしている言語では、接頭辞と接尾辞の演算子を任意に繰り返すことができるからです(のようなC式を考えてみて**a[1][2]ください)。

では、なぜParsecこの制限を設けるのでしょうか。また、どうすれば回避できますか。

プレフィックス/ポストフィックスパーサーは優先順位が最も高いため、パーサーに移動できると思いますterm

すなわち

**a + 1

として解析されます

(*(*(a)))+(1)

しかし、次のように解析したい場合はどうすればよいでしょうか。

*(*((a)+(1)))

buildExpressionParserやりたいことがあれば、テーブル内の演算子の順序を簡単に並べ替えることができます。

より良い解決策については、ここを参照してください

4

1 に答える 1

16

私はそれを使って自分で解決しましたchainl1

prefix  p = Prefix  . chainl1 p $ return       (.)
postfix p = Postfix . chainl1 p $ return (flip (.))

これらのコンビネータは、常に成功chainl1するパーサーとともに使用し、パーサーによって返される関数を左から右または右から左の順序で単純に構成します。これらはテーブルで使用できます。あなたがこれをしたであろう場所:optermbuildExprParser

exprTable = [ [ Postfix subscr
              , Postfix dot
              ]
            , [ Prefix pos
              , Prefix neg
              ]
            ]

あなたは今これをします:

exprTable = [ [ postfix $ choice [ subscr
                                 , dot
                                 ]
              ]
            , [ prefix $ choice [ pos
                                , neg
                                ]
              ]
            ]

このように、buildExprParser演算子の優先順位を設定するために引き続き使用できますが、各優先順位で単一Prefixまたは演算子のみが表示されるようになりました。Postfixただし、その演算子には、それ自体のコピーをできるだけ多く作成し、演算子が1つしかないように見せかける関数を返す機能があります。

于 2012-05-07T01:41:33.740 に答える