Parsing floating point format in Haskell + Parsec

by syoyo

When I tried to port simdmath library code to MUDA language,
I’ve faced a problem on parsing floating point format in Haskell.

Basic read function provided by Haskell Prelude cannot parse
C style floating point format fully. For example,


$ ghci
Prelude> read "1.0" :: Double
1.0
Prelude> read "1.0f" :: Double
*** Exception: Prelude.read: no parse
Prelude> read "1.0e-3f" :: Double
*** Exception: Prelude.read: no parse
Prelude> read "-1.0e-3" :: Double
-1.0e-3
Prelude> read "+1.0e-3" :: Double
*** Exception: Prelude.read: no parse
Prelude> read "1.0e+3" :: Double
1000.0

Hmm, explicitly specifying sign and “f” seems not supported by read function.

So I’ve searched a lot(really a lot, it was a waste of my time…)
and found Parsec provides better support for parsing floating point format.


Text.ParserCombinators.Parsec.Token
provides floating point parser float.


$ cat Parser.hs
import Text.ParserCombinators.Parsec
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language (emptyDef)

parseFloat :: GenParser Char st Double
parseFloat = do x <- P.float $ P.makeTokenParser emptyDef
                return x


main :: IO ()
main = do
            parseTest parseFloat "1.0f"
            parseTest parseFloat "1.0e-2f"
            parseTest parseFloat "-1.0e-2f"
            parseTest parseFloat "+1.0e-2f"
            parseTest parseFloat "12.3E+3"
            parseTest parseFloat ".1"

$ runhaskell Parser.hs

1.0
1.0e-2
parse error at (line 1, column 1):
unexpected "-"
expecting float
parse error at (line 1, column 1):
unexpected "+"
expecting float
12300.0
parse error at (line 1, column 1):
unexpected "."
expecting float

float parser still lacks support for handling sign character.
Thus, I’ve added extra code which parses sign.

Final solution is,



$ cat Parser.hs

import Text.ParserCombinators.Parsec
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language (emptyDef)

parseFloat :: GenParser Char st Double
parseFloat = do sign <- option 1 (do s <- oneOf "+-"
                                     return $ if s == '-' then-1.0 else 1.0)
                x    <- P.float $ P.makeTokenParser emptyDef

                return $ sign * x


main :: IO ()
main = do
            parseTest parseFloat "1.0f"
            parseTest parseFloat "1.0e-2f"
            parseTest parseFloat "-1.0e-2f"
            parseTest parseFloat "+1.0e-2f"
            parseTest parseFloat "12.3E+3"
            parseTest parseFloat ".1"

$ runhaskell Parser.hs

1.0
1.0e-2
-1.0e-2
1.0e-2
12300.0
parse error at (line 1, column 1):
unexpected "."
expecting float


Parsing “.1” still fails,
but MUDA doesn’t support such a format for floating point string
since it is something a confused format, by the low of my sense of beauty 😉

Advertisements