diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index bf19c7bf2..4420bb815 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -67,6 +67,8 @@ int Architecture::emit(ostream&out, Entity*entity) // Find typedefs that are present in the architecture body and // emit them, so that following code can use the name instead // of the full definition. + + typedef_context_t typedef_ctx; for (map::iterator cur = old_types_.begin() ; cur != old_types_.end() ; ++cur) { @@ -74,7 +76,7 @@ int Architecture::emit(ostream&out, Entity*entity) if (def == 0) continue; - errors += def->emit_typedef(out); + errors += def->emit_typedef(out, typedef_ctx); } for (map::iterator cur = old_constants_.begin() diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 5d8ec72bb..bf815ca7e 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -77,11 +77,16 @@ int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc) return 1; } - if (const VTypeArray*atype = dynamic_cast (peek_type())) + const VType*use_type = peek_type(); + while (const VTypeDef*def = dynamic_cast (use_type)) { + use_type = def->peek_definition(); + } + + if (const VTypeArray*atype = dynamic_cast (use_type)) return emit_array_(out, ent, arc, atype); out << "/* " << get_fileline() << ": internal error: " - << "I don't know how to elaborate aggregate in " << typeid(peek_type()).name() + << "I don't know how to elab/emit aggregate in " << typeid(use_type).name() << " type context. */"; return 1; } diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 44220729b..e6eb7da3d 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -21,6 +21,7 @@ # include # include +# include # include # include # include @@ -28,6 +29,10 @@ class Expression; class prange_t; +class VTypeDef; + +typedef enum typedef_topo_e { NONE=0, PENDING, MARKED } typedef_topo_t; +typedef std::map typedef_context_t; /* * A description of a VHDL type consists of a graph of VType @@ -58,6 +63,12 @@ class VType { // type. It is used to emit typedef's. virtual int emit_def(std::ostream&out) const =0; + // This virtual method causes VTypeDef types to emit typedefs + // of themselves. The VTypeDef implementation of this method + // uses this method recursively to do a depth-first emit of + // all the types that it emits. + virtual int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; + private: friend class decl_t; // This virtual method is called to emit the declaration. This @@ -157,6 +168,7 @@ class VTypeArray : public VType { const VType* element_type() const; int emit_def(std::ostream&out) const; + int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; private: const VType*etype_; @@ -244,7 +256,7 @@ class VTypeDef : public VType { void write_to_stream(std::ostream&fd) const; void write_type_to_stream(ostream&fd) const; - int emit_typedef(std::ostream&out) const; + int emit_typedef(std::ostream&out, typedef_context_t&ctx) const; int emit_def(std::ostream&out) const; private: diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index 7144bad6d..58cfc18a7 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -46,6 +46,11 @@ int VType::emit_decl(ostream&out, perm_string name, bool reg_flag) const return errors; } +int VType::emit_typedef(std::ostream&, typedef_context_t&) const +{ + return 0; +} + int VTypeArray::emit_def(ostream&out) const { int errors = 0; @@ -86,6 +91,11 @@ int VTypeArray::emit_def(ostream&out) const return errors; } +int VTypeArray::emit_typedef(std::ostream&out, typedef_context_t&ctx) const +{ + etype_->emit_typedef(out, ctx); +} + int VTypeEnum::emit_def(ostream&out) const { int errors = 0; @@ -153,10 +163,15 @@ int VTypeRecord::emit_def(ostream&out) const return errors; } +/* + * For VTypeDef objects, use the name of the defined type as the + * type. (We are defining a variable here, not the type itself.) The + * emit_typedef() method was presumably called to define type already. + */ int VTypeDef::emit_def(ostream&out) const { int errors = 0; - errors += type_->emit_def(out); + out << "\\" << name_ << " "; return errors; } @@ -173,9 +188,28 @@ int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const return errors; } -int VTypeDef::emit_typedef(ostream&out) const +int VTypeDef::emit_typedef(ostream&out, typedef_context_t&ctx) const { - int errors = 0; + // The typedef_context_t is used by me to determine if this + // typedef has already been emitted in this architecture. If + // it has, then it is MARKED, give up. Otherwise, recurse the + // emit_typedef to make sure all sub-types that I use have + // been emitted, then emit my typedef. + typedef_topo_t&flag = ctx[this]; + switch (flag) { + case MARKED: + return 0; + case PENDING: + out << "typedef \\" << name_ << " ; /* typedef cycle? */" << endl; + return 0; + case NONE: + break; + } + + flag = PENDING; + int errors = type_->emit_typedef(out, ctx); + flag = MARKED; + out << "typedef "; errors += type_->emit_def(out); out << " \\" << name_ << " ;" << endl;