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;
if (prefix_.get())
prefix_->dump(out, indent+8);
if (index_)
index_->dump(out, indent+6);
if (lsb_)
lsb_->dump(out, indent+6);
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
(*it)->dump(out, indent+6);
}
}
}
void ExpNameALL::dump(ostream&out, int indent) const

View File

@ -578,41 +578,54 @@ ExpLogical::~ExpLogical()
}
ExpName::ExpName(perm_string nn)
: name_(nn), index_(0), lsb_(0)
: name_(nn), indices_(NULL)
{
}
ExpName::ExpName(perm_string nn, list<Expression*>*indices)
: name_(nn), index_(0), lsb_(0)
{
/* 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)
: name_(nn), indices_(indices)
{
}
ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb)
: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb)
ExpName::ExpName(ExpName*prefix, perm_string nn, std::list<Expression*>*indices)
: prefix_(prefix), name_(nn), indices_(indices)
{
ivl_assert(*this, !msb || msb != lsb);
}
ExpName::~ExpName()
{
delete index_;
delete lsb_;
if(indices_) {
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
@ -624,25 +637,48 @@ bool ExpName::symbolic_compare(const Expression*that) const
if (name_ != that_name->name_)
return false;
if (that_name->index_ && !index_)
if (that_name->indices_ && !indices_)
return false;
if (index_ && !that_name->index_)
if (indices_ && !that_name->indices_)
return false;
if (index_) {
assert(that_name->index_);
return index_->symbolic_compare(that_name->index_);
if (indices_) {
assert(that_name->indices_);
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;
}
void ExpName::set_range(Expression*msb, Expression*lsb)
Expression*ExpName::index(unsigned int number) const
{
assert(index_==0);
index_ = msb;
assert(lsb_==0);
lsb_ = lsb;
if(!indices_)
return NULL;
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)
@ -650,11 +686,12 @@ void ExpName::visit(ExprVisitor& func)
if(prefix_.get())
prefix_.get()->visit(func);
if(index_)
index_->visit(func);
if(lsb_)
lsb_->visit(func);
if(indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
(*it)->visit(func);
}
}
func(this);
}

View File

@ -690,22 +690,18 @@ class ExpName : public Expression {
public:
explicit ExpName(perm_string nn);
ExpName(perm_string nn, std::list<Expression*>*indices);
ExpName(perm_string nn, Expression*msb, Expression*lsb);
ExpName(ExpName*prefix, perm_string nn);
ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb);
ExpName(ExpName*prefix, perm_string nn, std::list<Expression*>*indices = NULL);
~ExpName();
public: // Base methods
Expression*clone() const {
return new ExpName(static_cast<ExpName*>(safe_clone(prefix_.get())),
name_, safe_clone(index_), safe_clone(lsb_));
}
Expression*clone() const;
int elaborate_lval(Entity*ent, ScopeBase*scope, bool);
int elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*);
const VType* probe_type(Entity*ent, ScopeBase*scope) const;
const VType* fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*host) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
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;
bool is_primary(void) 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;
inline const char* 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);
private:
@ -760,10 +756,11 @@ class ExpName : public Expression {
const list<index_t*>&indices, int field_size) const;
private:
Expression*index(unsigned int number) const;
std::auto_ptr<ExpName> prefix_;
perm_string name_;
Expression*index_;
Expression*lsb_;
std::list<Expression*>*indices_;
};
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 (index_ && !lsb_) {
// If the name is an array or a vector, then an
// indexed name has the type of the element.
type = array->element_type();
Expression*idx = index(0);
} else if (index_ && lsb_) {
if (ExpRange*range = dynamic_cast<ExpRange*>(idx)) {
// If the name is an array, then a part select is
// also an array, but with different bounds.
int64_t use_msb, use_lsb;
bool flag;
flag = index_->evaluate(ent, scope, use_msb);
flag = range->msb()->evaluate(ent, scope, use_msb);
ivl_assert(*this, flag);
flag = lsb_->evaluate(ent, scope, use_lsb);
flag = range->lsb()->evaluate(ent, scope, use_lsb);
ivl_assert(*this, flag);
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;
@ -99,10 +101,14 @@ int ExpName::elaborate_lval_(Entity*ent, ScopeBase*scope, bool is_sequ, ExpName*
debug_log_file << get_fileline() << ": ExpName::elaborate_lval_: "
<< "name_=" << name_
<< ", suffix->name()=" << suffix->name();
if (index_)
debug_log_file << ", index_=" << *index_;
if (lsb_)
debug_log_file << ", lsb_=" << *lsb_;
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
debug_log_file << "[";
debug_log_file << **it;
debug_log_file << "]";
}
}
debug_log_file << endl;
}
@ -1032,11 +1038,12 @@ int ExpName::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype)
if(prefix_.get())
prefix_.get()->elaborate_expr(ent, scope, NULL);
if(index_)
index_->elaborate_expr(ent, scope, &primitive_INTEGER);
if(lsb_)
lsb_->elaborate_expr(ent, scope, &primitive_INTEGER);
if (indices_) {
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
(*it)->elaborate_expr(ent, scope, &primitive_INTEGER);
}
}
return 0;
}

View File

@ -694,6 +694,22 @@ int ExpLogical::emit(ostream&out, Entity*ent, ScopeBase*scope) const
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 errors = 0;
@ -702,12 +718,7 @@ int ExpName::emit_as_prefix_(ostream&out, Entity*ent, ScopeBase*scope) const
}
out << "\\" << name_ << " ";
if (index_) {
out << "[";
errors += index_->emit(out, ent, scope);
out << "]";
ivl_assert(*this, lsb_ == 0);
}
errors += emit_indices(out, ent, scope);
out << ".";
return errors;
}
@ -739,16 +750,7 @@ int ExpName::emit(ostream&out, Entity*ent, ScopeBase*scope) const
else
out << "\\" << name_ << " ";
if (index_) {
out << "[";
errors += index_->emit(out, ent, scope);
if (lsb_) {
out << ":";
errors += lsb_->emit(out, ent, scope);
}
out << "]";
}
errors += emit_indices(out, ent, scope);
return errors;
}
@ -759,6 +761,8 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
Expression*exp = NULL;
bool wrkand_required = false;
const VType*type = NULL;
Expression*idx = index(0);
ExpRange*range = dynamic_cast<ExpRange*>(idx);
if(!scope)
return false;
@ -766,7 +770,7 @@ bool ExpName::try_workarounds_(ostream&out, Entity*ent, ScopeBase*scope,
if(prefix_.get())
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)) {
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)) {
// Handle the case of array of records
if(prefix_->index_) {
if(prefix_->index(0)) {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
assert(arr);
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);
}
// Workarounds are currently implemented only for one-dimensional arrays
assert(!indices_ || indices_->size() == 1 || !wrkand_required);
return wrkand_required;
}
bool ExpName::check_const_array_workaround_(const VTypeArray*arr,
ScopeBase*scope, list<index_t*>&indices, int&data_size) const
{
assert(indices_ && indices_->size() == 1);
const VType*element = arr->element_type();
data_size = element->get_width(scope);
if(data_size < 0)
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;
}
@ -830,7 +840,7 @@ bool ExpName::check_const_record_workaround_(const VTypeRecord*rec,
data_size = tmp_field;
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);
assert(arr);
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_;
if (index_) {
fd << "(";
index_->write_to_stream(fd);
if (lsb_) {
fd << " downto ";
lsb_->write_to_stream(fd);
}
fd << ")";
if (indices_) {
fd << "(";
bool first = true;
for(list<Expression*>::const_iterator it = indices_->begin();
it != indices_->end(); ++it) {
if(first)
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_logical expression_logical_and expression_logical_or
%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> simple_expression simple_expression_2 term
%type <expr> variable_declaration_assign_opt waveform_element interface_element_expression
@ -1715,36 +1715,40 @@ name /* IEEE 1076-2008 P8.1 */
| selected_name
{ $$ = $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
function calls. The only way we can tell the difference is from
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. */
| IDENTIFIER argument_list
: IDENTIFIER '(' expression_list ')'
{ Expression*tmp;
perm_string name = lex_strings.make($1);
delete[]$1;
if (active_scope->is_vector_name(name) || is_subprogram_param(name))
tmp = new ExpName(name, $2);
else
tmp = new ExpFunc(name, $2);
FILE_NAME(tmp, @1);
delete[]$1;
if (active_scope->is_vector_name(name) || is_subprogram_param(name))
tmp = new ExpName(name, $3);
else
tmp = new ExpFunc(name, $3);
FILE_NAME(tmp, @1);
$$ = tmp;
}
| IDENTIFIER '(' range ')'
{ ExpName*tmp = new ExpName(lex_strings.make($1), $3->msb(), $3->lsb());
FILE_NAME(tmp, @1);
delete[]$1;
$$ = tmp;
}
| 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;
| indexed_name '(' expression_list ')'
{ ExpName*name = dynamic_cast<ExpName*>($1);
assert(name);
name->add_index($3);
$$ = $1;
}
;