Parsec.Expr不支持重复前缀/后缀运算符

时间:2012-05-07 00:04:11

标签: haskell parsec

Parsec.Expr.buildExpressionParser的文档说:

  

只能出现相同优先级的前缀和后缀运算符   一次(即 - 如果 - 是前缀否定,则不允许--2。)

实际上,这是咬我的,因为我试图解析的语言允许任意重复它的前缀和后缀运算符(想想像**a[1][2]这样的C表达式。)

那么,为什么Parsec会制定此限制,我该如何解决它呢?

我想我可以将我的前缀/后缀解析器移到term解析器中,因为它们具有最高优先级。

**a + 1

被解析为

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

但如果我希望它解析为

,我该怎么办?
*(*((a)+(1)))

如果buildExpressionParser做了我想要的,我可以简单地重新安排表中运算符的顺序。

注意有关更好的解决方案,请参阅here

1 个答案:

答案 0 :(得分:14)

我自己使用chainl1

解决了这个问题
prefix  p = Prefix  . chainl1 p $ return       (.)
postfix p = Postfix . chainl1 p $ return (flip (.))

这些组合器使用chainl1和一个始终成功的op解析器,只需按从左到右或从右到左的顺序组合term解析器返回的函数。这些可以在buildExprParser表中使用;你会在哪里做到这一点:

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

你现在这样做:

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

通过这种方式,buildExprParser仍可用于设置运算符优先级,但现在每个优先级只能看到一个PrefixPostfix运算符。但是,该操作符能够尽可能多地填充自身的副本,并返回一个函数,使其看起来好像只有一个操作符。