-- Copyright (c) 2002 John Meacham (john@foo.net) -- -- Permission is hereby granted, free of charge, to any person obtaining a -- copy of this software and associated documentation files (the -- "Software"), to deal in the Software without restriction, including -- without limitation the rights to use, copy, modify, merge, publish, -- distribute, sublicense, and/or sell copies of the Software, and to -- permit persons to whom the Software is furnished to do so, subject to -- the following conditions: -- -- The above copyright notice and this permission notice shall be included -- in all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. module SimpleParser where import Data.Char import Control.Monad import Data.List infixr 1 <|> -- very simple parser combinators with failure but limited non-determinism. -- designed for parsing single lines or simple expressions. -- advantages: pure haskell 98, simple. newtype GenParser c a = MkP ([c] -> Maybe (a,[c])) type Parser a = GenParser Char a instance Monad (GenParser c) where return a = MkP (\s -> (Just (a,s))) (MkP p) >>= q = MkP $ \s -> (maybe Nothing (\(v,s') -> app (q v) s') (p s)) fail _ = MkP $ \_ -> Nothing instance Functor (GenParser c) where fmap = liftM instance MonadPlus (GenParser c) where mzero = MkP (\_ -> Nothing) mplus = (<|>) app (MkP fn) s = fn s char :: Char -> Parser Char char c = sat (== c) eof :: GenParser c () eof = MkP eof' where eof' [] = Just ((),[]) eof' _ = Nothing oneOf cs = sat (`elem` cs) noneOf cs = sat (`notElem` cs) between o c p = o >> p >>= \v -> c >> return v {-# SPECIALIZE parseSome :: Int -> GenParser c [c] #-} parseSome :: Integral a => a -> GenParser c [c] parseSome count = MkP f where f xs | length xs >= (fromIntegral count) = Just (splitAt (fromIntegral count) xs) f _ = Nothing {-# SPECIALIZE parseExact :: String -> GenParser Char () #-} parseExact :: Eq c => [c] -> GenParser c () parseExact x = MkP f where f xs | x `isPrefixOf` xs = Just ((),drop (length x) xs) f _ = Nothing parseRest = MkP (\xs -> Just (xs,[])) option x p = p <|> return x skipOption p = option () $ liftM (const ()) p choice ps = foldl (<|>) mzero ps anyChar = satisfy (const True) upper = satisfy isUpper lower = satisfy isLower alphaNum = satisfy isAlphaNum digit = satisfy isDigit newline = char '\n' space = satisfy isSpace spaces = skipMany space sat p = MkP f where f (x:xs) | p x = Just (x,xs) f _ = Nothing satisfy = sat p <|> q = MkP $ \s -> maybe (app q s) Just (app p s) many :: GenParser c a -> GenParser c [a] many p = (p >>= \x -> many p >>= \xs -> return (x:xs)) <|> return [] many1 :: GenParser c a -> GenParser c [a] many1 p = p >>= \x -> many p >>= \xs -> return (x:xs) whitespace = skipMany (sat isSpace) token p = p >>= \x -> whitespace >> return x skipMany p = (p >> skipMany p) <|> return () number :: Parser Int number = token (liftM read $ many1 (sat isDigit)) word :: Parser String word = token $ (many1 (sat isAlpha)) exactWord s = do w <- word if w == s then return w else mzero parser :: GenParser c a -> [c] -> Maybe a parser (MkP fn) s = case fn s of Just (v,[]) -> Just v _ -> Nothing {- parseIO p xs = case parser p xs of Just v -> return v Nothing -> ioError $ userError "parse error" -} {- parse_file = do whitespace u <- number v <- number exactWord "done" return (u,v) main = do c <- getContents let v = parser parse_file c print v -}