如何获取Parsec解析器所消耗的输入流?
获取Parsec解析器消耗的输入流片段
可以借助Parsec提供的getInput工具实现一个通用包装combinator,无需修改所有底层解析器,仅需在顶层或目标子解析器上使用即可。
实现思路
通过在解析前后分别获取当前输入流,计算两者的差异得到解析器消耗的输入片段。对于String类型的输入,直接通过前后输入的长度差截取对应的字符即可。
代码实现
import Text.Parsec import Text.Parsec.String (Parser) -- 包装解析器,返回解析结果与消耗的输入片段的元组 trackConsumed :: Parser a -> Parser (a, String) trackConsumed parser = do preInput <- getInput result <- parser postInput <- getInput -- 计算消耗的输入:从原输入开头到剩余输入开头的部分 let consumed = take (length preInput - length postInput) preInput return (result, consumed)
使用方式
将你的顶层解析器传入trackConsumed即可,示例:
-- 假设你的顶层解析器是topLevelParser mainParser :: Parser (YourAST, String) mainParser = trackConsumed topLevelParser
细节说明
- 这个方法无需修改任何底层解析逻辑,仅通过包装器实现输入跟踪,完全符合你不想重写所有解析器的需求。
- 如果解析过程中存在回溯(比如使用
trycombinator),该方法依然有效——回溯后postInput会回到preInput的状态,此时consumed为空字符串,符合预期。 - 若需要基于位置(行号、列号)更精确地计算消耗的输入,可以结合
getPosition和getSourcePos相关函数,但对于纯字符流的解析,长度差的方式已经足够简单高效。 parsecMap仅用于映射解析结果,单独无法实现输入跟踪,但可以配合上述逻辑对返回的元组进行进一步处理,比如只保留消耗的输入或修改解析结果格式。
内容的提问来源于stack exchange,提问作者Peter Bergman
相关产品推荐
相关产品推荐

