-- ----------------------------------------------------------------------------- -- Alex wrapper code. -- -- This code is in the PUBLIC DOMAIN; you may copy it freely and use -- it for any purpose whatsoever. #if defined(ALEX_BASIC_BYTESTRING) || defined(ALEX_POSN_BYTESTRING) || defined(ALEX_MONAD_BYTESTRING) import qualified Data.ByteString.Lazy.Char8 as ByteString #elif defined(ALEX_STRICT_BYTESTRING) import qualified Data.ByteString.Char8 as ByteString import qualified Data.ByteString.Internal as ByteString import qualified Data.ByteString.Unsafe as ByteString #endif -- ----------------------------------------------------------------------------- -- The input type #if defined(ALEX_POSN) || defined(ALEX_MONAD) || defined(ALEX_GSCAN) type AlexInput = (AlexPosn, -- current position, Char, -- previous char String) -- current input string alexInputPrevChar :: AlexInput -> Char alexInputPrevChar (p,c,s) = c alexGetChar :: AlexInput -> Maybe (Char,AlexInput) alexGetChar (p,c,[]) = Nothing alexGetChar (p,_,(c:s)) = let p' = alexMove p c in p' `seq` Just (c, (p', c, s)) #endif #if defined(ALEX_POSN_BYTESTRING) || defined(ALEX_MONAD_BYTESTRING) type AlexInput = (AlexPosn, -- current position, Char, -- previous char ByteString.ByteString) -- current input string alexInputPrevChar :: AlexInput -> Char alexInputPrevChar (p,c,s) = c alexGetChar :: AlexInput -> Maybe (Char,AlexInput) alexGetChar (p,_,cs) | ByteString.null cs = Nothing | otherwise = let c = ByteString.head cs cs' = ByteString.tail cs p' = alexMove p c in p' `seq` cs' `seq` Just (c, (p', c, cs')) #endif -- ----------------------------------------------------------------------------- -- Token positions -- `Posn' records the location of a token in the input text. It has three -- fields: the address (number of chacaters preceding the token), line number -- and column of a token within the file. `start_pos' gives the position of the -- start of the file and `eof_pos' a standard encoding for the end of file. -- `move_pos' calculates the new position after traversing a given character, -- assuming the usual eight character tab stops. #if defined(ALEX_POSN) || defined(ALEX_MONAD) || defined(ALEX_POSN_BYTESTRING) || defined(ALEX_MONAD_BYTESTRING) || defined(ALEX_GSCAN) data AlexPosn = AlexPn !Int !Int !Int deriving (Eq,Show) alexStartPos :: AlexPosn alexStartPos = AlexPn 0 1 1 alexMove :: AlexPosn -> Char -> AlexPosn alexMove (AlexPn a l c) '\t' = AlexPn (a+1) l (((c+7) `div` 8)*8+1) alexMove (AlexPn a l c) '\n' = AlexPn (a+1) (l+1) 1 alexMove (AlexPn a l c) _ = AlexPn (a+1) l (c+1) #endif -- ----------------------------------------------------------------------------- -- Default monad #ifdef ALEX_MONAD data AlexState = AlexState { alex_pos :: !AlexPosn, -- position at current input location alex_inp :: String, -- the current input alex_chr :: !Char, -- the character before the input alex_scd :: !Int -- the current startcode #ifdef ALEX_MONAD_USER_STATE , alex_ust :: AlexUserState -- AlexUserState will be defined in the user program #endif } -- Compile with -funbox-strict-fields for best results! runAlex :: String -> Alex a -> Either String a runAlex input (Alex f) = case f (AlexState {alex_pos = alexStartPos, alex_inp = input, alex_chr = '\n', #ifdef ALEX_MONAD_USER_STATE alex_ust = alexInitUserState, #endif alex_scd = 0}) of Left msg -> Left msg Right ( _, a ) -> Right a newtype Alex a = Alex { unAlex :: AlexState -> Either String (AlexState, a) } instance Monad Alex where m >>= k = Alex $ \s -> case unAlex m s of Left msg -> Left msg Right (s',a) -> unAlex (k a) s' return a = Alex $ \s -> Right (s,a) alexGetInput :: Alex AlexInput alexGetInput = Alex $ \s@AlexState{alex_pos=pos,alex_chr=c,alex_inp=inp} -> Right (s, (pos,c,inp)) alexSetInput :: AlexInput -> Alex () alexSetInput (pos,c,inp) = Alex $ \s -> case s{alex_pos=pos,alex_chr=c,alex_inp=inp} of s@(AlexState{}) -> Right (s, ()) alexError :: String -> Alex a alexError message = Alex $ \s -> Left message alexGetStartCode :: Alex Int alexGetStartCode = Alex $ \s@AlexState{alex_scd=sc} -> Right (s, sc) alexSetStartCode :: Int -> Alex () alexSetStartCode sc = Alex $ \s -> Right (s{alex_scd=sc}, ()) alexMonadScan = do inp <- alexGetInput sc <- alexGetStartCode case alexScan inp sc of AlexEOF -> alexEOF AlexError inp' -> alexError "lexical error" AlexSkip inp' len -> do alexSetInput inp' alexMonadScan AlexToken inp' len action -> do alexSetInput inp' action inp len -- ----------------------------------------------------------------------------- -- Useful token actions type AlexAction result = AlexInput -> Int -> result -- just ignore this token and scan another one -- skip :: AlexAction result skip input len = alexMonadScan -- ignore this token, but set the start code to a new value -- begin :: Int -> AlexAction result begin code input len = do alexSetStartCode code; alexMonadScan -- perform an action for this token, and set the start code to a new value -- andBegin :: AlexAction result -> Int -> AlexAction result (action `andBegin` code) input len = do alexSetStartCode code; action input len -- token :: (String -> Int -> token) -> AlexAction token token t input len = return (t input len) #endif /* ALEX_MONAD */ -- ----------------------------------------------------------------------------- -- Monad (with ByteString input) #ifdef ALEX_MONAD_BYTESTRING data AlexState = AlexState { alex_pos :: !AlexPosn, -- position at current input location alex_inp :: ByteString.ByteString, -- the current input alex_chr :: !Char, -- the character before the input alex_scd :: !Int -- the current startcode #ifdef ALEX_MONAD_USER_STATE , alex_ust :: AlexUserState -- AlexUserState will be defined in the user program #endif } -- Compile with -funbox-strict-fields for best results! runAlex :: ByteString.ByteString -> Alex a -> Either String a runAlex input (Alex f) = case f (AlexState {alex_pos = alexStartPos, alex_inp = input, alex_chr = '\n', #ifdef ALEX_MONAD_USER_STATE alex_ust = alexInitUserState, #endif alex_scd = 0}) of Left msg -> Left msg Right ( _, a ) -> Right a newtype Alex a = Alex { unAlex :: AlexState -> Either String (AlexState, a) } instance Monad Alex where m >>= k = Alex $ \s -> case unAlex m s of Left msg -> Left msg Right (s',a) -> unAlex (k a) s' return a = Alex $ \s -> Right (s,a) alexGetInput :: Alex AlexInput alexGetInput = Alex $ \s@AlexState{alex_pos=pos,alex_chr=c,alex_inp=inp} -> Right (s, (pos,c,inp)) alexSetInput :: AlexInput -> Alex () alexSetInput (pos,c,inp) = Alex $ \s -> case s{alex_pos=pos,alex_chr=c,alex_inp=inp} of s@(AlexState{}) -> Right (s, ()) alexError :: String -> Alex a alexError message = Alex $ \s -> Left message alexGetStartCode :: Alex Int alexGetStartCode = Alex $ \s@AlexState{alex_scd=sc} -> Right (s, sc) alexSetStartCode :: Int -> Alex () alexSetStartCode sc = Alex $ \s -> Right (s{alex_scd=sc}, ()) alexMonadScan = do inp <- alexGetInput sc <- alexGetStartCode case alexScan inp sc of AlexEOF -> alexEOF AlexError inp' -> alexError "lexical error" AlexSkip inp' len -> do alexSetInput inp' alexMonadScan AlexToken inp' len action -> do alexSetInput inp' action inp len -- ----------------------------------------------------------------------------- -- Useful token actions type AlexAction result = AlexInput -> Int -> result -- just ignore this token and scan another one -- skip :: AlexAction result skip input len = alexMonadScan -- ignore this token, but set the start code to a new value -- begin :: Int -> AlexAction result begin code input len = do alexSetStartCode code; alexMonadScan -- perform an action for this token, and set the start code to a new value -- andBegin :: AlexAction result -> Int -> AlexAction result (action `andBegin` code) input len = do alexSetStartCode code; action input len -- token :: (String -> Int -> token) -> AlexAction token token t input len = return (t input len) #endif /* ALEX_MONAD_BYTESTRING */ -- ----------------------------------------------------------------------------- -- Basic wrapper #ifdef ALEX_BASIC type AlexInput = (Char,String) alexGetChar (_, []) = Nothing alexGetChar (_, c:cs) = Just (c, (c,cs)) alexInputPrevChar (c,_) = c -- alexScanTokens :: String -> [token] alexScanTokens str = go ('\n',str) where go inp@(_,str) = case alexScan inp 0 of AlexEOF -> [] AlexError _ -> error "lexical error" AlexSkip inp' len -> go inp' AlexToken inp' len act -> act (take len str) : go inp' #endif -- ----------------------------------------------------------------------------- -- Basic wrapper, ByteString version #ifdef ALEX_BASIC_BYTESTRING type AlexInput = (Char,ByteString.ByteString) alexGetChar (_, cs) | ByteString.null cs = Nothing | otherwise = Just (ByteString.head cs, (ByteString.head cs, ByteString.tail cs)) alexInputPrevChar (c,_) = c -- alexScanTokens :: String -> [token] alexScanTokens str = go ('\n',str) where go inp@(_,str) = case alexScan inp 0 of AlexEOF -> [] AlexError _ -> error "lexical error" AlexSkip inp' len -> go inp' AlexToken inp' len act -> act (ByteString.take (fromIntegral len) str) : go inp' #endif #ifdef ALEX_STRICT_BYTESTRING data AlexInput = AlexInput { alexChar :: {-# UNPACK #-}!Char , alexStr :: {-# UNPACK #-}!ByteString.ByteString } alexGetChar (AlexInput _ cs) | ByteString.null cs = Nothing | otherwise = Just $! (ByteString.head cs, AlexInput c cs') where (c,cs') = (ByteString.w2c (ByteString.unsafeHead cs) , ByteString.unsafeTail cs) alexInputPrevChar = alexChar -- alexScanTokens :: String -> [token] alexScanTokens str = go (AlexInput '\n' str) where go inp@(AlexInput _ str) = case alexScan inp 0 of AlexEOF -> [] AlexError _ -> error "lexical error" AlexSkip inp' len -> go inp' AlexToken inp' len act -> act (ByteString.unsafeTake len str) : go inp' #endif -- ----------------------------------------------------------------------------- -- Posn wrapper -- Adds text positions to the basic model. #ifdef ALEX_POSN --alexScanTokens :: String -> [token] alexScanTokens str = go (alexStartPos,'\n',str) where go inp@(pos,_,str) = case alexScan inp 0 of AlexEOF -> [] AlexError _ -> error "lexical error" AlexSkip inp' len -> go inp' AlexToken inp' len act -> act pos (take len str) : go inp' #endif -- ----------------------------------------------------------------------------- -- Posn wrapper, ByteString version #ifdef ALEX_POSN_BYTESTRING --alexScanTokens :: ByteString -> [token] alexScanTokens str = go (alexStartPos,'\n',str) where go inp@(pos,_,str) = case alexScan inp 0 of AlexEOF -> [] AlexError _ -> error "lexical error" AlexSkip inp' len -> go inp' AlexToken inp' len act -> act pos (ByteString.take (fromIntegral len) str) : go inp' #endif -- ----------------------------------------------------------------------------- -- GScan wrapper -- For compatibility with previous versions of Alex, and because we can. #ifdef ALEX_GSCAN alexGScan stop state inp = alex_gscan stop alexStartPos '\n' inp (0,state) alex_gscan stop p c inp (sc,state) = case alexScan (p,c,inp) sc of AlexEOF -> stop p c inp (sc,state) AlexError _ -> stop p c inp (sc,state) AlexSkip (p',c',inp') len -> alex_gscan stop p' c' inp' (sc,state) AlexToken (p',c',inp') len k -> k p c inp len (\scs -> alex_gscan stop p' c' inp' scs) (sc,state) #endif