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.
This commit is contained in:
parent
369a0b9eca
commit
621c09105c
|
|
@ -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<perm_string,const VType*>::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<perm_string,struct const_t*>::iterator cur = old_constants_.begin()
|
||||
|
|
|
|||
|
|
@ -77,11 +77,16 @@ int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (const VTypeArray*atype = dynamic_cast<const VTypeArray*> (peek_type()))
|
||||
const VType*use_type = peek_type();
|
||||
while (const VTypeDef*def = dynamic_cast<const VTypeDef*> (use_type)) {
|
||||
use_type = def->peek_definition();
|
||||
}
|
||||
|
||||
if (const VTypeArray*atype = dynamic_cast<const VTypeArray*> (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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
# include <iostream>
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include <vector>
|
||||
# include <climits>
|
||||
# include <inttypes.h>
|
||||
|
|
@ -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<const VTypeDef*, typedef_topo_t> 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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue