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:
parent
3f2fa29482
commit
b0e4a6884a
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
19
PScope.h
19
PScope.h
|
|
@ -20,14 +20,15 @@
|
|||
*/
|
||||
|
||||
# include "StringHeap.h"
|
||||
# include "pform_types.h"
|
||||
# include <map>
|
||||
|
||||
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.
|
||||
map<perm_string,PEvent*>events;
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
PScope*parent_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
4
PTask.cc
4
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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
4
PTask.h
4
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<PWire *>*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<PWire *>*p);
|
||||
|
|
|
|||
16
Statement.cc
16
Statement.cc
|
|
@ -86,18 +86,13 @@ PAssignNB::~PAssignNB()
|
|||
{
|
||||
}
|
||||
|
||||
PBlock::PBlock(perm_string n, BL_TYPE t, const svector<Statement*>&st)
|
||||
: name_(n), bl_type_(t), list_(st)
|
||||
{
|
||||
}
|
||||
|
||||
PBlock::PBlock(BL_TYPE t, const svector<Statement*>&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<Statement*>&st)
|
||||
{
|
||||
list_ = st;
|
||||
}
|
||||
|
||||
PCallTask::PCallTask(const pform_name_t&n, const svector<PExpr*>&p)
|
||||
: path_(n), parms_(p)
|
||||
{
|
||||
|
|
|
|||
10
Statement.h
10
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<Statement*>&st);
|
||||
explicit PBlock(BL_TYPE t, const svector<Statement*>&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<Statement*>&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_;
|
||||
svector<Statement*>list_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
167
parse.y
167
parse.y
|
|
@ -45,6 +45,12 @@ static struct {
|
|||
svector<PExpr*>* 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;
|
||||
}
|
||||
|
|
|
|||
49
pform.cc
49
pform.cc
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
map<perm_string,Module*> pform_modules;
|
||||
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 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<PWire*>*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);
|
||||
|
|
|
|||
7
pform.h
7
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<perm_string>*names,
|
|||
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_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
|
||||
$attribute syntax, which can only set string values to
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue