Implement subprogram bodies in package bodies.
This commit is contained in:
parent
6394a4d78d
commit
e927960121
|
|
@ -146,15 +146,16 @@ void Scope::dump_scope(ostream&out) const
|
|||
out << " signal " << cur->first.str() << ": ???" << endl;
|
||||
}
|
||||
// Dump subprograms
|
||||
out << " -- Subprograms" << endl;
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = old_subprograms_.begin()
|
||||
; cur != old_subprograms_.end() ; ++cur) {
|
||||
out << " -- Imported Subprograms" << endl;
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = use_subprograms_.begin()
|
||||
; cur != use_subprograms_.end() ; ++cur) {
|
||||
out << " subprogram " << cur->first << " is" << endl;
|
||||
cur->second->dump(out);
|
||||
out << " end subprogram " << cur->first << endl;
|
||||
}
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = new_subprograms_.begin()
|
||||
; cur != new_subprograms_.end() ; ++cur) {
|
||||
out << " -- Subprograms from this scope" << endl;
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
|
||||
; cur != cur_subprograms_.end() ; ++cur) {
|
||||
out << " subprogram " << cur->first << " is" << endl;
|
||||
cur->second->dump(out);
|
||||
out << " end subprogram " << cur->first << endl;
|
||||
|
|
|
|||
|
|
@ -120,7 +120,8 @@ void dump_libraries(ostream&file)
|
|||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
|
|
@ -139,6 +140,27 @@ void library_save_package(perm_string parse_library_name, Package*pack)
|
|||
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)
|
||||
{
|
||||
if (library_dir[name] != string())
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@ void Package::set_library(perm_string lname)
|
|||
*/
|
||||
void Package::write_to_stream(ostream&fd) const
|
||||
{
|
||||
ivl_assert(*this, new_subprograms_.size() == 0);
|
||||
|
||||
fd << "package " << name_ << " is" << endl;
|
||||
|
||||
// Start out pre-declaring all the type definitions so that
|
||||
|
|
@ -104,8 +102,8 @@ void Package::write_to_stream(ostream&fd) const
|
|||
fd << ";" << endl;
|
||||
}
|
||||
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = old_subprograms_.begin()
|
||||
; cur != old_subprograms_.end() ; ++cur) {
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
|
||||
; cur != cur_subprograms_.end() ; ++cur) {
|
||||
cur->second->write_to_stream(fd);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ class Package : public Scope, public LineInfo {
|
|||
|
||||
perm_string name() const { return name_; }
|
||||
|
||||
Subprogram* recall_subprogram(perm_string name) const;
|
||||
|
||||
// This method writes a package header to a library file.
|
||||
void write_to_stream(std::ostream&fd) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,9 @@ using namespace std;
|
|||
|
||||
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
|
||||
// cares about.
|
||||
if (cur_types_.empty() && cur_constants_.empty() && old_subprograms_.empty())
|
||||
if (cur_types_.empty() && cur_constants_.empty() && cur_subprograms_.empty())
|
||||
return 0;
|
||||
|
||||
// If this package was imported from a library, then do not
|
||||
|
|
@ -67,8 +65,8 @@ int Package::emit_package(ostream&fd) const
|
|||
fd << ";" << endl;
|
||||
}
|
||||
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = old_subprograms_.begin()
|
||||
; cur != old_subprograms_.end() ; ++ cur) {
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
|
||||
; cur != cur_subprograms_.end() ; ++ cur) {
|
||||
errors += cur->second->emit_package(fd);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -322,11 +322,12 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
|
|||
%type <record_elements> element_declaration element_declaration_list
|
||||
|
||||
%type <text> architecture_body_start package_declaration_start
|
||||
%type <text> package_body_start
|
||||
%type <text> identifier_opt identifier_colon_opt logical_name suffix
|
||||
%type <name_list> logical_name_list identifier_list
|
||||
%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> case_statement procedure_call procedure_call_statement
|
||||
%type <sequ> loop_statement variable_assignment_statement
|
||||
|
|
@ -1613,20 +1614,40 @@ package_declarative_part_opt
|
|||
|
|
||||
;
|
||||
|
||||
package_body
|
||||
: K_package K_body IDENTIFIER K_is
|
||||
package_body /* IEEE 1076-2008 P4.8 */
|
||||
: package_body_start K_is
|
||||
package_body_declarative_part_opt
|
||||
K_end K_package_opt identifier_opt ';'
|
||||
{ sorrymsg(@1, "Package body is not yet supported.\n");
|
||||
delete[] $3;
|
||||
if($8) delete[] $8;
|
||||
{ perm_string name = lex_strings.make($1);
|
||||
if ($6 && name != $6)
|
||||
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
|
||||
error
|
||||
K_end K_package_opt identifier_opt ';'
|
||||
{ errormsg(@1, "Errors in package body.\n");
|
||||
| package_body_start K_is error K_end K_package_opt identifier_opt ';'
|
||||
{ errormsg(@1, "Errors in package %s body.\n", $1);
|
||||
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_specification K_is
|
||||
subprogram_declarative_part
|
||||
K_begin subprogram_statement_part K_end
|
||||
subprogram_kind_opt identifier_opt ';'
|
||||
{ sorrymsg(@2, "Subprogram bodies not supported.\n");
|
||||
if ($1) delete $1;
|
||||
if ($8) delete[]$8;
|
||||
{ Subprogram*prog = $1;
|
||||
Subprogram*tmp = active_scope->recall_subprogram(prog->name());
|
||||
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
|
||||
|
|
@ -2122,8 +2153,8 @@ subprogram_specification
|
|||
sequential_statement. Also handle the special case of an empty
|
||||
list here. */
|
||||
subprogram_statement_part
|
||||
: sequence_of_statements
|
||||
|
|
||||
: sequence_of_statements { $$ = $1; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
subtype_declaration
|
||||
|
|
|
|||
|
|
@ -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 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_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident);
|
||||
|
|
|
|||
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
|
||||
# include "scope.h"
|
||||
# include "package.h"
|
||||
# include <algorithm>
|
||||
# include <iostream>
|
||||
# include <iterator>
|
||||
# include <cassert>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
|
@ -52,11 +54,9 @@ ScopeBase::ScopeBase(const ActiveScope&ref)
|
|||
);
|
||||
use_types_ = ref.use_types_;
|
||||
cur_types_ = ref.cur_types_;
|
||||
merge(ref.old_subprograms_.begin(), ref.old_subprograms_.end(),
|
||||
ref.new_subprograms_.begin(), ref.new_subprograms_.end(),
|
||||
insert_iterator<map<perm_string,Subprogram*> >(
|
||||
old_subprograms_, old_subprograms_.end())
|
||||
);
|
||||
|
||||
use_subprograms_ = ref.use_subprograms_;
|
||||
cur_subprograms_ = ref.cur_subprograms_;
|
||||
}
|
||||
|
||||
ScopeBase::~ScopeBase()
|
||||
|
|
@ -76,7 +76,7 @@ void ScopeBase::cleanup()
|
|||
delete_all(new_components_);
|
||||
delete_all(cur_types_);
|
||||
delete_all(cur_constants_);
|
||||
delete_all(new_subprograms_);
|
||||
delete_all(cur_subprograms_);
|
||||
}
|
||||
|
||||
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
|
||||
* definition from another scope.
|
||||
|
|
@ -158,19 +173,14 @@ void ScopeBase::do_use_from(const ScopeBase*that)
|
|||
old_components_[cur->first] = cur->second;
|
||||
}
|
||||
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = that->old_subprograms_.begin()
|
||||
; cur != that->old_subprograms_.end() ; ++ cur) {
|
||||
for (map<perm_string,Subprogram*>::const_iterator cur = that->cur_subprograms_.begin()
|
||||
; cur != that->cur_subprograms_.end() ; ++ cur) {
|
||||
if (cur->second == 0)
|
||||
continue;
|
||||
old_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;
|
||||
use_subprograms_[cur->first] = cur->second;
|
||||
}
|
||||
|
||||
|
||||
for (map<perm_string,const VType*>::const_iterator cur = that->cur_types_.begin()
|
||||
; cur != that->cur_types_.end() ; ++ cur) {
|
||||
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
|
||||
{
|
||||
if (find_signal(name))
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class ScopeBase {
|
|||
bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp);
|
||||
Signal* find_signal(perm_string by_name) const;
|
||||
Variable* find_variable(perm_string by_name) const;
|
||||
Subprogram* find_subprogram(perm_string by_name) const;
|
||||
|
||||
protected:
|
||||
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*> cur_constants_; //current constants
|
||||
|
||||
std::map<perm_string, Subprogram*> old_subprograms_; //previous scopes
|
||||
std::map<perm_string, Subprogram*> new_subprograms_; //current scope
|
||||
std::map<perm_string, Subprogram*> use_subprograms_; //imported
|
||||
std::map<perm_string, Subprogram*> cur_subprograms_; //current
|
||||
|
||||
void do_use_from(const ScopeBase*that);
|
||||
};
|
||||
|
|
@ -132,11 +133,16 @@ class Scope : public ScopeBase {
|
|||
class ActiveScope : public ScopeBase {
|
||||
|
||||
public:
|
||||
ActiveScope() : context_entity_(0) { }
|
||||
ActiveScope(ActiveScope*par) : ScopeBase(*par), context_entity_(0) { }
|
||||
ActiveScope() : package_header_(0), context_entity_(0) { }
|
||||
ActiveScope(ActiveScope*par) : ScopeBase(*par), package_header_(0), context_entity_(0) { }
|
||||
|
||||
~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); }
|
||||
|
||||
// This function returns true if the name is a vectorable
|
||||
|
|
@ -144,6 +150,11 @@ class ActiveScope : public ScopeBase {
|
|||
// calls and array index operations.
|
||||
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
|
||||
* in previous scopes. If it is found, it is erased (but 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);
|
||||
}
|
||||
|
||||
void bind_name(perm_string name, Subprogram*obj)
|
||||
inline void bind_name(perm_string name, Subprogram*obj)
|
||||
{ map<perm_string, Subprogram*>::iterator it;
|
||||
if((it = old_subprograms_.find(name)) != old_subprograms_.end() )
|
||||
old_subprograms_.erase(it);
|
||||
new_subprograms_[name] = obj;;
|
||||
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
|
||||
use_subprograms_.erase(it);
|
||||
cur_subprograms_[name] = obj;;
|
||||
}
|
||||
|
||||
void bind(Entity*ent)
|
||||
|
|
@ -208,6 +219,10 @@ class ActiveScope : public ScopeBase {
|
|||
std::map<perm_string,VTypeDef*> incomplete_types;
|
||||
|
||||
private:
|
||||
// If this is a package body, then there is a Package header
|
||||
// already declared.
|
||||
Package*package_header_;
|
||||
|
||||
Entity*context_entity_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
# include "subprogram.h"
|
||||
# include "entity.h"
|
||||
# include "vtype.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
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
|
||||
{
|
||||
fd << " function " << name_ << "(";
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@ class Subprogram : public LineInfo {
|
|||
|
||||
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.
|
||||
int emit_package(std::ostream&fd) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,11 @@ class VType {
|
|||
VType() { }
|
||||
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
|
||||
// of this type to the designated stream. This is used for
|
||||
// writing parsed types to library files.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue