1{-
2-- The main program for cpphs, a simple C pre-processor written in Haskell.
3
4-- Copyright (c) 2004 Malcolm Wallace
5-- This file is LGPL (relicensed from the GPL by Malcolm Wallace, October 2011).
6-}
7module Language.Preprocessor.Cpphs.RunCpphs ( runCpphs
8                                            , runCpphsPass1
9                                            , runCpphsPass2
10                                            , runCpphsReturningSymTab
11                                            ) where
12
13import Language.Preprocessor.Cpphs.CppIfdef (cppIfdef)
14import Language.Preprocessor.Cpphs.MacroPass(macroPass,macroPassReturningSymTab)
15import Language.Preprocessor.Cpphs.Options  (CpphsOptions(..), BoolOptions(..)
16                                            ,trailing)
17import Language.Preprocessor.Cpphs.Tokenise (deWordStyle, tokenise)
18import Language.Preprocessor.Cpphs.Position (cleanPath, Posn)
19import Language.Preprocessor.Unlit as Unlit (unlit)
20
21
22runCpphs :: CpphsOptions -> FilePath -> String -> IO String
23runCpphs options filename input = do
24  pass1 <- runCpphsPass1 options filename input
25  runCpphsPass2 (boolopts options) (defines options) filename pass1
26
27runCpphsPass1 :: CpphsOptions -> FilePath -> String -> IO [(Posn,String)]
28runCpphsPass1 options' filename input = do
29  let options= options'{ includes= map (trailing "\\/") (includes options') }
30  let bools  = boolopts options
31      preInc = case preInclude options of
32                 [] -> ""
33                 is -> concatMap (\f->"#include \""++f++"\"\n") is
34                       ++ "#line 1 \""++cleanPath filename++"\"\n"
35
36  pass1 <- cppIfdef filename (defines options) (includes options) bools
37                    (preInc++input)
38  return pass1
39
40runCpphsPass2 :: BoolOptions -> [(String,String)] -> FilePath -> [(Posn,String)] -> IO String
41runCpphsPass2 bools defines filename pass1 = do
42  pass2 <- macroPass defines bools pass1
43  let result= if not (macros bools)
44              then if   stripC89 bools || stripEol bools
45                   then concatMap deWordStyle $
46                        tokenise (stripEol bools) (stripC89 bools)
47                                 (ansi bools) (lang bools) pass1
48                   else unlines (map snd pass1)
49              else pass2
50      pass3 = if literate bools then Unlit.unlit filename else id
51  return (pass3 result)
52
53runCpphsReturningSymTab :: CpphsOptions -> FilePath -> String
54             -> IO (String,[(String,String)])
55runCpphsReturningSymTab options' filename input = do
56  let options= options'{ includes= map (trailing "\\/") (includes options') }
57  let bools  = boolopts options
58      preInc = case preInclude options of
59                 [] -> ""
60                 is -> concatMap (\f->"#include \""++f++"\"\n") is
61                       ++ "#line 1 \""++cleanPath filename++"\"\n"
62  (pass2,syms) <-
63      if macros bools then do
64          pass1 <- cppIfdef filename (defines options) (includes options)
65                            bools (preInc++input)
66          macroPassReturningSymTab (defines options) bools pass1
67      else do
68          pass1 <- cppIfdef filename (defines options) (includes options)
69                            bools{macros=True} (preInc++input)
70          (_,syms) <- macroPassReturningSymTab (defines options) bools pass1
71          pass1 <- cppIfdef filename (defines options) (includes options)
72                            bools (preInc++input)
73          let result = if   stripC89 bools || stripEol bools
74                       then concatMap deWordStyle $
75                            tokenise (stripEol bools) (stripC89 bools)
76                                     (ansi bools) (lang bools) pass1
77                       else init $ unlines (map snd pass1)
78          return (result,syms)
79
80  let pass3 = if literate bools then Unlit.unlit filename else id
81  return (pass3 pass2, syms)
82
83