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.
This commit is contained in:
Stephen Williams 2008-02-15 21:20:24 -08:00
parent 3f2fa29482
commit b0e4a6884a
14 changed files with 173 additions and 129 deletions

View File

@ -29,7 +29,7 @@
/* n is a permallocated string. */ /* n is a permallocated string. */
Module::Module(perm_string n) Module::Module(perm_string n)
: PScope(n) : PScope(n, 0)
{ {
library_flag = false; library_flag = false;
default_nettype = NetNet::NONE; default_nettype = NetNet::NONE;

View File

@ -21,8 +21,8 @@
#include "PTask.h" #include "PTask.h"
PFunction::PFunction(perm_string name) PFunction::PFunction(perm_string name, PScope*parent)
: PScope(name), ports_(0), statement_(0) : PScope(name, parent), ports_(0), statement_(0)
{ {
return_type_.type = PTF_NONE; return_type_.type = PTF_NONE;
} }

View File

@ -19,8 +19,8 @@
# include "PScope.h" # include "PScope.h"
PScope::PScope(perm_string n) PScope::PScope(perm_string n, PScope*p)
: name_(n) : name_(n), parent_(p)
{ {
} }

View File

@ -20,14 +20,15 @@
*/ */
# include "StringHeap.h" # include "StringHeap.h"
# include "pform_types.h"
# include <map> # include <map>
class PEvent; class PEvent;
/* /*
* The PScope class is a base representation of an object that * The PScope class is a base representation of an object that
* represents some sort of compile-time scope. For example, a module, * represents lexical scope. For example, a module, a function/task, a
* a function/task, a named block is derived from a PScope. * named block is derived from a PScope.
* *
* NOTE: This is note the same concept as the "scope" of an elaborated * NOTE: This is note the same concept as the "scope" of an elaborated
* hierarchy. That is represented by NetScope objects after elaboration. * hierarchy. That is represented by NetScope objects after elaboration.
@ -35,16 +36,26 @@ class PEvent;
class PScope { class PScope {
public: public:
PScope(perm_string name); // When created, a scope has a name and a parent. The name is
~PScope(); // 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_; } perm_string pscope_name() const { return name_; }
PScope* pscope_parent() { return parent_; }
// Named events in the scope. // Named events in the scope.
map<perm_string,PEvent*>events; map<perm_string,PEvent*>events;
private: private:
perm_string name_; perm_string name_;
PScope*parent_;
}; };
#endif #endif

View File

@ -21,8 +21,8 @@
# include "PTask.h" # include "PTask.h"
PTask::PTask(perm_string name) PTask::PTask(perm_string name, PScope*parent)
: PScope(name), ports_(0), statement_(0) : PScope(name, parent), ports_(0), statement_(0)
{ {
} }

View File

@ -51,7 +51,7 @@ struct PTaskFuncArg {
class PTask : public PScope, public LineInfo { class PTask : public PScope, public LineInfo {
public: public:
explicit PTask(perm_string name); explicit PTask(perm_string name, PScope*parent);
~PTask(); ~PTask();
void set_ports(svector<PWire *>*p); void set_ports(svector<PWire *>*p);
@ -90,7 +90,7 @@ class PTask : public PScope, public LineInfo {
class PFunction : public PScope, public LineInfo { class PFunction : public PScope, public LineInfo {
public: public:
explicit PFunction(perm_string name); explicit PFunction(perm_string name, PScope*parent);
~PFunction(); ~PFunction();
void set_ports(svector<PWire *>*p); void set_ports(svector<PWire *>*p);

View File

@ -86,18 +86,13 @@ PAssignNB::~PAssignNB()
{ {
} }
PBlock::PBlock(perm_string n, BL_TYPE t, const svector<Statement*>&st) PBlock::PBlock(perm_string n, PScope*parent, BL_TYPE t)
: name_(n), bl_type_(t), list_(st) : PScope(n, parent), bl_type_(t)
{
}
PBlock::PBlock(BL_TYPE t, const svector<Statement*>&st)
: bl_type_(t), list_(st)
{ {
} }
PBlock::PBlock(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]; delete list_[idx];
} }
void PBlock::set_statement(const svector<Statement*>&st)
{
list_ = st;
}
PCallTask::PCallTask(const pform_name_t&n, const svector<PExpr*>&p) PCallTask::PCallTask(const pform_name_t&n, const svector<PExpr*>&p)
: path_(n), parms_(p) : path_(n), parms_(p)
{ {

View File

@ -27,6 +27,7 @@
# include "StringHeap.h" # include "StringHeap.h"
# include "PDelays.h" # include "PDelays.h"
# include "PExpr.h" # include "PExpr.h"
# include "PScope.h"
# include "HName.h" # include "HName.h"
# include "LineInfo.h" # include "LineInfo.h"
class PExpr; class PExpr;
@ -147,25 +148,26 @@ class PAssignNB : public PAssign_ {
* statements before constructing this object, so it knows a priori * statements before constructing this object, so it knows a priori
* what is contained. * what is contained.
*/ */
class PBlock : public Statement { class PBlock : public PScope, public Statement {
public: public:
enum BL_TYPE { BL_SEQ, BL_PAR }; enum BL_TYPE { BL_SEQ, BL_PAR };
explicit PBlock(perm_string n, BL_TYPE t, const svector<Statement*>&st); // If the block has a name, it is a scope and also has a parent.
explicit PBlock(BL_TYPE t, const svector<Statement*>&st); 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); explicit PBlock(BL_TYPE t);
~PBlock(); ~PBlock();
BL_TYPE bl_type() const { return bl_type_; } BL_TYPE bl_type() const { return bl_type_; }
void set_statement(const svector<Statement*>&st);
virtual void dump(ostream&out, unsigned ind) const; virtual void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const;
private: private:
perm_string name_;
const BL_TYPE bl_type_; const BL_TYPE bl_type_;
svector<Statement*>list_; svector<Statement*>list_;
}; };

View File

@ -794,8 +794,8 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
{ {
NetScope*my_scope = scope; NetScope*my_scope = scope;
if (name_ != 0) { if (pscope_name() != 0) {
hname_t use_name(name_); hname_t use_name(pscope_name());
if (scope->child(use_name)) { if (scope->child(use_name)) {
cerr << get_fileline() << ": error: block/scope name " cerr << get_fileline() << ": error: block/scope name "
<< use_name << " already used in this context." << use_name << " already used in this context."

View File

@ -1846,12 +1846,12 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
: NetBlock::SEQU; : NetBlock::SEQU;
NetScope*nscope = 0; NetScope*nscope = 0;
if (name_.str() != 0) { if (pscope_name() != 0) {
nscope = scope->child(hname_t(name_)); nscope = scope->child(hname_t(pscope_name()));
if (nscope == 0) { if (nscope == 0) {
cerr << get_fileline() << ": internal error: " cerr << get_fileline() << ": internal error: "
"unable to find block scope " << scope_path(scope) "unable to find block scope " << scope_path(scope)
<< "<" << name_ << ">" << endl; << "<" << pscope_name() << ">" << endl;
des->errors += 1; des->errors += 1;
return 0; 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, // statement. There is no need to keep the block node. Also,
// don't elide named blocks, because they might be referenced // don't elide named blocks, because they might be referenced
// elsewhere. // elsewhere.
if ((list_.count() == 1) && (name_.str() == 0)) { if ((list_.count() == 1) && (pscope_name() == 0)) {
assert(list_[0]); assert(list_[0]);
NetProc*tmp = list_[0]->elaborate(des, nscope); NetProc*tmp = list_[0]->elaborate(des, nscope);
return tmp; return tmp;

167
parse.y
View File

@ -45,6 +45,12 @@ static struct {
svector<PExpr*>* range; svector<PExpr*>* range;
} port_declaration_context; } 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 /* Later version of bison (including 1.35) will not compile in stack
extension if the output is compiled with C++ and either the YYSTYPE 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 or YYLTYPE are provided by the source code. However, I can get the
@ -1843,33 +1849,31 @@ module_item
extension. */ extension. */
| K_task IDENTIFIER ';' | K_task IDENTIFIER ';'
{ pform_push_scope($2); } { current_task = pform_push_task_scope($2);
FILE_NAME(current_task, @1);
}
task_item_list_opt task_item_list_opt
statement_or_null statement_or_null
K_endtask K_endtask
{ perm_string task_name = lex_strings.make($2); { current_task->set_ports($5);
PTask*tmp = new PTask(task_name); current_task->set_statement($6);
FILE_NAME(tmp, @1);
tmp->set_ports($5);
tmp->set_statement($6);
pform_set_task(task_name, tmp);
pform_pop_scope(); pform_pop_scope();
current_task = 0;
delete $2; delete $2;
} }
| K_task IDENTIFIER | K_task IDENTIFIER
{ pform_push_scope($2); } { current_task = pform_push_task_scope($2);
FILE_NAME(current_task, @1);
}
'(' task_port_decl_list ')' ';' '(' task_port_decl_list ')' ';'
task_item_list_opt task_item_list_opt
statement_or_null statement_or_null
K_endtask K_endtask
{ perm_string task_name = lex_strings.make($2); { current_task->set_ports($5);
PTask*tmp = new PTask(task_name); current_task->set_statement($9);
FILE_NAME(tmp, @1);
tmp->set_ports($5);
tmp->set_statement($9);
pform_set_task(task_name, tmp);
pform_pop_scope(); pform_pop_scope();
current_task = 0;
delete $2; delete $2;
} }
@ -1878,20 +1882,17 @@ module_item
definitions in the func_body to take on the scope of the function definitions in the func_body to take on the scope of the function
instead of the module. */ instead of the module. */
| K_function function_range_or_type_opt IDENTIFIER ';' | K_function function_range_or_type_opt IDENTIFIER ';'
{ pform_push_scope($3); } { current_function = pform_push_function_scope($3); }
function_item_list statement function_item_list statement
K_endfunction K_endfunction
{ perm_string name = lex_strings.make($3); { current_function->set_ports($6);
PFunction *tmp = new PFunction(name); current_function->set_statement($7);
FILE_NAME(tmp, @1); current_function->set_return($2);
tmp->set_ports($6); pform_pop_scope();
tmp->set_statement($7); current_function = 0;
tmp->set_return($2); delete $3;
pform_set_function(name, tmp); }
pform_pop_scope();
delete $3;
}
/* A generate region can contain further module items. Actually, it /* A generate region can contain further module items. Actually, it
is supposed to be limited to certain kinds of module items, but 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 name. These are handled by pushing the scope name then matching
the declarations. The scope is popped at the end of the block. */ the declarations. The scope is popped at the end of the block. */
| K_begin statement_list K_end | K_begin statement_list K_end
{ PBlock*tmp = new PBlock(PBlock::BL_SEQ, *$2); { PBlock*tmp = new PBlock(PBlock::BL_SEQ);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
delete $2; tmp->set_statement(*$2);
$$ = tmp; delete $2;
} $$ = tmp;
| K_begin ':' IDENTIFIER }
{ pform_push_scope($3); } | K_begin ':' IDENTIFIER
block_item_decls_opt { current_block = pform_push_block_scope($3, PBlock::BL_SEQ);
statement_list K_end FILE_NAME(current_block, @1);
{ pform_pop_scope(); }
PBlock*tmp = new PBlock(lex_strings.make($3), block_item_decls_opt
PBlock::BL_SEQ, *$6); statement_list K_end
FILE_NAME(tmp, @1); { pform_pop_scope();
delete $3; current_block->set_statement(*$6);
delete $6; delete $3;
$$ = tmp; delete $6;
} $$ = current_block;
| K_begin K_end }
{ PBlock*tmp = new PBlock(PBlock::BL_SEQ); | K_begin K_end
FILE_NAME(tmp, @1); { PBlock*tmp = new PBlock(PBlock::BL_SEQ);
$$ = tmp; FILE_NAME(tmp, @1);
} $$ = tmp;
| K_begin ':' IDENTIFIER K_end }
{ PBlock*tmp = new PBlock(PBlock::BL_SEQ); | K_begin ':' IDENTIFIER K_end
FILE_NAME(tmp, @1); { PBlock*tmp = new PBlock(PBlock::BL_SEQ);
$$ = tmp; FILE_NAME(tmp, @1);
} $$ = tmp;
| K_begin error K_end }
{ yyerrok; } | K_begin error K_end
{ yyerrok; }
/* fork-join blocks are very similar to begin-end blocks. In fact, /* fork-join blocks are very similar to begin-end blocks. In fact,
from the parser's perspective there is no real difference. All we 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 need to do is remember that this is a parallel block so that the
code generator can do the right thing. */ code generator can do the right thing. */
| K_fork ':' IDENTIFIER | K_fork ':' IDENTIFIER
{ pform_push_scope($3); } { current_block = pform_push_block_scope($3, PBlock::BL_PAR);
block_item_decls_opt FILE_NAME(current_block, @1);
statement_list K_join }
{ pform_pop_scope(); block_item_decls_opt
PBlock*tmp = new PBlock(lex_strings.make($3), statement_list K_join
PBlock::BL_PAR, *$6); { pform_pop_scope();
FILE_NAME(tmp, @1); current_block->set_statement(*$6);
delete $3; delete $3;
delete $6; delete $6;
$$ = tmp; $$ = current_block;
} }
| K_fork K_join | K_fork K_join
{ PBlock*tmp = new PBlock(PBlock::BL_PAR); { PBlock*tmp = new PBlock(PBlock::BL_PAR);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| K_fork ':' IDENTIFIER K_join | K_fork ':' IDENTIFIER K_join
{ PBlock*tmp = new PBlock(PBlock::BL_PAR); { PBlock*tmp = new PBlock(PBlock::BL_PAR);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
delete $3; delete $3;
$$ = tmp; $$ = tmp;
} }
| K_disable hierarchy_identifier ';' | K_disable hierarchy_identifier ';'
{ PDisable*tmp = new PDisable(*$2); { PDisable*tmp = new PDisable(*$2);
@ -3039,8 +3041,9 @@ statement
$$ = tmp; $$ = tmp;
} }
| K_fork statement_list K_join | 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); FILE_NAME(tmp, @1);
tmp->set_statement(*$2);
delete $2; delete $2;
$$ = tmp; $$ = tmp;
} }

View File

@ -38,6 +38,7 @@
# include "ivl_assert.h" # include "ivl_assert.h"
map<perm_string,Module*> pform_modules; map<perm_string,Module*> pform_modules;
map<perm_string,PUdp*> pform_primitives; map<perm_string,PUdp*> pform_primitives;
@ -103,6 +104,7 @@ static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
*/ */
static pform_name_t scope_stack; static pform_name_t scope_stack;
static PScope* lexical_scope = 0;
void pform_push_scope(char*name) void pform_push_scope(char*name)
{ {
@ -112,6 +114,7 @@ void pform_push_scope(char*name)
void pform_pop_scope() void pform_pop_scope()
{ {
scope_stack.pop_back(); scope_stack.pop_back();
lexical_scope = lexical_scope->pscope_parent();
} }
static pform_name_t hier_name(const char*tail) static pform_name_t hier_name(const char*tail)
@ -121,6 +124,41 @@ static pform_name_t hier_name(const char*tail)
return name; 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) static PWire*get_wire_in_module(const pform_name_t&name)
{ {
/* Note that if we are processing a generate, then the /* Note that if we are processing a generate, then the
@ -1590,17 +1628,6 @@ svector<PWire*>*pform_make_task_ports(NetNet::PortType pt,
return res; 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) void pform_set_attrib(perm_string name, perm_string key, char*value)
{ {
pform_name_t path = hier_name(name); pform_name_t path = hier_name(name);

View File

@ -167,9 +167,12 @@ extern void pform_make_udp(perm_string name,
* name string onto the scope hierarchy. The pop pulls it off and * name string onto the scope hierarchy. The pop pulls it off and
* deletes it. Thus, the string pushed must be allocated. * deletes it. Thus, the string pushed must be allocated.
*/ */
extern void pform_push_scope(char*name);
extern void pform_pop_scope(); 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, extern verinum* pform_verinum_with_size(verinum*s, verinum*val,
const char*file, unsigned loneno); const char*file, unsigned loneno);
@ -248,8 +251,6 @@ extern void pform_set_net_range(list<perm_string>*names,
extern void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r); extern void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r);
extern void pform_set_reg_integer(list<perm_string>*names); extern void pform_set_reg_integer(list<perm_string>*names);
extern void pform_set_reg_time(list<perm_string>*names); extern void pform_set_reg_time(list<perm_string>*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 /* pform_set_attrib and pform_set_type_attrib exist to support the
$attribute syntax, which can only set string values to $attribute syntax, which can only set string values to

View File

@ -504,8 +504,8 @@ void PAssignNB::dump(ostream&out, unsigned ind) const
void PBlock::dump(ostream&out, unsigned ind) const void PBlock::dump(ostream&out, unsigned ind) const
{ {
out << setw(ind) << "" << "begin"; out << setw(ind) << "" << "begin";
if (name_ != 0) if (pscope_name() != 0)
out << " : " << name_; out << " : " << pscope_name();
out << endl; out << endl;
for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) { for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) {