diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 3669fd489..af4fd7a32 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -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::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + (*it)->dump(out, indent+6); + } + } } void ExpNameALL::dump(ostream&out, int indent) const diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 811d42457..7bb97642f 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -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*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*indices) +: prefix_(prefix), name_(nn), indices_(indices) { - ivl_assert(*this, !msb || msb != lsb); } ExpName::~ExpName() { - delete index_; - delete lsb_; + if(indices_) { + for(list::iterator it = indices_->begin(); + it != indices_->end(); ++it) { + delete *it; + } + + delete indices_; + } +} + +Expression*ExpName::clone() const { + list*new_indices = NULL; + + if(indices_) { + new_indices = new list(); + + for(list::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + new_indices->push_back((*it)->clone()); + } + } + + return new ExpName(static_cast(safe_clone(prefix_.get())), + name_, new_indices); +} + +void ExpName::add_index(std::list*idx) +{ + if(!indices_) + indices_ = new list(); + + 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::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::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::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + (*it)->visit(func); + } + } func(this); } diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 488c30421..8dc5d1126 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -690,22 +690,18 @@ class ExpName : public Expression { public: explicit ExpName(perm_string nn); ExpName(perm_string nn, std::list*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*indices = NULL); ~ExpName(); public: // Base methods - Expression*clone() const { - return new ExpName(static_cast(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*idx); void visit(ExprVisitor& func); private: @@ -760,10 +756,11 @@ class ExpName : public Expression { const list&indices, int field_size) const; private: + Expression*index(unsigned int number) const; + std::auto_ptr prefix_; perm_string name_; - Expression*index_; - Expression*lsb_; + std::list*indices_; }; class ExpNameALL : public ExpName { diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index e1cb258f2..fa6a16841 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -68,24 +68,26 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*sco } if (const VTypeArray*array = dynamic_cast(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(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::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::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + (*it)->elaborate_expr(ent, scope, &primitive_INTEGER); + } + } return 0; } diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 5104e502a..a66ee5e72 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -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::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(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(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(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&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(type); assert(arr); return check_const_array_workaround_(arr, scope, indices, data_size); diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index d545df69f..43756922a 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -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::const_iterator it = indices_->begin(); + it != indices_->end(); ++it) { + if(first) + first = false; + else + fd << ","; + + (*it)->write_to_stream(fd); + } + fd << ")"; } } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 3ce3c0db7..c080be9ff 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -331,7 +331,7 @@ static void touchup_interface_for_functions(std::list*ports) %type expression factor primary relation %type expression_logical expression_logical_and expression_logical_or %type expression_logical_xnor expression_logical_xor -%type name prefix selected_name +%type name prefix selected_name indexed_name %type shift_expression signal_declaration_assign_opt %type simple_expression simple_expression_2 term %type 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($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 ($1); - tmp->set_range($3->msb(), $3->lsb()); - $$ = tmp; - } - | selected_name '(' expression ')' - { ExpName*tmp = dynamic_cast ($1); - tmp->set_range($3, NULL); - $$ = tmp; + | indexed_name '(' expression_list ')' + { ExpName*name = dynamic_cast($1); + assert(name); + name->add_index($3); + $$ = $1; } ;