我想编写代码,做一些类似于C预处理的事情。所以我找了两个图书馆,attoparsec,megaparsec。
我需要特征报告错误的位置,megaparsec已经有了。但是attoparsec在性能上是可取的。
如果我在attoparsec的Parser monad中添加了错误位置特性,那么当我使用它们时,是否需要将其封装在StateT转换器中,并提升库的所有功能?我认为这是一项累人的工作。有什么更好的方法吗?
编辑
我将采用适合这种情况的megaparsec。但是我仍然想知道如何包装attoparsec的Parser monad,有人能告诉我上面提到的方法是否是最好的方法吗?
我只想知道单包装的方法。换句话说,是否解除所有内部单一功能是唯一的解决办法。
发布于 2017-07-30 10:38:29
您可以从attoparsec获得当前解析位置,而不需要转换器。但是没有导出函数来完成它;您必须自己定义它:
import qualified Data.Attoparsec.Internal.Types as T
offset :: T.Parser i T.Pos
offset = T.Parser $ \t pos more lose succ -> succ t pos more pos示例用法:
λ> parseOnly (many' (skipMany (word8 46) *> offset <* anyWord8)) ".a..a...a....a"
Right [Pos {fromPos = 1},Pos {fromPos = 4},Pos {fromPos = 8},Pos {fromPos = 13}]这与增量输入的预期效果一样。它只给您输入的偏移量,而不是(line, column),但是对于许多应用程序来说,偏移量已经足够了。
使用fromPos从Pos获取Int
λ> T.fromPos <$> parseOnly offset ""
Right 0现在,我们可以使用offset创建一个解析器,当它失败时报告当前偏移量。
reportOffsetOnError :: T.Parser i a -> T.Parser i a
reportOffsetOnError p =
p <|> (offset >>= \pos ->
fail ("failed at offset: " ++ show (T.fromPos pos)))示例用法:
λ> parseOnly (word8 46 *> word8 46 *> reportOffsetOnError (word8 97)) "..a"
Right 97
λ> parseOnly (word8 46 *> word8 46 *> reportOffsetOnError (word8 97)) "..b"
Left "Failed reading: failed at offset: 2"最后要注意的是:如果您确实需要一个转换器,并且希望继续使用attoparsec包,Data.Attoparsec.Zepto确实提供了ZeptoT转换器,但是这是一个与attoparsec中的主解析器不同的解析器类型。
https://stackoverflow.com/questions/41939715
复制相似问题