Blame src/Main.hs

Packit 2cbdf3
{-# LANGUAGE CPP #-}
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
--
Packit 2cbdf3
-- Main.hs, part of Alex
Packit 2cbdf3
--
Packit 2cbdf3
-- (c) Chris Dornan 1995-2000, Simon Marlow 2003
Packit 2cbdf3
--
Packit 2cbdf3
-- ----------------------------------------------------------------------------}
Packit 2cbdf3
Packit 2cbdf3
module Main (main) where
Packit 2cbdf3
Packit 2cbdf3
import AbsSyn
Packit 2cbdf3
import CharSet
Packit 2cbdf3
import DFA
Packit 2cbdf3
import DFAMin
Packit 2cbdf3
import NFA
Packit 2cbdf3
import Info
Packit 2cbdf3
import Map ( Map )
Packit 2cbdf3
import qualified Map hiding ( Map )
Packit 2cbdf3
import Output
Packit 2cbdf3
import ParseMonad ( runP )
Packit 2cbdf3
import Parser
Packit 2cbdf3
import Scan
Packit 2cbdf3
import Util ( hline )
Packit 2cbdf3
import Paths_alex ( version, getDataDir )
Packit 2cbdf3
Packit 2cbdf3
#if __GLASGOW_HASKELL__ < 610
Packit 2cbdf3
import Control.Exception as Exception ( block, unblock, catch, throw )
Packit 2cbdf3
#endif
Packit 2cbdf3
#if __GLASGOW_HASKELL__ >= 610
Packit 2cbdf3
import Control.Exception ( bracketOnError )
Packit 2cbdf3
#endif
Packit 2cbdf3
import Control.Monad ( when, liftM )
Packit 2cbdf3
import Data.Char ( chr )
Packit 2cbdf3
import Data.List ( isSuffixOf, nub )
Packit 2cbdf3
import Data.Maybe ( isJust, fromJust )
Packit 2cbdf3
import Data.Version ( showVersion )
Packit 2cbdf3
import System.Console.GetOpt ( getOpt, usageInfo, ArgOrder(..), OptDescr(..), ArgDescr(..) )
Packit 2cbdf3
import System.Directory ( removeFile )
Packit 2cbdf3
import System.Environment ( getProgName, getArgs )
Packit 2cbdf3
import System.Exit ( ExitCode(..), exitWith )
Packit 2cbdf3
import System.IO ( stderr, Handle, IOMode(..), openFile, hClose, hPutStr, hPutStrLn )
Packit 2cbdf3
#if __GLASGOW_HASKELL__ >= 612
Packit 2cbdf3
import System.IO ( hGetContents, hSetEncoding, utf8 )
Packit 2cbdf3
#endif
Packit 2cbdf3
Packit 2cbdf3
-- We need to force every file we open to be read in
Packit 2cbdf3
-- as UTF8
Packit 2cbdf3
alexReadFile :: FilePath -> IO String
Packit 2cbdf3
#if __GLASGOW_HASKELL__ >= 612
Packit 2cbdf3
alexReadFile file = do
Packit 2cbdf3
  h <- alexOpenFile file ReadMode
Packit 2cbdf3
  hGetContents h
Packit 2cbdf3
#else
Packit 2cbdf3
alexReadFile = readFile
Packit 2cbdf3
#endif
Packit 2cbdf3
Packit 2cbdf3
-- We need to force every file we write to be written
Packit 2cbdf3
-- to as UTF8
Packit 2cbdf3
alexOpenFile :: FilePath -> IOMode -> IO Handle
Packit 2cbdf3
#if __GLASGOW_HASKELL__ >= 612
Packit 2cbdf3
alexOpenFile file mode = do
Packit 2cbdf3
  h <- openFile file mode
Packit 2cbdf3
  hSetEncoding h utf8
Packit 2cbdf3
  return h
Packit 2cbdf3
#else
Packit 2cbdf3
alexOpenFile = openFile
Packit 2cbdf3
#endif
Packit 2cbdf3
Packit 2cbdf3
-- `main' decodes the command line arguments and calls `alex'.
Packit 2cbdf3
Packit 2cbdf3
main:: IO ()
Packit 2cbdf3
main =  do
Packit 2cbdf3
 args <- getArgs
Packit 2cbdf3
 case getOpt Permute argInfo args of
Packit 2cbdf3
    (cli,_,[]) | DumpHelp `elem` cli -> do
Packit 2cbdf3
        prog <- getProgramName
Packit 2cbdf3
        bye (usageInfo (usageHeader prog) argInfo)
Packit 2cbdf3
    (cli,_,[]) | DumpVersion `elem` cli ->
Packit 2cbdf3
        bye copyright
Packit 2cbdf3
    (cli,[file],[]) ->
Packit 2cbdf3
        runAlex cli file
Packit 2cbdf3
    (_,_,errors) -> do
Packit 2cbdf3
        prog <- getProgramName
Packit 2cbdf3
        die (concat errors ++ usageInfo (usageHeader prog) argInfo)
Packit 2cbdf3
Packit 2cbdf3
projectVersion :: String
Packit 2cbdf3
projectVersion = showVersion version
Packit 2cbdf3
Packit 2cbdf3
copyright :: String
Packit 2cbdf3
copyright = "Alex version " ++ projectVersion ++ ", (c) 2003 Chris Dornan and Simon Marlow\n"
Packit 2cbdf3
Packit 2cbdf3
usageHeader :: String -> String
Packit 2cbdf3
usageHeader prog = "Usage: " ++ prog ++ " [OPTION...] file\n"
Packit 2cbdf3
Packit 2cbdf3
runAlex :: [CLIFlags] -> FilePath -> IO ()
Packit 2cbdf3
runAlex cli file = do
Packit 2cbdf3
  basename <- case (reverse file) of
Packit 2cbdf3
                'x':'.':r -> return (reverse r)
Packit 2cbdf3
                _         -> die (file ++ ": filename must end in \'.x\'\n")
Packit 2cbdf3
Packit 2cbdf3
  prg <- alexReadFile file
Packit 2cbdf3
  script <- parseScript file prg
Packit 2cbdf3
  alex cli file basename script
Packit 2cbdf3
Packit 2cbdf3
parseScript :: FilePath -> String
Packit 2cbdf3
  -> IO (Maybe (AlexPosn,Code), [Directive], Scanner, Maybe (AlexPosn,Code))
Packit 2cbdf3
parseScript file prg =
Packit 2cbdf3
  case runP prg initialParserEnv parse of
Packit 2cbdf3
        Left (Just (AlexPn _ line col),err) ->
Packit 2cbdf3
                die (file ++ ":" ++ show line ++ ":" ++ show col
Packit 2cbdf3
                                 ++ ": " ++ err ++ "\n")
Packit 2cbdf3
        Left (Nothing, err) ->
Packit 2cbdf3
                die (file ++ ": " ++ err ++ "\n")
Packit 2cbdf3
Packit 2cbdf3
        Right script -> return script
Packit 2cbdf3
Packit 2cbdf3
alex :: [CLIFlags] -> FilePath -> FilePath
Packit 2cbdf3
     -> (Maybe (AlexPosn, Code), [Directive], Scanner, Maybe (AlexPosn, Code))
Packit 2cbdf3
     -> IO ()
Packit 2cbdf3
alex cli file basename script = do
Packit 2cbdf3
   (put_info, finish_info) <-
Packit 2cbdf3
      case [ f | OptInfoFile f <- cli ] of
Packit 2cbdf3
           []  -> return (\_ -> return (), return ())
Packit 2cbdf3
           [Nothing] -> infoStart file (basename ++ ".info")
Packit 2cbdf3
           [Just f]  -> infoStart file f
Packit 2cbdf3
           _   -> dieAlex "multiple -i/--info options"
Packit 2cbdf3
Packit 2cbdf3
   o_file <- case [ f | OptOutputFile f <- cli ] of
Packit 2cbdf3
                []  -> return (basename ++ ".hs")
Packit 2cbdf3
                [f] -> return f
Packit 2cbdf3
                _   -> dieAlex "multiple -o/--outfile options"
Packit 2cbdf3
Packit 2cbdf3
   tab_size <- case [ s | OptTabSize s <- cli ] of
Packit 2cbdf3
                []  -> return (8 :: Int)
Packit 2cbdf3
                [s] -> case reads s of
Packit 2cbdf3
                        [(n,"")] -> return n
Packit 2cbdf3
                        _        -> dieAlex "-s/--tab-size option is not a valid integer"
Packit 2cbdf3
                _   -> dieAlex "multiple -s/--tab-size options"
Packit 2cbdf3
Packit 2cbdf3
   let target
Packit 2cbdf3
        | OptGhcTarget `elem` cli = GhcTarget
Packit 2cbdf3
        | otherwise               = HaskellTarget
Packit 2cbdf3
Packit 2cbdf3
   let encodingsCli
Packit 2cbdf3
        | OptLatin1 `elem` cli = [Latin1]
Packit 2cbdf3
        | otherwise            = []
Packit 2cbdf3
Packit 2cbdf3
   template_dir  <- templateDir getDataDir cli
Packit 2cbdf3
Packit 2cbdf3
   let (maybe_header, directives, scanner1, maybe_footer) = script
Packit 2cbdf3
Packit 2cbdf3
   scheme <- getScheme directives
Packit 2cbdf3
Packit 2cbdf3
   -- open the output file; remove it if we encounter an error
Packit 2cbdf3
   bracketOnError
Packit 2cbdf3
        (alexOpenFile o_file WriteMode)
Packit 2cbdf3
        (\h -> do hClose h; removeFile o_file)
Packit 2cbdf3
        $ \out_h -> do
Packit 2cbdf3
Packit 2cbdf3
   let
Packit 2cbdf3
         wrapper_name = wrapperFile template_dir scheme
Packit 2cbdf3
         (scanner2, scs, sc_hdr) = encodeStartCodes scanner1
Packit 2cbdf3
         (scanner_final, actions) = extractActions scheme scanner2
Packit 2cbdf3
         encodingsScript = [ e | EncodingDirective e <- directives ]
Packit 2cbdf3
Packit 2cbdf3
   encoding <- case nub (encodingsCli ++ encodingsScript) of
Packit 2cbdf3
     []  -> return UTF8 -- default
Packit 2cbdf3
     [e] -> return e
Packit 2cbdf3
     _ | null encodingsCli -> dieAlex "conflicting %encoding directives"
Packit 2cbdf3
       | otherwise -> dieAlex "--latin1 flag conflicts with %encoding directive"
Packit 2cbdf3
Packit 2cbdf3
   hPutStr out_h (optsToInject target cli)
Packit 2cbdf3
   injectCode maybe_header file out_h
Packit 2cbdf3
Packit 2cbdf3
   hPutStr out_h (importsToInject target cli)
Packit 2cbdf3
Packit 2cbdf3
   -- add the wrapper, if necessary
Packit 2cbdf3
   when (isJust wrapper_name) $
Packit 2cbdf3
        do str <- alexReadFile (fromJust wrapper_name)
Packit 2cbdf3
           hPutStr out_h str
Packit 2cbdf3
Packit 2cbdf3
   -- Inject the tab size
Packit 2cbdf3
   hPutStrLn out_h $ "alex_tab_size :: Int"
Packit 2cbdf3
   hPutStrLn out_h $ "alex_tab_size = " ++ show (tab_size :: Int)
Packit 2cbdf3
Packit 2cbdf3
   let dfa = scanner2dfa encoding scanner_final scs
Packit 2cbdf3
       min_dfa = minimizeDFA dfa
Packit 2cbdf3
       nm  = scannerName scanner_final
Packit 2cbdf3
       usespreds = usesPreds min_dfa
Packit 2cbdf3
Packit 2cbdf3
Packit 2cbdf3
   put_info "\nStart codes\n"
Packit 2cbdf3
   put_info (show $ scs)
Packit 2cbdf3
   put_info "\nScanner\n"
Packit 2cbdf3
   put_info (show $ scanner_final)
Packit 2cbdf3
   put_info "\nNFA\n"
Packit 2cbdf3
   put_info (show $ scanner2nfa encoding scanner_final scs)
Packit 2cbdf3
   put_info "\nDFA"
Packit 2cbdf3
   put_info (infoDFA 1 nm dfa "")
Packit 2cbdf3
   put_info "\nMinimized DFA"
Packit 2cbdf3
   put_info (infoDFA 1 nm min_dfa "")
Packit 2cbdf3
   hPutStr out_h (outputDFA target 1 nm scheme min_dfa "")
Packit 2cbdf3
Packit 2cbdf3
   injectCode maybe_footer file out_h
Packit 2cbdf3
Packit 2cbdf3
   hPutStr out_h (sc_hdr "")
Packit 2cbdf3
   hPutStr out_h (actions "")
Packit 2cbdf3
Packit 2cbdf3
   -- add the template
Packit 2cbdf3
   let template_name = templateFile template_dir target usespreds cli
Packit 2cbdf3
   tmplt <- alexReadFile template_name
Packit 2cbdf3
   hPutStr out_h tmplt
Packit 2cbdf3
Packit 2cbdf3
   hClose out_h
Packit 2cbdf3
   finish_info
Packit 2cbdf3
Packit 2cbdf3
getScheme :: [Directive] -> IO Scheme
Packit 2cbdf3
getScheme directives =
Packit 2cbdf3
  do
Packit 2cbdf3
    token <- case [ ty | TokenType ty <- directives ] of
Packit 2cbdf3
      [] -> return Nothing
Packit 2cbdf3
      [res] -> return (Just res)
Packit 2cbdf3
      _ -> dieAlex "multiple %token directives"
Packit 2cbdf3
Packit 2cbdf3
    action <- case [ ty | ActionType ty <- directives ] of
Packit 2cbdf3
      [] -> return Nothing
Packit 2cbdf3
      [res] -> return (Just res)
Packit 2cbdf3
      _ -> dieAlex "multiple %action directives"
Packit 2cbdf3
Packit 2cbdf3
    typeclass <- case [ tyclass | TypeClass tyclass <- directives ] of
Packit 2cbdf3
      [] -> return Nothing
Packit 2cbdf3
      [res] -> return (Just res)
Packit 2cbdf3
      _ -> dieAlex "multiple %typeclass directives"
Packit 2cbdf3
Packit 2cbdf3
    case [ f | WrapperDirective f <- directives ] of
Packit 2cbdf3
        []  ->
Packit 2cbdf3
          case (typeclass, token, action) of
Packit 2cbdf3
            (Nothing, Nothing, Nothing) ->
Packit 2cbdf3
              return Default { defaultTypeInfo = Nothing }
Packit 2cbdf3
            (Nothing, Nothing, Just actionty) ->
Packit 2cbdf3
              return Default { defaultTypeInfo = Just (Nothing, actionty) }
Packit 2cbdf3
            (Just _, Nothing, Just actionty) ->
Packit 2cbdf3
              return Default { defaultTypeInfo = Just (typeclass, actionty) }
Packit 2cbdf3
            (_, Just _, _) ->
Packit 2cbdf3
              dieAlex "%token directive only allowed with a wrapper"
Packit 2cbdf3
            (Just _, Nothing, Nothing) ->
Packit 2cbdf3
              dieAlex "%typeclass directive without %token directive"
Packit 2cbdf3
        [single]
Packit 2cbdf3
          | single == "gscan" ->
Packit 2cbdf3
            case (typeclass, token, action) of
Packit 2cbdf3
              (Nothing, Nothing, Nothing) ->
Packit 2cbdf3
                return GScan { gscanTypeInfo = Nothing }
Packit 2cbdf3
              (Nothing, Just tokenty, Nothing) ->
Packit 2cbdf3
                return GScan { gscanTypeInfo = Just (Nothing, tokenty) }
Packit 2cbdf3
              (Just _, Just tokenty, Nothing) ->
Packit 2cbdf3
                return GScan { gscanTypeInfo = Just (typeclass, tokenty) }
Packit 2cbdf3
              (_, _, Just _) ->
Packit 2cbdf3
                dieAlex "%action directive not allowed with a wrapper"
Packit 2cbdf3
              (Just _, Nothing, Nothing) ->
Packit 2cbdf3
                dieAlex "%typeclass directive without %token directive"
Packit 2cbdf3
          | single == "basic" || single == "basic-bytestring" ||
Packit 2cbdf3
            single == "strict-bytestring" ->
Packit 2cbdf3
            let
Packit 2cbdf3
              strty = case single of
Packit 2cbdf3
                "basic" -> Str
Packit 2cbdf3
                "basic-bytestring" -> Lazy
Packit 2cbdf3
                "strict-bytestring" -> Strict
Packit 2cbdf3
                _ -> error "Impossible case"
Packit 2cbdf3
            in case (typeclass, token, action) of
Packit 2cbdf3
              (Nothing, Nothing, Nothing) ->
Packit 2cbdf3
                return Basic { basicStrType = strty,
Packit 2cbdf3
                               basicTypeInfo = Nothing }
Packit 2cbdf3
              (Nothing, Just tokenty, Nothing) ->
Packit 2cbdf3
                return Basic { basicStrType = strty,
Packit 2cbdf3
                               basicTypeInfo = Just (Nothing, tokenty) }
Packit 2cbdf3
              (Just _, Just tokenty, Nothing) ->
Packit 2cbdf3
                return Basic { basicStrType = strty,
Packit 2cbdf3
                               basicTypeInfo = Just (typeclass, tokenty) }
Packit 2cbdf3
              (_, _, Just _) ->
Packit 2cbdf3
                dieAlex "%action directive not allowed with a wrapper"
Packit 2cbdf3
              (Just _, Nothing, Nothing) ->
Packit 2cbdf3
                dieAlex "%typeclass directive without %token directive"
Packit 2cbdf3
          | single == "posn" || single == "posn-bytestring" ->
Packit 2cbdf3
            let
Packit 2cbdf3
              isByteString = single == "posn-bytestring"
Packit 2cbdf3
            in case (typeclass, token, action) of
Packit 2cbdf3
              (Nothing, Nothing, Nothing) ->
Packit 2cbdf3
                return Posn { posnByteString = isByteString,
Packit 2cbdf3
                              posnTypeInfo = Nothing }
Packit 2cbdf3
              (Nothing, Just tokenty, Nothing) ->
Packit 2cbdf3
                return Posn { posnByteString = isByteString,
Packit 2cbdf3
                              posnTypeInfo = Just (Nothing, tokenty) }
Packit 2cbdf3
              (Just _, Just tokenty, Nothing) ->
Packit 2cbdf3
                return Posn { posnByteString = isByteString,
Packit 2cbdf3
                              posnTypeInfo = Just (typeclass, tokenty) }
Packit 2cbdf3
              (_, _, Just _) ->
Packit 2cbdf3
                  dieAlex "%action directive not allowed with a wrapper"
Packit 2cbdf3
              (Just _, Nothing, Nothing) ->
Packit 2cbdf3
                dieAlex "%typeclass directive without %token directive"
Packit 2cbdf3
          | single == "monad" || single == "monad-bytestring" ||
Packit 2cbdf3
            single == "monadUserState" ||
Packit 2cbdf3
            single == "monadUserState-bytestring" ->
Packit 2cbdf3
            let
Packit 2cbdf3
              isByteString = single == "monad-bytestring" ||
Packit 2cbdf3
                             single == "monadUserState-bytestring"
Packit 2cbdf3
              userState = single == "monadUserState" ||
Packit 2cbdf3
                          single == "monadUserState-bytestring"
Packit 2cbdf3
            in case (typeclass, token, action) of
Packit 2cbdf3
              (Nothing, Nothing, Nothing) ->
Packit 2cbdf3
                return Monad { monadByteString = isByteString,
Packit 2cbdf3
                               monadUserState = userState,
Packit 2cbdf3
                               monadTypeInfo = Nothing }
Packit 2cbdf3
              (Nothing, Just tokenty, Nothing) ->
Packit 2cbdf3
                return Monad { monadByteString = isByteString,
Packit 2cbdf3
                               monadUserState = userState,
Packit 2cbdf3
                               monadTypeInfo = Just (Nothing, tokenty) }
Packit 2cbdf3
              (Just _, Just tokenty, Nothing) ->
Packit 2cbdf3
                return Monad { monadByteString = isByteString,
Packit 2cbdf3
                               monadUserState = userState,
Packit 2cbdf3
                               monadTypeInfo = Just (typeclass, tokenty) }
Packit 2cbdf3
              (_, _, Just _) ->
Packit 2cbdf3
                  dieAlex "%action directive not allowed with a wrapper"
Packit 2cbdf3
              (Just _, Nothing, Nothing) ->
Packit 2cbdf3
                dieAlex "%typeclass directive without %token directive"
Packit 2cbdf3
          | otherwise -> dieAlex ("unknown wrapper type " ++ single)
Packit 2cbdf3
        _many -> dieAlex "multiple %wrapper directives"
Packit 2cbdf3
Packit 2cbdf3
-- inject some code, and add a {-# LINE #-} pragma at the top
Packit 2cbdf3
injectCode :: Maybe (AlexPosn,Code) -> FilePath -> Handle -> IO ()
Packit 2cbdf3
injectCode Nothing _ _ = return ()
Packit 2cbdf3
injectCode (Just (AlexPn _ ln _,code)) filename hdl = do
Packit 2cbdf3
  hPutStrLn hdl ("{-# LINE " ++ show ln ++ " \"" ++ filename ++ "\" #-}")
Packit 2cbdf3
  hPutStrLn hdl code
Packit 2cbdf3
Packit 2cbdf3
optsToInject :: Target -> [CLIFlags] -> String
Packit 2cbdf3
optsToInject GhcTarget _ = optNoWarnings ++ "{-# LANGUAGE CPP,MagicHash #-}\n"
Packit 2cbdf3
optsToInject _         _ = optNoWarnings ++ "{-# LANGUAGE CPP #-}\n"
Packit 2cbdf3
Packit 2cbdf3
optNoWarnings :: String
Packit 2cbdf3
optNoWarnings = "{-# OPTIONS_GHC -fno-warn-unused-binds -fno-warn-missing-signatures #-}\n"
Packit 2cbdf3
Packit 2cbdf3
importsToInject :: Target -> [CLIFlags] -> String
Packit 2cbdf3
importsToInject _ cli = always_imports ++ debug_imports ++ glaexts_import
Packit 2cbdf3
  where
Packit 2cbdf3
        glaexts_import | OptGhcTarget `elem` cli    = import_glaexts
Packit 2cbdf3
                       | otherwise                  = ""
Packit 2cbdf3
Packit 2cbdf3
        debug_imports  | OptDebugParser `elem` cli = import_debug
Packit 2cbdf3
                       | otherwise                 = ""
Packit 2cbdf3
Packit 2cbdf3
-- CPP is turned on for -fglasogw-exts, so we can use conditional
Packit 2cbdf3
-- compilation.  We need to #include "config.h" to get hold of
Packit 2cbdf3
-- WORDS_BIGENDIAN (see GenericTemplate.hs).
Packit 2cbdf3
Packit 2cbdf3
always_imports :: String
Packit 2cbdf3
always_imports = "#if __GLASGOW_HASKELL__ >= 603\n" ++
Packit 2cbdf3
                 "#include \"ghcconfig.h\"\n" ++
Packit 2cbdf3
                 "#elif defined(__GLASGOW_HASKELL__)\n" ++
Packit 2cbdf3
                 "#include \"config.h\"\n" ++
Packit 2cbdf3
                 "#endif\n" ++
Packit 2cbdf3
                 "#if __GLASGOW_HASKELL__ >= 503\n" ++
Packit 2cbdf3
                 "import Data.Array\n" ++
Packit 2cbdf3
                 "import Data.Array.Base (unsafeAt)\n" ++
Packit 2cbdf3
                 "#else\n" ++
Packit 2cbdf3
                 "import Array\n" ++
Packit 2cbdf3
                 "#endif\n"
Packit 2cbdf3
Packit 2cbdf3
import_glaexts :: String
Packit 2cbdf3
import_glaexts = "#if __GLASGOW_HASKELL__ >= 503\n" ++
Packit 2cbdf3
                 "import GHC.Exts\n" ++
Packit 2cbdf3
                 "#else\n" ++
Packit 2cbdf3
                 "import GlaExts\n" ++
Packit 2cbdf3
                 "#endif\n"
Packit 2cbdf3
Packit 2cbdf3
import_debug :: String
Packit 2cbdf3
import_debug   = "#if __GLASGOW_HASKELL__ >= 503\n" ++
Packit 2cbdf3
                 "import System.IO\n" ++
Packit 2cbdf3
                 "import System.IO.Unsafe\n" ++
Packit 2cbdf3
                 "import Debug.Trace\n" ++
Packit 2cbdf3
                 "#else\n" ++
Packit 2cbdf3
                 "import IO\n" ++
Packit 2cbdf3
                 "import IOExts\n" ++
Packit 2cbdf3
                 "#endif\n"
Packit 2cbdf3
Packit 2cbdf3
templateDir :: IO FilePath -> [CLIFlags] -> IO FilePath
Packit 2cbdf3
templateDir def cli
Packit 2cbdf3
  = case [ d | OptTemplateDir d <- cli ] of
Packit 2cbdf3
      [] -> def
Packit 2cbdf3
      ds -> return (last ds)
Packit 2cbdf3
Packit 2cbdf3
templateFile :: FilePath -> Target -> UsesPreds -> [CLIFlags] -> FilePath
Packit 2cbdf3
templateFile dir target usespreds cli
Packit 2cbdf3
  = dir ++ "/AlexTemplate" ++ maybe_ghc ++ maybe_debug ++ maybe_nopred
Packit 2cbdf3
  where
Packit 2cbdf3
        maybe_ghc = case target of
Packit 2cbdf3
                      GhcTarget -> "-ghc"
Packit 2cbdf3
                      _         -> ""
Packit 2cbdf3
Packit 2cbdf3
        maybe_debug
Packit 2cbdf3
          | OptDebugParser `elem` cli  = "-debug"
Packit 2cbdf3
          | otherwise                  = ""
Packit 2cbdf3
Packit 2cbdf3
        maybe_nopred =
Packit 2cbdf3
          case usespreds of
Packit 2cbdf3
            DoesntUsePreds | not (null maybe_ghc)
Packit 2cbdf3
                          && null maybe_debug -> "-nopred"
Packit 2cbdf3
            _                                 -> ""
Packit 2cbdf3
Packit 2cbdf3
wrapperFile :: FilePath -> Scheme -> Maybe FilePath
Packit 2cbdf3
wrapperFile dir scheme =
Packit 2cbdf3
  do
Packit 2cbdf3
    f <- wrapperName scheme
Packit 2cbdf3
    return (dir ++ "/AlexWrapper-" ++ f)
Packit 2cbdf3
Packit 2cbdf3
infoStart :: FilePath -> FilePath -> IO (String -> IO (), IO ())
Packit 2cbdf3
infoStart x_file info_file = do
Packit 2cbdf3
  bracketOnError
Packit 2cbdf3
        (alexOpenFile info_file WriteMode)
Packit 2cbdf3
        (\h -> do hClose h; removeFile info_file)
Packit 2cbdf3
        (\h -> do infoHeader h x_file
Packit 2cbdf3
                  return (hPutStr h, hClose h)
Packit 2cbdf3
        )
Packit 2cbdf3
Packit 2cbdf3
infoHeader :: Handle -> FilePath -> IO ()
Packit 2cbdf3
infoHeader h file = do
Packit 2cbdf3
--  hSetBuffering h NoBuffering
Packit 2cbdf3
  hPutStrLn h ("Info file produced by Alex version " ++ projectVersion ++
Packit 2cbdf3
                ", from " ++ file)
Packit 2cbdf3
  hPutStrLn h hline
Packit 2cbdf3
  hPutStr h "\n"
Packit 2cbdf3
Packit 2cbdf3
initialParserEnv :: (Map String CharSet, Map String RExp)
Packit 2cbdf3
initialParserEnv = (initSetEnv, initREEnv)
Packit 2cbdf3
Packit 2cbdf3
initSetEnv :: Map String CharSet
Packit 2cbdf3
initSetEnv = Map.fromList [("white", charSet " \t\n\v\f\r"),
Packit 2cbdf3
                           ("printable", charSetRange (chr 32) (chr 0x10FFFF)), -- FIXME: Look it up the unicode standard
Packit 2cbdf3
                           (".", charSetComplement emptyCharSet
Packit 2cbdf3
                            `charSetMinus` charSetSingleton '\n')]
Packit 2cbdf3
Packit 2cbdf3
initREEnv :: Map String RExp
Packit 2cbdf3
initREEnv = Map.empty
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- Command-line flags
Packit 2cbdf3
Packit 2cbdf3
data CLIFlags
Packit 2cbdf3
  = OptDebugParser
Packit 2cbdf3
  | OptGhcTarget
Packit 2cbdf3
  | OptOutputFile FilePath
Packit 2cbdf3
  | OptInfoFile (Maybe FilePath)
Packit 2cbdf3
  | OptTabSize String
Packit 2cbdf3
  | OptTemplateDir FilePath
Packit 2cbdf3
  | OptLatin1
Packit 2cbdf3
  | DumpHelp
Packit 2cbdf3
  | DumpVersion
Packit 2cbdf3
  deriving Eq
Packit 2cbdf3
Packit 2cbdf3
argInfo :: [OptDescr CLIFlags]
Packit 2cbdf3
argInfo  = [
Packit 2cbdf3
   Option ['o'] ["outfile"] (ReqArg OptOutputFile "FILE")
Packit 2cbdf3
        "write the output to FILE (default: file.hs)",
Packit 2cbdf3
   Option ['i'] ["info"] (OptArg OptInfoFile "FILE")
Packit 2cbdf3
        "put detailed state-machine info in FILE (or file.info)",
Packit 2cbdf3
   Option ['t'] ["template"] (ReqArg OptTemplateDir "DIR")
Packit 2cbdf3
        "look in DIR for template files",
Packit 2cbdf3
   Option ['g'] ["ghc"]    (NoArg OptGhcTarget)
Packit 2cbdf3
        "use GHC extensions",
Packit 2cbdf3
   Option ['l'] ["latin1"]    (NoArg OptLatin1)
Packit 2cbdf3
        "generated lexer will use the Latin-1 encoding instead of UTF-8",
Packit 2cbdf3
   Option ['s'] ["tab-size"] (ReqArg OptTabSize "NUMBER")
Packit 2cbdf3
        "set tab size to be used in the generated lexer (default: 8)",
Packit 2cbdf3
   Option ['d'] ["debug"] (NoArg OptDebugParser)
Packit 2cbdf3
        "produce a debugging scanner",
Packit 2cbdf3
   Option ['?'] ["help"] (NoArg DumpHelp)
Packit 2cbdf3
        "display this help and exit",
Packit 2cbdf3
   Option ['V','v'] ["version"] (NoArg DumpVersion)  -- ToDo: -v is deprecated!
Packit 2cbdf3
        "output version information and exit"
Packit 2cbdf3
  ]
Packit 2cbdf3
Packit 2cbdf3
-- -----------------------------------------------------------------------------
Packit 2cbdf3
-- Utils
Packit 2cbdf3
Packit 2cbdf3
getProgramName :: IO String
Packit 2cbdf3
getProgramName = liftM (`withoutSuffix` ".bin") getProgName
Packit 2cbdf3
   where str `withoutSuffix` suff
Packit 2cbdf3
            | suff `isSuffixOf` str = take (length str - length suff) str
Packit 2cbdf3
            | otherwise             = str
Packit 2cbdf3
Packit 2cbdf3
bye :: String -> IO a
Packit 2cbdf3
bye s = putStr s >> exitWith ExitSuccess
Packit 2cbdf3
Packit 2cbdf3
die :: String -> IO a
Packit 2cbdf3
die s = hPutStr stderr s >> exitWith (ExitFailure 1)
Packit 2cbdf3
Packit 2cbdf3
dieAlex :: String -> IO a
Packit 2cbdf3
dieAlex s = getProgramName >>= \prog -> die (prog ++ ": " ++ s)
Packit 2cbdf3
Packit 2cbdf3
#if __GLASGOW_HASKELL__ < 610
Packit 2cbdf3
bracketOnError
Packit 2cbdf3
        :: IO a         -- ^ computation to run first (\"acquire resource\")
Packit 2cbdf3
        -> (a -> IO b)  -- ^ computation to run last (\"release resource\")
Packit 2cbdf3
        -> (a -> IO c)  -- ^ computation to run in-between
Packit 2cbdf3
        -> IO c         -- returns the value from the in-between computation
Packit 2cbdf3
bracketOnError before after thing =
Packit 2cbdf3
  block (do
Packit 2cbdf3
    a <- before
Packit 2cbdf3
    r <- Exception.catch
Packit 2cbdf3
           (unblock (thing a))
Packit 2cbdf3
           (\e -> do { after a; throw e })
Packit 2cbdf3
    return r
Packit 2cbdf3
 )
Packit 2cbdf3
#endif