Nicer option parsing, and a -o option to write output to a file
This commit is contained in:
parent
e64fa81f83
commit
dd991a5587
38
fco2/Main.hs
38
fco2/Main.hs
|
@ -22,14 +22,26 @@ passes =
|
|||
, ("Flatten nested declarations", unnest)
|
||||
]
|
||||
|
||||
options :: [OptDescr Flag]
|
||||
type OptFunc = ParseState -> IO ParseState
|
||||
|
||||
options :: [OptDescr OptFunc]
|
||||
options =
|
||||
[ Option [] ["parse-only"] (NoArg ParseOnly) "only parse input file"
|
||||
, Option ['v'] ["verbose"] (NoArg Verbose) "show progress information"
|
||||
, Option [] ["debug"] (NoArg Debug) "show detailed information for debugging"
|
||||
[ Option [] ["parse-only"] (NoArg optParseOnly) "only parse input file"
|
||||
, Option ['v'] ["verbose"] (NoArg $ optVerboseLevel 1) "show progress information"
|
||||
, Option [] ["debug"] (NoArg $ optVerboseLevel 2) "show detailed information for debugging"
|
||||
, Option ['o'] ["output"] (ReqArg optOutput "FILE") "output file (default \"-\")"
|
||||
]
|
||||
|
||||
getOpts :: [String] -> IO ([Flag], [String])
|
||||
optParseOnly :: OptFunc
|
||||
optParseOnly ps = return $ ps { psParseOnly = True }
|
||||
|
||||
optVerboseLevel :: Int -> OptFunc
|
||||
optVerboseLevel n ps = return $ ps { psVerboseLevel = max (psVerboseLevel ps) n }
|
||||
|
||||
optOutput :: String -> OptFunc
|
||||
optOutput s ps = return $ ps { psOutputFile = s }
|
||||
|
||||
getOpts :: [String] -> IO ([OptFunc], [String])
|
||||
getOpts argv =
|
||||
case getOpt RequireOrder options argv of
|
||||
(o,n,[] ) -> return (o,n)
|
||||
|
@ -48,11 +60,7 @@ main = do
|
|||
[fn] -> fn
|
||||
_ -> error "Must specify a single input file"
|
||||
|
||||
let state0 = emptyState { psFlags = opts }
|
||||
|
||||
progressIO state0 $ "Options: " ++ show opts
|
||||
progressIO state0 $ "Compiling " ++ fn
|
||||
progressIO state0 ""
|
||||
state0 <- foldl (>>=) (return emptyState) opts
|
||||
|
||||
debugIO state0 "{{{ Preprocess"
|
||||
state0a <- loadSource fn state0
|
||||
|
@ -64,7 +72,7 @@ main = do
|
|||
debugASTIO state1 ast1
|
||||
debugIO state1 "}}}"
|
||||
|
||||
if ParseOnly `elem` opts then
|
||||
if psParseOnly state1 then
|
||||
putStrLn $ show ast1
|
||||
else do
|
||||
progressIO state1 "Passes:"
|
||||
|
@ -73,7 +81,13 @@ main = do
|
|||
debugIO state2 "{{{ Generate C"
|
||||
progressIO state2 "Generate C"
|
||||
c <- generateC state2 ast2
|
||||
putStr c
|
||||
case psOutputFile state2 of
|
||||
"-" -> putStr c
|
||||
file ->
|
||||
do progressIO state2 $ "Writing output file " ++ file
|
||||
f <- openFile file WriteMode
|
||||
hPutStr f c
|
||||
hClose f
|
||||
debugIO state2 "}}}"
|
||||
progressIO state2 "Done"
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ $(targets): $(sources)
|
|||
CFLAGS = -g -std=gnu99 -Wall `kroc --cflags` `kroc --ccincpath`
|
||||
|
||||
%.fco.c: %.occ fco
|
||||
./fco -v $< >$@ || ( rm -f $@; exit 1 )
|
||||
./fco -v -o $@ $<
|
||||
indent -kr -pcs $@
|
||||
|
||||
%.fco: %.fco.o fco_support.h kroc-wrapper-c.o kroc-wrapper.occ
|
||||
|
|
|
@ -8,13 +8,12 @@ import qualified AST as A
|
|||
import Errors
|
||||
import Metadata
|
||||
|
||||
data Flag = ParseOnly | Verbose | Debug
|
||||
deriving (Eq, Show, Data, Typeable)
|
||||
|
||||
-- | State necessary for compilation.
|
||||
data ParseState = ParseState {
|
||||
-- Set by Main
|
||||
psFlags :: [Flag],
|
||||
-- Set by Main (from command-line options)
|
||||
psVerboseLevel :: Int,
|
||||
psParseOnly :: Bool,
|
||||
psOutputFile :: String,
|
||||
|
||||
-- Set by preprocessor
|
||||
psSourceFiles :: [(String, String)],
|
||||
|
@ -41,7 +40,9 @@ instance Show (A.Process -> A.Process) where
|
|||
|
||||
emptyState :: ParseState
|
||||
emptyState = ParseState {
|
||||
psFlags = [],
|
||||
psVerboseLevel = 0,
|
||||
psParseOnly = False,
|
||||
psOutputFile = "-",
|
||||
|
||||
psSourceFiles = [],
|
||||
|
||||
|
|
20
fco2/Pass.hs
20
fco2/Pass.hs
|
@ -38,25 +38,29 @@ runPasses ((s, p):ps) ast
|
|||
debug $ "}}}"
|
||||
runPasses ps ast'
|
||||
|
||||
verboseMessage :: Int -> String -> PassM ()
|
||||
verboseMessage n s
|
||||
= do ps <- get
|
||||
liftIO $ verboseMessageIO n ps s
|
||||
|
||||
verboseMessageIO :: Int -> ParseState -> String -> IO ()
|
||||
verboseMessageIO n ps s = when (psVerboseLevel ps >= n) $ hPutStrLn stderr s
|
||||
|
||||
-- | Print a progress message if appropriate.
|
||||
progress :: String -> PassM ()
|
||||
progress s
|
||||
= do ps <- get
|
||||
liftIO $ progressIO ps s
|
||||
progress = verboseMessage 1
|
||||
|
||||
-- | Print a progress message if appropriate (in the IO monad).
|
||||
progressIO :: ParseState -> String -> IO ()
|
||||
progressIO ps s = when (Verbose `elem` psFlags ps) $ hPutStrLn stderr s
|
||||
progressIO = verboseMessageIO 1
|
||||
|
||||
-- | Print a debugging message if appropriate.
|
||||
debug :: String -> PassM ()
|
||||
debug s
|
||||
= do ps <- get
|
||||
liftIO $ debugIO ps s
|
||||
debug = verboseMessage 2
|
||||
|
||||
-- | Print a debugging message if appropriate (in the IO monad).
|
||||
debugIO :: ParseState -> String -> IO ()
|
||||
debugIO ps s = when (Debug `elem` psFlags ps) $ hPutStrLn stderr s
|
||||
debugIO = verboseMessageIO 2
|
||||
|
||||
-- | Dump the AST and parse state if appropriate.
|
||||
debugAST :: A.Process -> PassM ()
|
||||
|
|
|
@ -23,8 +23,6 @@ Types needs cleaning up and Haddocking.
|
|||
|
||||
Add an option for whether to compile out overflow/bounds checks.
|
||||
|
||||
Add a -o option to control where the output goes (stdout by default for now).
|
||||
|
||||
## Parser
|
||||
|
||||
The indentation parser is way too simplistic.
|
||||
|
@ -37,6 +35,8 @@ Record literals aren't implemented.
|
|||
|
||||
Expression simplification -- this should use generics, so that we can have a
|
||||
default behaviour that simplifies expressions inside another one.
|
||||
(More generally, simplifyExpressions should really be split into a simplifier
|
||||
and a constant-finder -- or should return two values.)
|
||||
|
||||
Output item expressions should be pulled up to variables.
|
||||
|
||||
|
@ -73,9 +73,6 @@ to be a bad idea for very large counts (since I assume it'll allocate off the
|
|||
stack). We should probably do a malloc if it's not determinable at compile
|
||||
time.
|
||||
|
||||
The operator functions need to have the type name attached -- they'll only work
|
||||
for INT at the moment.
|
||||
|
||||
Real-to-integer conversions don't work correctly.
|
||||
|
||||
## Long-term
|
||||
|
|
Loading…
Reference in New Issue
Block a user