gpt4 book ai didi

haskell - Parsec:特定位置的错误消息

转载 作者:行者123 更新时间:2023-12-04 17:00:23 27 4
gpt4 key购买 nike

如果违反语义规则,使用 Parsec 如何在特定位置指示错误。我知道通常我们不想做这样的事情,但考虑一下示例语法。

<foo> ::= <bar> | ...
<bar> ::= a positive integer power of two
<bar>规则是一个有限集(我的例子是任意的),上述的纯粹方法可能是仔细应用 choice组合器,但这在空间和时间上可能是不切实际的。在递归下降或工具包生成的解析器中,标准技巧是解析一个整数(一种更宽松的语法),然后在语义上检查更难的约束。对于 Parsec,我可以使用 natural解析器并检查调用 fail 的结果如果不匹配或 unexpected管他呢。但如果我们这样做,默认错误位置是错误的。不知何故,我需要在较早的状态下提出错误。

我尝试了一个蛮力解决方案并编写了一个使用 getPosition 的组合器和 setPositionthis very similar question 所示.当然,我也没有成功(错误的位置,当然是错误的)。我已经多次遇到这种模式。我正在寻找这种类型的组合器:
withPredicate :: (a -> Bool) -> String -> P a -> P a
withPredicate pred lbl p = do
ok <- lookAhead $ fmap pred (try p) <|> return False -- peek ahead
if ok then p -- consume the input if the value passed the predicate
else fail lbl -- otherwise raise the error at the *start* of this token

pPowerOfTwo = withPredicate isPowerOfTwo "power of two" natural
where isPowerOfTwo = (`elem` [2^i | i<-[1..20]])

以上不起作用。 (我也尝试过变体。)解析器以某种方式回溯说它期待一个数字。我认为它正在返回使其最远的错误。偶 {get,set}ParserState未能抹去那段内存。

我处理这种句法模式错了吗?所有 Parsec 用户将如何处理这些类型的问题?

谢谢!

最佳答案

我认为您的两个想法都可以。其他两个答案涉及 Parsec,但我想指出,在这两个
案例 Megaparsec 只是做正确的事:

{-# LANGUAGE TypeApplications #-}

module Main (main) where

import Control.Monad
import Data.Void
import Text.Megaparsec
import qualified Text.Megaparsec.Char.Lexer as L

type Parser = Parsec Void String

withPredicate1 :: (a -> Bool) -> String -> Parser a -> Parser a
withPredicate1 f msg p = do
r <- lookAhead p
if f r
then p
else fail msg

withPredicate2 :: (a -> Bool) -> String -> Parser a -> Parser a
withPredicate2 f msg p = do
mpos <- getNextTokenPosition -- †
r <- p
if f r
then return r
else do
forM_ mpos setPosition
fail msg

main :: IO ()
main = do
let msg = "I only like numbers greater than 42!"
parseTest' (withPredicate1 @Integer (> 42) msg L.decimal) "11"
parseTest' (withPredicate2 @Integer (> 42) msg L.decimal) "22"

如果我运行它:

The next big Haskell project is about to start!
λ> :main
1:1:
|
1 | 11
| ^
I only like numbers greater than 42!
1:1:
|
1 | 22
| ^
I only like numbers greater than 42!
λ>

自己试试吧!按预期工作。

getNextTokenPositiongetPosition 更正确对于 token 本身包含其开始和结束位置的流。在您的情况下,这可能很重要,也可能不重要。

关于haskell - Parsec:特定位置的错误消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23964405/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com