Haskell 在Parsec中,有没有一种方法可以防止lexeme使用换行符?
Haskell 在Parsec中,有没有一种方法可以防止lexeme使用换行符?,haskell,parsec,Haskell,Parsec,Text.Parsec.Token中的所有解析器都礼貌地使用lexeme来吃令牌后面的空格。不幸的是,空格中包含新行,我想将其用作表达式终止符。有没有办法说服lexeme留下新行?如果新行是您的表达式终止符,那么在每个新行拆分输入并单独解析每行可能是有意义的。没有。这是相关代码 发件人: 词素p =do{x”“) |noMulti=skipMany(simpleSpace oneLineComment“”) |否则=skipMany(simpleSpace oneLineComment Mult
Text.Parsec.Token
中的所有解析器都礼貌地使用lexeme
来吃令牌后面的空格。不幸的是,空格中包含新行,我想将其用作表达式终止符。有没有办法说服lexeme留下新行?如果新行是您的表达式终止符,那么在每个新行拆分输入并单独解析每行可能是有意义的。没有。这是相关代码
发件人:
词素p
=do{x”“)
|noMulti=skipMany(simpleSpace oneLineComment“”)
|否则=skipMany(simpleSpace oneLineComment Multilecomment“”)
哪里
noLine=null(注释行语言定义)
noMulti=null(commentStart语言定义)
在whitespace
的where子句中,我们会注意到,所查看的唯一选项是处理注释的。lexeme
函数使用whitespace
,它在parsec.token
的其余部分中大量使用
更新日期:2015年9月28日
对我来说,最终的解决办法是使用合适的词汇分析器().Parsec作为一个解析库做得很好,它可以用来进行词法分析,这是设计的功劳,但对于所有小型和简单的项目来说,它很快就会变得笨拙。我现在使用alex创建一组线性标记,然后Parsec将它们转换为AST。尽管关于它的其他答案不是这样如果您的回答是正确的,我想指出,字符分析器没有使用词素分析器。
我使用parsec分析一些html小胡子模板。空格在分析中很重要。我所做的只是用
Text.parsec.Char.string
因为我对标记之间的空格感兴趣,而不是标记内部的空格,所以我仍然可以使用保留运算符来解析“嗯,
Text.Parsec.Token
中的并非所有解析器都使用lexeme
,尽管
他们应该这样做。最糟糕的是,没有记录他们中的哪一个食用白色
空格,哪些没有空格。Text.Parsec.Token
一定要在词素后加上空格,有些不加,有些不加
同时使用前导空格。您应该阅读上的现有问题
GitHub问题跟踪器,如果您想完全控制局势
特别是:
、十进制
和十六进制
解析器不使用尾随符 空白,请参见 , 及八进制
也使用前导空格,请参见 )integer
- 其余部分可能使用尾随空格,因此使用换行符, 然而,这很难确定,因为Parsec的代码是 特别多毛(IMHO),项目没有测试套件(3个测试套件除外) 但是,检查已经修复的bug不会再次出现的测试 仅仅防止倒退是不够的,每一个来源的改变都可能会导致衰退 )
Text.Parsec.Token
的设计,它会锁定
由makeTokenParser
构建的解决方案中的用户。此设计特别适用于
不灵活。在许多情况下,只有一种解决方案是复制
整个模块,并根据需要进行编辑
但是,如果您想要现代且一致的Parsec,可以选择切换到
这(以及
许多其他的)问题是不存在的
披露:我是Megaparsec的作者之一。你看过uu parsinglib吗?它有词素和非词素版本的解析器,还有内置的错误更正。我以前通过复制和重命名Parsec.Token模块,然后更改
simpleSpace
的定义(靠近文件底部)来解决这个问题。这不是一个非常模块化的解决方案,但确实有效。与换行符相关的是潜在的终止符,但不一定如此。与Haskell本身的语义相同。@John--您是否试图处理类似于布局/越位规则的事情?有一整套专门的技术。@sclv不,只是作为表达式的新行。@类似Ruby或JavaScript+1中的minators,因为它是一些语言的可用解决方案,即使它在asker的情况下不起作用。我尝试用Parsec解析相当多的格式,包括识别新行。解决方案一直是逐行解析。这是不正确的,simpleSpace
使用新行在宣传(甚至讨论)你自己的项目/包时,你应该公开你的联系。
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)