home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
gofer230.zip
/
Progs
/
Gofer
/
Demos
/
Ccexamples
/
parsers.gs
< prev
Wrap
Text File
|
1994-06-23
|
6KB
|
184 lines
-------------------------------------------------------------------------------
-- A variety of parsers, with the ability to use overloading to choose between
-- parsers by a top-level type signature:
--
-- ? parse topExpr "1+2" :: [Int] ==> [3
-- Program error:
-- Unexpected character `+'
-- ? parse topExpr "1+2" :: Maybe Int ==> Just 3
-- ? parse topExpr "1+2" :: ParseResult Int ==> ParsedAs 3
--
-- ? parse topExpr "(1+2" :: [Int] ==> Program error: missing `)'
-- ? parse topExpr "(1+2" :: Maybe Int ==> Program error: missing `)'
-- ? parse topExpr "(1+2" :: ParseResult Int ==> ParseError "missing `)'"
--
-- Mark P. Jones, April 12 1993
-------------------------------------------------------------------------------
infixr 7 `seq`
infixl 6 `pam`, `bind_`
-- All parsers are constructed from a monad in the following way: -------------
type Parser m a = String -> m (a,String)
in mapP, resultP, bindP, zeroP, plusP, parse, lookahead, sat, errPE
mapP :: Monad m => (a -> b) -> Parser m a -> Parser m b
mapP f p s = [ (f x, s') | ~(x,s') <- p s ]
resultP :: Monad m => a -> Parser m a
resultP x s = result (x,s)
bindP :: Monad m => Parser m a -> (a -> Parser m b) -> Parser m b
(p `bindP` q) s = p s `bind` \ ~(x,s') -> q x s'
zeroP :: Monad0 m => Parser m a
zeroP s = zero
plusP :: MonadPlus m => Parser m a -> Parser m a -> Parser m a
(p `plusP` q) s = p s ++ q s
instance Monad m => Functor (Parser m) where
map = mapP
instance Monad m => Monad (Parser m) where
result = resultP
bind = bindP
instance Monad0 m => Monad0 (Parser m) where
zero = zeroP
instance MonadPlus m => MonadPlus (Parser m) where
(++) = plusP
class MonadPlus (Parser m) => ParseMonad m where
parseError :: String -> Parser m a
parseError s = error s -- the user really ought to use a monad that
-- provides a better defn than this if they
-- want to use parseError in real programs
-- Auxiliary functions, using the definition of Parser: -----------------------
parse :: Monad m => Parser m a -> String -> m a
parse p s = [ x | ~(x,s') <- p s ]
parse' p s = [ x | ~(x,s') <- p s ]
lookahead :: Monad m => Parser m String
lookahead s = [ (s,s) ]
sat :: Monad0 m => (Char -> Bool) -> Parser m Char
sat p [] = zero
sat p (h:ts) = [ (h,ts) | p h ]
-- General utility functions: -------------------------------------------------
pam :: Functor f => f a -> (a -> b) -> f b
m `pam` f = map f m
bind_ :: Monad m => m a -> m b -> m b
p `bind_` q = p `bind` const q
seq :: Monad m => m a -> m b -> m (a,b)
p `seq` q = p `bind` \x -> q `bind` \y -> result (x,y)
many :: MonadPlus m => m a -> m [a]
many p = q where q = (p `bind` \x -> q `bind` \xs -> result (x:xs))
++
result []
many1 :: MonadPlus m => m a -> m [a]
many1 p = p `bind` \x -> many p `bind` \xs -> result (x:xs)
tok :: ParseMonad m => String -> Parser m ()
tok = foldr bind_ (result ()) . map (sat . (==))
-- Simple parsers, uncontrolled backtracking, list of parses: -----------------
instance ParseMonad []
-- The Maybe monad: -----------------------------------------------------------
data Maybe a = Just a | None
instance Functor Maybe where
map f (Just x) = Just (f x)
map f None = None
instance Monad Maybe where
result = Just
Just x `bind` f = f x
None `bind` f = None
instance Monad0 Maybe where
zero = None
instance MonadPlus Maybe where
None ++ y = y
Just x ++ y = Just x
instance ParseMonad Maybe
-- Simple parsers, uncontrolled backtracking, list of parses: -----------------
data ParseResult a = ParsedAs a
| ParseError String
| Backtrack
instance Functor ParseResult where
map f (ParsedAs x) = ParsedAs (f x)
map f (ParseError msg) = ParseError msg
map f Backtrack = Backtrack
instance Monad ParseResult where
result x = ParsedAs x
ParsedAs x `bind` f = f x
ParseError msg `bind` f = ParseError msg
Backtrack `bind` f = Backtrack
instance Monad0 ParseResult where
zero = Backtrack
instance MonadPlus ParseResult where
Backtrack ++ y = y
other ++ y = other
errPE :: String -> Parser ParseResult a
errPE msg s = ParseError msg
instance ParseMonad ParseResult where
parseError = errPE
-- A silly grammar for arithmetic expressions: -------------------------------
topExpr, expr, term, atom, number, digit:: ParseMonad m => Parser m Int
topExpr = expr `bind` \e ->
lookahead `bind` \s ->
if null s then result e
else parseError ("Unexpected character `"++[head s]++"'")
expr = term `bind` \x ->
(tok "+" `bind_` expr `pam` (x+) ++
tok "-" `bind_` expr `pam` (x-) ++
result x)
term = atom `bind` \x ->
(tok "*" `bind_` term `pam` (x*) ++
tok "/" `bind_` term `pam` (x/) ++
result x)
atom = tok "-" `bind_` expr `pam` negate
++
tok "(" `bind_` expr `bind` (\n -> tok ")" `bind_` result n
++
parseError "missing `)'")
++
number
number = many1 digit `pam` foldl1 (\a x -> 10*a+x)
digit = sat isDigit `pam` \d -> ord d - ord '0'
-------------------------------------------------------------------------------