Parsec: No newline after last line and 'many'
Till Doerges
till@doerges.net
Sun, 7 Apr 2002 19:44:42 +0200
Hi folks,
when trying to write a parser for unix-style textfiles, I stumbled
across the problem having to distinguish between lines w/ a newline
character at the end and lines w/o a newline at the end (i.e. the last
line in a file doesn't have to have it).
Eventually I want to be able to use my parser 'linep' with 'many' on
no matter which text-files.
The first version I tried, was
--- snip ---
skip1 :: Parser()
skip1 = do
anyChar
return()
linep :: Parser(String)
linep = do { cs <- many (noneOf "\n")
; skip1
; return cs
}
--- snap ---
Well, this only works, if the last line in the file is also terminated
by '\n'. So, I tried to be smarter using:
--- snip ---
lineWith :: Parser(String)
lineWith = try (do { cs <- many (noneOf "\n")
; skip1
; return cs
})
lineWithOut :: Parser(String)
lineWithOut = many anyChar
linep :: Parser(String)
linep = lineWith
<|> lineWithOut
<?> "line"
--- snap ---
But this doesn't do the trick either, instead it'll overflow my stack
if used in conjunction w/ 'many':
--- snip ---
parse (do {many linep}) "stdin" (unlines ["hallo","ballo"])
^CInterrupted.
ReadOrig> parse (do {many linep}) "stdin" ("hallo\nballo")
^CInterrupted.
--- snap ---
Avoiding many OTOH works fine:
--- snip ---
parse (do {linep;linep}) "stdin" (unlines ["hallo","ballo"])
Right "ballo"
ReadOrig> parse (do {linep;linep}) "stdin" ("hallo\nballo")
Right "ballo"
--- snap ---
Besides these two attempts explicitly spelled out I've made quite a
few others, but none of them did the trick.
The documentation for 'try' says that it'll only consume input upon
success, but why doesn't it work w/ 'many'?
I know about the Prelude-functions unlines, lines etc., but they don't
really help, since linep should be used within another parser of mine.
I am using Parsec as of Jan 25, 2001 (the version included w/ ghc 5.02).
Any hints/solutions/... would be greatly appreciated!
Bye -- Till