tock-mirror/Main.hs
Adam Sampson c8d5a4ff40 Add licensing information.
The compiler itself is under the GPLv2+; the support code that gets built into
user programs is under the LGPLv2+. This matches the existing practice for the
KRoC project.

(As with Occade, I've used the new GPLv3-style license header in the source
files, though, since that avoids having to update the FSF's postal address.)
2007-08-18 20:42:11 +00:00

180 lines
4.9 KiB
Haskell

{-
Tock: a compiler for parallel languages
Copyright (C) 2007 University of Kent
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
-}
-- | Driver for the compiler.
module Main where
import Control.Monad
import Control.Monad.Error
import Control.Monad.State
import List
import System
import System.Console.GetOpt
import System.IO
import AnalyseAsm
import CompState
import Errors
import GenerateC
import GenerateCPPCSP
import Parse
import Pass
import PrettyShow
import SimplifyExprs
import SimplifyProcs
import SimplifyTypes
import Unnest
passes :: [(String, Pass)]
passes =
[ ("Simplify types", simplifyTypes)
, ("Simplify expressions", simplifyExprs)
, ("Simplify processes", simplifyProcs)
, ("Flatten nested declarations", unnest)
]
type OptFunc = CompState -> IO CompState
options :: [OptDescr OptFunc]
options =
[ Option [] ["mode"] (ReqArg optMode "MODE") "select mode (options: parse, compile, post-c)"
, Option [] ["backend"] (ReqArg optBackend "BACKEND") "code-generating backend (options: c, cppcsp)"
, Option ['v'] ["verbose"] (NoArg $ optVerbose) "be more verbose (use multiple times for more detail)"
, Option ['o'] ["output"] (ReqArg optOutput "FILE") "output file (default \"-\")"
]
optMode :: String -> OptFunc
optMode s ps
= do mode <- case s of
"parse" -> return ModeParse
"compile" -> return ModeCompile
"post-c" -> return ModePostC
_ -> dieIO $ "Unknown mode: " ++ s
return $ ps { csMode = mode }
optBackend :: String -> OptFunc
optBackend s ps
= do backend <- case s of
"c" -> return BackendC
"cppcsp" -> return BackendCPPCSP
_ -> dieIO $ "Unknown backend: " ++ s
return $ ps { csBackend = backend }
optVerbose :: OptFunc
optVerbose ps = return $ ps { csVerboseLevel = csVerboseLevel ps + 1 }
optOutput :: String -> OptFunc
optOutput s ps = return $ ps { csOutputFile = s }
getOpts :: [String] -> IO ([OptFunc], [String])
getOpts argv =
case getOpt RequireOrder options argv of
(o,n,[] ) -> return (o,n)
(_,_,errs) -> error (concat errs ++ usageInfo header options)
where header = "Usage: tock [OPTION...] SOURCEFILE"
main :: IO ()
main = do
argv <- getArgs
(opts, args) <- getOpts argv
let fn = case args of
[fn] -> fn
_ -> error "Must specify a single input file"
initState <- foldl (>>=) (return emptyState) opts
let operation
= case csMode initState of
ModeParse -> compile fn
ModeCompile -> compile fn
ModePostC -> postCAnalyse fn
-- Run the compiler.
v <- evalStateT (runErrorT operation) initState
case v of
Left e -> dieIO e
Right r -> return ()
-- | Write the output to the file the user wanted.
writeOutput :: String -> PassM ()
writeOutput output
= do optsPS <- get
case csOutputFile optsPS of
"-" -> liftIO $ putStr output
file ->
do progress $ "Writing output file " ++ file
f <- liftIO $ openFile file WriteMode
liftIO $ hPutStr f output
liftIO $ hClose f
-- | Compile a file.
-- This is written in the PassM monad -- as are most of the things it calls --
-- because then it's very easy to pass the state around.
compile :: String -> PassM ()
compile fn
= do optsPS <- get
debug "{{{ Preprocess"
loadSource fn
debug "}}}"
debug "{{{ Parse"
progress "Parse"
ast1 <- parseProgram fn
debugAST ast1
debug "}}}"
showWarnings
output <-
case csMode optsPS of
ModeParse -> return $ show ast1
ModeCompile ->
do progress "Passes:"
ast2 <- (runPasses passes) ast1
debug "{{{ Generate code"
let generator
= case csBackend optsPS of
BackendC -> generateC
BackendCPPCSP -> generateCPPCSP
code <- generator ast2
debug "}}}"
return code
showWarnings
writeOutput output
progress "Done"
-- | Analyse an assembly file.
postCAnalyse :: String -> PassM ()
postCAnalyse fn
= do asm <- liftIO $ readSource fn
progress "Analysing assembly"
output <- analyseAsm asm
showWarnings
writeOutput output