在具有共同前缀的两个解析器之间进行选择
Choosing between two parsers with a common prefix
我目前正尝试在 Parsec 中编写一个简单的解析器,但 运行 陷入有关白色的问题space:作为一个最小的例子,我有一个解析器可以解析两个字母,或者两个小写或一个大写和一个小写。我会这样做
testP :: Parser String
testP = do
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2]
对于“as”或“Bs”等字符串,这可以按预期工作。现在我想在输入字符串的开头处理可能的 whitespace 。如果我这样做
testP :: Parser String
testP = do
spaces
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2]
我希望程序现在能够解析“as”和“Bs”,但对于第二个字符串,我得到一个错误“expecting space or lowercase letter”。
好的,我认为无论选择哪个选项,space 都会被解析,但显然不是这样,让我们在第二个选项的开头放置另一个 spaces
,如下所示:
testP :: Parser String
testP = do
spaces
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
spaces
a1 <- upper
a2 <- lower
return [a1,a2]
不过,当我尝试解析“Bs”时,仍然出现同样的错误。我怎么会误解 whitespace 在这里处理,我怎样才能正确地做到这一点?
如果第一个解析器消耗了 任何东西,<|>
将不会尝试第二个选择。这样做是为了防止 space 泄漏。这是 parsec 的基础设计之一。
当 spaces
消耗一些输入时,一切都已决定,该解析器现在必须成功 - 否则,将不会尝试替代方案,整个机器就会失败。这就是您观察此行为的原因。 spaces
消耗一些输入,lookAhead lower
失败,整个解析器失败。
你 可以 通过 try
实现任意前瞻并确保即使第一个消耗输入也尝试第二个备选方案,但你不应该,在这种情况下不是.这里,spaces
是一个 非致命 解析器,它对这两个操作都是 初步 - 所以只需使用解析器 在你的任何一个选择之前。
testP :: Parser String
testP = spaces *> (do
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2])
我目前正尝试在 Parsec 中编写一个简单的解析器,但 运行 陷入有关白色的问题space:作为一个最小的例子,我有一个解析器可以解析两个字母,或者两个小写或一个大写和一个小写。我会这样做
testP :: Parser String
testP = do
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2]
对于“as”或“Bs”等字符串,这可以按预期工作。现在我想在输入字符串的开头处理可能的 whitespace 。如果我这样做
testP :: Parser String
testP = do
spaces
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2]
我希望程序现在能够解析“as”和“Bs”,但对于第二个字符串,我得到一个错误“expecting space or lowercase letter”。
好的,我认为无论选择哪个选项,space 都会被解析,但显然不是这样,让我们在第二个选项的开头放置另一个 spaces
,如下所示:
testP :: Parser String
testP = do
spaces
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
spaces
a1 <- upper
a2 <- lower
return [a1,a2]
不过,当我尝试解析“Bs”时,仍然出现同样的错误。我怎么会误解 whitespace 在这里处理,我怎样才能正确地做到这一点?
<|>
将不会尝试第二个选择。这样做是为了防止 space 泄漏。这是 parsec 的基础设计之一。
当 spaces
消耗一些输入时,一切都已决定,该解析器现在必须成功 - 否则,将不会尝试替代方案,整个机器就会失败。这就是您观察此行为的原因。 spaces
消耗一些输入,lookAhead lower
失败,整个解析器失败。
你 可以 通过 try
实现任意前瞻并确保即使第一个消耗输入也尝试第二个备选方案,但你不应该,在这种情况下不是.这里,spaces
是一个 非致命 解析器,它对这两个操作都是 初步 - 所以只需使用解析器 在你的任何一个选择之前。
testP :: Parser String
testP = spaces *> (do
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2])