From b0e4a6884a3308e5f960670a0ea7b1a26dd19dd1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 15 Feb 2008 21:20:24 -0800 Subject: [PATCH] Objects of lexical scope use PScope base class. All the pform objects that represent lexical scope now are derived from the PScope class, and are kept in a lexical_scope table so that the scope can be managed. --- Module.cc | 2 +- PFunction.cc | 4 +- PScope.cc | 4 +- PScope.h | 19 ++++-- PTask.cc | 4 +- PTask.h | 4 +- Statement.cc | 16 ++--- Statement.h | 10 +-- elab_scope.cc | 4 +- elaborate.cc | 8 +-- parse.y | 167 +++++++++++++++++++++++++------------------------- pform.cc | 49 +++++++++++---- pform.h | 7 ++- pform_dump.cc | 4 +- 14 files changed, 173 insertions(+), 129 deletions(-) diff --git a/Module.cc b/Module.cc index 74f36f678c..596d902102 100644 --- a/Module.cc +++ b/Module.cc @@ -29,7 +29,7 @@ /* n is a permallocated string. */ Module::Module(perm_string n) -: PScope(n) +: PScope(n, 0) { library_flag = false; default_nettype = NetNet::NONE; diff --git a/PFunction.cc b/PFunction.cc index f8f5e6027e..fb26c434be 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -21,8 +21,8 @@ #include "PTask.h" -PFunction::PFunction(perm_string name) -: PScope(name), ports_(0), statement_(0) +PFunction::PFunction(perm_string name, PScope*parent) +: PScope(name, parent), ports_(0), statement_(0) { return_type_.type = PTF_NONE; } diff --git a/PScope.cc b/PScope.cc index 3c1b1da4a4..541d52d43a 100644 --- a/PScope.cc +++ b/PScope.cc @@ -19,8 +19,8 @@ # include "PScope.h" -PScope::PScope(perm_string n) -: name_(n) +PScope::PScope(perm_string n, PScope*p) + : name_(n), parent_(p) { } diff --git a/PScope.h b/PScope.h index 5125f4bbae..39c445e912 100644 --- a/PScope.h +++ b/PScope.h @@ -20,14 +20,15 @@ */ # include "StringHeap.h" +# include "pform_types.h" # include class PEvent; /* * The PScope class is a base representation of an object that - * represents some sort of compile-time scope. For example, a module, - * a function/task, a named block is derived from a PScope. + * represents lexical scope. For example, a module, a function/task, a + * named block is derived from a PScope. * * NOTE: This is note the same concept as the "scope" of an elaborated * hierarchy. That is represented by NetScope objects after elaboration. @@ -35,16 +36,26 @@ class PEvent; class PScope { public: - PScope(perm_string name); - ~PScope(); + // When created, a scope has a name and a parent. The name is + // the name of the definition. For example, if this is a + // module declaration, the name is the name after the "module" + // keyword, and if this is a task scope, the name is the task + // name. The parent is the lexical parent of this scope. Since + // modules do not nest in Verilog, the parent must be nil for + // modules. Scopes for tasks and functions point to their + // containing module. + PScope(perm_string name, PScope*parent); + virtual ~PScope(); perm_string pscope_name() const { return name_; } + PScope* pscope_parent() { return parent_; } // Named events in the scope. mapevents; private: perm_string name_; + PScope*parent_; }; #endif diff --git a/PTask.cc b/PTask.cc index 9155cb0b2f..b829e03f20 100644 --- a/PTask.cc +++ b/PTask.cc @@ -21,8 +21,8 @@ # include "PTask.h" -PTask::PTask(perm_string name) -: PScope(name), ports_(0), statement_(0) +PTask::PTask(perm_string name, PScope*parent) +: PScope(name, parent), ports_(0), statement_(0) { } diff --git a/PTask.h b/PTask.h index 9c296a78d2..4d9c24e9c4 100644 --- a/PTask.h +++ b/PTask.h @@ -51,7 +51,7 @@ struct PTaskFuncArg { class PTask : public PScope, public LineInfo { public: - explicit PTask(perm_string name); + explicit PTask(perm_string name, PScope*parent); ~PTask(); void set_ports(svector*p); @@ -90,7 +90,7 @@ class PTask : public PScope, public LineInfo { class PFunction : public PScope, public LineInfo { public: - explicit PFunction(perm_string name); + explicit PFunction(perm_string name, PScope*parent); ~PFunction(); void set_ports(svector*p); diff --git a/Statement.cc b/Statement.cc index f6f14fa654..1ab66ec353 100644 --- a/Statement.cc +++ b/Statement.cc @@ -86,18 +86,13 @@ PAssignNB::~PAssignNB() { } -PBlock::PBlock(perm_string n, BL_TYPE t, const svector&st) -: name_(n), bl_type_(t), list_(st) -{ -} - -PBlock::PBlock(BL_TYPE t, const svector&st) -: bl_type_(t), list_(st) +PBlock::PBlock(perm_string n, PScope*parent, BL_TYPE t) +: PScope(n, parent), bl_type_(t) { } PBlock::PBlock(BL_TYPE t) -: bl_type_(t) +: PScope(perm_string(),0), bl_type_(t) { } @@ -107,6 +102,11 @@ PBlock::~PBlock() delete list_[idx]; } +void PBlock::set_statement(const svector&st) +{ + list_ = st; +} + PCallTask::PCallTask(const pform_name_t&n, const svector&p) : path_(n), parms_(p) { diff --git a/Statement.h b/Statement.h index 21864a8315..09567b4183 100644 --- a/Statement.h +++ b/Statement.h @@ -27,6 +27,7 @@ # include "StringHeap.h" # include "PDelays.h" # include "PExpr.h" +# include "PScope.h" # include "HName.h" # include "LineInfo.h" class PExpr; @@ -147,25 +148,26 @@ class PAssignNB : public PAssign_ { * statements before constructing this object, so it knows a priori * what is contained. */ -class PBlock : public Statement { +class PBlock : public PScope, public Statement { public: enum BL_TYPE { BL_SEQ, BL_PAR }; - explicit PBlock(perm_string n, BL_TYPE t, const svector&st); - explicit PBlock(BL_TYPE t, const svector&st); + // If the block has a name, it is a scope and also has a parent. + explicit PBlock(perm_string n, PScope*parent, BL_TYPE t); + // If it doesn't have a name, it's not a scope explicit PBlock(BL_TYPE t); ~PBlock(); BL_TYPE bl_type() const { return bl_type_; } + void set_statement(const svector&st); virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; private: - perm_string name_; const BL_TYPE bl_type_; svectorlist_; }; diff --git a/elab_scope.cc b/elab_scope.cc index c954da0258..2807813359 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -794,8 +794,8 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const { NetScope*my_scope = scope; - if (name_ != 0) { - hname_t use_name(name_); + if (pscope_name() != 0) { + hname_t use_name(pscope_name()); if (scope->child(use_name)) { cerr << get_fileline() << ": error: block/scope name " << use_name << " already used in this context." diff --git a/elaborate.cc b/elaborate.cc index 50481b0445..45438b9fb2 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1846,12 +1846,12 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const : NetBlock::SEQU; NetScope*nscope = 0; - if (name_.str() != 0) { - nscope = scope->child(hname_t(name_)); + if (pscope_name() != 0) { + nscope = scope->child(hname_t(pscope_name())); if (nscope == 0) { cerr << get_fileline() << ": internal error: " "unable to find block scope " << scope_path(scope) - << "<" << name_ << ">" << endl; + << "<" << pscope_name() << ">" << endl; des->errors += 1; return 0; } @@ -1869,7 +1869,7 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const // statement. There is no need to keep the block node. Also, // don't elide named blocks, because they might be referenced // elsewhere. - if ((list_.count() == 1) && (name_.str() == 0)) { + if ((list_.count() == 1) && (pscope_name() == 0)) { assert(list_[0]); NetProc*tmp = list_[0]->elaborate(des, nscope); return tmp; diff --git a/parse.y b/parse.y index 96c9a8111d..4b5461c99b 100644 --- a/parse.y +++ b/parse.y @@ -45,6 +45,12 @@ static struct { svector* range; } port_declaration_context; +/* The task and function rules need to briefly hold the pointer to the + task/function that is currently in progress. */ +static PTask* current_task = 0; +static PFunction* current_function = 0; +static PBlock* current_block = 0; + /* Later version of bison (including 1.35) will not compile in stack extension if the output is compiled with C++ and either the YYSTYPE or YYLTYPE are provided by the source code. However, I can get the @@ -1843,33 +1849,31 @@ module_item extension. */ | K_task IDENTIFIER ';' - { pform_push_scope($2); } + { current_task = pform_push_task_scope($2); + FILE_NAME(current_task, @1); + } task_item_list_opt statement_or_null K_endtask - { perm_string task_name = lex_strings.make($2); - PTask*tmp = new PTask(task_name); - FILE_NAME(tmp, @1); - tmp->set_ports($5); - tmp->set_statement($6); - pform_set_task(task_name, tmp); + { current_task->set_ports($5); + current_task->set_statement($6); pform_pop_scope(); + current_task = 0; delete $2; } | K_task IDENTIFIER - { pform_push_scope($2); } + { current_task = pform_push_task_scope($2); + FILE_NAME(current_task, @1); + } '(' task_port_decl_list ')' ';' task_item_list_opt statement_or_null K_endtask - { perm_string task_name = lex_strings.make($2); - PTask*tmp = new PTask(task_name); - FILE_NAME(tmp, @1); - tmp->set_ports($5); - tmp->set_statement($9); - pform_set_task(task_name, tmp); + { current_task->set_ports($5); + current_task->set_statement($9); pform_pop_scope(); + current_task = 0; delete $2; } @@ -1878,20 +1882,17 @@ module_item definitions in the func_body to take on the scope of the function instead of the module. */ - | K_function function_range_or_type_opt IDENTIFIER ';' - { pform_push_scope($3); } - function_item_list statement - K_endfunction - { perm_string name = lex_strings.make($3); - PFunction *tmp = new PFunction(name); - FILE_NAME(tmp, @1); - tmp->set_ports($6); - tmp->set_statement($7); - tmp->set_return($2); - pform_set_function(name, tmp); - pform_pop_scope(); - delete $3; - } + | K_function function_range_or_type_opt IDENTIFIER ';' + { current_function = pform_push_function_scope($3); } + function_item_list statement + K_endfunction + { current_function->set_ports($6); + current_function->set_statement($7); + current_function->set_return($2); + pform_pop_scope(); + current_function = 0; + delete $3; + } /* A generate region can contain further module items. Actually, it is supposed to be limited to certain kinds of module items, but @@ -2961,65 +2962,66 @@ statement name. These are handled by pushing the scope name then matching the declarations. The scope is popped at the end of the block. */ - | K_begin statement_list K_end - { PBlock*tmp = new PBlock(PBlock::BL_SEQ, *$2); - FILE_NAME(tmp, @1); - delete $2; - $$ = tmp; - } - | K_begin ':' IDENTIFIER - { pform_push_scope($3); } - block_item_decls_opt - statement_list K_end - { pform_pop_scope(); - PBlock*tmp = new PBlock(lex_strings.make($3), - PBlock::BL_SEQ, *$6); - FILE_NAME(tmp, @1); - delete $3; - delete $6; - $$ = tmp; - } - | K_begin K_end - { PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_begin ':' IDENTIFIER K_end - { PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_begin error K_end - { yyerrok; } + | K_begin statement_list K_end + { PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + tmp->set_statement(*$2); + delete $2; + $$ = tmp; + } + | K_begin ':' IDENTIFIER + { current_block = pform_push_block_scope($3, PBlock::BL_SEQ); + FILE_NAME(current_block, @1); + } + block_item_decls_opt + statement_list K_end + { pform_pop_scope(); + current_block->set_statement(*$6); + delete $3; + delete $6; + $$ = current_block; + } + | K_begin K_end + { PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_begin ':' IDENTIFIER K_end + { PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_begin error K_end + { yyerrok; } /* fork-join blocks are very similar to begin-end blocks. In fact, from the parser's perspective there is no real difference. All we need to do is remember that this is a parallel block so that the code generator can do the right thing. */ - | K_fork ':' IDENTIFIER - { pform_push_scope($3); } - block_item_decls_opt - statement_list K_join - { pform_pop_scope(); - PBlock*tmp = new PBlock(lex_strings.make($3), - PBlock::BL_PAR, *$6); - FILE_NAME(tmp, @1); - delete $3; - delete $6; - $$ = tmp; - } - | K_fork K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_fork ':' IDENTIFIER K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR); - FILE_NAME(tmp, @1); - delete $3; - $$ = tmp; - } + | K_fork ':' IDENTIFIER + { current_block = pform_push_block_scope($3, PBlock::BL_PAR); + FILE_NAME(current_block, @1); + } + block_item_decls_opt + statement_list K_join + { pform_pop_scope(); + current_block->set_statement(*$6); + delete $3; + delete $6; + $$ = current_block; + } + | K_fork K_join + { PBlock*tmp = new PBlock(PBlock::BL_PAR); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_fork ':' IDENTIFIER K_join + { PBlock*tmp = new PBlock(PBlock::BL_PAR); + FILE_NAME(tmp, @1); + delete $3; + $$ = tmp; + } | K_disable hierarchy_identifier ';' { PDisable*tmp = new PDisable(*$2); @@ -3039,8 +3041,9 @@ statement $$ = tmp; } | K_fork statement_list K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR, *$2); + { PBlock*tmp = new PBlock(PBlock::BL_PAR); FILE_NAME(tmp, @1); + tmp->set_statement(*$2); delete $2; $$ = tmp; } diff --git a/pform.cc b/pform.cc index 425a2162e1..1fabe8a424 100644 --- a/pform.cc +++ b/pform.cc @@ -38,6 +38,7 @@ # include "ivl_assert.h" + map pform_modules; map pform_primitives; @@ -103,6 +104,7 @@ static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where) */ static pform_name_t scope_stack; +static PScope* lexical_scope = 0; void pform_push_scope(char*name) { @@ -112,6 +114,7 @@ void pform_push_scope(char*name) void pform_pop_scope() { scope_stack.pop_back(); + lexical_scope = lexical_scope->pscope_parent(); } static pform_name_t hier_name(const char*tail) @@ -121,6 +124,41 @@ static pform_name_t hier_name(const char*tail) return name; } +PTask* pform_push_task_scope(char*name) +{ + pform_push_scope(name); + perm_string task_name = lex_strings.make(name); + PTask*task = new PTask(task_name, pform_cur_module); + + // Add the task to the current module + pform_cur_module->add_task(task->pscope_name(), task); + // Make this the current lexical scope + lexical_scope = task; + return task; +} + +PFunction* pform_push_function_scope(char*name) +{ + pform_push_scope(name); + perm_string func_name = lex_strings.make(name); + PFunction*func = new PFunction(func_name, lexical_scope); + + // Add the task to the current module + pform_cur_module->add_function(func->pscope_name(), func); + // Make this the current lexical scope + lexical_scope = func; + return func; +} + +PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) +{ + pform_push_scope(name); + perm_string block_name = lex_strings.make(name); + PBlock*block = new PBlock(block_name, lexical_scope, bt); + + return block; +} + static PWire*get_wire_in_module(const pform_name_t&name) { /* Note that if we are processing a generate, then the @@ -1590,17 +1628,6 @@ svector*pform_make_task_ports(NetNet::PortType pt, return res; } -void pform_set_task(perm_string name, PTask*task) -{ - pform_cur_module->add_task(name, task); -} - - -void pform_set_function(perm_string name, PFunction*func) -{ - pform_cur_module->add_function(name, func); -} - void pform_set_attrib(perm_string name, perm_string key, char*value) { pform_name_t path = hier_name(name); diff --git a/pform.h b/pform.h index 5dc556f304..45738a57f7 100644 --- a/pform.h +++ b/pform.h @@ -167,9 +167,12 @@ extern void pform_make_udp(perm_string name, * name string onto the scope hierarchy. The pop pulls it off and * deletes it. Thus, the string pushed must be allocated. */ -extern void pform_push_scope(char*name); extern void pform_pop_scope(); +extern PTask*pform_push_task_scope(char*name); +extern PFunction*pform_push_function_scope(char*name); +extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); + extern verinum* pform_verinum_with_size(verinum*s, verinum*val, const char*file, unsigned loneno); @@ -248,8 +251,6 @@ extern void pform_set_net_range(list*names, extern void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); -extern void pform_set_task(perm_string name, PTask*); -extern void pform_set_function(perm_string name, PFunction*); /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to diff --git a/pform_dump.cc b/pform_dump.cc index cee72d81db..f025b2c060 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -504,8 +504,8 @@ void PAssignNB::dump(ostream&out, unsigned ind) const void PBlock::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "begin"; - if (name_ != 0) - out << " : " << name_; + if (pscope_name() != 0) + out << " : " << pscope_name(); out << endl; for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) {