------------------------------------------------------------------------------
--- $Id: Main.hs,v 1.8 2001/01/12 22:54:23 qrczak Exp $
---
--- (originally "GlueHsc.hs" by Marcin 'Qrczak' Kowalczyk)
+------------------------------------------------------------------------
+-- $Id: Main.hs,v 1.26 2001/03/16 09:07:41 qrczak Exp $
--
-- Program for converting .hsc files to .hs files, by converting the
-- file into a C program which is run to generate the Haskell source.
-- See the documentation in the Users' Guide for more details.
import GetOpt
-import System (getProgName, getArgs, ExitCode(..), system, exitWith, exitFailure)
-import Directory (removeFile)
-import Parsec
-import Monad (liftM, liftM2, when)
-import Char (ord, intToDigit, isSpace, isAlpha, isAlphaNum, toUpper)
-import List (intersperse)
+import System (getProgName, getArgs, ExitCode(..), exitWith, exitFailure)
+import KludgedSystem (system, defaultCompiler)
+import Directory (removeFile)
+import Monad (MonadPlus(..), liftM, liftM2, when, unless)
+import Char (isAlpha, isAlphaNum, isSpace, isDigit, toUpper, intToDigit, ord)
+import List (intersperse)
version :: String
-version = "hsc2hs-0.64"
+version = "hsc2hs-0.65"
data Flag
= Help
| Version
- | Template String
- | Compiler String
- | Linker String
- | CompFlag String
- | LinkFlag String
- | Include String
+ | Template String
+ | Compiler String
+ | Linker String
+ | CompFlag String
+ | LinkFlag String
+ | NoCompile
+ | Include String
include :: String -> Flag
include s@('\"':_) = Include s
options :: [OptDescr Flag]
options = [
- Option "t" ["template"] (ReqArg Template "FILE") "template file",
- Option "" ["cc"] (ReqArg Compiler "PROG") "C compiler to use",
- Option "" ["ld"] (ReqArg Linker "PROG") "linker to use",
- Option "" ["cflag"] (ReqArg CompFlag "FLAG") "flag to pass to the C compiler",
- Option "I" [] (ReqArg (CompFlag . ("-I"++))
- "DIR") "passed to the C compiler",
- Option "" ["lflag"] (ReqArg LinkFlag "FLAG") "flag to pass to the linker",
- Option "" ["include"] (ReqArg include "FILE") "as if placed in the source",
- Option "" ["help"] (NoArg Help) "display this help and exit",
- Option "" ["version"] (NoArg Version) "output version information and exit"]
+ Option "t" ["template"] (ReqArg Template "FILE") "template file",
+ Option "c" ["cc"] (ReqArg Compiler "PROG") "C compiler to use",
+ Option "l" ["ld"] (ReqArg Linker "PROG") "linker to use",
+ Option "C" ["cflag"] (ReqArg CompFlag "FLAG") "flag to pass to the C compiler",
+ Option "I" [] (ReqArg (CompFlag . ("-I"++))
+ "DIR") "passed to the C compiler",
+ Option "L" ["lflag"] (ReqArg LinkFlag "FLAG") "flag to pass to the linker",
+ Option "" ["no-compile"] (NoArg NoCompile) "stop after writing *.hs_make.c",
+ Option "i" ["include"] (ReqArg include "FILE") "as if placed in the source",
+ Option "" ["help"] (NoArg Help) "display this help and exit",
+ Option "" ["version"] (NoArg Version) "output version information and exit"]
main :: IO ()
main = do
processFile :: [Flag] -> String -> IO ()
processFile flags name = do
- parsed <- parseFromFile parser name
- case parsed of
- Left err -> do print err; exitFailure
- Right toks -> output flags name toks
+ s <- readFile name
+ case parser of
+ Parser p -> case p (SourcePos name 1) s of
+ Success _ _ _ toks -> output flags name toks
+ Failure (SourcePos name' line) msg -> do
+ putStrLn (name'++":"++show line++": "++msg)
+ exitFailure
+
+------------------------------------------------------------------------
+-- A deterministic parser which remembers the text which has been parsed.
+
+newtype Parser a = Parser (SourcePos -> String -> ParseResult a)
+
+data ParseResult a = Success !SourcePos String String a
+ | Failure !SourcePos String
+
+data SourcePos = SourcePos String !Int
+
+updatePos :: SourcePos -> Char -> SourcePos
+updatePos pos@(SourcePos name line) ch = case ch of
+ '\n' -> SourcePos name (line + 1)
+ _ -> pos
+
+instance Monad Parser where
+ return a = Parser $ \pos s -> Success pos [] s a
+ Parser m >>= k =
+ Parser $ \pos s -> case m pos s of
+ Success pos' out1 s' a -> case k a of
+ Parser k' -> case k' pos' s' of
+ Success pos'' out2 imp'' b ->
+ Success pos'' (out1++out2) imp'' b
+ Failure pos'' msg -> Failure pos'' msg
+ Failure pos' msg -> Failure pos' msg
+ fail msg = Parser $ \pos _ -> Failure pos msg
+
+instance MonadPlus Parser where
+ mzero = fail "mzero"
+ Parser m `mplus` Parser n =
+ Parser $ \pos s -> case m pos s of
+ success@(Success _ _ _ _) -> success
+ Failure _ _ -> n pos s
+
+getPos :: Parser SourcePos
+getPos = Parser $ \pos s -> Success pos [] s pos
+
+setPos :: SourcePos -> Parser ()
+setPos pos = Parser $ \_ s -> Success pos [] s ()
+
+message :: Parser a -> String -> Parser a
+Parser m `message` msg =
+ Parser $ \pos s -> case m pos s of
+ success@(Success _ _ _ _) -> success
+ Failure pos' _ -> Failure pos' msg
+
+catchOutput_ :: Parser a -> Parser String
+catchOutput_ (Parser m) =
+ Parser $ \pos s -> case m pos s of
+ Success pos' out s' _ -> Success pos' [] s' out
+ Failure pos' msg -> Failure pos' msg
+
+fakeOutput :: Parser a -> String -> Parser a
+Parser m `fakeOutput` out =
+ Parser $ \pos s -> case m pos s of
+ Success pos' _ s' a -> Success pos' out s' a
+ Failure pos' msg -> Failure pos' msg
+
+lookAhead :: Parser String
+lookAhead = Parser $ \pos s -> Success pos [] s s
+
+satisfy :: (Char -> Bool) -> Parser Char
+satisfy p =
+ Parser $ \pos s -> case s of
+ c:cs | p c -> Success (updatePos pos c) [c] cs c
+ _ -> Failure pos "Bad character"
+
+char_ :: Char -> Parser ()
+char_ c = do
+ satisfy (== c) `message` (show c++" expected")
+ return ()
+
+anyChar_ :: Parser ()
+anyChar_ = do
+ satisfy (const True) `message` "Unexpected end of file"
+ return ()
+
+any2Chars_ :: Parser ()
+any2Chars_ = anyChar_ >> anyChar_
+
+many :: Parser a -> Parser [a]
+many p = many1 p `mplus` return []
+
+many1 :: Parser a -> Parser [a]
+many1 p = liftM2 (:) p (many p)
+
+many_ :: Parser a -> Parser ()
+many_ p = many1_ p `mplus` return ()
+
+many1_ :: Parser a -> Parser ()
+many1_ p = p >> many_ p
+
+manySatisfy, manySatisfy1 :: (Char -> Bool) -> Parser String
+manySatisfy = many . satisfy
+manySatisfy1 = many1 . satisfy
+
+manySatisfy_, manySatisfy1_ :: (Char -> Bool) -> Parser ()
+manySatisfy_ = many_ . satisfy
+manySatisfy1_ = many1_ . satisfy
+
+------------------------------------------------------------------------
+-- Parser of hsc syntax.
data Token
- = Text String
- | Special String String
+ = Text SourcePos String
+ | Special SourcePos String String
parser :: Parser [Token]
-parser = many (text <|> special)
-
-text :: Parser Token
-text =
- liftM (Text . concat) $ many1
- ( many1 (satisfy (\ch -> not (isAlpha ch || ch `elem` "\"#'-_{")))
- <|> (do a <- satisfy (\ch -> isAlpha ch || ch == '_')
- b <- many (satisfy (\ch -> isAlphaNum ch || ch == '_' || ch == '\''))
- return (a:b))
- <|> (do char '\"'; a <- hsString '\"'; char '\"'; return ("\""++a++"\""))
- <|> (do try (string "##"); return "#")
- <|> (do char '\''; a <- hsString '\''; char '\''; return ("\'"++a++"\'"))
- <|> (do try (string "--"); a <- many (satisfy (/= '\n')); return ("--"++a))
- <|> string "-"
- <|> (do try (string "{-"); a <- hsComment; return ("{-"++a))
- <|> string "{"
- <?> "Haskell source")
-
-hsComment :: Parser String
-hsComment =
- ( (do a <- many1 (noneOf "-{"); b <- hsComment; return (a++b))
- <|> try (string "-}")
- <|> (do char '-'; b <- hsComment; return ('-':b))
- <|> (do try (string "{-"); a <- hsComment; b <- hsComment; return ("{-"++a++b))
- <|> (do char '{'; b <- hsComment; return ('{':b))
- <?> "Haskell comment")
-
-hsString :: Char -> Parser String
-hsString quote =
- liftM concat $ many
- ( many1 (noneOf (quote:"\n\\"))
- <|> (do char '\\'; a <- escape; return ('\\':a))
- <?> "Haskell character or string")
+parser = do
+ pos <- getPos
+ t <- catchOutput_ text
+ s <- lookAhead
+ rest <- case s of
+ [] -> return []
+ _:_ -> liftM2 (:) (special `fakeOutput` []) parser
+ return (if null t then rest else Text pos t : rest)
+
+text :: Parser ()
+text = do
+ s <- lookAhead
+ case s of
+ [] -> return ()
+ c:_ | isAlpha c || c == '_' -> do
+ anyChar_
+ manySatisfy_ (\c' -> isAlphaNum c' || c' == '_' || c' == '\'')
+ text
+ c:_ | isHsSymbol c -> do
+ symb <- catchOutput_ (manySatisfy_ isHsSymbol)
+ case symb of
+ "#" -> return ()
+ '-':'-':symb' | all (== '-') symb' -> do
+ return () `fakeOutput` symb
+ manySatisfy_ (/= '\n')
+ text
+ _ -> do
+ return () `fakeOutput` unescapeHashes symb
+ text
+ '\"':_ -> do anyChar_; hsString '\"'; text
+ '\'':_ -> do anyChar_; hsString '\''; text
+ '{':'-':_ -> do any2Chars_; linePragma `mplus` hsComment; text
+ _:_ -> do anyChar_; text
+
+hsString :: Char -> Parser ()
+hsString quote = do
+ s <- lookAhead
+ case s of
+ [] -> return ()
+ c:_ | c == quote -> anyChar_
+ '\\':c:_
+ | isSpace c -> do
+ anyChar_
+ manySatisfy_ isSpace
+ char_ '\\' `mplus` return ()
+ hsString quote
+ | otherwise -> do any2Chars_; hsString quote
+ _:_ -> do anyChar_; hsString quote
+
+hsComment :: Parser ()
+hsComment = do
+ s <- lookAhead
+ case s of
+ [] -> return ()
+ '-':'}':_ -> any2Chars_
+ '{':'-':_ -> do any2Chars_; hsComment; hsComment
+ _:_ -> do anyChar_; hsComment
+
+linePragma :: Parser ()
+linePragma = do
+ char_ '#'
+ manySatisfy_ isSpace
+ satisfy (\c -> c == 'L' || c == 'l')
+ satisfy (\c -> c == 'I' || c == 'i')
+ satisfy (\c -> c == 'N' || c == 'n')
+ satisfy (\c -> c == 'E' || c == 'e')
+ manySatisfy1_ isSpace
+ line <- liftM read $ manySatisfy1 isDigit
+ manySatisfy1_ isSpace
+ char_ '\"'
+ name <- manySatisfy (/= '\"')
+ char_ '\"'
+ manySatisfy_ isSpace
+ char_ '#'
+ char_ '-'
+ char_ '}'
+ setPos (SourcePos name (line - 1))
+
+isHsSymbol :: Char -> Bool
+isHsSymbol '!' = True; isHsSymbol '#' = True; isHsSymbol '$' = True
+isHsSymbol '%' = True; isHsSymbol '&' = True; isHsSymbol '*' = True
+isHsSymbol '+' = True; isHsSymbol '.' = True; isHsSymbol '/' = True
+isHsSymbol '<' = True; isHsSymbol '=' = True; isHsSymbol '>' = True
+isHsSymbol '?' = True; isHsSymbol '@' = True; isHsSymbol '\\' = True
+isHsSymbol '^' = True; isHsSymbol '|' = True; isHsSymbol '-' = True
+isHsSymbol '~' = True
+isHsSymbol _ = False
+
+unescapeHashes :: String -> String
+unescapeHashes [] = []
+unescapeHashes ('#':'#':s) = '#' : unescapeHashes s
+unescapeHashes (c:s) = c : unescapeHashes s
+
+lookAheadC :: Parser String
+lookAheadC = liftM joinLines lookAhead
where
- escape = (do a <- many1 (satisfy isSpace); char '\\'; return (a++"\\"))
- <|> (do a <- anyChar; return [a])
+ joinLines [] = []
+ joinLines ('\\':'\n':s) = joinLines s
+ joinLines (c:s) = c : joinLines s
+
+satisfyC :: (Char -> Bool) -> Parser Char
+satisfyC p = do
+ s <- lookAhead
+ case s of
+ '\\':'\n':_ -> do any2Chars_ `fakeOutput` []; satisfyC p
+ _ -> satisfy p
+
+charC_ :: Char -> Parser ()
+charC_ c = do
+ satisfyC (== c) `message` (show c++" expected")
+ return ()
+
+anyCharC_ :: Parser ()
+anyCharC_ = do
+ satisfyC (const True) `message` "Unexpected end of file"
+ return ()
+
+any2CharsC_ :: Parser ()
+any2CharsC_ = anyCharC_ >> anyCharC_
+
+manySatisfyC :: (Char -> Bool) -> Parser String
+manySatisfyC = many . satisfyC
+
+manySatisfyC_ :: (Char -> Bool) -> Parser ()
+manySatisfyC_ = many_ . satisfyC
special :: Parser Token
special = do
- char '#'
- skipMany (oneOf " \t")
- key <- liftM2 (:) (letter <|> char '_') (many (alphaNum <|> char '_'))
- <?> "hsc directive"
- skipMany (oneOf " \t")
- arg <- argument pzero
- return (Special key arg)
-
-argument :: Parser String -> Parser String
-argument eol =
- liftM concat $ many
- ( many1 (noneOf "\n\"\'()/[\\]{}")
- <|> eol
- <|> (do char '\"'; a <- cString '\"'; char '\"'; return ("\""++a++"\""))
- <|> (do char '\''; a <- cString '\''; char '\''; return ("\'"++a++"\'"))
- <|> (do char '('; a <- nested; char ')'; return ("("++a++")"))
- <|> (do try (string "/*"); cComment; return " ")
- <|> (do try (string "//"); skipMany (satisfy (/= '\n')); return " ")
- <|> string "/"
- <|> (do char '['; a <- nested; char ']'; return ("["++a++"]"))
- <|> (do char '\\'; a <- anyChar; return $ if a == '\n' then [] else ['\\',a])
- <|> (do char '{'; a <- nested; char '}'; return ("{"++a++"}"))
- <?> "C expression")
- where nested = argument (string "\n")
+ manySatisfyC_ (\c -> isSpace c && c /= '\n')
+ s <- lookAheadC
+ case s of
+ '{':_ -> do
+ anyCharC_
+ manySatisfyC_ isSpace
+ sp <- keyArg (== '\n')
+ charC_ '}'
+ return sp
+ _ -> keyArg (const False)
+
+keyArg :: (Char -> Bool) -> Parser Token
+keyArg eol = do
+ pos <- getPos
+ key <- keyword `message` "hsc keyword or '{' expected"
+ manySatisfyC_ (\c' -> isSpace c' && c' /= '\n' || eol c')
+ arg <- catchOutput_ (argument eol)
+ return (Special pos key arg)
+
+keyword :: Parser String
+keyword = do
+ c <- satisfyC (\c' -> isAlpha c' || c' == '_')
+ cs <- manySatisfyC (\c' -> isAlphaNum c' || c' == '_')
+ return (c:cs)
+
+argument :: (Char -> Bool) -> Parser ()
+argument eol = do
+ s <- lookAheadC
+ case s of
+ [] -> return ()
+ c:_ | eol c -> do anyCharC_; argument eol
+ '\n':_ -> return ()
+ '\"':_ -> do anyCharC_; cString '\"'; argument eol
+ '\'':_ -> do anyCharC_; cString '\''; argument eol
+ '(':_ -> do anyCharC_; nested ')'; argument eol
+ ')':_ -> return ()
+ '/':'*':_ -> do any2CharsC_; cComment; argument eol
+ '/':'/':_ -> do
+ any2CharsC_; manySatisfyC_ (/= '\n'); argument eol
+ '[':_ -> do anyCharC_; nested ']'; argument eol
+ ']':_ -> return ()
+ '{':_ -> do anyCharC_; nested '}'; argument eol
+ '}':_ -> return ()
+ _:_ -> do anyCharC_; argument eol
+
+nested :: Char -> Parser ()
+nested c = do argument (== '\n'); charC_ c
cComment :: Parser ()
-cComment =
- ( (do skipMany1 (noneOf "*"); cComment)
- <|> (do try (string "*/"); return ())
- <|> (do char '*'; cComment)
- <?> "C comment")
-
-cString :: Char -> Parser String
-cString quote =
- liftM concat $ many
- ( many1 (noneOf (quote:"\n\\"))
- <|> (do char '\\'; a <- anyChar; return ['\\',a])
- <?> "C character or string")
+cComment = do
+ s <- lookAheadC
+ case s of
+ [] -> return ()
+ '*':'/':_ -> do any2CharsC_
+ _:_ -> do anyCharC_; cComment
+
+cString :: Char -> Parser ()
+cString quote = do
+ s <- lookAheadC
+ case s of
+ [] -> return ()
+ c:_ | c == quote -> anyCharC_
+ '\\':_:_ -> do any2CharsC_; cString quote
+ _:_ -> do anyCharC_; cString quote
+
+------------------------------------------------------------------------
+-- Output the output files.
output :: [Flag] -> String -> [Token] -> IO ()
output flags name toks = let
baseName = case reverse name of
'c':base -> reverse base
_ -> name++".hs"
- cProgName = baseName++"c_make_hs.c"
- oProgName = baseName++"c_make_hs.o"
- progName = baseName++"c_make_hs"
+ cProgName = baseName++"_make.c"
+ oProgName = baseName++"_make.o"
+ progName = baseName++"_make"
outHsName = baseName
outHName = baseName++".h"
outCName = baseName++".c"
'/':_ -> progName
_ -> "./"++progName
- specials = [(key, arg) | Special key arg <- toks]
+ specials = [(pos, key, arg) | Special pos key arg <- toks]
- needsC = any (\(key, _) -> key == "def") specials
+ needsC = any (\(_, key, _) -> key == "def") specials
needsH = needsC
includeGuard = map fixChar outHName
[c] -> return c
_ -> onlyOne "compiler"
linker <- case [l | Linker l <- flags] of
- [] -> return "gcc"
+ [] -> return defaultCompiler
[l] -> return l
_ -> onlyOne "linker"
-
+
writeFile cProgName $
concat ["#include \""++t++"\"\n" | Template t <- flags]++
concat ["#include "++f++"\n" | Include f <- flags]++
outHeaderCProg specials++
"\nint main (void)\n{\n"++
outHeaderHs flags (if needsH then Just outHName else Nothing) specials++
+ outHsLine (SourcePos name 0)++
concatMap outTokenHs toks++
" return 0;\n}\n"
+ unless (null [() | NoCompile <- flags]) $ exitWith ExitSuccess
+
compilerStatus <- system $
compiler++
" -c"++
\#if __GLASGOW_HASKELL__ && __GLASGOW_HASKELL__ < 409\n\
\#include <Rts.h>\n\
\#endif\n\
- \#include <HsFFI.h>\n"++
+ \#include <HsFFI.h>\n\
+ \#if __NHC__\n\
+ \#undef HsChar\n\
+ \#define HsChar int\n\
+ \#endif\n"++
concat ["#include "++n++"\n" | Include n <- flags]++
concatMap outTokenH specials++
"#endif\n"
putStrLn ("Only one "++what++" may be specified")
exitFailure
-outHeaderCProg :: [(String, String)] -> String
-outHeaderCProg = concatMap $ \(key, arg) -> case key of
- "include" -> "#include "++arg++"\n"
- "define" -> "#define "++arg++"\n"
- "undef" -> "#undef "++arg++"\n"
- "def" -> case arg of
- 's':'t':'r':'u':'c':'t':' ':_ -> arg++"\n"
- 't':'y':'p':'e':'d':'e':'f':' ':_ -> arg++"\n"
+outHeaderCProg :: [(SourcePos, String, String)] -> String
+outHeaderCProg =
+ concatMap $ \(pos, key, arg) -> case key of
+ "include" -> outCLine pos++"#include "++arg++"\n"
+ "define" -> outCLine pos++"#define "++arg++"\n"
+ "undef" -> outCLine pos++"#undef "++arg++"\n"
+ "def" -> case arg of
+ 's':'t':'r':'u':'c':'t':' ':_ -> outCLine pos++arg++"\n"
+ 't':'y':'p':'e':'d':'e':'f':' ':_ -> outCLine pos++arg++"\n"
+ _ -> ""
+ _ | conditional key -> outCLine pos++"#"++key++" "++arg++"\n"
+ "let" -> case break (== '=') arg of
+ (_, "") -> ""
+ (header, _:body) -> case break isSpace header of
+ (name, args) ->
+ outCLine pos++
+ "#define hsc_"++name++"("++dropWhile isSpace args++") \
+ \printf ("++joinLines body++");\n"
_ -> ""
- _ | conditional key -> "#"++key++" "++arg++"\n"
- "let" -> case break (== '=') arg of
- (_, "") -> ""
- (header, _:body) -> case break isSpace header of
- (name, args) ->
- "#define hsc_"++name++"("++dropWhile isSpace args++") \
- \printf ("++joinLines body++");\n"
- _ -> ""
where
joinLines = concat . intersperse " \\\n" . lines
-outHeaderHs :: [Flag] -> Maybe String -> [(String, String)] -> String
+outHeaderHs :: [Flag] -> Maybe String -> [(SourcePos, String, String)] -> String
outHeaderHs flags inH toks =
- " hsc_begin_options();\n"++
+ "#if __GLASGOW_HASKELL__ && __GLASGOW_HASKELL__ < 409\n\
+ \ printf (\"{-# OPTIONS -optc-D__GLASGOW_HASKELL__=%d #-}\\n\", \
+ \__GLASGOW_HASKELL__);\n\
+ \#endif\n"++
includeH++
- concatMap outSpecial toks++
- " hsc_end_options();\n\n"
+ concatMap outSpecial toks
where
- outSpecial (key, arg) = case key of
+ outSpecial (pos, key, arg) = case key of
"include" -> case inH of
Nothing -> outOption ("-#include "++arg)
Just _ -> ""
"define" -> case inH of
Nothing | goodForOptD arg -> outOption ("-optc-D"++toOptD arg)
_ -> ""
- "option" -> outOption arg
- _ | conditional key -> "#"++key++" "++arg++"\n"
+ _ | conditional key -> outCLine pos++"#"++key++" "++arg++"\n"
_ -> ""
goodForOptD arg = case arg of
"" -> True
| name <- case inH of
Nothing -> [name | Include name <- flags]
Just name -> ["\""++name++"\""]]
- outOption s = " hsc_option (\""++showCString s++"\");\n"
+ outOption s = " printf (\"{-# OPTIONS %s #-}\\n\", \""++
+ showCString s++"\");\n"
outTokenHs :: Token -> String
-outTokenHs (Text s) = " fputs (\""++showCString s++"\", stdout);\n"
-outTokenHs (Special key arg) = case key of
- "include" -> ""
- "define" -> ""
- "undef" -> ""
- "option" -> ""
- "def" -> ""
- _ | conditional key -> "#"++key++" "++arg++"\n"
- "let" -> ""
- _ -> " hsc_"++key++" ("++arg++");\n"
-
-outTokenH :: (String, String) -> String
-outTokenH (key, arg) = case key of
- "include" -> "#include "++arg++"\n"
- "define" -> "#define " ++arg++"\n"
- "undef" -> "#undef " ++arg++"\n"
- "def" -> case arg of
- 's':'t':'r':'u':'c':'t':' ':_ -> arg++"\n"
- 't':'y':'p':'e':'d':'e':'f':' ':_ -> arg++"\n"
- 'i':'n':'l':'i':'n':'e':' ':_ ->
- "#ifdef __GNUC__\n\
- \extern\n\
- \#endif\n"++
- arg++"\n"
- _ -> "extern "++header++";\n"
- where header = takeWhile (\c -> c/='{' && c/='=') arg
- _ | conditional key -> "#"++key++" "++arg++"\n"
- _ -> ""
-
-outTokenC :: (String, String) -> String
-outTokenC (key, arg) = case key of
- "def" -> case arg of
- 's':'t':'r':'u':'c':'t':' ':_ -> ""
- 't':'y':'p':'e':'d':'e':'f':' ':_ -> ""
- 'i':'n':'l':'i':'n':'e':' ':_ ->
- "#ifndef __GNUC__\n\
- \extern\n\
- \#endif\n"++
- header++
- "\n#ifndef __GNUC__\n\
- \;\n\
- \#else\n"++
- body++
- "\n#endif\n"
- _ -> arg++"\n"
- where (header, body) = span (\c -> c/='{' && c/='=') arg
- _ | conditional key -> "#"++key++" "++arg++"\n"
- _ -> ""
+outTokenHs (Text pos text) =
+ case break (== '\n') text of
+ (all, []) -> outText all
+ (first, _:rest) ->
+ outText (first++"\n")++
+ outHsLine pos++
+ outText rest
+ where
+ outText s = " fputs (\""++showCString s++"\", stdout);\n"
+outTokenHs (Special pos key arg) =
+ case key of
+ "include" -> ""
+ "define" -> ""
+ "undef" -> ""
+ "def" -> ""
+ _ | conditional key -> outCLine pos++"#"++key++" "++arg++"\n"
+ "let" -> ""
+ "enum" -> outCLine pos++outEnum arg
+ _ -> outCLine pos++" hsc_"++key++" ("++arg++");\n"
+
+outEnum :: String -> String
+outEnum arg =
+ case break (== ',') arg of
+ (_, []) -> ""
+ (t, _:afterT) -> case break (== ',') afterT of
+ (f, afterF) -> let
+ enums [] = ""
+ enums (_:s) = case break (== ',') s of
+ (enum, rest) -> let
+ this = case break (== '=') $ dropWhile isSpace enum of
+ (name, []) ->
+ " hsc_enum ("++t++", "++f++", \
+ \hsc_haskellize (\""++name++"\"), "++
+ name++");\n"
+ (hsName, _:cName) ->
+ " hsc_enum ("++t++", "++f++", \
+ \printf (\"%s\", \""++hsName++"\"), "++
+ cName++");\n"
+ in this++enums rest
+ in enums afterF
+
+outTokenH :: (SourcePos, String, String) -> String
+outTokenH (pos, key, arg) =
+ case key of
+ "include" -> outCLine pos++"#include "++arg++"\n"
+ "define" -> outCLine pos++"#define " ++arg++"\n"
+ "undef" -> outCLine pos++"#undef " ++arg++"\n"
+ "def" -> outCLine pos++case arg of
+ 's':'t':'r':'u':'c':'t':' ':_ -> arg++"\n"
+ 't':'y':'p':'e':'d':'e':'f':' ':_ -> arg++"\n"
+ 'i':'n':'l':'i':'n':'e':' ':_ ->
+ "#ifdef __GNUC__\n\
+ \extern\n\
+ \#endif\n"++
+ arg++"\n"
+ _ -> "extern "++header++";\n"
+ where header = takeWhile (\c -> c /= '{' && c /= '=') arg
+ _ | conditional key -> outCLine pos++"#"++key++" "++arg++"\n"
+ _ -> ""
+
+outTokenC :: (SourcePos, String, String) -> String
+outTokenC (pos, key, arg) =
+ case key of
+ "def" -> case arg of
+ 's':'t':'r':'u':'c':'t':' ':_ -> ""
+ 't':'y':'p':'e':'d':'e':'f':' ':_ -> ""
+ 'i':'n':'l':'i':'n':'e':' ':_ ->
+ outCLine pos++
+ "#ifndef __GNUC__\n\
+ \extern\n\
+ \#endif\n"++
+ header++
+ "\n#ifndef __GNUC__\n\
+ \;\n\
+ \#else\n"++
+ body++
+ "\n#endif\n"
+ _ -> outCLine pos++arg++"\n"
+ where (header, body) = span (\c -> c /= '{' && c /= '=') arg
+ _ | conditional key -> outCLine pos++"#"++key++" "++arg++"\n"
+ _ -> ""
conditional :: String -> Bool
-conditional "if" = True
-conditional "ifdef" = True
-conditional "ifndef" = True
-conditional "elif" = True
-conditional "else" = True
-conditional "endif" = True
-conditional "error" = True
-conditional _ = False
+conditional "if" = True
+conditional "ifdef" = True
+conditional "ifndef" = True
+conditional "elif" = True
+conditional "else" = True
+conditional "endif" = True
+conditional "error" = True
+conditional "warning" = True
+conditional _ = False
+
+outCLine :: SourcePos -> String
+outCLine (SourcePos name line) =
+ "# "++show line++" \""++showCString (basename name)++"\"\n"
+
+outHsLine :: SourcePos -> String
+outHsLine (SourcePos name line) =
+ " hsc_line ("++show (line + 1)++", \""++
+ showCString (basename name)++"\");\n"
+
+basename :: String -> String
+basename s = case break (== '/') s of
+ (name, []) -> name
+ (_, _:rest) -> basename rest
showCString :: String -> String
showCString = concatMap showCChar