Changed the C and C++ backends to write directly to the output file, to save building up the strings in memory

This commit is contained in:
Neil Brown 2008-03-08 14:10:05 +00:00
parent c87581e490
commit ba9ac70d7c
5 changed files with 83 additions and 46 deletions

17
Main.hs
View File

@ -272,9 +272,8 @@ compile mode fn outHandle
debugAST ast1 debugAST ast1
debug "}}}" debug "}}}"
output <-
case mode of case mode of
ModeParse -> return $ pshow ast1 ModeParse -> liftIO $ hPutStr outHandle $ pshow ast1
ModeFlowGraph -> ModeFlowGraph ->
do procs <- findAllProcesses do procs <- findAllProcesses
let fs :: Data t => t -> PassM String let fs :: Data t => t -> PassM String
@ -290,7 +289,7 @@ compile mode fn outHandle
-- graphs is of course identical to graphsTyped, as you can see here: -- graphs is of course identical to graphsTyped, as you can see here:
let (graphsTyped :: [Maybe (FlowGraph' Identity String A.Process)]) = map (transformMaybe fst) graphs let (graphsTyped :: [Maybe (FlowGraph' Identity String A.Process)]) = map (transformMaybe fst) graphs
-- TODO: output each process to a separate file, rather than just taking the first: -- TODO: output each process to a separate file, rather than just taking the first:
return $ head $ map makeFlowGraphInstr (catMaybes graphsTyped) liftIO $ hPutStr outHandle $ head $ map makeFlowGraphInstr (catMaybes graphsTyped)
ModeCompile -> ModeCompile ->
do progress "Passes:" do progress "Passes:"
@ -301,16 +300,12 @@ compile mode fn outHandle
progress $ "- Backend: " ++ (show $ csBackend optsPS) progress $ "- Backend: " ++ (show $ csBackend optsPS)
let generator let generator
= case csBackend optsPS of = case csBackend optsPS of
BackendC -> generateC BackendC -> generateC outHandle
BackendCPPCSP -> generateCPPCSP BackendCPPCSP -> generateCPPCSP outHandle
BackendDumpAST -> return . pshow BackendDumpAST -> liftIO . hPutStr outHandle . pshow
code <- generator ast2 generator ast2
debug "}}}" debug "}}}"
return code
liftIO $ hPutStr outHandle output
progress "Done" progress "Done"
-- | Analyse an assembly file. -- | Analyse an assembly file.

View File

@ -24,9 +24,8 @@ import Data.Generics
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import qualified Data.Set as Set import qualified Data.Set as Set
import Control.Monad.Reader
import Control.Monad.State import Control.Monad.State
import Control.Monad.Writer import System.IO
import Text.Printf import Text.Printf
import Text.Regex import Text.Regex
@ -139,10 +138,7 @@ cgenOps = GenOps {
--}}} --}}}
--{{{ top-level --{{{ top-level
generate :: GenOps -> A.AST -> PassM String generateC :: Handle -> A.AST -> PassM ()
generate ops ast = execWriterT (runReaderT (call genTopLevel ast) ops) >>* concat
generateC :: A.AST -> PassM String
generateC = generate cgenOps generateC = generate cgenOps
cgenTLPChannel :: TLPChannel -> CGen () cgenTLPChannel :: TLPChannel -> CGen ()
@ -153,7 +149,7 @@ cgenTLPChannel TLPError = tell ["err"]
cgenTopLevel :: A.AST -> CGen () cgenTopLevel :: A.AST -> CGen ()
cgenTopLevel s cgenTopLevel s
= do tell ["#include <tock_support_cif.h>\n"] = do tell ["#include <tock_support_cif.h>\n"]
cs <- get cs <- getCompState
(tlpName, chans) <- tlpInterface (tlpName, chans) <- tlpInterface
sequence_ $ map (call genForwardDeclaration) sequence_ $ map (call genForwardDeclaration)
@ -219,7 +215,7 @@ genRightB = tell ["}"]
cgenOverArray :: Meta -> A.Variable -> (SubscripterFunction -> Maybe (CGen ())) -> CGen () cgenOverArray :: Meta -> A.Variable -> (SubscripterFunction -> Maybe (CGen ())) -> CGen ()
cgenOverArray m var func cgenOverArray m var func
= do A.Array ds _ <- typeOfVariable var = do A.Array ds _ <- typeOfVariable var
specs <- sequence [makeNonceVariable "i" m A.Int A.VariableName A.Original | _ <- ds] specs <- sequence [csmLift $ makeNonceVariable "i" m A.Int A.VariableName A.Original | _ <- ds]
let indices = [A.Variable m n | A.Specification _ n _ <- specs] let indices = [A.Variable m n | A.Specification _ n _ <- specs]
let arg = (\var -> foldl (\v s -> A.SubscriptedVariable m s v) var [A.Subscript m $ A.ExprVariable m i | i <- indices]) let arg = (\var -> foldl (\v s -> A.SubscriptedVariable m s v) var [A.Subscript m $ A.ExprVariable m i | i <- indices])
@ -997,7 +993,7 @@ cgenReplicatorLoop (A.For m index base count)
general :: CGen () general :: CGen ()
general general
= do counter <- makeNonce "replicator_count" = do counter <- csmLift $ makeNonce "replicator_count"
tell ["int ", counter, "="] tell ["int ", counter, "="]
call genExpression count call genExpression count
tell [","] tell [","]
@ -1192,7 +1188,7 @@ cintroduceSpec (A.Specification _ n (A.IsExpr _ am t e))
(A.ValAbbrev, A.Record _, A.Literal _ _ _) -> (A.ValAbbrev, A.Record _, A.Literal _ _ _) ->
-- Record literals are even trickier, because there's no way of -- Record literals are even trickier, because there's no way of
-- directly writing a struct literal in C that you can use -> on. -- directly writing a struct literal in C that you can use -> on.
do tmp <- makeNonce "record_literal" do tmp <- csmLift $ makeNonce "record_literal"
tell ["const "] tell ["const "]
call genType t call genType t
tell [" ", tmp, " = "] tell [" ", tmp, " = "]
@ -1469,7 +1465,7 @@ cgenSeq s = call genStructured s doP
--{{{ if --{{{ if
cgenIf :: Meta -> A.Structured A.Choice -> CGen () cgenIf :: Meta -> A.Structured A.Choice -> CGen ()
cgenIf m s cgenIf m s
= do label <- makeNonce "if_end" = do label <- csmLift $ makeNonce "if_end"
tell ["/*",label,"*/"] tell ["/*",label,"*/"]
genIfBody label s genIfBody label s
call genStop m "no choice matched in IF process" call genStop m "no choice matched in IF process"
@ -1533,7 +1529,37 @@ cgenWhile e p
-- the same as PAR. -- the same as PAR.
cgenPar :: A.ParMode -> A.Structured A.Process -> CGen () cgenPar :: A.ParMode -> A.Structured A.Process -> CGen ()
cgenPar pm s cgenPar pm s
= do (count, _, _) <- constantFold $ countStructured s = do (size, _, _) <- constantFold $ addOne (sizeOfStructured s)
pids <- makeNonce "pids"
pris <- makeNonce "priorities"
index <- makeNonce "i"
when (pm == A.PriPar) $
do tell ["int ", pris, "["]
call genExpression size
tell ["];\n"]
tell ["Process *", pids, "["]
call genExpression size
tell ["];\n"]
tell ["int ", index, " = 0;\n"]
call genStructured s (createP pids pris index)
tell [pids, "[", index, "] = NULL;\n"]
tell ["if(",pids,"[0] != NULL){"] -- CIF seems to deadlock when you give ProcParList a list
-- beginning with NULL (i.e. with no processes)
case pm of
A.PriPar -> tell ["ProcPriParList (", pids, ", ", pris, ");\n"]
_ -> tell ["ProcParList (", pids, ");\n"]
tell ["}"]
tell [index, " = 0;\n"]
call genStructured s (freeP pids index)
where
createP pids pris index _ p
= do when (pm == A.PriPar) $
tell [pris, "[", index, "] = ", index, ";\n"]
tell [pids, "[", index, "++] = "]
genProcAlloc p
tell [";\n"]
freeP pids index _ _
= do tell ["ProcAllocClean (", pids, "[", index, "++]);\n"]
bar <- makeNonce "par_barrier" bar <- makeNonce "par_barrier"
tell ["LightProcBarrier ", bar, ";\n"] tell ["LightProcBarrier ", bar, ";\n"]
@ -1562,15 +1588,15 @@ cgenAlt isPri s
tell ["}\n"] tell ["}\n"]
-- Like occ21, this is always a PRI ALT, so we can use it for both. -- Like occ21, this is always a PRI ALT, so we can use it for both.
tell ["AltWait (wptr);\n"] tell ["AltWait (wptr);\n"]
id <- makeNonce "alt_id" id <- csmLift $ makeNonce "alt_id"
tell ["int ", id, " = 0;\n"] tell ["int ", id, " = 0;\n"]
tell ["{\n"] tell ["{\n"]
genAltDisable id s genAltDisable id s
tell ["}\n"] tell ["}\n"]
fired <- makeNonce "alt_fired" fired <- csmLift $ makeNonce "alt_fired"
tell ["int ", fired, " = AltEnd (wptr);\n"] tell ["int ", fired, " = AltEnd (wptr);\n"]
tell [id, " = 0;\n"] tell [id, " = 0;\n"]
label <- makeNonce "alt_end" label <- csmLift $ makeNonce "alt_end"
tell ["{\n"] tell ["{\n"]
genAltProcesses id fired label s genAltProcesses id fired label s
tell ["}\n"] tell ["}\n"]

View File

@ -21,8 +21,10 @@ module GenerateCBased where
import Control.Monad.Error import Control.Monad.Error
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Writer import Control.Monad.Writer
import Data.Generics import Data.Generics
import System.IO
import qualified AST as A import qualified AST as A
import CompState import CompState
@ -54,14 +56,26 @@ cCppCommonPreReq =
--{{{ monad definition --{{{ monad definition
type CGen' = WriterT [String] PassM type CGen' = StateT (Either [String] Handle) PassM
type CGen = ReaderT GenOps CGen' type CGen = ReaderT GenOps CGen'
instance Die CGen where instance Die CGen where
dieReport = throwError dieReport = throwError
instance CSMR m => CSMR (ReaderT GenOps m) where instance CSMR CGen' where
getCompState = lift getCompState getCompState = lift getCompState
instance CSMR CGen where
getCompState = lift getCompState
tell :: [String] -> CGen ()
tell x = do st <- get
case st of
Left prev -> put $ Left (prev ++ x)
Right h -> liftIO $ mapM_ (hPutStr h) x
csmLift :: PassM a -> CGen a
csmLift = lift . lift
--}}} --}}}
-- | A function that applies a subscript to a variable. -- | A function that applies a subscript to a variable.
@ -218,3 +232,5 @@ instance CGenCall (a -> b -> c -> d -> (CGen x, y -> CGen z)) where
fget :: (GenOps -> a) -> CGen a fget :: (GenOps -> a) -> CGen a
fget = asks fget = asks
generate :: GenOps -> Handle -> A.AST -> PassM ()
generate ops h ast = evalStateT (runReaderT (call genTopLevel ast) ops) (Right h)

View File

@ -31,11 +31,11 @@ For channels of direction 'A.DirInput' or 'A.DirOutput' I actually pass the Chan
module GenerateCPPCSP (cppcspPrereq, cppgenOps, generateCPPCSP, genCPPCSPPasses) where module GenerateCPPCSP (cppcspPrereq, cppgenOps, generateCPPCSP, genCPPCSPPasses) where
import Control.Monad.State import Control.Monad.State
import Control.Monad.Writer
import Data.Char import Data.Char
import Data.Generics import Data.Generics
import Data.List import Data.List
import Data.Maybe import Data.Maybe
import System.IO
import qualified AST as A import qualified AST as A
import CompState import CompState
@ -116,7 +116,7 @@ chansToAny x = do st <- get
--{{{ top-level --{{{ top-level
-- | Transforms the given AST into a pass that generates C++ code. -- | Transforms the given AST into a pass that generates C++ code.
generateCPPCSP :: A.AST -> PassM String generateCPPCSP :: Handle -> A.AST -> PassM ()
generateCPPCSP = generate cppgenOps generateCPPCSP = generate cppgenOps
cppcspPrereq :: [Property] cppcspPrereq :: [Property]
@ -133,7 +133,7 @@ cppgenTopLevel s
(name, chans) <- tlpInterface (name, chans) <- tlpInterface
tell ["int main (int argc, char** argv) { csp::Start_CPPCSP();"] tell ["int main (int argc, char** argv) { csp::Start_CPPCSP();"]
(chanType,writer) <- (chanType,writer) <-
do st <- get do st <- getCompState
case csFrontend st of case csFrontend st of
FrontendOccam -> return ("tockSendableArrayOfBytes","StreamWriterByteArray") FrontendOccam -> return ("tockSendableArrayOfBytes","StreamWriterByteArray")
_ -> return ("uint8_t","StreamWriter") _ -> return ("uint8_t","StreamWriter")
@ -246,14 +246,14 @@ Otherwise, it must not have.
-} -}
genCPPCSPTime :: A.Expression -> CGen String genCPPCSPTime :: A.Expression -> CGen String
genCPPCSPTime e genCPPCSPTime e
= do time <- makeNonce "time_exp" = do time <- csmLift $ makeNonce "time_exp"
tell ["unsigned ",time," = (unsigned)"] tell ["unsigned ",time," = (unsigned)"]
call genExpression e call genExpression e
tell [" ; "] tell [" ; "]
curTime <- makeNonce "time_exp" curTime <- csmLift $ makeNonce "time_exp"
curTimeLow <- makeNonce "time_exp" curTimeLow <- csmLift $ makeNonce "time_exp"
curTimeHigh <- makeNonce "time_exp" curTimeHigh <- csmLift $ makeNonce "time_exp"
retTime <- makeNonce "time_exp" retTime <- csmLift $ makeNonce "time_exp"
tell ["double ",curTime," = csp::GetSeconds(csp::CurrentTime());"] tell ["double ",curTime," = csp::GetSeconds(csp::CurrentTime());"]
tell ["unsigned ",curTimeLow," = (unsigned)remainder(1000000.0 * ",curTime,",4294967296.0);"] tell ["unsigned ",curTimeLow," = (unsigned)remainder(1000000.0 * ",curTime,",4294967296.0);"]
tell ["unsigned ",curTimeHigh," = (unsigned)((1000000.0 * ",curTime,") / 4294967296.0);"] tell ["unsigned ",curTimeHigh," = (unsigned)((1000000.0 * ",curTime,") / 4294967296.0);"]
@ -373,7 +373,7 @@ cppgenOutputCase c tag ois
--We use forking instead of Run\/InParallelOneThread, because it is easier to use forking with replication. --We use forking instead of Run\/InParallelOneThread, because it is easier to use forking with replication.
cppgenPar :: A.ParMode -> A.Structured A.Process -> CGen () cppgenPar :: A.ParMode -> A.Structured A.Process -> CGen ()
cppgenPar _ s cppgenPar _ s
= do forking <- makeNonce "forking" = do forking <- csmLift $ makeNonce "forking"
tell ["{ csp::ScopedForking ",forking," ; "] tell ["{ csp::ScopedForking ",forking," ; "]
call genStructured s (genPar' forking) call genStructured s (genPar' forking)
tell [" }"] tell [" }"]
@ -394,17 +394,17 @@ cppgenPar _ s
-- | Changed to use C++CSP's Alternative class: -- | Changed to use C++CSP's Alternative class:
cppgenAlt :: Bool -> A.Structured A.Alternative -> CGen () cppgenAlt :: Bool -> A.Structured A.Alternative -> CGen ()
cppgenAlt _ s cppgenAlt _ s
= do guards <- makeNonce "alt_guards" = do guards <- csmLift $ makeNonce "alt_guards"
tell ["std::list< csp::Guard* > ", guards, " ; "] tell ["std::list< csp::Guard* > ", guards, " ; "]
initAltGuards guards s initAltGuards guards s
alt <- makeNonce "alt" alt <- csmLift $ makeNonce "alt"
tell ["csp::Alternative ",alt, " ( ", guards, " ); "] tell ["csp::Alternative ",alt, " ( ", guards, " ); "]
id <- makeNonce "alt_id" id <- csmLift $ makeNonce "alt_id"
tell ["int ", id, " = 0;\n"] tell ["int ", id, " = 0;\n"]
fired <- makeNonce "alt_fired" fired <- csmLift $ makeNonce "alt_fired"
tell ["int ", fired, " = ", alt, " .priSelect();"] tell ["int ", fired, " = ", alt, " .priSelect();"]
label <- makeNonce "alt_end" label <- csmLift $ makeNonce "alt_end"
tell ["{\n"] tell ["{\n"]
genAltProcesses id fired label s genAltProcesses id fired label s
tell ["}\n"] tell ["}\n"]
@ -714,7 +714,7 @@ cppgenUnfoldedVariable m var
cppgenIf :: Meta -> A.Structured A.Choice -> CGen () cppgenIf :: Meta -> A.Structured A.Choice -> CGen ()
cppgenIf m s cppgenIf m s
= do ifExc <- makeNonce "if_exc" = do ifExc <- csmLift $ makeNonce "if_exc"
tell ["class ",ifExc, "{};try{"] tell ["class ",ifExc, "{};try{"]
genIfBody ifExc s genIfBody ifExc s
call genStop m "no choice matched in IF process" call genStop m "no choice matched in IF process"

View File

@ -34,7 +34,7 @@ module GenerateCTest (tests) where
import Control.Monad.Error import Control.Monad.Error
import Control.Monad.State import Control.Monad.State
import Control.Monad.Reader import Control.Monad.Reader
import Control.Monad.Writer import Control.Monad.Writer hiding (tell)
import Data.Generics import Data.Generics
import Data.List (isInfixOf, intersperse) import Data.List (isInfixOf, intersperse)
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
@ -109,7 +109,7 @@ evalCGen :: CGen () -> GenOps -> CompState -> IO (Either Errors.ErrorReport [Str
evalCGen act ops state = evalCGen' (runReaderT act ops) state evalCGen act ops state = evalCGen' (runReaderT act ops) state
evalCGen' :: CGen' () -> CompState -> IO (Either Errors.ErrorReport [String]) evalCGen' :: CGen' () -> CompState -> IO (Either Errors.ErrorReport [String])
evalCGen' act state = runWriterT (evalStateT (runErrorT $ execWriterT act) state) >>* fst evalCGen' act state = runWriterT (evalStateT (runErrorT $ execStateT act (Left []) >>* (\(Left x) -> x)) state) >>* fst
-- | Checks that running the test for the C and C++ backends produces the right output for each. -- | Checks that running the test for the C and C++ backends produces the right output for each.
testBothS :: testBothS ::