Search code examples
parsinghaskellparsec

Unexpected end of input with Parsec


I try to parse the following text file with series of data between keywords :

many text many text  many text 

BEGIN
T   LISTE2
1   154
2   321
3   519
4   520
5   529
6   426
END

many text  many text  many text

By using the following haskell program

import Text.Parsec
import Text.Parsec.String
import Text.Parsec.Char
import Text.Parsec.Combinator

endOfLine :: Parser String
endOfLine =     try (string "\n") 
            <|> try (string "\r\n") 

line = many $ noneOf "\n"

parseListing = do 
  spaces
  many $ noneOf "\n"
  spaces
  cont <- between (string "BEGIN\n") (string "END\n") $ endBy line endOfLine
  spaces
  many $ noneOf "\n"
  spaces
  eof
  return cont

main :: IO ()
main = do
    file <- readFile ("test_list.txt")
    case parse parseListing "(stdin)" file of
            Left err -> do putStrLn "!!! Error !!!"
                           print err
            Right resu -> do  putStrLn $  concat resu

And when I parse my text file, I get the following error :

"(stdin)" (line 16, column 1):
unexpected end of input
expecting "\n", "\r\n" or "END\n"

I'm a newbie with parsing and I don't understand why it fail? My sequence is yet between BEGIN and END

Do you know what is wrong with my parser and how to correct it ?


Solution

  • Your between will never stop, because endBy line endOfLine consumes any line and END\n too, so it will eat more and more lines until it fails. Then your parser tries to consume string "END\n" and fails too, that's why error message mentions "END\n" You must rewrite line parser to fail on END\n. For example:

    parseListing :: Parsec String () [String]
    parseListing = do 
        spaces
        many $ noneOf "\n"
        spaces
        cont <- between begin end $ endBy (notFollowedBy end >> line) endOfLine
        spaces
        many $ noneOf "\n"
        spaces
        eof
        return cont
        where
            begin = string "BEGIN\n"
            end = string "END\n"