我有一个如下所示的解析器:
module Parser2 where
import Text.Parsec
import Text.Parsec.String (Parser)
import Text.Parsec.Language (emptyDef)
import qualified Text.Parsec.Expr as Ex
import qualified Text.Parsec.Token as Tok
data Expr
= Map [(Expr, Expr)]
| Int Integer
| Str String
deriving (Eq, Ord, Show)
lexer :: Tok.TokenParser ()
lexer = Tok.makeTokenParser style
where
ops = ["=>"]
names = []
style = emptyDef {
Tok.commentLine = "#"
, Tok.reservedOpNames = ops
, Tok.reservedNames = names
}
integer :: Parser Integer
integer = Tok.integer lexer
commaSep :: Parser a -> Parser [a]
commaSep = Tok.commaSep lexer
reserved :: String -> Parser ()
reserved = Tok.reserved lexer
int :: Parser Expr
int = Int <$> integer
maplit :: Parser Expr
maplit = do
reserved "{"
c <- commaSep $ do
k <- expr
reserved "=>"
v <- expr
return (k, v)
reserved "}"
return $ Map c
expr :: Parser Expr
expr = Ex.buildExpressionParser [] factor
stringLit :: Parser Expr
stringLit = Str <$> Tok.stringLiteral lexer
factor :: Parser Expr
factor = try stringLit
<|> try maplit
<|> try int
contents :: Parser a -> Parser a
contents p = do
Tok.whiteSpace lexer
r <- p
eof
return r
parseExpr :: String -> Either ParseError Expr
parseExpr = parse (contents expr) "<stdin>"
这可以正确解析整数周围有空格的“映射”,但不能解析没有空格的“映射”。对于字符串来说,这似乎无关紧要:
ghci> parseExpr "{\"a\"=> 1,\"b\"=> 2}"
Right (Map [(Str "a",Int 1),(Str "b",Int 2)])
ghci> parseExpr "{\"b\"=>\"c\"}"
Right (Map [(Str "b",Str "c")])
ghci> parseExpr "{\"a\"=>1}"
Left "<stdin>" (line 1, column 8):
unexpected '1'
expecting end of "=>"
我意识到可能有一个与makeTokenParser
默认值相关的明显答案,但我并不清楚为什么会发生这种情况,而且我还没有弄清楚如何正确调试它。
任何帮助都将受到赞赏。