diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 0a5dfc6c8..a6f9542b9 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -146,15 +146,16 @@ void Scope::dump_scope(ostream&out) const out << " signal " << cur->first.str() << ": ???" << endl; } // Dump subprograms - out << " -- Subprograms" << endl; - for (map::const_iterator cur = old_subprograms_.begin() - ; cur != old_subprograms_.end() ; ++cur) { + out << " -- Imported Subprograms" << endl; + for (map::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::const_iterator cur = new_subprograms_.begin() - ; cur != new_subprograms_.end() ; ++cur) { + out << " -- Subprograms from this scope" << endl; + for (map::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; diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 01b5e0ee4..86c7c8ccc 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -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::iterator lib = libraries.find(use_libname); + if (lib == libraries.end()) + return 0; + + map::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()) diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index aea43c1bf..44f9ca3bc 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -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::const_iterator cur = old_subprograms_.begin() - ; cur != old_subprograms_.end() ; ++cur) { + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { cur->second->write_to_stream(fd); } diff --git a/vhdlpp/package.h b/vhdlpp/package.h index 484bea53b..046708c30 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -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; diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc index b4b0836a2..5792cd728 100644 --- a/vhdlpp/package_emit.cc +++ b/vhdlpp/package_emit.cc @@ -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::const_iterator cur = old_subprograms_.begin() - ; cur != old_subprograms_.end() ; ++ cur) { + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++ cur) { errors += cur->second->emit_package(fd); } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index e15c199ae..cc278f3ab 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -322,11 +322,12 @@ static list* record_elements(list*names, %type element_declaration element_declaration_list %type architecture_body_start package_declaration_start +%type package_body_start %type identifier_opt identifier_colon_opt logical_name suffix %type logical_name_list identifier_list %type enumeration_literal_list enumeration_literal -%type sequence_of_statements if_statement_else +%type if_statement_else sequence_of_statements subprogram_statement_part %type sequential_statement if_statement signal_assignment_statement %type case_statement procedure_call procedure_call_statement %type 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 diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index da1fd0135..d54a648f9 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -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*names); extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident); diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 33fdeb2f4..77ba7c4f6 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -18,9 +18,11 @@ */ # include "scope.h" +# include "package.h" # include # include # include +# include 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 >( - 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::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::const_iterator cur = that->old_subprograms_.begin() - ; cur != that->old_subprograms_.end() ; ++ cur) { + for (map::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::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::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)) diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index 7c0644817..790c709c9 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -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 use_constants_; //imported constants std::map cur_constants_; //current constants - std::map old_subprograms_; //previous scopes - std::map new_subprograms_; //current scope + std::map use_subprograms_; //imported + std::map 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 ::*" 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::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 incomplete_types; private: + // If this is a package body, then there is a Package header + // already declared. + Package*package_header_; + Entity*context_entity_; }; diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc index 3aa1fb94b..25b6deb9d 100644 --- a/vhdlpp/subprogram.cc +++ b/vhdlpp/subprogram.cc @@ -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*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_ << "("; diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h index 7ec691d32..ea12e3934 100644 --- a/vhdlpp/subprogram.h +++ b/vhdlpp/subprogram.h @@ -38,6 +38,12 @@ class Subprogram : public LineInfo { inline const perm_string&name() const { return name_; } + void set_program_body(std::list*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; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 3edbe44a2..9d185ad0e 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -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. diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc new file mode 100644 index 000000000..e0559d24d --- /dev/null +++ b/vhdlpp/vtype_match.cc @@ -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; +}