1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
{
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
-- For ancient GHC 7.0.4
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
import Control.Monad (liftM, ap)
import Control.Applicative as A
}
%name parse exp
%tokentype { Token }
%error { parseError }
%monad { (MonadIO m) } { Parser m }
%lexer { lexer } { EOF }
%token ID { Id _ }
NUM { Num _ }
PLUS { Plus }
MINUS { Minus }
TIMES { Times }
LPAREN { LParen }
RPAREN { RParen }
%%
exp :: { AST }
: exp PLUS prod
{ Sum $1 $3 }
| prod
{ $1 }
prod :: { AST }
: prod TIMES neg
{ Prod $1 $3 }
| neg
{ $1 }
neg :: { AST }
: MINUS neg
{ Neg $2 }
| atom
{ $1 }
atom :: { AST }
: ID
{ let Id str = $1 in Var str }
| NUM
{ let Num n = $1 in Lit n }
| LPAREN exp RPAREN
{ $2 }
{
data Token =
Plus
| Minus
| Times
| LParen
| RParen
| Id String
| Num Int
| EOF
deriving (Eq, Ord, Show)
data AST =
Sum AST AST
| Prod AST AST
| Neg AST
| Var String
| Lit Int
deriving (Eq, Ord)
type Parser m = ExceptT () (Lexer m)
type Lexer m = StateT [Token] m
parseError :: MonadIO m => Token -> Parser m a
parseError tok =
do
liftIO (putStrLn ("Parse error at " ++ show tok))
throwError ()
lexer :: MonadIO m => (Token -> Parser m a) -> Parser m a
lexer cont =
do
toks <- get
case toks of
[] -> cont EOF
first : rest ->
do
put rest
cont first
parse :: (MonadIO m) => Parser m AST
parser :: (MonadIO m) =>
[Token]
-> m (Maybe AST)
parser input =
let
run :: (MonadIO m) =>
Lexer m (Maybe AST)
run =
do
res <- runExceptT parse
case res of
Left () -> return Nothing
Right ast -> return (Just ast)
in do
(out, _) <- runStateT run input
return out
main :: IO ()
main =
let
input = [Id "x", Plus,
Minus, Num 1, Times,
LParen, Num 2, Plus, Id "y", RParen]
expected = Sum (Var "x") (Prod (Neg (Lit 1)) (Sum (Lit 2) (Var "y")))
in do
res <- parser input
case res of
Nothing -> print "Test failed\n"
Just actual
| expected == actual -> print "Test works\n"
| otherwise -> print "Test failed\n"
-- vendored in parts of mtl
class Monad m => MonadIO m where liftIO :: IO a -> m a
instance MonadIO IO where liftIO = id
class Monad m => MonadState s m | m -> s where
put :: s -> m ()
get :: m s
newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }
instance Monad m => Functor (StateT s m) where
fmap = liftM
instance Monad m => A.Applicative (StateT s m) where
pure = return
(<*>) = ap
instance Monad m => Monad (StateT s m) where
return x = StateT $ \s -> return (x, s)
m >>= k = StateT $ \s0 -> do
(x, s1) <- runStateT m s0
runStateT (k x) s1
instance Monad m => MonadState s (StateT s m) where
put s = StateT $ \_ -> return ((), s)
get = StateT $ \s -> return (s, s)
instance MonadIO m => MonadIO (StateT e m) where
liftIO m = StateT $ \s -> liftM (\x -> (x, s)) (liftIO m)
class Monad m => MonadError e m | m -> e where
throwError :: e -> m a
newtype ExceptT e m a = ExceptT { runExceptT :: m (Either e a) }
instance Monad m => Functor (ExceptT e m) where
fmap = liftM
instance Monad m => A.Applicative (ExceptT e m) where
pure = return
(<*>) = ap
instance Monad m => Monad (ExceptT e m) where
return = ExceptT . return . Right
m >>= k = ExceptT $ do
x <- runExceptT m
case x of
Left e -> return (Left e)
Right y -> runExceptT (k y)
instance MonadState s m => MonadState s (ExceptT e m) where
put s = ExceptT (liftM Right (put s))
get = ExceptT (liftM Right get)
instance MonadIO m => MonadIO (ExceptT e m) where
liftIO = ExceptT . liftM Right . liftIO
instance Monad m => MonadError e (ExceptT e m) where
throwError = ExceptT . return . Left
}
|