A software analysis framework built around the QBE intermediate language
git clone https://git.8pit.net/quebex.git
1-- SPDX-FileCopyrightText: 1999-2001 Daan Leijen 2-- SPDX-FileCopyrightText: 2007 Paolo Martini 3-- SPDX-FileCopyrightText: 2013-2014 Christian Maeder <chr.maeder@web.de> 4-- SPDX-FileCopyrightText: 2025 Sören Tempel <soeren+git@soeren-tempel.net> 5-- 6-- SPDX-License-Identifier: BSD-2-Clause AND GPL-3.0-only 7 8module Language.QBE.Numbers where 9 10import Control.Monad (ap) 11import Data.Char (digitToInt) 12import Text.Parsec 13 14-- ** float parts 15 16-- | parse a floating point number given the number before a dot, e or E 17fractExponent :: (Floating f, Stream s m Char) => Integer -> ParsecT s u m f 18fractExponent i = fractExp i True 19 20-- | parse a floating point number given the number before a dot, e or E 21fractExp :: 22 (Floating f, Stream s m Char) => 23 Integer -> 24 Bool -> 25 ParsecT s u m f 26fractExp i b = genFractExp i (fraction b) exponentFactor 27 28-- | parse a floating point number given the number before the fraction and 29-- exponent 30genFractExp :: 31 (Floating f, Stream s m Char) => 32 Integer -> 33 ParsecT s u m f -> 34 ParsecT s u m (f -> f) -> 35 ParsecT s u m f 36genFractExp i frac expo = case fromInteger i of 37 f -> genFractAndExp f frac expo <|> fmap ($ f) expo 38 39-- | parse a floating point number given the number before the fraction and 40-- exponent that must follow the fraction 41genFractAndExp :: 42 (Floating f, Stream s m Char) => 43 f -> 44 ParsecT s u m f -> 45 ParsecT s u m (f -> f) -> 46 ParsecT s u m f 47genFractAndExp f frac = ap (fmap (flip id . (f +)) frac) . option id 48 49-- | parse a floating point exponent starting with e or E 50exponentFactor :: (Floating f, Stream s m Char) => ParsecT s u m (f -> f) 51exponentFactor = oneOf "eE" >> extExponentFactor 10 <?> "exponent" 52 53-- | parse a signed decimal and compute the exponent factor given a base. 54-- For hexadecimal exponential notation (IEEE 754) the base is 2 and the 55-- leading character a p. 56extExponentFactor :: 57 (Floating f, Stream s m Char) => 58 Int -> ParsecT s u m (f -> f) 59extExponentFactor base = 60 fmap (flip (*) . exponentValue base) (ap sign (decimal <?> "exponent")) 61 62-- | compute the factor given by the number following e or E. This 63-- implementation uses @**@ rather than @^@ for more efficiency for large 64-- integers. 65exponentValue :: (Floating f) => Int -> Integer -> f 66exponentValue base = (fromIntegral base **) . fromInteger 67 68-- ** fractional parts 69 70-- | parse a dot followed by decimal digits as fractional part 71fraction :: (Fractional f, Stream s m Char) => Bool -> ParsecT s u m f 72fraction b = baseFraction b 10 digit 73 74-- | parse a dot followed by base dependent digits as fractional part 75baseFraction :: 76 (Fractional f, Stream s m Char) => 77 Bool -> 78 Int -> 79 ParsecT s u m Char -> 80 ParsecT s u m f 81baseFraction requireDigit base baseDigit = 82 char '.' 83 >> fmap 84 (fractionValue base) 85 ((if requireDigit then many1 else many) baseDigit <?> "fraction") 86 <?> "fraction" 87 88-- | compute the fraction given by a sequence of digits following the dot. 89-- Only one division is performed and trailing zeros are ignored. 90fractionValue :: (Fractional f) => Int -> String -> f 91fractionValue base = 92 uncurry (/) 93 . foldl 94 ( \(s, p) d -> 95 (p * fromIntegral (digitToInt d) + s, p * fromIntegral base) 96 ) 97 (0, 1) 98 . dropWhile (== '0') 99 . reverse100101-- * integers and naturals102103-- | parse an optional plus or minus sign, returning 'negate' or 'id'104sign :: (Num a, Stream s m Char) => ParsecT s u m (a -> a)105sign = (char '-' >> return negate) <|> (optional (char '+') >> return id)106107-- | parse plain non-negative decimal numbers given by a non-empty sequence108-- of digits109decimal :: (Integral i, Stream s m Char) => ParsecT s u m i110decimal = number 10 digit111112-- ** natural parts113114-- | parse a hexadecimal number115hexnum :: (Integral i, Stream s m Char) => ParsecT s u m i116hexnum = number 16 hexDigit117118-- | parse a non-negative number given a base and a parser for the digits119number ::120 (Integral i, Stream s m t) =>121 Int ->122 ParsecT s u m Char ->123 ParsecT s u m i124number base baseDigit = do125 n <- fmap (numberValue base) (many1 baseDigit)126 seq n (return n)127128-- | compute the value from a string of digits using a base129numberValue :: (Integral i) => Int -> String -> i130numberValue base =131 foldl (\x -> ((fromIntegral base * x) +) . fromIntegral . digitToInt) 0