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.
This commit is contained in:
Stephen Williams 2013-03-31 15:46:36 -07:00
parent 23dbfabb1e
commit bae0f1d3a7
10 changed files with 259 additions and 50 deletions

View File

@ -174,7 +174,7 @@ PEBShift::~PEBShift()
}
PECallFunction::PECallFunction(const pform_name_t&n, const vector<PExpr *> &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<PExpr *> &parms)
: package_(pkg), path_(pn_from_ps(n)), parms_(parms.size())
{
int tmp_idx = 0;
assert(parms_.size() == parms.size());
for (list<PExpr*>::const_iterator idx = parms.begin()
; idx != parms.end() ; ++idx)
parms_[tmp_idx++] = *idx;
}
PECallFunction::PECallFunction(perm_string n, const vector<PExpr*>&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<PExpr *> &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<PExpr *> &parms)
}
PECallFunction::PECallFunction(perm_string n, const list<PExpr*>&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());

11
PExpr.h
View File

@ -770,11 +770,15 @@ class PETernary : public PExpr {
class PECallFunction : public PExpr {
public:
explicit PECallFunction(const pform_name_t&n, const vector<PExpr *> &parms);
// Call function defined in package.
explicit PECallFunction(PPackage*pkg, perm_string n, const std::vector<PExpr *> &parms);
explicit PECallFunction(PPackage*pkg, perm_string n, const std::list<PExpr *> &parms);
// Call of system function (name is not hierarchical)
explicit PECallFunction(perm_string n, const vector<PExpr *> &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<PExpr *> &parms);
explicit PECallFunction(perm_string n, const list<PExpr *> &parms);
@ -794,14 +798,17 @@ class PECallFunction : public PExpr {
width_mode_t&mode);
private:
PPackage*package_;
pform_name_t path_;
vector<PExpr *> parms_;
std::vector<PExpr *> 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

View File

@ -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] == '$')

View File

@ -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()) {

33
parse.y
View File

@ -401,6 +401,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
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<Statement*>
list<index_component_t> *dimensions;
};
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL
%token <data_type> TYPE_IDENTIFIER
%token <package> PACKAGE_IDENTIFIER
%token <discipline> DISCIPLINE_IDENTIFIER
%token <text> PATHPULSE_IDENTIFIER
%token <number> 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<PExpr*> empty;
PECallFunction*tmp = new PECallFunction(*$1, empty);
FILE_NAME(tmp, @1);
{ const list<PExpr*> 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 vector<PExpr*>empty;

View File

@ -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
* <package> :: <foo>
* Then the parser calls this function to set the package context so
* that the lexor can interpret <foo> 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

View File

@ -519,18 +519,70 @@ data_type_t* pform_test_type_identifier(const char*txt)
return 0;
perm_string name = lex_strings.make(txt);
map<perm_string,data_type_t*>::iterator cur;
LexicalScope*cur_scope = lexical_scope;
do {
map<perm_string,data_type_t*>::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<perm_string,PPackage*>::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<PExpr*>&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<perm_string,PPackage*>::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);

13
pform.h
View File

@ -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<PExpr*>&parms);
/*
* The makewire functions announce to the pform code new wires. These
* go into a module that is currently opened.

View File

@ -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;
}

View File

@ -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<perm_string,PPackage*>::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<perm_string,LexicalScope::param_expr_t>::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<perm_string,data_type_t*>::const_iterator tcur;
tcur = pkg->typedefs.find(use_ident);
if (tcur != pkg->typedefs.end()) {
scope->imports[tcur->first] = pkg;
return;
}
map<perm_string,PFunction*>::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<perm_string,LexicalScope::param_expr_t>::const_iterator cur = pkg->localparams.begin()
; cur != pkg->localparams.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (map<perm_string,data_type_t*>::const_iterator cur = pkg->typedefs.begin()
; cur != pkg->typedefs.end() ; ++cur) {
scope->imports[cur->first] = pkg;
}
for (map<perm_string,PFunction*>::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<perm_string,PPackage*>::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<perm_string,data_type_t*>::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<perm_string,PPackage*>::const_iterator pcur = pform_packages.find(use_name);
if (pcur == pform_packages.end())
return 0;
assert(pcur->second);
return pcur->second;
}