假设我在Parsec中有Parser p
并且我想指定我想忽略p中的所有多余/冗余空格。例如,假设我将列表定义为以“[”开头,以“]”结尾,并且在列表中是由空格分隔的整数。但是如果在“[”之后的“[”之前,在“[”和第一个整数之间有空格,那么我不想要任何错误,等等。
在我的情况下,我希望这适用于我的解析器,用于玩具编程语言。
如果需要/必要,我会用代码更新。
答案 0 :(得分:3)
用space
围绕所有内容:
parseIntList :: Parsec String u [Int]
parseIntList = do
spaces
char '['
spaces
first <- many1 digit
rest <- many $ try $ do
spaces
char ','
spaces
many1 digit
spaces
char ']'
return $ map read $ first : rest
这是一个非常基本的问题,有些情况会失败(例如空列表),但这是开始工作的良好开端。
@ Joehillen的建议也可行,但它需要更多类型魔法来使用Parsec的令牌功能。 spaces
的定义匹配满足Data.Char.isSpace
的0个或更多字符,这是所有标准ASCII空格字符。
答案 1 :(得分:2)
使用组合器说出你的意思:
import Control.Applicative
import Text.Parsec
import Text.Parsec.String
program :: Parser [[Int]]
program = spaces *> many1 term <* eof
term :: Parser [Int]
term = list
list :: Parser [Int]
list = between listBegin listEnd (number `sepBy` listSeparator)
listBegin, listEnd, listSeparator :: Parser Char
listBegin = lexeme (char '[')
listEnd = lexeme (char ']')
listSeparator = lexeme (char ',')
lexeme :: Parser a -> Parser a
lexeme parser = parser <* spaces
number :: Parser Int
number = lexeme $ do
digits <- many1 digit
return (read digits :: Int)
尝试一下:
λ :l Parse.hs
Ok, modules loaded: Main.
λ parseTest program " [1, 2, 3] [4, 5, 6] "
[[1,2,3],[4,5,6]]
这个lexeme
组合子接受一个解析器,并在它之后允许任意空格。然后,您只需在{* 1}}和lexeme
语言的原始令牌周围使用listSeparator
。
或者,您可以将字符流解析为令牌流,然后将令牌流解析为解析树。这样,词法分析器和解析器都可以大大简化。但是,对于较大的语法来说,这是值得做的,因为可维护性是一个问题;并且您必须使用一些较低级别的Parsec API,例如number
。