所有的解析器都Text.Parsec.Token
礼貌地lexeme
在令牌后使用空格。对我来说不幸的是,空格包含新行,我想将其用作表达式终止符。有没有办法说服lexeme
离开新线路?
4 回答
不它不是。这是相关的代码。
lexeme p
= do{ x <- p; whiteSpace; return x }
--whiteSpace
whiteSpace
| noLine && noMulti = skipMany (simpleSpace <?> "")
| noLine = skipMany (simpleSpace <|> multiLineComment <?> "")
| noMulti = skipMany (simpleSpace <|> oneLineComment <?> "")
| otherwise = skipMany (simpleSpace <|> oneLineComment <|> multiLineComment <?> "")
where
noLine = null (commentLine languageDef)
noMulti = null (commentStart languageDef)
人们会注意到,在 where 子句中whitespace
,唯一的选项是处理注释。该lexeme
函数使用whitespace
,并且在parsec.token
.
2015 年 9 月 28 日更新
对我来说最终的解决方案是使用适当的词法分析器(alex)。Parsec 作为一个解析库做得非常好,它的设计值得称赞,它可以进行词法分析,但是对于除了小而简单的项目之外的所有项目,它很快就会变得笨拙。我现在使用 alex 创建一组线性标记,然后 Parsec 将它们转换为 AST。
如果换行符是您的表达式终止符,那么在每个换行符处拆分输入并自行解析每一行可能是有意义的。
好吧,不是所有的解析器都在Text.Parsec.Token
使用lexeme
,尽管它们都应该。最糟糕的是,没有记录其中哪些消耗空白,哪些不消耗。中的一些解析器Text.Parsec.Token
确实在词位之后消耗了空格,而其中一些则没有。其中一些也消耗前导空格。如果您想完全控制情况,您应该阅读 GitHub 问题跟踪器上的现有问题。
尤其:
integer
也消耗前导空格,请参阅 此问题;他们中的其他人可能会消耗尾随空格并因此换行,但这很难确定,因为 Parsec 的代码特别多毛(恕我直言)并且该项目没有测试套件(除了 3 个测试检查已经修复的错误没有出现再次,但是这还不足以防止回归,并且源代码中的每一次更改都可能 在 Parsec 的下一个版本中破坏您的代码。)
有各种建议如何使其可配置(什么应该被视为空白),由于某种原因,它们都没有被合并或评论。
但真正的问题在于设计Text.Parsec.Token
,它将用户锁定在由makeTokenParser
. 这种设计特别不灵活。在很多情况下,只有一种解决方案是复制整个模块并根据需要对其进行编辑。
但是,如果您想要现代且一致的 Parsec,则可以选择切换到 Megaparsec,其中不存在这个(和许多其他)问题。
披露:我是 Megaparsec 的作者之一。
尽管关于不可能的其他答案是正确的,但我想指出,字符解析器没有使用词素解析器。
我使用 parsec 来分析一些 html mustache 模板。空格在该分析中很重要。我所做的只是用Text.Parsec.Char.string
.
由于我对标签之间的空格而不是它们内部的空格感兴趣,我仍然可以使用保留的运算符来解析“<”和“{{”等,因为词位解析器只使用尾随空格。