不支持Parsec.Expr重复前缀/后缀操作符 [英] Parsec.Expr repeated Prefix/Postfix operator not supported
问题描述
Parsec.Expr.buildExpressionParser
的文件说:
前缀和具有相同优先级的后缀运算符只能出现
一次(例如,如果 - 前缀为否定,则不允许使用-2)。
<事实上,这是咬我的,因为我想解析的语言允许任意重复它的前缀和后缀操作符(想想C表达式就像 ** a [1] [2]
)。
那么,为什么 Parsec
这个限制,我该如何工作我认为我可以将我的前缀/后缀解析器向下移动到术语
解析器中,因为它们具有最高优先权。
** a + 1
被解析为
(*(*(a)))+(1)
如果我想将它解析为
*(*((a)+(1)))
如果 buildExpressionParser
做了我想要的,我可以简单地重新排列表中的运算符。
$ b 注意请参阅在这里更好的解决方案 我通过使用
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 = [[后缀$ choice [subscr
,dot
]
]
,[前缀$ choice [pos
,neg
]
]
]
通过这种方式, buildExprParser
仍可用于设置运算符优先级,但现在只能看到单个前缀
或后缀
运算符在每个优先级。但是,该运算符有能力尽可能多地复制它自己的副本,并返回一个函数,使其看起来好像只有一个运算符。
The documentation for Parsec.Expr.buildExpressionParser
says:
Prefix and postfix operators of the same precedence can only occur once (i.e. --2 is not allowed if - is prefix negate).
and indeed, this is biting me, since the language I am trying to parse allows arbitrary repetition of its prefix and postfix operators (think of a C expression like **a[1][2]
).
So, why does Parsec
make this restriction, and how can I work around it?
I think I can move my prefix/postfix parsers down into the term
parser since they have the highest precedence.
i.e.
**a + 1
is parsed as
(*(*(a)))+(1)
but what could I have done if I wanted it to parse as
*(*((a)+(1)))
if buildExpressionParser
did what I want, I could simply have rearranged the order of the operators in the table.
Note See here for a better solution
I solved it myself by using chainl1
:
prefix p = Prefix . chainl1 p $ return (.)
postfix p = Postfix . chainl1 p $ return (flip (.))
These combinators use chainl1
with an op
parser that always succeeds, and simply composes the functions returned by the term
parser in left-to-right or right-to-left order. These can be used in the buildExprParser
table; where you would have done this:
exprTable = [ [ Postfix subscr
, Postfix dot
]
, [ Prefix pos
, Prefix neg
]
]
you now do this:
exprTable = [ [ postfix $ choice [ subscr
, dot
]
]
, [ prefix $ choice [ pos
, neg
]
]
]
in this way, buildExprParser
can still be used to set operator precedence, but now only sees a single Prefix
or Postfix
operator at each precedence. However, that operator has the ability to slurp up as many copies of itself as it can, and return a function which makes it look as if there were only a single operator.
这篇关于不支持Parsec.Expr重复前缀/后缀操作符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!