17

的文档Parsec.Expr.buildExpressionParser说:

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

确实,这让我很痛苦,因为我试图解析的语言允许任意重复其前缀和后缀运算符(想想像这样的 C 表达式**a[1][2])。

那么,为什么要Parsec做出这个限制,我该如何解决呢?

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

IE

**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 (.))

这些组合器chainl1op总是成功的解析器一起使用,并且简单地term以从左到右或从右到左的顺序组合解析器返回的函数。这些可以在buildExprParser表中使用;你会在哪里这样做:

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

你现在这样做:

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

这样,buildExprParser仍然可以用来设置运算符优先级,但现在每个优先级只能看到一个PrefixPostfix运算符。但是,该运算符有能力尽可能多地复制自身,并返回一个函数,使其看起来好像只有一个运算符。

于 2012-05-07T01:41:33.740 回答