Plan 9 from Bell Labs’s /usr/web/sources/contrib/fernan/nhc98/src/compiler98/Front.hs

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


{-
The front phase of the compiler this needs to

- do lexical analysis
- parse the program source code
- do "need" analysis which determines which symbols are needed by the program

It is especially useful to have this as a seperate phase because it is used repeatedly
by Make.lhs in doing dependency analysis.

There are two public items

  front      - the function to do the front end of the compiler
  FrontData  - the useful data extracted from the front end
-}

module Front(front, FrontData(..)) where

import System
import IO

import Util.Extra
import Flags
import Syntax hiding (TokenId)
import Info
import Error
import qualified Data.Map as Map
import qualified Data.Set as Set
import Parse.Lexical(lexical)
import Parse.Parse(parseProg)
import Parse.ParseCore(parseit)
import Parse.Pragma(parsePragmas)
import Need(needProg,NeedTable)
import Import(HideDeclIds,importOne)
import Language.Preprocessor.Unlit(unlit)
import Overlap(Overlap)
import SysDeps(PackedString)
import PrettySyntax(ppModule, prettyPrintTokenId)
import Data.PackedString(unpackPS)
import Phase
import TokenId
import Language.Preprocessor.Cpphs
import System.FilePath
import System.Console.GetOpt

{-
FrontData is the data returns by the front end
FIXME: unsure about some things here ...

   fParsedPrg       the abstract syntax tree of the parsed program
   fNeed            the table of values needed by this module
   fQualFun         ... unsure find out what this does!!
   fOverlap         ... unsure find out what this does!!
   fExpFun          ... unsure find out what this does!!
   fImports         a list of things that need to be imported, which is of the form
                          [(mrps, needFun, hideFun)]
                    where
                         mrps          the reversed packed string of the imported module
                         needFun       .. unsure find out what this does!!
                         hideFun       .. unsure find out what this does!!
-}

data FrontData = FrontData { fParsedPrg :: Module TokenId,
                             fNeed :: NeedTable,
                             fQualFun :: TokenId -> [TokenId],
                             fOverlap :: Overlap,
                             fExpFun :: (TokenId -> Bool) -> TokenId -> IdKind -> IE,
                             fImports :: [(PackedString,
                                          (PackedString, PackedString, Set.Set TokenId) -> [[TokenId]] -> Bool,
                                           HideDeclIds)],
                             fModName :: String,
                             fFlags :: Flags,
                             fFileFlags :: FileFlags }

{-
front is the proper front end of the compiler.
   flags             compiler flags
   filename          the filename of the module to load and parse
   returns           a FrontData representing what was loaded from the file
-}
front :: Flags -> FilePath -> IO FrontData
front flags filename = do

  -- assume unlit for .lhs files
  flags <- return $ flags{sUnlit = sUnlit flags || (takeExtension filename == ".lhs")}

  -- do lexical analysis, giving a list of tokens
  beginPhase "lex"
  mainChar      -- :: String
           <- tryReadFile "" filename

  -- read any pragma's that might be around
  let pragmas = parsePragmas mainChar
  let (flagchanges, _, _) = getOpt Permute allOpts (concatMap words pragmas)
  flags <- return $ foldr ($) flags flagchanges

  mainCpp       -- :: String -- The string after running cpphs (if necessary)
           <- if sCpp flags then cpphs flags filename mainChar else return mainChar

  lexdata       -- :: [PosToken]
           <- return $ lexical (sUnderscore flags) filename
                     $ (if sUnlit flags then unlit filename else id)
                     $ mainCpp

  pF (sLex flags) "Lexical"
       (mixSpace (map (\ (p,l,_,_) -> strPos p ++ ':':show l) lexdata))

  -- parse the source code giving an abstract syntax tree of the program
  beginPhase "parse"
  parsedPrg     -- :: Module TokenId
            <- catchError2 (parseit parseProg lexdata) (showErr filename)
  pF (sParse flags) "Parse" (prettyPrintTokenId flags ppModule parsedPrg)

  -- change the module decl to say to export everything, if that's appropriate ...
  -- FIXME: bit of a hack really, should be a nicer way to do it
  -- FIXME: shouldn't this be just before exporting the interface?
  parsedPrg <- if sExportAll flags then
                  case parsedPrg of
                      Module pos modidl _ impdecls fixdecls topdecls ->
                          let exports = Just [ExportModid pos modidl] in
                          return (Module pos modidl exports impdecls fixdecls topdecls)
                else
                  return parsedPrg


  -- Perform "need" analysis (what imported entities are required?)
  -- Second argument may contain error message or parse tree
  beginPhase "need"
  (need         -- :: NeedTable
   ,qualFun     -- :: TokenId -> [TokenId]
   ,overlap     -- :: Overlap
   ,info)       -- :: Either String (expFun,imports)
         <- return (needProg flags parsedPrg)
  (expFun       -- :: (TokenId->Bool) -> TokenId -> IdKind -> IE
   ,imports)    -- :: [ ( PackedString
                --      , (PackedString, PackedString, Tree (TokenId,IdKind))
                --            -> [[TokenId]] -> Bool
                --      , HideDeclIds
                --      )
                --    ]
            <- catchError info ("In file: " ++ filename) id
  pF (sNeed flags) "Need (after reading source module)"
            (show (Map.toList need))

  let (Module _ (Visible modid) _ _ _ _ ) = parsedPrg
      modName = reverse (unpackPS modid)
      fileflags = getFileFlags flags filename modName

  return (FrontData parsedPrg need qualFun overlap expFun imports modName flags fileflags)


cpphs :: Flags -> FilePath -> String -> IO String
cpphs flags filename contents = return $ runCpphs opts filename contents
      where
          opts = defaultCpphsOptions {defines = macros,
                  boolopts = defaultBoolOptions{ansi=True, stripC89=False, stripEol=False}}
          macros = [("__HASKELL__","98"), ("__HASKELL_98__", "1"), ("__HASKELL98__", "1"), ("__YHC__", "1")]

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].