在Haskell中正确解析uu parsinglib中的行缩进

在Haskell中正确解析uu parsinglib中的行缩进,parsing,haskell,parsec,uu-parsinglib,Parsing,Haskell,Parsec,Uu Parsinglib,我想创建一个解析器组合器,它将收集当前位置下的所有行,这些行的缩进级别将大于或等于某些I。我认为这个想法很简单: 使用一行-如果其缩进为: 确定->为下一行执行此操作 错误->失败 让我们考虑下面的代码: import qualified Text.ParserCombinators.UU as UU import Text.ParserCombinators.UU hiding(parse) import Text.ParserCombinators

我想创建一个解析器组合器,它将收集当前位置下的所有行,这些行的缩进级别将大于或等于某些
I
。我认为这个想法很简单:

使用一行-如果其缩进为:

  • 确定->为下一行执行此操作
  • 错误->失败

让我们考虑下面的代码:

import qualified Text.ParserCombinators.UU as UU
import           Text.ParserCombinators.UU hiding(parse)
import           Text.ParserCombinators.UU.BasicInstances hiding (Parser)

-- end of line
pEOL   = pSym '\n'

pSpace = pSym ' '
pTab   = pSym '\t'

indentOf s = case s of
    ' '  -> 1
    '\t' -> 4

-- return the indentation level (number of spaces on the beginning of the line)
pIndent = (+) <$> (indentOf <$> (pSpace <|> pTab)) <*> pIndent `opt` 0

-- returns tuple of (indentation level, result of parsing the second argument)
pIndentLine p = (,) <$> pIndent <*> p <* pEOL

-- SHOULD collect all lines below witch indentations greater or equal i
myParse p i = do
    (lind, expr) <- pIndentLine p
    if lind < i
        then pFail
        else do
            rest <- myParse p i `opt` []
            return $ expr:rest

-- sample inputs
s1 = " a\
   \\n a\
   \\n"

s2 = " a\
   \\na\
   \\n"

-- execution
pProgram = myParse (pSym 'a') 1 

parse p s = UU.parse ( (,) <$> p <*> pEnd) (createStr (LineColPos 0 0 0) s)

main :: IO ()
main = do 
    print $ parse pProgram s1
    print $ parse pProgram s2
    return ()

s1
的结果是正确的。
s2
的结果应首先消耗“a”并停止消耗。此错误来自何处?

您正在构建的解析器将始终尝试继续;如有必要,将丢弃或添加输入。然而,
pFail
是一条死胡同。它充当
的单位元素

但是,在解析器中,如果输入不符合解析器识别的语言,则没有其他替代方案。在您的规范中,您表示希望解析器在输入s2时失败。现在它失败了,一条消息说它失败了,你会感到惊讶

也许你不希望它失败,但你想停止接受进一步的输入?那么 将
pFail
替换为
return[]

请注意,案文如下:

do
    rest <- myParse p i `opt` []
    return $ expr:rest
do

rest谢谢,但它还没有完全解决我的问题(我已经更新了相关代码)-如果缩进可以是空格或制表符,其中制表符是4个空格怎么办?额外的
return[]
不能像我们所希望的那样工作-如果我们将
pFail
替换为
return[]
解析器将使用第二个“a”(它将被使用,并且
[]
将被返回)-我不希望使用示例s2中的第二个“a”。如果您希望正确处理制表符(而不是仅用四个空格替换制表符),则必须编写自己的“知道”的小型有限状态机tab代表什么。你能告诉我更多关于这种状态机如何与uu parsinglib一起使用吗?另外,你已经告诉我,“
pFail
充当
的一个单元元素”-所以(可能我错了)它仍然应该工作:请注意-它被用在表达式
myParse p I`opt`[]
-如果
myParse
失败,那么
opt
应该返回
[]
,不是吗?
do
    rest <- myParse p i `opt` []
    return $ expr:rest
pIndented p = do i <- pGetIndent
             (:) <$> p <* pEOL  <*> pMany (pToken (take i (repeat ' ')) *> p <* pEOL)

pIndent = length <$> pMany (pSym ' ')