add --oneunit, which treats all input files as being part of one compilation unit

This commit is contained in:
Zachary Snow 2019-08-05 22:00:04 -04:00
parent 376f0d3f2a
commit 90bc30d4be
8 changed files with 51 additions and 18 deletions

View File

@ -20,6 +20,7 @@ data Job = Job
, files :: [FilePath]
, incdir :: [FilePath]
, define :: [String]
, oneunit :: Bool
} deriving (Show, Typeable, Data)
defaultJob :: Job
@ -29,6 +30,7 @@ defaultJob = Job
, files = def &= args &= typ "FILES"
, incdir = def &= typDir &= help "add directory to include search path"
, define = def &= typ "NAME[=VALUE]" &= help "define a macro for preprocessing"
, oneunit = False &= help "compile all files in one compilation unit"
}
&= program "sv2v"
&= summary "sv2v v0.0.1, (C) 2019 Zachary Snow, 2011-2015 Tom Hawkins"

View File

@ -2,15 +2,32 @@
- Author: Zachary Snow <zach@zachjs.com>
-}
module Language.SystemVerilog.Parser
( parseFile
( parseFiles
) where
import qualified Data.Map.Strict as Map
import Language.SystemVerilog.AST (AST)
import Language.SystemVerilog.Parser.Lex (lexFile)
import Language.SystemVerilog.Parser.Lex (lexFile, Env)
import Language.SystemVerilog.Parser.Parse (parse)
-- parses a compilation unit given include search paths and predefined macros
parseFiles :: [FilePath] -> [(String, String)] -> [FilePath] -> IO [AST]
parseFiles includePaths defines paths = do
let env = Map.map (\a -> (a, [])) $ Map.fromList defines
parseFiles' includePaths env paths
-- parses a compilation unit given include search paths and predefined macros
parseFiles' :: [FilePath] -> Env -> [FilePath] -> IO [AST]
parseFiles' _ _ [] = return []
parseFiles' includePaths env (path : paths) = do
(ast, env') <- parseFile' includePaths env path
asts <- parseFiles' includePaths env' paths
return $ ast : asts
-- parses a file given include search paths, a table of predefined macros, and
-- the file path
parseFile :: [String] -> [(String, String)] -> FilePath -> IO AST
parseFile includePaths defines path =
lexFile includePaths defines path >>= return . parse
parseFile' :: [String] -> Env -> FilePath -> IO (AST, Env)
parseFile' includePaths env path = do
(tokens, env') <- lexFile includePaths env path
let ast = parse tokens
return (ast, env')

View File

@ -20,7 +20,10 @@
-- been fixed on their development branch, so this can be removed once they roll
-- a new release. (no new release as of 3/29/2018)
module Language.SystemVerilog.Parser.Lex (lexFile) where
module Language.SystemVerilog.Parser.Lex
( lexFile
, Env
) where
import System.FilePath (dropFileName)
import System.Directory (findFile)
@ -322,11 +325,14 @@ data Cond
| NeverTrue
deriving (Eq, Show)
-- map from macro to definition, plus arguments
type Env = Map.Map String (String, [(String, Maybe String)])
-- our custom lexer state
data AlexUserState = LS
{ lsToks :: [Token] -- tokens read so far, *in reverse order* for efficiency
, lsCurrFile :: FilePath -- currently active filename
, lsEnv :: Map.Map String (String, [(String, Maybe String)]) -- active macro definitions
, lsEnv :: Env -- active macro definitions
, lsCondStack :: [Cond] -- if-else cascade state
, lsIncludePaths :: [FilePath] -- folders to search for includes
} deriving (Eq, Show)
@ -338,7 +344,7 @@ alexInitUserState :: AlexUserState
alexInitUserState = LS [] "" Map.empty [] []
-- public-facing lexer entrypoint
lexFile :: [String] -> [(String, String)] -> FilePath -> IO [Token]
lexFile :: [String] -> Env -> FilePath -> IO ([Token], Env)
lexFile includePaths env path = do
str <- readFile path
let result = runAlex str $ setEnv >> alexMonadScan >> get
@ -346,16 +352,15 @@ lexFile includePaths env path = do
Left msg -> error $ "Lexical Error: " ++ msg
Right finalState ->
if null $ lsCondStack finalState
then reverse $ lsToks finalState
then (reverse $ lsToks finalState, lsEnv finalState)
else error $ "unfinished conditional directives: " ++
(show $ length $ lsCondStack finalState)
where
initialEnv = Map.map (\a -> (a, [])) $ Map.fromList env
setEnv = do
-- standardize the file path format
path' <- includeSearch path
modify $ \s -> s
{ lsEnv = initialEnv
{ lsEnv = env
, lsIncludePaths = includePaths
, lsCurrFile = path'
}

View File

@ -8,9 +8,9 @@ import System.IO
import System.Exit
import Data.List (elemIndex)
import Job (readJob, files, exclude, incdir, define)
import Job (readJob, files, exclude, incdir, define, oneunit)
import Convert (convert)
import Language.SystemVerilog.Parser
import Language.SystemVerilog.Parser (parseFiles)
splitDefine :: String -> (String, String)
splitDefine str =
@ -21,12 +21,17 @@ splitDefine str =
main :: IO ()
main = do
job <- readJob
-- parse the input file
-- parse the input files
let includePaths = incdir job
let defines = map splitDefine $ define job
asts <- mapM (parseFile includePaths defines) (files job)
-- convert the file
let singleton = \x -> [x]
let toFileLists = if oneunit job then singleton else map singleton
astLists <- mapM
(parseFiles includePaths defines)
(toFileLists $ files job)
let asts = concat astLists
-- convert the files
let asts' = convert (exclude job) asts
-- print the converted file out
-- print the converted files out
hPrint stdout $ concat asts'
exitSuccess

View File

@ -5,5 +5,6 @@ module top
assign o = i + 1'b1;
initial begin
$display(width);
$display(`FANCY_SEEING_YOU);
end
endmodule

View File

@ -1,3 +1,4 @@
`define FANCY_SEEING_YOU 1337
package pkg;
function automatic integer width_calc;
input integer a;

View File

@ -1,3 +1,4 @@
`define FANCY_SEEING_YOU 1337
module top;
parameter width = 5;
input [width-1:0] i;
@ -5,5 +6,6 @@ module top;
assign o = i + 1'b1;
initial begin
$display(width);
$display(`FANCY_SEEING_YOU);
end
endmodule

View File

@ -2,7 +2,7 @@
test_main() {
cv="$SHUNIT_TMPDIR/conv.v"
convert "$cv" package.svh module.sv
convert "$cv" --oneunit package.svh module.sv
simulateAndCompare "reference.v" "$cv" "$SCRIPT_DIR/empty.v"
}