Implement subprogram bodies in package bodies.

This commit is contained in:
Stephen Williams 2013-05-18 17:36:29 -07:00
parent 6394a4d78d
commit e927960121
13 changed files with 224 additions and 53 deletions

View File

@ -146,15 +146,16 @@ void Scope::dump_scope(ostream&out) const
out << " signal " << cur->first.str() << ": ???" << endl; out << " signal " << cur->first.str() << ": ???" << endl;
} }
// Dump subprograms // Dump subprograms
out << " -- Subprograms" << endl; out << " -- Imported Subprograms" << endl;
for (map<perm_string,Subprogram*>::const_iterator cur = old_subprograms_.begin() for (map<perm_string,Subprogram*>::const_iterator cur = use_subprograms_.begin()
; cur != old_subprograms_.end() ; ++cur) { ; cur != use_subprograms_.end() ; ++cur) {
out << " subprogram " << cur->first << " is" << endl; out << " subprogram " << cur->first << " is" << endl;
cur->second->dump(out); cur->second->dump(out);
out << " end subprogram " << cur->first << endl; out << " end subprogram " << cur->first << endl;
} }
for (map<perm_string,Subprogram*>::const_iterator cur = new_subprograms_.begin() out << " -- Subprograms from this scope" << endl;
; cur != new_subprograms_.end() ; ++cur) { for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++cur) {
out << " subprogram " << cur->first << " is" << endl; out << " subprogram " << cur->first << " is" << endl;
cur->second->dump(out); cur->second->dump(out);
out << " end subprogram " << cur->first << endl; out << " end subprogram " << cur->first << endl;

View File

@ -120,7 +120,8 @@ void dump_libraries(ostream&file)
/* /*
* This function saves a package into the named library. Create the * This function saves a package into the named library. Create the
* library if necessary. * library if necessary. The parser uses this when it is finished with
* a package declaration.
*/ */
void library_save_package(perm_string parse_library_name, Package*pack) void library_save_package(perm_string parse_library_name, Package*pack)
{ {
@ -139,6 +140,27 @@ void library_save_package(perm_string parse_library_name, Package*pack)
pack->set_library(parse_library_name); pack->set_library(parse_library_name);
} }
/*
* The parser uses this function in the package body rule to recall
* the package that was declared earlier.
*/
Package*library_recall_package(perm_string parse_library_name, perm_string package_name)
{
perm_string use_libname = parse_library_name.str()
? parse_library_name
: perm_string::literal("work");
map<perm_string,struct library_contents>::iterator lib = libraries.find(use_libname);
if (lib == libraries.end())
return 0;
map<perm_string,Package*>::iterator pkg = lib->second.packages.find(package_name);
if (pkg == lib->second.packages.end())
return 0;
return pkg->second;
}
static void import_library_name(const YYLTYPE&loc, perm_string name) static void import_library_name(const YYLTYPE&loc, perm_string name)
{ {
if (library_dir[name] != string()) if (library_dir[name] != string())

View File

@ -46,8 +46,6 @@ void Package::set_library(perm_string lname)
*/ */
void Package::write_to_stream(ostream&fd) const void Package::write_to_stream(ostream&fd) const
{ {
ivl_assert(*this, new_subprograms_.size() == 0);
fd << "package " << name_ << " is" << endl; fd << "package " << name_ << " is" << endl;
// Start out pre-declaring all the type definitions so that // Start out pre-declaring all the type definitions so that
@ -104,8 +102,8 @@ void Package::write_to_stream(ostream&fd) const
fd << ";" << endl; fd << ";" << endl;
} }
for (map<perm_string,Subprogram*>::const_iterator cur = old_subprograms_.begin() for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
; cur != old_subprograms_.end() ; ++cur) { ; cur != cur_subprograms_.end() ; ++cur) {
cur->second->write_to_stream(fd); cur->second->write_to_stream(fd);
} }

View File

@ -36,6 +36,8 @@ class Package : public Scope, public LineInfo {
perm_string name() const { return name_; } perm_string name() const { return name_; }
Subprogram* recall_subprogram(perm_string name) const;
// This method writes a package header to a library file. // This method writes a package header to a library file.
void write_to_stream(std::ostream&fd) const; void write_to_stream(std::ostream&fd) const;

View File

@ -26,11 +26,9 @@ using namespace std;
int Package::emit_package(ostream&fd) const int Package::emit_package(ostream&fd) const
{ {
ivl_assert(*this, new_subprograms_.empty());
// Don't emit the package if there is nothing in it that SV // Don't emit the package if there is nothing in it that SV
// cares about. // cares about.
if (cur_types_.empty() && cur_constants_.empty() && old_subprograms_.empty()) if (cur_types_.empty() && cur_constants_.empty() && cur_subprograms_.empty())
return 0; return 0;
// If this package was imported from a library, then do not // If this package was imported from a library, then do not
@ -67,8 +65,8 @@ int Package::emit_package(ostream&fd) const
fd << ";" << endl; fd << ";" << endl;
} }
for (map<perm_string,Subprogram*>::const_iterator cur = old_subprograms_.begin() for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
; cur != old_subprograms_.end() ; ++ cur) { ; cur != cur_subprograms_.end() ; ++ cur) {
errors += cur->second->emit_package(fd); errors += cur->second->emit_package(fd);
} }

View File

@ -322,11 +322,12 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <record_elements> element_declaration element_declaration_list %type <record_elements> element_declaration element_declaration_list
%type <text> architecture_body_start package_declaration_start %type <text> architecture_body_start package_declaration_start
%type <text> package_body_start
%type <text> identifier_opt identifier_colon_opt logical_name suffix %type <text> identifier_opt identifier_colon_opt logical_name suffix
%type <name_list> logical_name_list identifier_list %type <name_list> logical_name_list identifier_list
%type <name_list> enumeration_literal_list enumeration_literal %type <name_list> enumeration_literal_list enumeration_literal
%type <sequ_list> sequence_of_statements if_statement_else %type <sequ_list> if_statement_else sequence_of_statements subprogram_statement_part
%type <sequ> sequential_statement if_statement signal_assignment_statement %type <sequ> sequential_statement if_statement signal_assignment_statement
%type <sequ> case_statement procedure_call procedure_call_statement %type <sequ> case_statement procedure_call procedure_call_statement
%type <sequ> loop_statement variable_assignment_statement %type <sequ> loop_statement variable_assignment_statement
@ -1613,20 +1614,40 @@ package_declarative_part_opt
| |
; ;
package_body package_body /* IEEE 1076-2008 P4.8 */
: K_package K_body IDENTIFIER K_is : package_body_start K_is
package_body_declarative_part_opt package_body_declarative_part_opt
K_end K_package_opt identifier_opt ';' K_end K_package_opt identifier_opt ';'
{ sorrymsg(@1, "Package body is not yet supported.\n"); { perm_string name = lex_strings.make($1);
delete[] $3; if ($6 && name != $6)
if($8) delete[] $8; errormsg(@6, "Package name (%s) doesn't match closing name (%s).\n", $1, $6);
delete[] $1;
if($6) delete[]$6;
pop_scope();
} }
| K_package K_body IDENTIFIER K_is | package_body_start K_is error K_end K_package_opt identifier_opt ';'
error { errormsg(@1, "Errors in package %s body.\n", $1);
K_end K_package_opt identifier_opt ';'
{ errormsg(@1, "Errors in package body.\n");
yyerrok; yyerrok;
pop_scope();
}
;
/*
* This is a portion of the package_body rule that we factor out so
* that we can use this rule to start the scope.
*/
package_body_start
: K_package K_body IDENTIFIER
{ perm_string name = lex_strings.make($3);
push_scope();
Package*pkg = library_recall_package(parse_library_name, name);
if (pkg != 0) {
active_scope->set_package_header(pkg);
} else {
errormsg(@1, "Package body for %s has no matching header.\n", $3);
}
$$ = $3;
} }
; ;
@ -2065,14 +2086,24 @@ signal_assignment_statement
} }
; ;
/* This is a function/task body. This may have a matching subprogram
declaration, and if so it will be in the active scope. */
subprogram_body /* IEEE 1076-2008 P4.3 */ subprogram_body /* IEEE 1076-2008 P4.3 */
: subprogram_specification K_is : subprogram_specification K_is
subprogram_declarative_part subprogram_declarative_part
K_begin subprogram_statement_part K_end K_begin subprogram_statement_part K_end
subprogram_kind_opt identifier_opt ';' subprogram_kind_opt identifier_opt ';'
{ sorrymsg(@2, "Subprogram bodies not supported.\n"); { Subprogram*prog = $1;
if ($1) delete $1; Subprogram*tmp = active_scope->recall_subprogram(prog->name());
if ($8) delete[]$8; if (tmp && prog->compare_specification(tmp)) {
delete prog;
prog = tmp;
} else if (tmp) {
errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str());
}
prog->set_program_body($5);
active_scope->bind_name(prog->name(), prog);
} }
| subprogram_specification K_is | subprogram_specification K_is
@ -2122,8 +2153,8 @@ subprogram_specification
sequential_statement. Also handle the special case of an empty sequential_statement. Also handle the special case of an empty
list here. */ list here. */
subprogram_statement_part subprogram_statement_part
: sequence_of_statements : sequence_of_statements { $$ = $1; }
| | { $$ = 0; }
; ;
subtype_declaration subtype_declaration

View File

@ -57,6 +57,8 @@ extern const VType* parse_type_by_name(perm_string name);
*/ */
extern void library_save_package(perm_string library_parse_name, Package*pack); extern void library_save_package(perm_string library_parse_name, Package*pack);
extern Package*library_recall_package(perm_string library_parse_name, perm_string name);
extern void library_import(const YYLTYPE&loc, const std::list<perm_string>*names); extern void library_import(const YYLTYPE&loc, const std::list<perm_string>*names);
extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident); extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident);

View File

@ -18,9 +18,11 @@
*/ */
# include "scope.h" # include "scope.h"
# include "package.h"
# include <algorithm> # include <algorithm>
# include <iostream> # include <iostream>
# include <iterator> # include <iterator>
# include <cassert>
using namespace std; using namespace std;
@ -52,11 +54,9 @@ ScopeBase::ScopeBase(const ActiveScope&ref)
); );
use_types_ = ref.use_types_; use_types_ = ref.use_types_;
cur_types_ = ref.cur_types_; cur_types_ = ref.cur_types_;
merge(ref.old_subprograms_.begin(), ref.old_subprograms_.end(),
ref.new_subprograms_.begin(), ref.new_subprograms_.end(), use_subprograms_ = ref.use_subprograms_;
insert_iterator<map<perm_string,Subprogram*> >( cur_subprograms_ = ref.cur_subprograms_;
old_subprograms_, old_subprograms_.end())
);
} }
ScopeBase::~ScopeBase() ScopeBase::~ScopeBase()
@ -76,7 +76,7 @@ void ScopeBase::cleanup()
delete_all(new_components_); delete_all(new_components_);
delete_all(cur_types_); delete_all(cur_types_);
delete_all(cur_constants_); delete_all(cur_constants_);
delete_all(new_subprograms_); delete_all(cur_subprograms_);
} }
const VType*ScopeBase::find_type(perm_string by_name) const VType*ScopeBase::find_type(perm_string by_name)
@ -139,6 +139,21 @@ Variable* ScopeBase::find_variable(perm_string by_name) const
} }
} }
Subprogram* ScopeBase::find_subprogram(perm_string name) const
{
map<perm_string,Subprogram*>::const_iterator cur;
cur = cur_subprograms_.find(name);
if (cur != cur_subprograms_.end())
return cur->second;
cur = use_subprograms_.find(name);
if (cur != use_subprograms_.find(name))
return cur->second;
return 0;
}
/* /*
* This method is only used by the ActiveScope derived class to import * This method is only used by the ActiveScope derived class to import
* definition from another scope. * definition from another scope.
@ -158,19 +173,14 @@ void ScopeBase::do_use_from(const ScopeBase*that)
old_components_[cur->first] = cur->second; old_components_[cur->first] = cur->second;
} }
for (map<perm_string,Subprogram*>::const_iterator cur = that->old_subprograms_.begin() for (map<perm_string,Subprogram*>::const_iterator cur = that->cur_subprograms_.begin()
; cur != that->old_subprograms_.end() ; ++ cur) { ; cur != that->cur_subprograms_.end() ; ++ cur) {
if (cur->second == 0) if (cur->second == 0)
continue; continue;
old_subprograms_[cur->first] = cur->second; use_subprograms_[cur->first] = cur->second;
}
for (map<perm_string,Subprogram*>::const_iterator cur = that->new_subprograms_.begin()
; cur != that->new_subprograms_.end() ; ++ cur) {
if (cur->second == 0)
continue;
old_subprograms_[cur->first] = cur->second;
} }
for (map<perm_string,const VType*>::const_iterator cur = that->cur_types_.begin() for (map<perm_string,const VType*>::const_iterator cur = that->cur_types_.begin()
; cur != that->cur_types_.end() ; ++ cur) { ; cur != that->cur_types_.end() ; ++ cur) {
if (cur->second == 0) if (cur->second == 0)
@ -184,6 +194,23 @@ void ScopeBase::do_use_from(const ScopeBase*that)
} }
} }
void ActiveScope::set_package_header(Package*pkg)
{
assert(package_header_ == 0);
package_header_ = pkg;
}
Subprogram* ActiveScope::recall_subprogram(perm_string name) const
{
if (Subprogram*tmp = find_subprogram(name))
return tmp;
if (package_header_)
return package_header_->find_subprogram(name);
return 0;
}
bool ActiveScope::is_vector_name(perm_string name) const bool ActiveScope::is_vector_name(perm_string name) const
{ {
if (find_signal(name)) if (find_signal(name))

View File

@ -57,6 +57,7 @@ class ScopeBase {
bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp); bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp);
Signal* find_signal(perm_string by_name) const; Signal* find_signal(perm_string by_name) const;
Variable* find_variable(perm_string by_name) const; Variable* find_variable(perm_string by_name) const;
Subprogram* find_subprogram(perm_string by_name) const;
protected: protected:
void cleanup(); void cleanup();
@ -100,8 +101,8 @@ class ScopeBase {
std::map<perm_string, struct const_t*> use_constants_; //imported constants std::map<perm_string, struct const_t*> use_constants_; //imported constants
std::map<perm_string, struct const_t*> cur_constants_; //current constants std::map<perm_string, struct const_t*> cur_constants_; //current constants
std::map<perm_string, Subprogram*> old_subprograms_; //previous scopes std::map<perm_string, Subprogram*> use_subprograms_; //imported
std::map<perm_string, Subprogram*> new_subprograms_; //current scope std::map<perm_string, Subprogram*> cur_subprograms_; //current
void do_use_from(const ScopeBase*that); void do_use_from(const ScopeBase*that);
}; };
@ -132,11 +133,16 @@ class Scope : public ScopeBase {
class ActiveScope : public ScopeBase { class ActiveScope : public ScopeBase {
public: public:
ActiveScope() : context_entity_(0) { } ActiveScope() : package_header_(0), context_entity_(0) { }
ActiveScope(ActiveScope*par) : ScopeBase(*par), context_entity_(0) { } ActiveScope(ActiveScope*par) : ScopeBase(*par), package_header_(0), context_entity_(0) { }
~ActiveScope() { } ~ActiveScope() { }
void set_package_header(Package*);
// Pull items from "that" scope into "this" scope as is
// defined by a "use" directive. The parser uses this method
// to implement the "use <pkg>::*" directive.
void use_from(const Scope*that) { do_use_from(that); } void use_from(const Scope*that) { do_use_from(that); }
// This function returns true if the name is a vectorable // This function returns true if the name is a vectorable
@ -144,6 +150,11 @@ class ActiveScope : public ScopeBase {
// calls and array index operations. // calls and array index operations.
bool is_vector_name(perm_string name) const; bool is_vector_name(perm_string name) const;
// Locate the subprogram by name. The subprogram body uses
// this to locate the sobprogram declaration. Note that the
// subprogram may be in a package header.
Subprogram* recall_subprogram(perm_string name) const;
/* All bind_name function check if the given name was present /* All bind_name function check if the given name was present
* in previous scopes. If it is found, it is erased (but the pointer * in previous scopes. If it is found, it is erased (but the pointer
* is not freed), in order to implement name shadowing. The pointer * is not freed), in order to implement name shadowing. The pointer
@ -188,11 +199,11 @@ class ActiveScope : public ScopeBase {
cur_constants_[name] = new const_t(obj, val); cur_constants_[name] = new const_t(obj, val);
} }
void bind_name(perm_string name, Subprogram*obj) inline void bind_name(perm_string name, Subprogram*obj)
{ map<perm_string, Subprogram*>::iterator it; { map<perm_string, Subprogram*>::iterator it;
if((it = old_subprograms_.find(name)) != old_subprograms_.end() ) if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
old_subprograms_.erase(it); use_subprograms_.erase(it);
new_subprograms_[name] = obj;; cur_subprograms_[name] = obj;;
} }
void bind(Entity*ent) void bind(Entity*ent)
@ -208,6 +219,10 @@ class ActiveScope : public ScopeBase {
std::map<perm_string,VTypeDef*> incomplete_types; std::map<perm_string,VTypeDef*> incomplete_types;
private: private:
// If this is a package body, then there is a Package header
// already declared.
Package*package_header_;
Entity*context_entity_; Entity*context_entity_;
}; };

View File

@ -21,6 +21,7 @@
# include "subprogram.h" # include "subprogram.h"
# include "entity.h" # include "entity.h"
# include "vtype.h" # include "vtype.h"
# include "ivl_assert.h"
using namespace std; using namespace std;
@ -34,6 +35,43 @@ Subprogram::~Subprogram()
{ {
} }
void Subprogram::set_program_body(list<SequentialStmt*>*stmt)
{
ivl_assert(*this, statements_==0);
statements_ = stmt;
}
bool Subprogram::compare_specification(Subprogram*that) const
{
if (name_ != that->name_)
return false;
if (return_type_==0) {
if (that->return_type_!=0)
return false;
} else {
if (that->return_type_==0)
return false;
if (! return_type_->type_match(that->return_type_))
return false;
}
if (ports_==0) {
if (that->ports_!=0)
return false;
} else {
if (that->ports_==0)
return false;
if (ports_->size() != that->ports_->size())
return false;
}
return true;
}
void Subprogram::write_to_stream(ostream&fd) const void Subprogram::write_to_stream(ostream&fd) const
{ {
fd << " function " << name_ << "("; fd << " function " << name_ << "(";

View File

@ -38,6 +38,12 @@ class Subprogram : public LineInfo {
inline const perm_string&name() const { return name_; } inline const perm_string&name() const { return name_; }
void set_program_body(std::list<SequentialStmt*>*statements);
// Return true if the specification (name, types, ports)
// matches this subprogram and that subprogram.
bool compare_specification(Subprogram*that) const;
// Emit a definition as it would show up in a package. // Emit a definition as it would show up in a package.
int emit_package(std::ostream&fd) const; int emit_package(std::ostream&fd) const;

View File

@ -45,6 +45,11 @@ class VType {
VType() { } VType() { }
virtual ~VType() =0; virtual ~VType() =0;
// This virtual method returns true if that is equivalent to
// this type. This method is used for example to compare
// function prototypes.
virtual bool type_match(const VType*that) const;
// This virtual method writes a VHDL-accurate representation // This virtual method writes a VHDL-accurate representation
// of this type to the designated stream. This is used for // of this type to the designated stream. This is used for
// writing parsed types to library files. // writing parsed types to library files.

26
vhdlpp/vtype_match.cc Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "vtype.h"
bool VType::type_match(const VType*that) const
{
return this == that;
}