4
votes

I am developing a simple calculator that takes one line of input, parses it using parsec and then processes it.

I want to make the parsec parse-error messages smaller. They include position info which is not necessary for a one line input. I've tried using <?> but it doesn't quite do what I want.

Trying to extract the cause of parse error didn't yield good results.

Some way to specify errors for unmatched parentheses, or just a syntax error message would be nice.

1

1 Answers

1
votes

You can get at the error messages and source position of an error using the errorMessages, messageString, errorPos and sourceColumn functions from Text.Parsec.Error.

Here is an example taken from this blog post. It demonstrates the use of <?> and using the above mentioned functions to customize error processing:

import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import Text.Parsec.Error

expr :: Parser Integer
expr = buildExpressionParser table factor <?> "expression"

table :: [[ Operator Char st Integer ]]
table = [
    [ op "*" (*) AssocLeft, op "/" div AssocLeft ],
    [ op "+" (+) AssocLeft, op "-" (-) AssocLeft ]
    ]
  where
    op s f assoc = Infix (do { string s ; return f }) assoc

factor = do { char '(' ; x <- expr ; char ')' ; return x }
   <|> number
   <?> "simple expression"

number :: Parser Integer
number = do { ds <- many1 digit; return (read ds) } <?> "number"

doit str =
  case parse expr "blah" str of
    Left e -> do let msgs = filter (not.null) $ map messageString (errorMessages e)
                 let col = sourceColumn (errorPos e)
                 putStrLn $ "error at column " ++ show col ++ ": " ++ show msgs
    Right x -> putStrLn $ "ok - got: " ++ show x

main = do
  doit "3+5"
  doit "5-"
  doit "("