diff --git a/src/Language/SystemVerilog/Parser/Keywords.hs b/src/Language/SystemVerilog/Parser/Keywords.hs new file mode 100644 index 0000000..727ace2 --- /dev/null +++ b/src/Language/SystemVerilog/Parser/Keywords.hs @@ -0,0 +1,84 @@ +{- sv2v + - Author: Zachary Snow + - + - To implement the `begin_keywords` directive, this module defines which IEEE + - 1800-2017 keywords are not keywords in preceding specifications. + -} +module Language.SystemVerilog.Parser.Keywords + ( specMap + ) where + +import qualified Data.Map.Strict as Map +import qualified Data.Set as Set + +import Language.SystemVerilog.Parser.Tokens + +newKeywords :: [(String, [TokenName])] +newKeywords = [ + + ("1364-1995", [KW_always, KW_and, KW_assign, KW_begin, KW_buf, KW_bufif0, + KW_bufif1, KW_case, KW_casex, KW_casez, KW_cmos, KW_deassign, KW_default, + KW_defparam, KW_disable, KW_edge, KW_else, KW_end, KW_endcase, + KW_endfunction, KW_endmodule, KW_endprimitive, KW_endspecify, KW_endtable, + KW_endtask, KW_event, KW_for, KW_force, KW_forever, KW_fork, KW_function, + KW_highz0, KW_highz1, KW_if, KW_ifnone, KW_initial, KW_inout, KW_input, + KW_integer, KW_join, KW_large, KW_macromodule, KW_medium, KW_module, + KW_nand, KW_negedge, KW_nmos, KW_nor, KW_not, KW_notif0, KW_notif1, KW_or, + KW_output, KW_parameter, KW_pmos, KW_posedge, KW_primitive, KW_pull0, + KW_pull1, KW_pulldown, KW_pullup, KW_rcmos, KW_real, KW_realtime, KW_reg, + KW_release, KW_repeat, KW_rnmos, KW_rpmos, KW_rtran, KW_rtranif0, + KW_rtranif1, KW_scalared, KW_small, KW_specify, KW_specparam, KW_strong0, + KW_strong1, KW_supply0, KW_supply1, KW_table, KW_task, KW_time, KW_tran, + KW_tranif0, KW_tranif1, KW_tri, KW_tri0, KW_tri1, KW_triand, KW_trior, + KW_trireg, KW_vectored, KW_wait, KW_wand, KW_weak0, KW_weak1, KW_while, + KW_wire, KW_wor, KW_xnor, KW_xor]), + + ("1364-2001-noconfig", [KW_cell, KW_config, KW_design, KW_endconfig, + KW_incdir, KW_include, KW_instance, KW_liblist, KW_library, KW_use]), + + ("1364-2001", [KW_automatic, KW_endgenerate, KW_generate, KW_genvar, + KW_localparam, KW_noshowcancelled, KW_pulsestyle_ondetect, + KW_pulsestyle_onevent, KW_showcancelled, KW_signed, KW_unsigned]), + + ("1364-2005", [KW_uwire]), + + ("1800-2005", [KW_alias, KW_always_comb, KW_always_ff, KW_always_latch, + KW_assert, KW_assume, KW_before, KW_bind, KW_bins, KW_binsof, KW_bit, + KW_break, KW_byte, KW_chandle, KW_class, KW_clocking, KW_const, + KW_constraint, KW_context, KW_continue, KW_cover, KW_covergroup, + KW_coverpoint, KW_cross, KW_dist, KW_do, KW_endclass, KW_endclocking, + KW_endgroup, KW_endinterface, KW_endpackage, KW_endprogram, KW_endproperty, + KW_endsequence, KW_enum, KW_expect, KW_export, KW_extends, KW_extern, + KW_final, KW_first_match, KW_foreach, KW_forkjoin, KW_iff, KW_ignore_bins, + KW_illegal_bins, KW_import, KW_inside, KW_int, KW_interface, KW_intersect, + KW_join_any, KW_join_none, KW_local, KW_logic, KW_longint, KW_matches, + KW_modport, KW_new, KW_null, KW_package, KW_packed, KW_priority, KW_program, + KW_property, KW_protected, KW_pure, KW_rand, KW_randc, KW_randcase, + KW_randsequence, KW_ref, KW_return, KW_sequence, KW_shortint, KW_shortreal, + KW_solve, KW_static, KW_string, KW_struct, KW_super, KW_tagged, KW_this, + KW_throughout, KW_timeprecision, KW_timeunit, KW_type, KW_typedef, KW_union, + KW_unique, KW_var, KW_virtual, KW_void, KW_wait_order, KW_wildcard, KW_with, + KW_within]), + + ("1800-2009", [KW_accept_on, KW_checker, KW_endchecker, KW_eventually, + KW_global, KW_implies, KW_let, KW_nexttime, KW_reject_on, KW_restrict, + KW_s_always, KW_s_eventually, KW_s_nexttime, KW_s_until, KW_s_until_with, + KW_strong, KW_sync_accept_on, KW_sync_reject_on, KW_unique0, KW_until, + KW_until_with, KW_untyped, KW_weak]), + + ("1800-2012", [KW_implements, KW_nettype, KW_interconnect, KW_soft]), + + ("1800-2017", []) + + ] + +specMap :: Map.Map String (Set.Set TokenName) +specMap = + Map.fromList $ zip keys vals + where + keys = map fst newKeywords + sets = map (Set.fromList . snd) newKeywords + allKeywords = Set.unions sets + vals = + map (Set.difference allKeywords) $ + scanl1 Set.union sets diff --git a/src/Language/SystemVerilog/Parser/Lex.x b/src/Language/SystemVerilog/Parser/Lex.x index c963c0c..e3f03e8 100644 --- a/src/Language/SystemVerilog/Parser/Lex.x +++ b/src/Language/SystemVerilog/Parser/Lex.x @@ -33,9 +33,11 @@ import System.FilePath (dropFileName) import System.Directory (findFile) import System.IO.Unsafe (unsafePerformIO) import qualified Data.Map.Strict as Map +import qualified Data.Set as Set import Data.List (span, elemIndex, dropWhileEnd) import Data.Maybe (isJust, fromJust) +import Language.SystemVerilog.Parser.Keywords (specMap) import Language.SystemVerilog.Parser.Tokens } @@ -513,13 +515,14 @@ data AlexUserState = LS , lsEnv :: Env -- active macro definitions , lsCondStack :: [Cond] -- if-else cascade state , lsIncludePaths :: [FilePath] -- folders to search for includes + , lsSpecStack :: [Set.Set TokenName] -- stack of non-keyword token names } deriving (Eq, Show) -- this initial user state does not contain the initial filename, environment, -- or include paths; alex requires that this be defined; we override it before -- we begin the actual lexing procedure alexInitUserState :: AlexUserState -alexInitUserState = LS [] "" Map.empty [] [] +alexInitUserState = LS [] "" Map.empty [] [] [] -- public-facing lexer entrypoint lexFile :: [String] -> Env -> FilePath -> IO (Either String ([Token], Env)) @@ -529,10 +532,14 @@ lexFile includePaths env path = do return $ case result of Left msg -> Left msg Right finalState -> - if null $ lsCondStack finalState - then Right (finalToks, lsEnv finalState) - else Left $ path ++ ": unfinished conditional directives: " ++ - (show $ length $ lsCondStack finalState) + if not $ null $ lsCondStack finalState then + Left $ path ++ ": unfinished conditional directives: " ++ + (show $ length $ lsCondStack finalState) + else if not $ null $ lsSpecStack finalState then + Left $ path ++ ": unterminated begin_keywords blocks: " ++ + (show $ length $ lsSpecStack finalState) + else + Right (finalToks, lsEnv finalState) where finalToks = coalesce $ reverse $ lsToks finalState where setEnv = do @@ -910,6 +917,27 @@ handleDirective (posOrig, _, _, strOrig) len = do "pragma" -> passThrough "resetall" -> passThrough + "begin_keywords" -> do + quotedSpec <- takeQuotedString + let spec = tail $ init quotedSpec + case Map.lookup spec specMap of + Nothing -> + lexicalError $ "invalid keyword set name: " ++ show spec + Just set -> do + specStack <- gets lsSpecStack + modify $ \s -> s { lsSpecStack = set : specStack } + dropWhitespace + alexMonadScan + "end_keywords" -> do + specStack <- gets lsSpecStack + if null specStack + then + lexicalError "unexpected end_keywords before begin_keywords" + else do + modify $ \s -> s { lsSpecStack = tail specStack } + dropWhitespace + alexMonadScan + "__FILE__" -> do tokPos <- toTokPos posOrig currFile <- gets lsCurrFile @@ -1070,7 +1098,11 @@ tok tokId (pos, _, _, input) len = do tokPos <- toTokPos pos condStack <- gets lsCondStack () <- if any (/= CurrentlyTrue) condStack - then modify id - else modify (push $ Token tokId tokStr tokPos) + then return () + else do + specStack <- gets lsSpecStack + if null specStack || Set.notMember tokId (head specStack) + then modify (push $ Token tokId tokStr tokPos) + else modify (push $ Token Id_simple ('_' : tokStr) tokPos) alexMonadScan } diff --git a/src/Language/SystemVerilog/Parser/Tokens.hs b/src/Language/SystemVerilog/Parser/Tokens.hs index 658a9a0..48e86a8 100644 --- a/src/Language/SystemVerilog/Parser/Tokens.hs +++ b/src/Language/SystemVerilog/Parser/Tokens.hs @@ -381,4 +381,4 @@ data TokenName | Spe_Directive | Unknown | MacroBoundary - deriving (Show, Eq) + deriving (Show, Eq, Ord) diff --git a/sv2v.cabal b/sv2v.cabal index ac07580..085d746 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -48,6 +48,7 @@ executable sv2v Language.SystemVerilog.AST.Stmt Language.SystemVerilog.AST.Type Language.SystemVerilog.Parser + Language.SystemVerilog.Parser.Keywords Language.SystemVerilog.Parser.Lex Language.SystemVerilog.Parser.Parse Language.SystemVerilog.Parser.ParseDecl diff --git a/test/lex/begin_keywords.sv b/test/lex/begin_keywords.sv new file mode 100644 index 0000000..fded8dc --- /dev/null +++ b/test/lex/begin_keywords.sv @@ -0,0 +1,16 @@ +`begin_keywords "1364-2001-noconfig" +task foo; + integer automatic = 2; + $display(automatic * automatic); +endtask +`begin_keywords "1364-2005" +task automatic bar; + integer logic = 3; + $display(logic * logic); +endtask +`end_keywords +`end_keywords +module top; + initial foo; + initial bar; +endmodule diff --git a/test/lex/begin_keywords.v b/test/lex/begin_keywords.v new file mode 100644 index 0000000..8a301fe --- /dev/null +++ b/test/lex/begin_keywords.v @@ -0,0 +1,18 @@ +module top; + task foo; + integer x; + begin + x = 2; + $display(x * x); + end + endtask + task bar; + integer y; + begin + y = 3; + $display(y * y); + end + endtask + initial foo; + initial bar; +endmodule