2016-01-21 50 views
2

我有一个简单的解析器scriptParser,它使用用户状态(类型和内容在这里不重要)。它返回无论是对错误信息或Statement列表(再次,并不重要,这是怎么定义的)一个Stringparsec,解析后访问最后一个用户状态

parseScript :: String -> Either String [Statement] 
parseScript input 
    = let parsed = runParser scriptParser initialUserState "" input 
    in case parsed of 
      Left e -> Left (parseError input e) 
      Right ss -> Right ss 

parseError简单地格式化基于einput错误消息(它显示的代码片断围绕错误位置)。

我的问题是,如果我想根据最后一个可用的用户状态自定义错误信息呢?显然用户状态在runParser结束后不见了。 runParserT后允许访问用户状态吗?

+0

我担心这个问题在语义上是不合格的。如果我的解析器是'(put 3 >> fail“)<|>(put 4 >> fail”“)',哪个状态是”last“?更一般地说,如果出现错误,导致分支失败的许多州中的哪一个应被视为“最后可用”的一个,为什么? –

+0

谢谢@DanielWagner。通过“最后”,我指的是失败前的那个人,无论这可能发生在哪里。也许我是误解,但是因为内部Parsec状态是回溯,所以我认为这是有道理的。 – cornuz

+0

我期望在正常情况下,因为回溯会出现*很多*失败,每个失败都有可能不同的“最终”状态。目前尚不清楚这些失败中的任何一个是否“特殊”足以保证其状态被称为最终状态。报告所有最终状态可能在语义上是明智的,但在成功解析的情况下可能是严重的内存泄漏。 –

回答

4

据我所知,Parsec抛出错误的内置用户状态,所以无法恢复它。

或者,您可以将用户状态转移到ParsecT s u m a中的m monad,因此您可能有ParsecT String() (State s) a

那样,runParserT返回类型State s (Either ParseError a),您可以从中恢复最后一个状态。

而且,由于ParsecT String() (State s) aMonadState sinstance,您可以使用get和其他MonadState功能没有问题。

+0

对。内部状态的一大优势是它是回溯,我曾希望保持这种状态。 – cornuz

+0

我也许可以通过使用这两种状态来实现这一点。像我现在所做的那样使用内部状态,但在每次更新后将其镜像到全局状态。丑陋,非常丑陋。但也许唯一的选择,如果我想要一个回溯状态,并从解析器外部访问它? – cornuz

+0

我不确定这是否可行。即使您在更新时进行镜像,您也不会在回溯时反映回退。 –