Haskell 在Parsec中,在解析器失败之前修复损坏的令牌

Haskell 在Parsec中,在解析器失败之前修复损坏的令牌,haskell,parsec,parser-combinators,Haskell,Parsec,Parser Combinators,背景: 我使用Alex和Parsec的组合来解析缩进敏感语言。比上一行缩进更多的行可以是该行的数据,也可以是该行上命令的延续。Alex无法确定,因此它只返回一个Block{…}token 解析器知道何时需要数据块,并将数据传递到抽象语法树中供解释器使用 当解析器需要其他东西时遇到块标记时,就会出现问题。我有一个函数,可以将块标记转换为名为lex_block的token列表,但我似乎无法将其应用到输入流中的正确位置 问题: 给定一个解析器组合器,它在输入流中的某个令牌处失败,是否有方法修改导致失败

背景

我使用Alex和Parsec的组合来解析缩进敏感语言。比上一行缩进更多的行可以是该行的数据,也可以是该行上命令的延续。Alex无法确定,因此它只返回一个
Block{…}
token

解析器知道何时需要数据块,并将数据传递到抽象语法树中供解释器使用

当解析器需要其他东西时遇到
标记时,就会出现问题。我有一个函数,可以将块标记转换为名为
lex_block
token
列表,但我似乎无法将其应用到输入流中的正确位置

问题:

给定一个解析器组合器,它在输入流中的某个令牌处失败,是否有方法修改导致失败的令牌,然后继续计算新的输入流,或者至少重试一次

我想写一个函数
retry
,如下所示:

> retry :: (s -> Maybe s) -> ParsecT s u m a -> ParsecT s u m a
retry f p
的作用类似于解析器
p
,但如果
p
失败,则函数
f
用于更改
p
失败点处的输入流,并重试
p
。当
f
返回
Nothing
时,将传递故障


我曾尝试使用
getInput
setInput
try
编写此代码,但我不知道如何在解析器组合器失败时而不是在其启动时获取输入流。我认为,如果我能找到一种方法来告诉输入流中的故障发生在哪里,我就能做到这一点。

我记得,Haskell(GHC)和Python的缩进敏感lexer都不会将块作为一个单元发送,而是提供特殊的标记来标记它们的开始、新行和结束(对于Haskell,“隐式”
{
}
令牌)。是否有某些原因使这对您不起作用?(我想如果这两个子表单的词法完全不同,这将是一个问题。)想想看,即使lexer是不同的,您也可以通过让lexer首先给出一个标记,告诉一个块开始,然后解析器给出一个信号,告诉保持lexer的格式。(顺便说一句,Haskell也有一些从解析器到lexer的反标记,因为隐式
}
s有时由解析器请求插入。)在我的例子中,缩进块要么是多行语句的其余部分,要么是缩进末尾描述的字符串文字。lexer不知道它可能是哪种情况,所以只返回
块字符串
作为标记。我想捕捉“意外块”…“期望x”然后用lexed块重新运行x,我只是不知道如何在解析器实际即将失败的时候捕获它。我非常确定我的第二个建议应该可以做到这一点-基本上让Parsec在Alex解析初始缩进之外的任何内容之前告诉它什么时候需要数据块。然而,我对Alex或更高级的Parsec接口并不精通,因此我真的不知道如何在正确的时候将信息发送回Alex。