Support module/package/interface/block scope for typedef names.
authorPeter Crozier <peter@crozier.com>
Mon, 23 Mar 2020 20:07:22 +0000 (20:07 +0000)
committerPeter Crozier <peter@crozier.com>
Mon, 23 Mar 2020 20:07:22 +0000 (20:07 +0000)
README.md
frontends/verilog/verilog_frontend.cc
frontends/verilog/verilog_frontend.h
frontends/verilog/verilog_lexer.l
frontends/verilog/verilog_parser.y
tests/svtypes/typedef_scopes.sv

index d1f7ddf8ee23a5ff0061342aa69062fa0b14bf03..ce7b264110386a883af32ebfe6a4d0b540d42c8d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -541,8 +541,6 @@ from SystemVerilog:
   SystemVerilog files being read into the same design afterwards.
 
 - typedefs are supported (including inside packages)
-       - type identifiers must currently be enclosed in (parentheses) when declaring
-         signals of that type (this is syntactically incorrect SystemVerilog)
        - type casts are currently not supported
 
 - enums are supported (including inside packages)
index f2c1c227f39f5a09e7b54b83bce3672ad00c6a19..1c88d479b5feeed3099acc5129688ad5adfb5dd4 100644 (file)
@@ -51,7 +51,6 @@ static void add_package_types(std::map<std::string, AST::AstNode *> &user_types,
 {
        // prime the parser's user type lookup table with the package qualified names
        // of typedefed names in the packages seen so far.
-       user_types.clear();
        for (const auto &pkg : package_list) {
                log_assert(pkg->type==AST::AST_PACKAGE);
                for (const auto &node: pkg->children) {
@@ -61,6 +60,8 @@ static void add_package_types(std::map<std::string, AST::AstNode *> &user_types,
                        }
                }
        }
+       user_type_stack.clear();
+       user_type_stack.push_back(new UserTypeMap());
 }
 
 struct VerilogFrontend : public Frontend {
index 73ea51e6cbdc892a9eb373ded1555874da8fd3b3..caa6246ef1d548560ebd1305af12e6b987881763 100644 (file)
@@ -45,8 +45,9 @@ namespace VERILOG_FRONTEND
        // this function converts a Verilog constant to an AST_CONSTANT node
        AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
 
-       // names of locally typedef'ed types
-       extern std::map<std::string, AST::AstNode*> user_types;
+       // names of locally typedef'ed types in a stack
+       typedef std::map<std::string, AST::AstNode*> UserTypeMap;
+       extern std::vector<UserTypeMap *> user_type_stack;
 
        // names of package typedef'ed types
        extern std::map<std::string, AST::AstNode*> pkg_user_types;
index 74e8dce7f9636ac99a34bd50e06e6b6134ab7c2a..bccdf48413c839d70386e5d934e2be30fea1b568 100644 (file)
@@ -99,6 +99,18 @@ YYLTYPE old_location;
 #define YY_BUF_SIZE 65536
 
 extern int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param);
+
+static bool isUserType(std::string &s)
+{
+       // check current scope then outer scopes for a name
+       for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) {
+               if ((*it)->count(s) > 0) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 %}
 
 %option yylineno
@@ -376,7 +388,7 @@ supply1 { return TOK_SUPPLY1; }
        // package qualifier
        auto s = std::string("\\") + yytext;
        if (pkg_user_types.count(s) > 0) {
-               // found it
+               // package qualified typedefed name
                yylval->string = new std::string(s);
                return TOK_USER_TYPE;
        }
@@ -391,7 +403,8 @@ supply1 { return TOK_SUPPLY1; }
 
 [a-zA-Z_$][a-zA-Z0-9_$]* {
        auto s = std::string("\\") + yytext;
-       if (user_types.count(s) > 0) {
+       if (isUserType(s)) {
+               // previously typedefed name
                yylval->string = new std::string(s);
                return TOK_USER_TYPE;
        }
index f7e3afd13ff3804687f22cd606d74bac990b9ea4..1a195bbfd0278e5f46d1599e86efe7a14b08353e 100644 (file)
@@ -54,7 +54,7 @@ namespace VERILOG_FRONTEND {
        std::map<std::string, AstNode*> *attr_list, default_attr_list;
        std::stack<std::map<std::string, AstNode*> *> attr_list_stack;
        std::map<std::string, AstNode*> *albuf;
-       std::map<std::string, AstNode*> user_types;
+       std::vector<UserTypeMap*> user_type_stack;
        std::map<std::string, AstNode*> pkg_user_types;
        std::vector<AstNode*> ast_stack;
        struct AstNode *astbuf1, *astbuf2, *astbuf3;
@@ -130,14 +130,10 @@ struct specify_rise_fall {
 static void addTypedefNode(std::string *name, AstNode *node)
 {
        log_assert(node);
-       // seems to be support for local scoped typedefs in simplify()
-       // and tests redefine types.
-       //if (user_types.count(*name) > 0) {
-       //      frontend_verilog_yyerror("Type already defined.");
-       //}
        auto *tnode = new AstNode(AST_TYPEDEF, node);
        tnode->str = *name;
-       user_types[*name] = tnode;
+       auto user_types = user_type_stack.back();
+       (*user_types)[*name] = tnode;
        if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) {
                // typedef inside a package so we need the qualified name
                auto qname = current_ast_mod->str + "::" + (*name).substr(1);
@@ -147,6 +143,17 @@ static void addTypedefNode(std::string *name, AstNode *node)
        ast_stack.back()->children.push_back(tnode);
 }
 
+static void enterTypeScope()
+{
+       auto user_types = new UserTypeMap();
+       user_type_stack.push_back(user_types);
+}
+
+static void exitTypeScope()
+{
+       user_type_stack.pop_back();
+}
+
 static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true)
 {
        auto range = new AstNode(AST_RANGE);
@@ -359,7 +366,7 @@ hierarchical_type_id:
        ;
 
 module:
-       attr TOK_MODULE TOK_ID {
+       attr module_start TOK_ID {
                do_not_require_port_stubs = false;
                AstNode *mod = new AstNode(AST_MODULE);
                ast_stack.back()->children.push_back(mod);
@@ -378,9 +385,12 @@ module:
                ast_stack.pop_back();
                log_assert(ast_stack.size() == 1);
                current_ast_mod = NULL;
-               user_types.clear();
+               exitTypeScope();
        };
 
+module_start: TOK_MODULE       { enterTypeScope(); }
+       ;
+
 module_para_opt:
        '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;
 
@@ -482,7 +492,7 @@ module_arg:
        };
 
 package:
-       attr TOK_PACKAGE TOK_ID {
+       attr package_start TOK_ID {
                AstNode *mod = new AstNode(AST_PACKAGE);
                ast_stack.back()->children.push_back(mod);
                ast_stack.push_back(mod);
@@ -492,9 +502,12 @@ package:
        } ';' package_body TOK_ENDPACKAGE {
                ast_stack.pop_back();
                current_ast_mod = NULL;
-               user_types.clear();
+               exitTypeScope();
        };
 
+package_start: TOK_PACKAGE     { enterTypeScope(); }
+       ;
+
 package_body:
        package_body package_body_stmt
        | // optional
@@ -505,7 +518,7 @@ package_body_stmt:
        localparam_decl;
 
 interface:
-       TOK_INTERFACE TOK_ID {
+       interface_start TOK_ID {
                do_not_require_port_stubs = false;
                AstNode *intf = new AstNode(AST_INTERFACE);
                ast_stack.back()->children.push_back(intf);
@@ -522,9 +535,12 @@ interface:
                ast_stack.pop_back();
                log_assert(ast_stack.size() == 1);
                current_ast_mod = NULL;
-               user_types.clear();
+               exitTypeScope();
        };
 
+interface_start: TOK_INTERFACE { enterTypeScope(); }
+       ;
+
 interface_body:
        interface_body interface_body_stmt |;
 
@@ -2210,7 +2226,7 @@ behavioral_stmt:
        } opt_arg_list ';'{
                ast_stack.pop_back();
        } |
-       attr TOK_BEGIN opt_label {
+       attr begin opt_label {
                AstNode *node = new AstNode(AST_BLOCK);
                ast_stack.back()->children.push_back(node);
                ast_stack.push_back(node);
@@ -2218,6 +2234,7 @@ behavioral_stmt:
                if ($3 != NULL)
                        node->str = *$3;
        } behavioral_stmt_list TOK_END opt_label {
+               exitTypeScope();
                if ($3 != NULL && $7 != NULL && *$3 != *$7)
                        frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
                if ($3 != NULL)
@@ -2301,6 +2318,9 @@ behavioral_stmt:
                ast_stack.pop_back();
        };
 
+begin: TOK_BEGIN       { enterTypeScope(); }
+       ;
+
 unique_case_attr:
        /* empty */ {
                $$ = false;
@@ -2516,12 +2536,13 @@ gen_stmt:
                case_type_stack.pop_back();
                ast_stack.pop_back();
        } |
-       TOK_BEGIN opt_label {
+       begin opt_label {
                AstNode *node = new AstNode(AST_GENBLOCK);
                node->str = $2 ? *$2 : std::string();
                ast_stack.back()->children.push_back(node);
                ast_stack.push_back(node);
        } module_gen_body TOK_END opt_label {
+               exitTypeScope();
                if ($2 != NULL)
                        delete $2;
                if ($6 != NULL)
index d41a58147afbf5bf1f98a1bfabbed81238bf18c0..5507d84f28e3c540f1fa7fd4cca1c20f6562fc2b 100644 (file)
@@ -31,5 +31,12 @@ module top;
        always @(*) assert(inner_i2 == 4'h2);
        always @(*) assert(inner_enum2 == 3'h4);
 
+endmodule
+
+typedef logic[7:0]  between_t;
 
+module other;
+       between_t a = 8'h42;
+       always @(*) assert(a == 8'h42);
 endmodule
+