From bae0f1d3a722f007697bf8b6974611f0daa5c545 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 31 Mar 2013 15:46:36 -0700 Subject: [PATCH] Parse more package items Rework lexical support for PACKAGE_IDENTIFIER so that the lexor can help with package scoped identifiers. Pform package types and package functions up to elaboration. --- PExpr.cc | 20 +++++++--- PExpr.h | 11 +++++- elab_expr.cc | 16 ++++++++ lexor.lex | 41 +++++++++++++++++++ parse.y | 33 ++++++++++------ parse_misc.h | 16 ++++++++ pform.cc | 54 ++++++++++++++++++++++++- pform.h | 13 +++++- pform_dump.cc | 4 ++ pform_package.cc | 101 +++++++++++++++++++++++++++++++++-------------- 10 files changed, 259 insertions(+), 50 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index ba6451891..a6bffbc00 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -174,7 +174,7 @@ PEBShift::~PEBShift() } PECallFunction::PECallFunction(const pform_name_t&n, const vector &parms) -: path_(n), parms_(parms) +: package_(0), path_(n), parms_(parms) { } @@ -186,19 +186,29 @@ static pform_name_t pn_from_ps(perm_string n) return tmp; } +PECallFunction::PECallFunction(PPackage*pkg, perm_string n, const list &parms) +: package_(pkg), path_(pn_from_ps(n)), parms_(parms.size()) +{ + int tmp_idx = 0; + assert(parms_.size() == parms.size()); + for (list::const_iterator idx = parms.begin() + ; idx != parms.end() ; ++idx) + parms_[tmp_idx++] = *idx; +} + PECallFunction::PECallFunction(perm_string n, const vector&parms) -: path_(pn_from_ps(n)), parms_(parms) +: package_(0), path_(pn_from_ps(n)), parms_(parms) { } PECallFunction::PECallFunction(perm_string n) -: path_(pn_from_ps(n)) +: package_(0), path_(pn_from_ps(n)) { } // NOTE: Anachronism. Try to work all use of svector out. PECallFunction::PECallFunction(const pform_name_t&n, const list &parms) -: path_(n), parms_(parms.size()) +: package_(0), path_(n), parms_(parms.size()) { int tmp_idx = 0; assert(parms_.size() == parms.size()); @@ -208,7 +218,7 @@ PECallFunction::PECallFunction(const pform_name_t&n, const list &parms) } PECallFunction::PECallFunction(perm_string n, const list&parms) -: path_(pn_from_ps(n)), parms_(parms.size()) +: package_(0), path_(pn_from_ps(n)), parms_(parms.size()) { int tmp_idx = 0; assert(parms_.size() == parms.size()); diff --git a/PExpr.h b/PExpr.h index 21dd268c7..0076bc5b8 100644 --- a/PExpr.h +++ b/PExpr.h @@ -770,11 +770,15 @@ class PETernary : public PExpr { class PECallFunction : public PExpr { public: explicit PECallFunction(const pform_name_t&n, const vector &parms); + // Call function defined in package. + explicit PECallFunction(PPackage*pkg, perm_string n, const std::vector &parms); + explicit PECallFunction(PPackage*pkg, perm_string n, const std::list &parms); + // Call of system function (name is not hierarchical) explicit PECallFunction(perm_string n, const vector &parms); explicit PECallFunction(perm_string n); - // svector versions. Should be removed! + // std::list versions. Should be removed! explicit PECallFunction(const pform_name_t&n, const list &parms); explicit PECallFunction(perm_string n, const list &parms); @@ -794,14 +798,17 @@ class PECallFunction : public PExpr { width_mode_t&mode); private: + PPackage*package_; pform_name_t path_; - vector parms_; + std::vector parms_; bool check_call_matches_definition_(Design*des, NetScope*dscope) const; NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const; + NetExpr*elaborate_expr_pkg_(Design*des, NetScope*scope, + unsigned expr_wid, unsigned flags)const; NetExpr*elaborate_expr_method_(Design*des, NetScope*scope, unsigned expr_wid) const; #if 0 diff --git a/elab_expr.cc b/elab_expr.cc index 50c1fb199..27c081521 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1775,10 +1775,26 @@ static NetExpr* check_for_class_property(const LineInfo*li, return tmp; } +NetExpr* PECallFunction::elaborate_expr_pkg_(Design*des, NetScope*scope, + unsigned expr_wid, + unsigned flags) const +{ + if (debug_elaborate) { + cerr << get_fileline() << ": PECallFunction::elaborate_expr_pkg_: " + << "Elaborate " << path_ + << " as function in package " << package_->pscope_name() + << "." << endl; + } + + return 0; +} NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { + if (package_) + return elaborate_expr_pkg_(des, scope, expr_wid, flags); + flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag if (peek_tail_name(path_)[0] == '$') diff --git a/lexor.lex b/lexor.lex index 4d3619406..2a362be39 100644 --- a/lexor.lex +++ b/lexor.lex @@ -91,6 +91,19 @@ static bool in_module = false; static bool in_UDP = false; bool in_celldefine = false; UCDriveType uc_drive = UCD_NONE; + +/* + * The parser sometimes needs to indicate to the lexor that the next + * identifier needs to be understood in the context of a package. The + * parser feeds back that left context with calls to the + * lex_in_package_scope. + */ +static PPackage* in_package_scope = 0; +void lex_in_package_scope(PPackage*pkg) +{ + in_package_scope = pkg; +} + %} %x CCOMMENT @@ -297,6 +310,24 @@ TU [munpf] break; } + /* Special case: If this is part of a scoped name, then check + the package for identifier details. For example, if the + source file is foo::bar, the parse.y will note the + PACKAGE_IDENTIFIER and "::" token and mark the + "in_package_scope" variable. Then this lexor will see the + identifier here and interpret it in the package scope. */ + if (in_package_scope) { + if (rc == IDENTIFIER) { + if (data_type_t*type = pform_test_type_identifier(in_package_scope, yylval.text)) { + delete[]yylval.text; + yylval.data_type = type; + rc = TYPE_IDENTIFIER; + } + } + in_package_scope = 0; + return rc; + } + /* If this identifier names a discipline, then return this as a DISCIPLINE_IDENTIFIER and return the discipline as the value instead. */ @@ -310,6 +341,16 @@ TU [munpf] } } + /* If this identifer names a previously declared package, then + return this as a PACKAGE_IDENTIFIER instead. */ + if (rc == IDENTIFIER && gn_system_verilog()) { + if (PPackage*pkg = pform_test_package_identifier(yylval.text)) { + delete[]yylval.text; + yylval.package = pkg; + rc = PACKAGE_IDENTIFIER; + } + } + /* If this identifier names a previously declared type, then return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { diff --git a/parse.y b/parse.y index 49c2c30f8..595bb1775 100644 --- a/parse.y +++ b/parse.y @@ -401,6 +401,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector class_type_t*class_type; real_type_t::type_t real_type; property_qualifier_t property_qualifier; + PPackage*package; verinum* number; @@ -410,8 +411,9 @@ static void current_function_set_statement(const YYLTYPE&loc, vector list *dimensions; }; -%token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL +%token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL %token TYPE_IDENTIFIER +%token PACKAGE_IDENTIFIER %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER %token BASED_NUMBER DEC_NUMBER UNBASED_NUMBER @@ -925,6 +927,12 @@ data_type /* IEEE1800-2005: A.2.2.1 */ { if ($2) $$ = new parray_type_t($1, $2); else $$ = $1; } + | PACKAGE_IDENTIFIER K_SCOPE_RES + { lex_in_package_scope($1); } + TYPE_IDENTIFIER + { lex_in_package_scope(0); + $$ = $4; + } | K_string { string_type_t*tmp = new string_type_t; FILE_NAME(tmp, @1); @@ -1373,14 +1381,12 @@ package_import_declaration /* IEEE1800-2005 A.2.1.3 */ ; package_import_item - : IDENTIFIER K_SCOPE_RES IDENTIFIER + : PACKAGE_IDENTIFIER K_SCOPE_RES IDENTIFIER { pform_package_import(@2, $1, $3); - delete[]$1; delete[]$3; } - | IDENTIFIER K_SCOPE_RES '*' + | PACKAGE_IDENTIFIER K_SCOPE_RES '*' { pform_package_import(@2, $1, 0); - delete[]$1; } ; @@ -2985,7 +2991,7 @@ expr_primary delete $1; } - | IDENTIFIER K_SCOPE_RES IDENTIFIER + | PACKAGE_IDENTIFIER K_SCOPE_RES IDENTIFIER { $$ = pform_package_ident(@2, $1, $3); } /* An identifier followed by an expression list in parentheses is a @@ -2993,8 +2999,7 @@ expr_primary call. */ | hierarchy_identifier '(' expression_list_proper ')' - { PECallFunction*tmp = new PECallFunction(*$1, *$3); - FILE_NAME(tmp, @1); + { PECallFunction*tmp = pform_make_call_function(@1, *$1, *$3); delete $1; $$ = tmp; } @@ -3006,15 +3011,21 @@ expr_primary $$ = tmp; } | hierarchy_identifier '(' ')' - { const vector empty; - PECallFunction*tmp = new PECallFunction(*$1, empty); - FILE_NAME(tmp, @1); + { const list empty; + PECallFunction*tmp = pform_make_call_function(@1, *$1, empty); delete $1; $$ = tmp; if (!gn_system_verilog()) { yyerror(@1, "error: Empty function argument list requires SystemVerilog."); } } + | PACKAGE_IDENTIFIER K_SCOPE_RES IDENTIFIER '(' expression_list_proper ')' + { perm_string use_name = lex_strings.make($3); + PECallFunction*tmp = new PECallFunction($1, use_name, *$5); + FILE_NAME(tmp, @3); + delete[]$3; + $$ = tmp; + } | SYSTEM_IDENTIFIER '(' ')' { perm_string tn = lex_strings.make($1); const vectorempty; diff --git a/parse_misc.h b/parse_misc.h index a0a8fe817..8d1431542 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -78,6 +78,15 @@ extern UCDriveType uc_drive; extern bool have_timeunit_decl; extern bool have_timeprec_decl; +/* + * The parser signals back to the lexor that the next identifier + * should be in the package scope. For example, if the source is + * :: + * Then the parser calls this function to set the package context so + * that the lexor can interpret in the package context. + */ +extern void lex_in_package_scope(PPackage*pkg); + /* * Test if this identifier is a type identifier in the current * context. The pform code needs to help the lexor here because the @@ -85,6 +94,13 @@ extern bool have_timeprec_decl; * type names. */ extern data_type_t* pform_test_type_identifier(const char*txt); +extern data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt); + +/* + * Test if this identigier is a package name. The pform needs to help + * the lexor here because the parser detects packages and saves them. + */ +extern PPackage* pform_test_package_identifier(const char*txt); /* * Export these functions because we have to generate PENumber class diff --git a/pform.cc b/pform.cc index 3d43377d2..4ccca2767 100644 --- a/pform.cc +++ b/pform.cc @@ -519,18 +519,70 @@ data_type_t* pform_test_type_identifier(const char*txt) return 0; perm_string name = lex_strings.make(txt); - map::iterator cur; + LexicalScope*cur_scope = lexical_scope; do { + map::iterator cur; + + // First look to see if this identifier is imported from + // a package. If it is, see if it is a type in that + // package. If it is, then great. If imported as + // something other then a type, then give up now becase + // the name has at least shadowed any other possible + // meaning for this name. + map::iterator cur_pkg; + cur_pkg = cur_scope->imports.find(name); + if (cur_pkg != cur_scope->imports.end()) { + PPackage*pkg = cur_pkg->second; + cur = pkg->typedefs.find(name); + if (cur != pkg->typedefs.end()) + return cur->second; + + // Not a type. Give up. + return 0; + } + cur = cur_scope->typedefs.find(name); if (cur != cur_scope->typedefs.end()) return cur->second; cur_scope = cur_scope->parent_scope(); } while (cur_scope); + return 0; } +PECallFunction* pform_make_call_function(const struct vlltype&loc, + const pform_name_t&name, + const list&parms) +{ + PECallFunction*tmp = 0; + + // First try to get the function name from a package. Check + // the imports, and if the name is there, make the function as + // a package member. + do { + if (name.size() != 1) + break; + + perm_string use_name = peek_tail_name(name); + + map::iterator cur_pkg; + cur_pkg = lexical_scope->imports.find(use_name); + if (cur_pkg == lexical_scope->imports.end()) + break; + + tmp = new PECallFunction(cur_pkg->second, use_name, parms); + } while(0); + + if (tmp == 0) { + tmp = new PECallFunction(name, parms); + } + + FILE_NAME(tmp, loc); + return tmp; +} + static void pform_put_behavior_in_scope(PProcess*pp) { lexical_scope->behaviors.push_back(pp); diff --git a/pform.h b/pform.h index e1ac7e1a9..2cf2a35b0 100644 --- a/pform.h +++ b/pform.h @@ -57,6 +57,7 @@ */ class PGate; class PExpr; +class PPackage; class PSpecPath; class PClass; class PPackage; @@ -207,10 +208,10 @@ extern void pform_start_package_declaration(const struct vlltype&loc, const char*type); extern void pform_end_package_declaration(const struct vlltype&loc); extern void pform_package_import(const struct vlltype&loc, - const char*pkg_name, const char*ident); + PPackage*pkg, const char*ident); extern PExpr* pform_package_ident(const struct vlltype&loc, - const char*pkg_name, const char*ident); + PPackage*pkg, const char*ident); /* * This creates an identifier aware of names that may have been @@ -272,6 +273,14 @@ extern PGenerate* pform_parent_generate(void); extern void pform_set_typedef(perm_string name, data_type_t*data_type); +/* + * This function makes a PECallFunction of the named function. Decide + * if this function is in the scope or is imported from a package. + */ +extern PECallFunction* pform_make_call_function(const struct vlltype&loc, + const pform_name_t&name, + const list&parms); + /* * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. diff --git a/pform_dump.cc b/pform_dump.cc index 1b54b275d..7d6e9d67f 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -239,6 +239,8 @@ void PEConcat::dump(ostream&out) const void PECallFunction::dump(ostream &out) const { + if (package_) out << package_->pscope_name() << "::"; + out << path_ << "("; if (! parms_.empty()) { @@ -1537,5 +1539,7 @@ void PPackage::pform_dump(std::ostream&out) const out << "package " << pscope_name() << endl; dump_localparams_(out, 4); dump_parameters_(out, 4); + dump_tasks_(out, 4); + dump_funcs_(out, 4); out << "endpackage" << endl; } diff --git a/pform_package.cc b/pform_package.cc index 24cf52da2..ae82e8814 100644 --- a/pform_package.cc +++ b/pform_package.cc @@ -71,18 +71,8 @@ void pform_end_package_declaration(const struct vlltype&loc) * package is declared in pform ahead of time (it is) and that we can * simply transfer definitions to the current scope (we can). */ -void pform_package_import(const struct vlltype&, const char*pkg_name, const char*ident) +void pform_package_import(const struct vlltype&, PPackage*pkg, const char*ident) { - perm_string use_name = lex_strings.make(pkg_name); - map::const_iterator pcur = pform_packages.find(use_name); - if (pcur == pform_packages.end()) { - ostringstream msg; - msg << "Package " << pkg_name << " not found." << ends; - VLerror(msg.str().c_str()); - return; - } - - PPackage*pkg = pcur->second; LexicalScope*scope = pform_peek_scope(); if (ident) { @@ -90,15 +80,36 @@ void pform_package_import(const struct vlltype&, const char*pkg_name, const char map::const_iterator cur = pkg->parameters.find(use_ident); - if (cur == pkg->parameters.end()) { - ostringstream msg; - msg << "Symbol " << use_ident - << " not found in package " << pcur->first << "." << ends; - VLerror(msg.str().c_str()); + if (cur != pkg->parameters.end()) { + scope->imports[cur->first] = pkg; return; } - scope->imports[cur->first] = pkg; + cur = pkg->localparams.find(use_ident); + if (cur != pkg->localparams.end()) { + scope->imports[cur->first] = pkg; + return; + } + + map::const_iterator tcur; + tcur = pkg->typedefs.find(use_ident); + if (tcur != pkg->typedefs.end()) { + scope->imports[tcur->first] = pkg; + return; + } + + map::const_iterator fcur; + fcur = pkg->funcs.find(use_ident); + if (fcur != pkg->funcs.end()) { + scope->imports[fcur->first] = pkg; + return; + } + + ostringstream msg; + msg << "Symbol " << use_ident + << " not found in package " << pkg->pscope_name() << "." << ends; + VLerror(msg.str().c_str()); + return; } else { @@ -109,24 +120,56 @@ void pform_package_import(const struct vlltype&, const char*pkg_name, const char scope->imports[cur->first] = pkg; } + + for (map::const_iterator cur = pkg->localparams.begin() + ; cur != pkg->localparams.end() ; ++cur) { + + scope->imports[cur->first] = pkg; + } + + for (map::const_iterator cur = pkg->typedefs.begin() + ; cur != pkg->typedefs.end() ; ++cur) { + + scope->imports[cur->first] = pkg; + } + + for (map::const_iterator cur = pkg->funcs.begin() + ; cur != pkg->funcs.end() ; ++cur) { + + scope->imports[cur->first] = pkg; + } } } PExpr* pform_package_ident(const struct vlltype&loc, - const char*pkg_name, const char*ident_name) + PPackage*pkg, const char*ident_name) { - perm_string use_name = lex_strings.make(pkg_name); - map::const_iterator pcur = pform_packages.find(use_name); - if (pcur == pform_packages.end()) { - ostringstream msg; - msg << "Package " << pkg_name << " not found." << ends; - VLerror(msg.str().c_str()); - return 0; - } - - assert(pcur->second); perm_string use_ident = lex_strings.make(ident_name); - PEIdent*tmp = new PEIdent(pcur->second, use_ident); + PEIdent*tmp = new PEIdent(pkg, use_ident); FILE_NAME(tmp, loc); return tmp; } + +data_type_t* pform_test_type_identifier(PPackage*pkg, const char*txt) +{ + perm_string use_name = lex_strings.make(txt); + map::const_iterator cur = pkg->typedefs.find(use_name); + if (cur != pkg->typedefs.end()) + return cur->second; + + return 0; +} + +/* + * The lexor uses this function to know if the + */ +PPackage* pform_test_package_identifier(const char*pkg_name) +{ + perm_string use_name = lex_strings.make(pkg_name); + map::const_iterator pcur = pform_packages.find(use_name); + if (pcur == pform_packages.end()) + return 0; + + assert(pcur->second); + return pcur->second; +}