fix handling of comments, quotes, and trailing whitespace in macro arguments

This commit is contained in:
Zachary Snow 2021-07-08 16:30:02 -04:00
parent 4c7e9d0353
commit 9aa8b7033e
3 changed files with 98 additions and 18 deletions

View File

@ -16,7 +16,7 @@ module Language.SystemVerilog.Parser.Preprocess
import Control.Monad.Except
import Control.Monad.State.Strict
import Data.Char (ord)
import Data.List (dropWhileEnd, tails, isPrefixOf, findIndex, intercalate)
import Data.List (tails, isPrefixOf, findIndex, intercalate)
import Data.Maybe (isJust, fromJust)
import System.Directory (findFile)
import System.FilePath (dropFileName)
@ -397,34 +397,59 @@ takeMacroArguments = do
argLoop :: PPS [String]
argLoop = do
dropWhitespace
(arg, isEnd) <- loop "" []
let arg' = dropWhileEnd isWhitespaceChar arg
(argRev, isEnd) <- loop "" []
let arg = trimAndRev argRev
if isEnd
then return [arg']
then return [arg]
else do
rest <- argLoop
return $ arg' : rest
return $ arg : rest
loop :: String -> [Char] -> PPS (String, Bool)
loop curr stack = do
ch <- takeChar
case (stack, ch) of
( s,'\\') -> do
ch2 <- takeChar
loop (curr ++ [ch, ch2]) s
([ ], ',') -> return (curr, False)
([ ], ')') -> return (curr, True)
('"' : s, '"') -> loop (curr ++ [ch]) s
( s, '"') -> loop (curr ++ [ch]) ('"' : s)
('[' : s, ']') -> loop (curr ++ [ch]) s
( s, '[') -> loop (curr ++ [ch]) ('[' : s)
('(' : s, ')') -> loop (curr ++ [ch]) s
( s, '(') -> loop (curr ++ [ch]) ('(' : s)
('{' : s, '}') -> loop (curr ++ [ch]) s
( s, '{') -> loop (curr ++ [ch]) ('{' : s)
-- simple quoted strings, allowing escaped quotes
('\\': s, _ ) -> loop (ch : curr) s
('"' : s, '"') -> loop (ch : curr) s
('"' : _,'\\') -> loop (ch : curr) ('\\': stack)
('"' : _, _ ) -> loop (ch : curr) stack
( _, '"') -> loop (ch : curr) ('"' : stack)
( s,'\n') -> loop (curr ++ [' ']) s
( s, _ ) -> loop (curr ++ [ch ]) s
('[' : s, ']') -> loop (ch : curr) s
( s, '[') -> loop (ch : curr) ('[' : s)
('(' : s, ')') -> loop (ch : curr) s
( s, '(') -> loop (ch : curr) ('(' : s)
('{' : s, '}') -> loop (ch : curr) s
( s, '{') -> loop (ch : curr) ('{' : s)
( s, '/') -> do
next <- peekChar
case next of
'/' -> takeChar >> dropLineComment >> loop curr s
'*' -> takeChar >> dropBlockComment >> loop curr s
_ -> loop ('/' : curr) s
( s,'\n') -> loop (' ' : curr) s
( s, _ ) -> loop (ch : curr) s
trimAndRev = -- drop surrounding whitespace and reverse string
dropWhile isWhitespaceChar . reverse . dropWhile isWhitespaceChar
dropLineComment :: PPS ()
dropLineComment = do
ch <- takeChar
when (ch /= '\n') dropLineComment
dropBlockComment :: PPS ()
dropBlockComment = do
ch1 <- takeChar
ch2 <- peekChar
if ch1 == '*' && ch2 == '/'
then takeChar >> return ()
else dropBlockComment
defaultMacroArgs :: [Maybe String] -> [String] -> PPS [String]
defaultMacroArgs [] [] = return []

View File

@ -0,0 +1,39 @@
`define MACRO_A(
// comment
/* intentional tab */
/* comment */ x /* comment */
/* intentional tab */
// comment
,
// comment
/* intentional tab */
/* comment */ y /* comment */
/* intentional tab */
// comment
) \
initial begin \
$display(`"x %b`", x); \
$display(`"y %b`", y); \
end
`define MACRO_B(x, y, z) initial $display(x, y, z);
module top;
`MACRO_A(
// comment
/* intentional tab */
/* comment */ 1 + 2 /* comment */
/* intentional tab */
// comment
,
/* intentional tab */
/* comment */ 1'b1 & 1 /* comment */
/* intentional tab */
// comment
)
`MACRO_B(
"/* not a block comment */",
"// not a line comment",
"cool \046 \" ( } { beans\\"
)
endmodule

View File

@ -0,0 +1,16 @@
`define MACRO_A(x, y) \
initial begin \
$display(`"x %b`", x); \
$display(`"y %b`", y); \
end
`define MACRO_B(x, y, z) initial $display(x, y, z);
module top;
`MACRO_A(1 + 2, 1'b1 & 1)
`MACRO_B(
"/* not a block comment */",
"// not a line comment",
"cool \046 \042 ( } { beans\\"
)
endmodule