From d9acfe57b135df7bea4cf092a1259713aeb978e9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 15 Oct 2011 17:41:48 -0700 Subject: [PATCH] Put off array bound evaluation / describe entity generics as parameters Entity generics are easily implemented as module parameters, so make it so. Give the parameters their default values from the generic declaration. Array bounds may use values that cannot be evaluated right away, so put off their evaluation. --- vhdlpp/debug.cc | 22 ++++++++ vhdlpp/entity.cc | 10 ++++ vhdlpp/entity.h | 8 +-- vhdlpp/entity_elaborate.cc | 6 +-- vhdlpp/entity_emit.cc | 25 +++++++-- vhdlpp/expression.cc | 51 ------------------ vhdlpp/expression.h | 4 ++ vhdlpp/expression_elaborate.cc | 22 ++++++-- vhdlpp/expression_emit.cc | 53 ++++++++++++++---- vhdlpp/expression_evaluate.cc | 98 ++++++++++++++++++++++++++++++++++ vhdlpp/library.cc | 5 ++ vhdlpp/parse.y | 5 ++ vhdlpp/parse_misc.cc | 14 +---- vhdlpp/sequential_emit.cc | 4 +- vhdlpp/vtype.h | 16 +++--- vhdlpp/vtype_emit.cc | 9 +++- 16 files changed, 252 insertions(+), 100 deletions(-) create mode 100644 vhdlpp/expression_evaluate.cc diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index b35c28731..7d72dd0b5 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -55,6 +55,27 @@ void dump_design_entities(ostream&file) } } +void ComponentBase::dump_generics(ostream&out, int indent) const +{ + if (parms_.empty()) { + out << setw(indent) << "" << "No generics" << endl; + } else { + out << setw(indent) << "" << "GENERICS:" << endl; + for (vector::const_iterator cur = parms_.begin() + ; cur != parms_.end() ; ++cur) { + InterfacePort*item = *cur; + out << setw(indent+2) << "" << item->name + << " : " << item->mode + << ", type="; + if (item->type) + item->type->show(out); + else + out << ""; + out << ", file=" << item->get_fileline() << endl; + } + } +} + void ComponentBase::dump_ports(ostream&out, int indent) const { if (ports_.empty()) { @@ -122,6 +143,7 @@ void Scope::dump_scope(ostream&out) const for (map::const_iterator cur = old_components_.begin() ; cur != old_components_.end() ; ++cur) { out << " component " << cur->first << " is" << endl; + cur->second->dump_generics(out); cur->second->dump_ports(out); out << " end component " << cur->first << endl; } diff --git a/vhdlpp/entity.cc b/vhdlpp/entity.cc index 411596178..68d3c6280 100644 --- a/vhdlpp/entity.cc +++ b/vhdlpp/entity.cc @@ -63,6 +63,16 @@ const InterfacePort* ComponentBase::find_port(perm_string my_name) const return 0; } +const InterfacePort* ComponentBase::find_generic(perm_string my_name) const +{ + for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) { + if (parms_[idx]->name == my_name) + return parms_[idx]; + } + + return 0; +} + Entity::Entity(perm_string name) : ComponentBase(name) { diff --git a/vhdlpp/entity.h b/vhdlpp/entity.h index 05e24f4c4..faf66af8b 100644 --- a/vhdlpp/entity.h +++ b/vhdlpp/entity.h @@ -60,7 +60,9 @@ class ComponentBase : public LineInfo { // Entities have names. perm_string get_name() const { return name_; } + const InterfacePort* find_port(perm_string by_name) const; + const InterfacePort* find_generic(perm_string by_name) const; // Declare the ports for the entity. The parser calls this // method with a list of interface elements that were parsed @@ -73,14 +75,12 @@ class ComponentBase : public LineInfo { void write_to_stream(std::ostream&fd) const; public: + void dump_generics(std::ostream&out, int indent =0) const; void dump_ports(std::ostream&out, int indent = 0) const; - protected: - // This is really only used by the Entity derived class. - const std::vector&get_ports() const { return ports_; } - private: perm_string name_; + protected: std::vector parms_; std::vector ports_; }; diff --git a/vhdlpp/entity_elaborate.cc b/vhdlpp/entity_elaborate.cc index 586c9041d..c37d2dea4 100644 --- a/vhdlpp/entity_elaborate.cc +++ b/vhdlpp/entity_elaborate.cc @@ -87,10 +87,8 @@ int Entity::elaborate() int Entity::elaborate_ports_(void) { int errors = 0; - const std::vector&ports = get_ports(); - - for (std::vector::const_iterator cur = ports.begin() - ; cur != ports.end() ; ++cur) { + for (std::vector::const_iterator cur = ports_.begin() + ; cur != ports_.end() ; ++cur) { InterfacePort*cur_port = *cur; diff --git a/vhdlpp/entity_emit.cc b/vhdlpp/entity_emit.cc index 6ffd54b69..92d652562 100644 --- a/vhdlpp/entity_emit.cc +++ b/vhdlpp/entity_emit.cc @@ -22,6 +22,7 @@ # include # include # include +# include int emit_entities(void) { @@ -39,16 +40,30 @@ int Entity::emit(ostream&out) { int errors = 0; - const std::vector&ports = get_ports(); + out << "module "; + // If there are generics, emit them + if (parms_.size() > 0) { + out << "#("; + for (vector::const_iterator cur = parms_.begin() + ; cur != parms_.end() ; ++cur) { + const InterfacePort*curp = *cur; + if (cur != parms_.begin()) + out << ", "; + out << "parameter \\" << curp->name << " = "; + ivl_assert(*this, curp->expr); + errors += curp->expr->emit(out, this, 0); + } + out << ") "; + } - out << "module " << get_name(); + out << get_name(); // If there are ports, emit them. - if (ports.size() > 0) { + if (ports_.size() > 0) { out << "("; const char*sep = 0; - for (vector::const_iterator cur = ports.begin() - ; cur != ports.end() ; ++cur) { + for (vector::const_iterator cur = ports_.begin() + ; cur != ports_.end() ; ++cur) { InterfacePort*port = *cur; VType::decl_t&decl = declarations_[port->name]; diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index cd8e71469..d5bee38e1 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -42,11 +42,6 @@ void Expression::set_type(const VType*typ) type_ = typ; } -bool Expression::evaluate(ScopeBase*, int64_t&) const -{ - return false; -} - bool Expression::symbolic_compare(const Expression*) const { cerr << get_fileline() << ": internal error: " @@ -87,40 +82,6 @@ ExpAttribute::~ExpAttribute() delete base_; } -bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const -{ - /* Special Case: The length attribute can be calculated all - the down to a literal integer at compile time, and all it - needs is the type of the base expression. (The base - expression doesn't even need to be evaluated.) */ - if (name_ == "length") { - const VType*base_type = base_->peek_type(); - //if (base_type == 0) - // base_type = base_->probe_type(ent,arc); - - ivl_assert(*this, base_type); - - const VTypeArray*arr = dynamic_cast(base_type); - if (arr == 0) { - cerr << get_fileline() << ": error: " - << "Cannot apply the 'length attribute to non-array objects" - << endl; - return false; - } - - int64_t size = 1; - for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) { - const VTypeArray::range_t&dim = arr->dimension(idx); - ivl_assert(*this, ! dim.is_box()); - size *= 1 + labs(dim.msb() - dim.lsb()); - } - val = size; - return true; - } - - return false; -} - ExpBinary::ExpBinary(Expression*op1, Expression*op2) : operand1_(op1), operand2_(op2) { @@ -402,18 +363,6 @@ const char* ExpName::name() const return name_; } -bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const -{ - const VType*type; - Expression*exp; - - bool rc = scope->find_constant(name_, type, exp); - if (rc == false) - return false; - - return exp->evaluate(scope, val); -} - ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2) : ExpBinary(op1, op2), fun_(ty) { diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index d9cdea674..a05e3c5dc 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -80,6 +80,8 @@ class Expression : public LineInfo { // argument if the evaluation works, or return false if it // cannot be done. virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + virtual bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; + // The symbolic compare returns true if the two expressions // are equal without actually calculating the value. @@ -266,6 +268,7 @@ class ExpAttribute : public Expression { int emit(ostream&out, Entity*ent, Architecture*arc); // Some attributes can be evaluated at compile time bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; void dump(ostream&out, int indent = 0) const; private: @@ -427,6 +430,7 @@ class ExpName : public Expression { int emit(ostream&out, Entity*ent, Architecture*arc); bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; + bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const; bool symbolic_compare(const Expression*that) const; void dump(ostream&out, int indent = 0) const; const char* name() const; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 35d50413f..5e3a88fbc 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -30,7 +30,7 @@ using namespace std; int Expression::elaborate_lval(Entity*, Architecture*, bool) { - cerr << get_fileline() << ": error: Expression is not a valie l-value." << endl; + cerr << get_fileline() << ": error: Expression is not a valid l-value." << endl; return 1; } @@ -57,6 +57,13 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) found_type = cur->type; + } else if (ent->find_generic(name_)) { + + cerr << get_fileline() << ": error: Assignment to generic " + << name_ << " from entity " + << ent->get_name() << "." << endl; + return 1; + } else if (Signal*sig = arc->find_signal(name_)) { // Tell the target signal that this may be a sequential l-value. if (is_sequ) sig->count_ref_sequ(); @@ -93,8 +100,10 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ) flag = lsb_->evaluate(arc, use_lsb); ivl_assert(*this, flag); + Expression*exp_msb = new ExpInteger(use_msb); + Expression*exp_lsb = new ExpInteger(use_lsb); vector use_dims (1); - use_dims[0] = VTypeArray::range_t(use_msb, use_lsb); + use_dims[0] = VTypeArray::range_t(exp_msb, exp_lsb); found_type = new VTypeArray(array->element_type(), use_dims); } } @@ -366,8 +375,15 @@ int ExpLogical::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const { - if (const InterfacePort*cur = ent->find_port(name_)) + if (const InterfacePort*cur = ent->find_port(name_)) { + ivl_assert(*this, cur->type); return cur->type; + } + + if (const InterfacePort*cur = ent->find_generic(name_)) { + ivl_assert(*this, cur->type); + return cur->type; + } if (Signal*sig = arc->find_signal(name_)) return sig->peek_type(); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 02dc5fae3..1777da7fa 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -87,11 +87,38 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V const VTypeArray::range_t&rang = atype->dimension(0); assert(! rang.is_box()); - int asize = abs(rang.msb() - rang.lsb()) + 1; + int64_t use_msb; + int64_t use_lsb; + bool rc_msb, rc_lsb; + rc_msb = rang.msb()->evaluate(ent, arc, use_msb); + rc_lsb = rang.lsb()->evaluate(ent, arc, use_lsb); - out << "{" << asize << "{"; - errors += aggregate_[0].expr->emit(out, ent, arc); - out << "}}"; + if (rc_msb && rc_lsb) { + int asize = abs(use_msb - use_lsb) + 1; + out << "{" << asize << "{"; + errors += aggregate_[0].expr->emit(out, ent, arc); + out << "}}"; + } else { + out << "{("; + if (rc_msb) { + out << use_msb; + } else { + out << "("; + errors += rang.msb()->emit(out, ent, arc); + out << ")"; + } + if (rc_lsb && use_lsb==0) { + } else if (rc_lsb) { + out << "-" << use_lsb; + } else { + out << "-("; + errors += rang.lsb()->emit(out, ent, arc); + out << ")"; + } + out << "+1){"; + errors += aggregate_[0].expr->emit(out, ent, arc); + out << "}}"; + } return errors; } @@ -110,7 +137,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V Expression*tmp = aggregate_[idx].choice->simple_expression(false); int64_t tmp_val; - if (! tmp->evaluate(arc, tmp_val)) { + if (! tmp->evaluate(ent, arc, tmp_val)) { cerr << tmp->get_fileline() << ": error: Unable to evaluate aggregate choice expression." << endl; errors += 1; continue; @@ -119,16 +146,22 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V element_map[tmp_val] = &aggregate_[idx]; } - ivl_assert(*this, rang.msb() >= rang.lsb()); + int64_t use_msb, use_lsb; + bool rc; + rc = rang.msb()->evaluate(ent, arc, use_msb); + ivl_assert(*this, rc); + rc = rang.lsb()->evaluate(ent, arc, use_lsb); + ivl_assert(*this, rc); + ivl_assert(*this, use_msb >= use_lsb); out << "{"; - for (int idx = rang.msb() ; idx >= rang.lsb() ; idx -= 1) { + for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) { choice_element*cur = element_map[idx]; if (cur == 0) cur = element_other; ivl_assert(*this, cur != 0); - if (idx < rang.msb()) + if (idx < use_msb) out << ", "; errors += cur->expr->emit(out, ent, arc); } @@ -154,7 +187,7 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) expression doesn't even need to be evaluated.) */ if (name_ == "length") { int64_t val; - bool rc = evaluate(arc, val); + bool rc = evaluate(ent, arc, val); out << val; if (rc) return errors; @@ -356,7 +389,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) } else if (name_ == "to_unsigned" && argv_.size() == 2) { int64_t use_size; - bool rc = argv_[1]->evaluate(arc, use_size); + bool rc = argv_[1]->evaluate(ent, arc, use_size); ivl_assert(*this, rc); out << "$unsigned(" << use_size << "'("; diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc new file mode 100644 index 000000000..3596e9fd5 --- /dev/null +++ b/vhdlpp/expression_evaluate.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "expression.h" +# include "architec.h" +# include + +bool Expression::evaluate(ScopeBase*, int64_t&) const +{ + return false; +} + +bool Expression::evaluate(Entity*, Architecture*arc, int64_t&val) const +{ + return evaluate(arc, val); +} + + +bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const +{ + /* Special Case: The length attribute can be calculated all + the down to a literal integer at compile time, and all it + needs is the type of the base expression. (The base + expression doesn't even need to be evaluated.) */ + if (name_ == "length") { + const VType*base_type = base_->peek_type(); + //if (base_type == 0) + // base_type = base_->probe_type(ent,arc); + + ivl_assert(*this, base_type); + + const VTypeArray*arr = dynamic_cast(base_type); + if (arr == 0) { + cerr << get_fileline() << ": error: " + << "Cannot apply the 'length attribute to non-array objects" + << endl; + return false; + } + + int64_t size = 1; + for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) { + const VTypeArray::range_t&dim = arr->dimension(idx); + ivl_assert(*this, ! dim.is_box()); + size *= 1 + labs(dim.msb() - dim.lsb()); + } + val = size; + return true; + } + + return false; +} + +bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const +{ + return evaluate(arc, val); +} + +bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const +{ + const VType*type; + Expression*exp; + + bool rc = scope->find_constant(name_, type, exp); + if (rc == false) + return false; + + return exp->evaluate(scope, val); +} + +bool ExpName::evaluate(Entity*ent, Architecture*arc, int64_t&val) const +{ + const InterfacePort*gen = ent->find_generic(name_); + if (gen) { + cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl; + + // Evaluate the default expression and use that. + if (gen->expr) + return gen->expr->evaluate(ent, arc, val); + } + + return evaluate(arc, val); +} diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 9aaed533d..08b312fa8 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -17,6 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +# define __STDC_LIMIT_MACROS # include "parse_misc.h" # include "compiler.h" # include "package.h" @@ -24,6 +25,7 @@ # include # include # include +# include # include # include @@ -312,6 +314,8 @@ const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BI const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER); const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC); +const VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0); + const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); @@ -322,6 +326,7 @@ void generate_global_types(ActiveScope*res) res->bind_name(perm_string::literal("integer"), primitive_INTEGER); res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC); res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); + res->bind_name(perm_string::literal("natural"), primitive_NATURAL); } void library_set_work_path(const char*path) diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index fdbc55a62..94694a0b9 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -43,6 +43,7 @@ # include # include # include "parse_types.h" +# include # include inline void FILE_NAME(LineInfo*tmp, const struct yyltype&where) @@ -1095,6 +1096,7 @@ interface_element port->name = *(cur); port->type = $4; port->expr = $5; + ivl_assert(*port, port->type); tmp->push_back(port); } delete $1; @@ -1746,6 +1748,9 @@ subtype_declaration subtype_indication : IDENTIFIER { const VType*tmp = parse_type_by_name(lex_strings.make($1)); + if (tmp == 0) { + errormsg(@1, "Can't find type name `%s'\n", $1); + } delete[]$1; $$ = tmp; } diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 7b4c49e36..045988f6c 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -66,7 +66,7 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch) } const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, - ScopeBase*scope, + ScopeBase* /* scope */, Expression*array_left, bool /* downto*/ , Expression*array_right) @@ -89,17 +89,7 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, // For now, I only know how to handle 1 dimension assert(base_array->dimensions() == 1); - int64_t left_val; - int64_t right_val; - bool rc = array_left->evaluate(scope, left_val); - if (rc == false) - return 0; - - rc = array_right->evaluate(scope, right_val); - if (rc == false) - return 0; - - range[0] = VTypeArray::range_t(left_val, right_val); + range[0] = VTypeArray::range_t(array_left, array_right); VTypeArray*subtype = new VTypeArray(base_array->element_type(), range, base_array->signed_vector()); return subtype; diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index 83708bca1..92e49b821 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -195,10 +195,10 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) ivl_assert(*this, range_); int64_t start_val; - bool start_rc = range_->msb()->evaluate(arc, start_val); + bool start_rc = range_->msb()->evaluate(ent, arc, start_val); int64_t finish_val; - bool finish_rc = range_->lsb()->evaluate(arc, finish_val); + bool finish_rc = range_->lsb()->evaluate(ent, arc, finish_val); ivl_assert(*this, start_rc); ivl_assert(*this, finish_rc); diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 0fe6e835a..c315de95f 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -26,6 +26,8 @@ # include # include "StringHeap.h" +class Expression; + /* * A description of a VHDL type consists of a graph of VType * objects. Derived types are specific kinds of types, and those that @@ -123,17 +125,17 @@ class VTypeArray : public VType { public: class range_t { public: - range_t() : msb_(INT_MAX), lsb_(INT_MIN) { } - range_t(int m, int l) : msb_(m), lsb_(l) { } + range_t() : msb_(0), lsb_(0) { } + range_t(Expression*m, Expression*l) : msb_(m), lsb_(l) { } - bool is_box() const { return msb_==INT_MAX && lsb_==INT_MIN; } + bool is_box() const { return msb_==0 && lsb_==0; } - int msb() const { return msb_; } - int lsb() const { return lsb_; } + Expression* msb() const { return msb_; } + Expression* lsb() const { return lsb_; } private: - int msb_; - int lsb_; + Expression* msb_; + Expression* lsb_; }; public: diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index d661bc689..d5f67a6b0 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -19,7 +19,8 @@ # include "vtype.h" -# include +# include "expression.h" +# include # include # include @@ -43,7 +44,11 @@ int VTypeArray::emit_def(ostream&out, perm_string name) const if (signed_flag_) out << "signed "; - out << "[" << dimension(0).msb() << ":" << dimension(0).lsb() << "] "; + out << "["; + errors += dimension(0).msb()->emit(out, 0, 0); + out << ":"; + errors += dimension(0).lsb()->emit(out, 0, 0); + out << "] "; out << "\\" << name << " ";