Functional parsing library from chapter 8 of Programming in Haskell, Graham Hutton, Cambridge University Press, 2007. Modifications by F. Warren Burton to support backtracking parsers. > module MyParsing where > > import Char > import Monad > > infixr 5 +++ The monad of parsers -------------------- > newtype Parser a = P (String -> [(a,String)]) > > instance Monad Parser where > return v = P (\inp -> [(v,inp)]) > p >>= f = > P (\inp -> concat [parse (f v) out | (v,out) <- parse p inp]) Basic parsers ------------- > failure :: Parser a > failure = P (\inp -> []) > > item :: Parser Char > item = P (\inp -> case inp of > [] -> [] > (x:xs) -> [(x,xs)]) > > parse, fullParse :: Parser a -> String -> [(a,String)] > parse (P p) inp = p inp > fullParse (P p) inp = filter (null . snd) (p inp) Choice ------ The (+++) operator supports choice with backtracking while the (+!+) operator is similar to the choice operator implemented by Hutton and does not allow backtracking. > (+!+), (+++) :: Parser a -> Parser a -> Parser a > p +++ q = P (\inp -> parse p inp ++ parse q inp) > p +!+ q = P (\inp -> case parse p inp of > [] -> parse q inp > other -> other) Derived primitives ------------------ > sat :: (Char -> Bool) -> Parser Char > sat p = do x <- item > if p x then return x else failure > > digit :: Parser Char > digit = sat isDigit > > lower :: Parser Char > lower = sat isLower > > upper :: Parser Char > upper = sat isUpper > > letter :: Parser Char > letter = sat isAlpha > > alphanum :: Parser Char > alphanum = sat isAlphaNum > > char :: Char -> Parser Char > char x = sat (== x) > > string :: String -> Parser String > string [] = return [] > string (x:xs) = do char x > string xs > return (x:xs) > > many :: Parser a -> Parser [a] > many p = many1 p +++ return [] > > many1 :: Parser a -> Parser [a] > many1 p = do v <- p > vs <- many p > return (v:vs) > The nonbacktracking versions of many and many1 are most and most1. > most :: Parser a -> Parser [a] > most p = most1 p +!+ return [] > > most1 :: Parser a -> Parser [a] > most1 p = do v <- p > vs <- most p > return (v:vs) > > ident :: Parser String > ident = do x <- lower > xs <- most alphanum > return (x:xs) > > nat :: Parser Int > nat = do xs <- most1 digit > return (read xs) > > int :: Parser Int > int = do char '-' > n <- nat > return (-n) > +!+ nat > > space :: Parser () > space = do most (sat isSpace) > return () Ignoring spacing ---------------- > token :: Parser a -> Parser a > token p = do space > v <- p > space > return v > > identifier :: Parser String > identifier = token ident > > natural :: Parser Int > natural = token nat > > integer :: Parser Int > integer = token int > > symbol :: String -> Parser String > symbol xs = token (string xs)