From 621c09105c08ac631b62b4e9e76599629e164dbf Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 12 May 2012 18:38:49 -0700 Subject: [PATCH] Sort the typedef emits so that types are emitted in the order used. It is common for typedefs of complex types to use further typedefs. Emit the type definitions depth first so that the types that are used are defined first. This reduces the need for pre-declaration of types. --- vhdlpp/architec_emit.cc | 4 +++- vhdlpp/expression_emit.cc | 9 +++++++-- vhdlpp/vtype.h | 14 +++++++++++++- vhdlpp/vtype_emit.cc | 40 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 60 insertions(+), 7 deletions(-) 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;