vhdlpp: Support for ExpNames with multiple indices.

This commit is contained in:
Maciej Suminski 2016-02-02 16:24:02 +01:00
parent 34b5834a84
commit 5488ea1e2c
7 changed files with 183 additions and 119 deletions

View File

@ -395,10 +395,13 @@ void ExpName::dump(ostream&out, int indent) const
<< " at " << get_fileline() << endl; << " at " << get_fileline() << endl;
if (prefix_.get()) if (prefix_.get())
prefix_->dump(out, indent+8); prefix_->dump(out, indent+8);
if (index_)
index_->dump(out, indent+6); if (indices_) {
if (lsb_) for(list<Expression*>::const_iterator it = indices_->begin();
lsb_->dump(out, indent+6); it != indices_->end(); ++it) {
(*it)->dump(out, indent+6);
}
}
} }
void ExpNameALL::dump(ostream&out, int indent) const void ExpNameALL::dump(ostream&out, int indent) const

View File

@ -578,41 +578,54 @@ ExpLogical::~ExpLogical()
} }
ExpName::ExpName(perm_string nn) ExpName::ExpName(perm_string nn)
: name_(nn), index_(0), lsb_(0) : name_(nn), indices_(NULL)
{ {
} }
ExpName::ExpName(perm_string nn, list<Expression*>*indices) ExpName::ExpName(perm_string nn, list<Expression*>*indices)
: name_(nn), index_(0), lsb_(0) : name_(nn), indices_(indices)
{
/* For now, assume a single index. */
ivl_assert(*this, indices->size() == 1);
index_ = indices->front();
indices->pop_front();
}
ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb)
: name_(nn), index_(msb), lsb_(lsb)
{
ivl_assert(*this, !msb || msb != lsb);
}
ExpName::ExpName(ExpName*prefix, perm_string nn)
: prefix_(prefix), name_(nn), index_(0), lsb_(0)
{ {
} }
ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb) ExpName::ExpName(ExpName*prefix, perm_string nn, std::list<Expression*>*indices)
: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb) : prefix_(prefix), name_(nn), indices_(indices)
{ {
ivl_assert(*this, !msb || msb != lsb);
} }
ExpName::~ExpName() ExpName::~ExpName()
{ {
delete index_; if(indices_) {
delete lsb_; for(list<Expression*>::iterator it = indices_->begin();
it != indices_->end(); ++it) {
delete *it;
}
delete indices_;
}
}
Expression*ExpName::clone() const {
list<Expression*>*new_indices = NULL;
if(indices_) {
new_indices = new list<Expression*>();
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
new_indices->push_back((*it)->clone());
}
}
return new ExpName(static_cast<ExpName*>(safe_clone(prefix_.get())),
name_, new_indices);
}
void ExpName::add_index(std::list<Expression*>*idx)
{
if(!indices_)
indices_ = new list<Expression*>();
indices_->splice(indices_->end(), *idx);
} }
bool ExpName::symbolic_compare(const Expression*that) const bool ExpName::symbolic_compare(const Expression*that) const
@ -624,25 +637,48 @@ bool ExpName::symbolic_compare(const Expression*that) const
if (name_ != that_name->name_) if (name_ != that_name->name_)
return false; return false;
if (that_name->index_ && !index_) if (that_name->indices_ && !indices_)
return false; return false;
if (index_ && !that_name->index_) if (indices_ && !that_name->indices_)
return false; return false;
if (index_) { if (indices_) {
assert(that_name->index_); assert(that_name->indices_);
return index_->symbolic_compare(that_name->index_);
if(indices_->size() != that_name->indices_->size())
return false;
list<Expression*>::const_iterator it, jt;
it = indices_->begin();
jt = that_name->indices_->begin();
for(unsigned int i = 0; i < indices_->size(); ++i) {
if(!(*it)->symbolic_compare(*jt))
return false;
++it;
++jt;
}
} }
return true; return true;
} }
void ExpName::set_range(Expression*msb, Expression*lsb) Expression*ExpName::index(unsigned int number) const
{ {
assert(index_==0); if(!indices_)
index_ = msb; return NULL;
assert(lsb_==0);
lsb_ = lsb; if(number >= indices_->size())
return NULL;
if(number == 0)
return indices_->front();
list<Expression*>::const_iterator it = indices_->begin();
advance(it, number);
return *it;
} }
void ExpName::visit(ExprVisitor& func) void ExpName::visit(ExprVisitor& func)
@ -650,11 +686,12 @@ void ExpName::visit(ExprVisitor& func)
if(prefix_.get()) if(prefix_.get())
prefix_.get()->visit(func); prefix_.get()->visit(func);
if(index_) if(indices_) {
index_->visit(func); for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
if(lsb_) (*it)->visit(func);
lsb_->visit(func); }
}
func(this); func(this);
} }

View File

@ -690,22 +690,18 @@ class ExpName : public Expression {
public: public:
explicit ExpName(perm_string nn); explicit ExpName(perm_string nn);
ExpName(perm_string nn, std::list<Expression*>*indices); ExpName(perm_string nn, std::list<Expression*>*indices);
ExpName(perm_string nn, Expression*msb, Expression*lsb); ExpName(ExpName*prefix, perm_string nn, std::list<Expression*>*indices = NULL);
ExpName(ExpName*prefix, perm_string nn);
ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb);
~ExpName(); ~ExpName();
public: // Base methods public: // Base methods
Expression*clone() const { Expression*clone() const;
return new ExpName(static_cast<ExpName*>(safe_clone(prefix_.get())),
name_, safe_clone(index_), safe_clone(lsb_));
}
int elaborate_lval(Entity*ent, ScopeBase*scope, bool); int elaborate_lval(Entity*ent, ScopeBase*scope, bool);
int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*); int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*);
const VType* probe_type(Entity*ent, ScopeBase*scope) const; const VType* probe_type(Entity*ent, ScopeBase*scope) const;
const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const; const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype); int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const; void write_to_stream(std::ostream&fd) const;
int emit_indices(ostream&out, Entity*ent, ScopeBase*scope) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope) const; int emit(ostream&out, Entity*ent, ScopeBase*scope) const;
bool is_primary(void) const; bool is_primary(void) const;
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const; bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
@ -713,7 +709,7 @@ class ExpName : public Expression {
void dump(ostream&out, int indent = 0) const; void dump(ostream&out, int indent = 0) const;
inline const char* name() const { return name_; } inline const char* name() const { return name_; }
inline const perm_string& peek_name() const { return name_; } inline const perm_string& peek_name() const { return name_; }
void set_range(Expression*msb, Expression*lsb); void add_index(std::list<Expression*>*idx);
void visit(ExprVisitor& func); void visit(ExprVisitor& func);
private: private:
@ -760,10 +756,11 @@ class ExpName : public Expression {
const list<index_t*>&indices, int field_size) const; const list<index_t*>&indices, int field_size) const;
private: private:
Expression*index(unsigned int number) const;
std::auto_ptr<ExpName> prefix_; std::auto_ptr<ExpName> prefix_;
perm_string name_; perm_string name_;
Expression*index_; std::list<Expression*>*indices_;
Expression*lsb_;
}; };
class ExpNameALL : public ExpName { class ExpNameALL : public ExpName {

View File

@ -68,24 +68,26 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*sco
} }
if (const VTypeArray*array = dynamic_cast<const VTypeArray*>(type)) { if (const VTypeArray*array = dynamic_cast<const VTypeArray*>(type)) {
if (index_ && !lsb_) { Expression*idx = index(0);
// If the name is an array or a vector, then an
// indexed name has the type of the element.
type = array->element_type();
} else if (index_ && lsb_) { if (ExpRange*range = dynamic_cast<ExpRange*>(idx)) {
// If the name is an array, then a part select is // If the name is an array, then a part select is
// also an array, but with different bounds. // also an array, but with different bounds.
int64_t use_msb, use_lsb; int64_t use_msb, use_lsb;
bool flag; bool flag;
flag = index_->evaluate(ent, scope, use_msb); flag = range->msb()->evaluate(ent, scope, use_msb);
ivl_assert(*this, flag); ivl_assert(*this, flag);
flag = lsb_->evaluate(ent, scope, use_lsb); flag = range->lsb()->evaluate(ent, scope, use_lsb);
ivl_assert(*this, flag); ivl_assert(*this, flag);
type = new VTypeArray(array->element_type(), use_msb, use_lsb); type = new VTypeArray(array->element_type(), use_msb, use_lsb);
} }
else if(idx) {
// If the name is an array or a vector, then an
// indexed name has the type of the element.
type = array->element_type();
}
} }
return type; return type;
@ -99,10 +101,14 @@ int ExpName::elaborate_lval_(Entity*ent, ScopeBase*scope, bool is_sequ, ExpName*
debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: " debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: "
<< "name_=" << name_ << "name_=" << name_
<< ", suffix->name()=" << suffix->name(); << ", suffix->name()=" << suffix->name();
if (index_) if (indices_) {
debug_log_file << ", index_=" << *index_; for(list<Expression*>::const_iterator it = indices_->begin();
if (lsb_) it != indices_->end(); ++it) {
debug_log_file << ", lsb_=" << *lsb_; debug_log_file << "[";
debug_log_file << **it;
debug_log_file << "]";
}
}
debug_log_file << endl; debug_log_file << endl;
} }
@ -1032,11 +1038,12 @@ int ExpName::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
if(prefix_.get()) if(prefix_.get())
prefix_.get()->elaborate_expr(ent, scope, NULL); prefix_.get()->elaborate_expr(ent, scope, NULL);
if(index_) if (indices_) {
index_->elaborate_expr(ent, scope, &primitive_INTEGER); for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
if(lsb_) (*it)->elaborate_expr(ent, scope, &primitive_INTEGER);
lsb_->elaborate_expr(ent, scope, &primitive_INTEGER); }
}
return 0; return 0;
} }

View File

@ -694,6 +694,22 @@ int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) const
return errors; return errors;
} }
int ExpName::emit_indices(ostream&out, Entity*ent, ScopeBase*scope) const
{
int errors = 0;
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
out << "[";
errors += (*it)->emit(out, ent, scope);
out << "]";
}
}
return errors;
}
int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const
{ {
int errors = 0; int errors = 0;
@ -702,12 +718,7 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const
} }
out << "\\" << name_ << " "; out << "\\" << name_ << " ";
if (index_) { errors += emit_indices(out, ent, scope);
out << "[";
errors += index_->emit(out, ent, scope);
out << "]";
ivl_assert(*this, lsb_ == 0);
}
out << "."; out << ".";
return errors; return errors;
} }
@ -739,16 +750,7 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) const
else else
out << "\\" << name_ << " "; out << "\\" << name_ << " ";
if (index_) { errors += emit_indices(out, ent, scope);
out << "[";
errors += index_->emit(out, ent, scope);
if (lsb_) {
out << ":";
errors += lsb_->emit(out, ent, scope);
}
out << "]";
}
return errors; return errors;
} }
@ -759,6 +761,8 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
Expression*exp = NULL; Expression*exp = NULL;
bool wrkand_required = false; bool wrkand_required = false;
const VType*type = NULL; const VType*type = NULL;
Expression*idx = index(0);
ExpRange*range = dynamic_cast<ExpRange*>(idx);
if(!scope) if(!scope)
return false; return false;
@ -766,7 +770,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
if(prefix_.get()) if(prefix_.get())
prefix_->try_workarounds_(out, ent, scope, indices, data_size); prefix_->try_workarounds_(out, ent, scope, indices, data_size);
if(index_ && !lsb_ && scope->find_constant(name_, type, exp)) { if(idx && !range && scope->find_constant(name_, type, exp)) {
while(const VTypeDef*type_def = dynamic_cast<const VTypeDef*>(type)) { while(const VTypeDef*type_def = dynamic_cast<const VTypeDef*>(type)) {
type = type_def->peek_definition(); type = type_def->peek_definition();
} }
@ -778,7 +782,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
if(prefix_.get() && scope->find_constant(prefix_->name_, type, exp)) { if(prefix_.get() && scope->find_constant(prefix_->name_, type, exp)) {
// Handle the case of array of records // Handle the case of array of records
if(prefix_->index_) { if(prefix_->index(0)) {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type); const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
assert(arr); assert(arr);
type = arr->element_type(); type = arr->element_type();
@ -795,17 +799,23 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
wrkand_required |= check_const_record_workaround_(rec, scope, indices, data_size); wrkand_required |= check_const_record_workaround_(rec, scope, indices, data_size);
} }
// Workarounds are currently implemented only for one-dimensional arrays
assert(!indices_ || indices_->size() == 1 || !wrkand_required);
return wrkand_required; return wrkand_required;
} }
bool ExpName::check_const_array_workaround_(const VTypeArray*arr, bool ExpName::check_const_array_workaround_(const VTypeArray*arr,
ScopeBase*scope, list<index_t*>&indices, int&data_size) const ScopeBase*scope, list<index_t*>&indices, int&data_size) const
{ {
assert(indices_ && indices_->size() == 1);
const VType*element = arr->element_type(); const VType*element = arr->element_type();
data_size = element->get_width(scope); data_size = element->get_width(scope);
if(data_size < 0) if(data_size < 0)
return false; return false;
indices.push_back(new index_t(index_->clone(), new ExpInteger(data_size)));
indices.push_back(new index_t(index(0)->clone(), new ExpInteger(data_size)));
return true; return true;
} }
@ -830,7 +840,7 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec,
data_size = tmp_field; data_size = tmp_field;
indices.push_back(new index_t(NULL, NULL, new ExpInteger(tmp_offset))); indices.push_back(new index_t(NULL, NULL, new ExpInteger(tmp_offset)));
if(index_) { if(index(0)) {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type); const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
assert(arr); assert(arr);
return check_const_array_workaround_(arr, scope, indices, data_size); return check_const_array_workaround_(arr, scope, indices, data_size);

View File

@ -217,14 +217,20 @@ void ExpName::write_to_stream(ostream&fd) const
} }
fd << name_; fd << name_;
if (index_) {
fd << "("; if (indices_) {
index_->write_to_stream(fd); fd << "(";
if (lsb_) { bool first = true;
fd << " downto "; for(list<Expression*>::const_iterator it = indices_->begin();
lsb_->write_to_stream(fd); it != indices_->end(); ++it) {
} if(first)
fd << ")"; first = false;
else
fd << ",";
(*it)->write_to_stream(fd);
}
fd << ")";
} }
} }

View File

@ -331,7 +331,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
%type <expr> expression factor primary relation %type <expr> expression factor primary relation
%type <expr> expression_logical expression_logical_and expression_logical_or %type <expr> expression_logical expression_logical_and expression_logical_or
%type <expr> expression_logical_xnor expression_logical_xor %type <expr> expression_logical_xnor expression_logical_xor
%type <expr> name prefix selected_name %type <expr> name prefix selected_name indexed_name
%type <expr> shift_expression signal_declaration_assign_opt %type <expr> shift_expression signal_declaration_assign_opt
%type <expr> simple_expression simple_expression_2 term %type <expr> simple_expression simple_expression_2 term
%type <expr> variable_declaration_assign_opt waveform_element interface_element_expression %type <expr> variable_declaration_assign_opt waveform_element interface_element_expression
@ -1715,36 +1715,40 @@ name /* IEEE 1076-2008 P8.1 */
| selected_name | selected_name
{ $$ = $1; } { $$ = $1; }
| indexed_name
{ $$ = $1; }
| selected_name '(' expression_list ')'
{
ExpName*name = dynamic_cast<ExpName*>($1);
assert(name);
name->add_index($3);
delete $3; // contents of the list is moved to the selected_name
}
;
indexed_name
/* Note that this rule can match array element selects and various /* Note that this rule can match array element selects and various
function calls. The only way we can tell the difference is from function calls. The only way we can tell the difference is from
left context, namely whether the name is a type name or function left context, namely whether the name is a type name or function
name. If none of the above, treat it as a array element select. */ name. If none of the above, treat it as a array element select. */
| IDENTIFIER argument_list : IDENTIFIER '(' expression_list ')'
{ Expression*tmp; { Expression*tmp;
perm_string name = lex_strings.make($1); perm_string name = lex_strings.make($1);
delete[]$1; delete[]$1;
if (active_scope->is_vector_name(name) || is_subprogram_param(name)) if (active_scope->is_vector_name(name) || is_subprogram_param(name))
tmp = new ExpName(name, $2); tmp = new ExpName(name, $3);
else else
tmp = new ExpFunc(name, $2); tmp = new ExpFunc(name, $3);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
} }
| IDENTIFIER '(' range ')' | indexed_name '(' expression_list ')'
{ ExpName*tmp = new ExpName(lex_strings.make($1), $3->msb(), $3->lsb()); { ExpName*name = dynamic_cast<ExpName*>($1);
FILE_NAME(tmp, @1); assert(name);
delete[]$1; name->add_index($3);
$$ = tmp; $$ = $1;
}
| selected_name '(' range ')'
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
tmp->set_range($3->msb(), $3->lsb());
$$ = tmp;
}
| selected_name '(' expression ')'
{ ExpName*tmp = dynamic_cast<ExpName*> ($1);
tmp->set_range($3, NULL);
$$ = tmp;
} }
; ;