From 63b7fe059df67cabe1120f9e329b334a917ba86d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 22 Apr 2012 11:42:16 -0700 Subject: [PATCH] Reword concat to handle aggregate arguments. When concatenation expressions have aggregate arguments, we need to get the type of the result down to the aggregate expressions so that it can know how to interpret the elements. --- vhdlpp/Makefile.in | 2 +- vhdlpp/debug.cc | 35 -------- vhdlpp/expression.cc | 62 ++++---------- vhdlpp/expression.h | 53 +++++++++++- vhdlpp/expression_debug.cc | 70 ++++++++++++++++ vhdlpp/expression_elaborate.cc | 146 ++++++++++++++++++++++++++++++++- vhdlpp/expression_emit.cc | 75 +++++++++++++---- vhdlpp/expression_evaluate.cc | 53 ++++++++++++ vhdlpp/expression_stream.cc | 13 ++- vhdlpp/parse.y | 13 ++- 10 files changed, 417 insertions(+), 105 deletions(-) create mode 100644 vhdlpp/expression_debug.cc diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index b7c9115c8..36e49fae6 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -68,7 +68,7 @@ O = main.o architec.o compiler.o entity.o \ lexor.o lexor_keyword.o parse.o \ parse_misc.o library.o vhdlreal.o vhdlint.o \ architec_emit.o entity_emit.o expression_emit.o sequential_emit.o vtype_emit.o \ - debug.o architec_debug.o sequential_debug.o \ + debug.o architec_debug.o expression_debug.o sequential_debug.o \ $M all: dep vhdlpp@EXEEXT@ diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 6201a6325..3a2de4f5f 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -221,41 +221,6 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const out << setw(indent) << "" << "?choice_t?" << endl; } -void ExpArithmetic::dump(ostream&out, int indent) const -{ - const char*fun_name = "?"; - switch (fun_) { - case PLUS: - fun_name = "+"; - break; - case MINUS: - fun_name = "-"; - break; - case MULT: - fun_name = "*"; - break; - case DIV: - fun_name = "/"; - break; - case MOD: - fun_name = "mod"; - break; - case REM: - fun_name = "rem"; - break; - case POW: - fun_name = "**"; - break; - case CONCAT: - fun_name = "&"; - break; - } - - out << setw(indent) << "" << "Arithmetic " << fun_name - << " at " << get_fileline() << endl; - dump_operands(out, indent+4); -} - void ExpAttribute::dump(ostream&out, int indent) const { out << setw(indent) << "" << "Attribute " << name_ diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index a6aee6e47..898c07475 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -160,6 +160,11 @@ Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag) return res; } +prange_t*ExpAggregate::choice_t::range_expressions(void) +{ + return range_.get(); +} + ExpAggregate::element_t::element_t(list*fields, Expression*val) : fields_(fields? fields->size() : 0), val_(val) { @@ -184,56 +189,14 @@ ExpAggregate::element_t::~element_t() ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2) : ExpBinary(op1, op2), fun_(op) { + // The xCONCAT type is not actually used. + assert(op != xCONCAT); } ExpArithmetic::~ExpArithmetic() { } -bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const -{ - int64_t val1, val2; - bool rc; - - rc = eval_operand1(scope, val1); - if (rc == false) - return false; - - rc = eval_operand2(scope, val2); - if (rc == false) - return false; - - switch (fun_) { - case PLUS: - val = val1 + val2; - break; - case MINUS: - val = val1 - val2; - break; - case MULT: - val = val1 * val2; - break; - case DIV: - if (val2 == 0) - return false; - val = val1 / val2; - break; - case MOD: - if (val2 == 0) - return false; - val = val1 % val2; - break; - case REM: - return false; - case POW: - return false; - case CONCAT: - return false; - } - - return true; -} - /* * Store bitstrings in little-endian order. */ @@ -257,6 +220,17 @@ ExpCharacter::~ExpCharacter() { } +ExpConcat::ExpConcat(Expression*op1, Expression*op2) +: operand1_(op1), operand2_(op2) +{ +} + +ExpConcat::~ExpConcat() +{ + delete operand1_; + delete operand2_; +} + ExpConditional::ExpConditional(Expression*co, list*tru, list*fal) : cond_(co) diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 4736a5d06..6e89174ce 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -61,6 +61,14 @@ class Expression : public LineInfo { // this may be called before the elaborate_expr method. virtual const VType*probe_type(Entity*ent, Architecture*arc) const; + // The fit_type virtual method is used by the ExpConcat class + // to probe the type of operands. The atype argument is the + // type of the ExpConcat expression itself. This expression + // returns its type as interpreted in this context. Really, + // this is mostly about helping aggregate expressions within + // concatenations to figure out their type. + virtual const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; + // This virtual method elaborates an expression. The ltype is // the type of the lvalue expression, if known, and can be // used to calculate the type for the expression being @@ -129,6 +137,8 @@ class ExpUnary : public Expression { ExpUnary(Expression*op1); virtual ~ExpUnary() =0; + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; + protected: inline void write_to_stream_operand1(std::ostream&fd) { operand1_->write_to_stream(fd); } @@ -179,6 +189,10 @@ class ExpBinary : public Expression { class ExpAggregate : public Expression { public: + // A "choice" is only part of an element. It is the thing that + // is used to identify an element of the aggregate. It can + // represent the index (or range) of an array, or the name of + // a record member. class choice_t { public: // Create an "others" choice @@ -195,6 +209,8 @@ class ExpAggregate : public Expression { bool others() const; // Return expression if this represents a simple_expression. Expression*simple_expression(bool detach_flag =true); + // Return prange_t if this represents a range_expression + prange_t*range_expressions(void); void dump(ostream&out, int indent) const; @@ -212,6 +228,9 @@ class ExpAggregate : public Expression { bool alias_flag; }; + // Elements are the syntactic items in an aggregate + // expression. Each element expressions a bunch of fields + // (choices) and binds them to a single expression class element_t { public: explicit element_t(std::list*fields, Expression*val); @@ -236,6 +255,9 @@ class ExpAggregate : public Expression { ExpAggregate(std::list*el); ~ExpAggregate(); + + const VType*probe_type(Entity*ent, Architecture*arc) const; + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -257,7 +279,7 @@ class ExpAggregate : public Expression { class ExpArithmetic : public ExpBinary { public: - enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, CONCAT }; + enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, xCONCAT }; public: ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2); @@ -269,9 +291,6 @@ class ExpArithmetic : public ExpBinary { virtual bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; - private: - int emit_concat_(ostream&out, Entity*ent, Architecture*arc); - private: fun_t fun_; }; @@ -305,6 +324,7 @@ class ExpBitstring : public Expression { explicit ExpBitstring(const char*); ~ExpBitstring(); + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -321,6 +341,7 @@ class ExpCharacter : public Expression { ExpCharacter(char val); ~ExpCharacter(); + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -337,6 +358,28 @@ class ExpCharacter : public Expression { char value_; }; +class ExpConcat : public Expression { + + public: + ExpConcat(Expression*op1, Expression*op2); + ~ExpConcat(); + + const VType*probe_type(Entity*ent, Architecture*arc) const; + int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); + void write_to_stream(std::ostream&fd); + int emit(ostream&out, Entity*ent, Architecture*arc); + virtual bool evaluate(ScopeBase*scope, int64_t&val) const; + bool is_primary(void) const; + void dump(ostream&out, int indent = 0) const; + + private: + int elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*ltype); + + private: + Expression*operand1_; + Expression*operand2_; +}; + /* * The conditional expression represents the VHDL when-else * expressions. Note that by the VHDL syntax rules, these cannot show @@ -474,6 +517,7 @@ class ExpName : public Expression { int elaborate_lval(Entity*ent, Architecture*arc, bool); int elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*); const VType* probe_type(Entity*ent, Architecture*arc) const; + const VType* fit_type(Entity*ent, Architecture*arc, const VTypeArray*host) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); @@ -538,6 +582,7 @@ class ExpString : public Expression { explicit ExpString(const char*); ~ExpString(); + const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const; int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); diff --git a/vhdlpp/expression_debug.cc b/vhdlpp/expression_debug.cc new file mode 100644 index 000000000..9754e842e --- /dev/null +++ b/vhdlpp/expression_debug.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012 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 "entity.h" +# include "architec.h" +# include "expression.h" +# include +# include +# include +# include + +using namespace std; + +void ExpArithmetic::dump(ostream&out, int indent) const +{ + const char*fun_name = "?"; + switch (fun_) { + case PLUS: + fun_name = "+"; + break; + case MINUS: + fun_name = "-"; + break; + case MULT: + fun_name = "*"; + break; + case DIV: + fun_name = "/"; + break; + case MOD: + fun_name = "mod"; + break; + case REM: + fun_name = "rem"; + break; + case POW: + fun_name = "**"; + break; + case xCONCAT: + ivl_assert(*this, 0); + break; + } + + out << setw(indent) << "" << "Arithmetic " << fun_name + << " at " << get_fileline() << endl; + dump_operands(out, indent+4); +} + +void ExpConcat::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Concatenation at " << get_fileline() << endl; + operand1_->dump(out, indent); + operand2_->dump(out, indent); +} diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index 05c8fd4e3..3e7d3cc39 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -24,6 +24,7 @@ # include "vsignal.h" # include # include +# include "parse_types.h" # include "ivl_assert.h" using namespace std; @@ -39,6 +40,18 @@ const VType* Expression::probe_type(Entity*, Architecture*) const return 0; } +const VType* Expression::fit_type(Entity*ent, Architecture*arc, const VTypeArray*) const +{ + const VType*res = probe_type(ent,arc); + if (res == 0) { + cerr << get_fileline() << ": internal error: " + << "fit_type for " << typeid(*this).name() + << " is not implemented." << endl; + } + + return res; +} + const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, Architecture*arc, const VType*type) { @@ -287,6 +300,47 @@ int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype) return errors; } +/* + * the default fit_type method for unary operator expressions is to + * return the fit_type for the operand. The assumption is that the + * operator doesn't change the type. + */ +const VType*ExpUnary::fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const +{ + return operand1_->fit_type(ent, arc, atype); +} + +const VType*ExpAggregate::probe_type(Entity*ent, Architecture*arc) const +{ + return Expression::probe_type(ent, arc); +} + +const VType*ExpAggregate::fit_type(Entity*, Architecture*, const VTypeArray*host) const +{ + ivl_assert(*this, elements_.size() == 1); + size_t choice_count = elements_[0]->count_choices(); + + ivl_assert(*this, choice_count > 0); + vector ce (choice_count); + elements_[0]->map_choices(&ce[0]); + + ivl_assert(*this, ce.size() == 1); + prange_t*prange = ce[0].choice->range_expressions(); + ivl_assert(*this, prange); + + Expression*use_msb = prange->msb(); + Expression*use_lsb = prange->lsb(); + + ivl_assert(*this, host->dimensions() == 1); + vector range (1); + + range[0] = VTypeArray::range_t(use_msb, use_lsb); + + const VTypeArray*res = new VTypeArray(host->element_type(), range); + + return res; +} + int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) { if (ltype == 0) { @@ -406,12 +460,26 @@ int ExpAttribute::elaborate_expr(Entity*ent, Architecture*arc, const VType*) return errors; } +const VType*ExpBitstring::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +{ + // Really should check that this string can work with the + // array element type? + return atype->element_type(); +} + int ExpBitstring::elaborate_expr(Entity*, Architecture*, const VType*) { int errors = 0; return errors; } +const VType*ExpCharacter::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +{ + // Really should check that this character can work with the + // array element type? + return atype->element_type(); +} + int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype) { ivl_assert(*this, ltype != 0); @@ -419,6 +487,54 @@ int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype) return 0; } +/* + * I don't know how to probe the type of a concatenation, quite yet. + */ +const VType*ExpConcat::probe_type(Entity*, Architecture*) const +{ + ivl_assert(*this, 0); + return 0; +} + +int ExpConcat::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) +{ + int errors = 0; + + if (ltype == 0) { + ltype = probe_type(ent, arc); + } + + ivl_assert(*this, ltype != 0); + + if (const VTypeArray*atype = dynamic_cast(ltype)) { + errors += elaborate_expr_array_(ent, arc, atype); + } else { + errors += operand1_->elaborate_expr(ent, arc, ltype); + errors += operand2_->elaborate_expr(ent, arc, ltype); + } + + return errors; +} + +int ExpConcat::elaborate_expr_array_(Entity*ent, Architecture*arc, const VTypeArray*atype) +{ + int errors = 0; + + // For now, only support single-dimension arrays here. + ivl_assert(*this, atype->dimensions() == 1); + + const VType*type1 = operand1_->fit_type(ent, arc, atype); + ivl_assert(*this, type1); + + const VType*type2 = operand2_->fit_type(ent, arc, atype); + ivl_assert(*this, type2); + + errors += operand1_->elaborate_expr(ent, arc, type1); + errors += operand2_->elaborate_expr(ent, arc, type2); + + return errors; +} + const VType* ExpConditional::probe_type(Entity*, Architecture*) const { return 0; @@ -584,6 +700,11 @@ const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const return 0; } +const VType* ExpName::fit_type(Entity*ent, Architecture*arc, const VTypeArray*)const +{ + return probe_type(ent, arc); +} + int ExpName::elaborate_expr(Entity*, Architecture*, const VType*ltype) { if (ltype) { @@ -601,8 +722,8 @@ const VType* ExpNameALL::probe_type(Entity*, Architecture*) const const VType* ExpRelation::probe_type(Entity*ent, Architecture*arc) const { - const VType*type1 = peek_operand1()->probe_type(ent, arc); - const VType*type2 = peek_operand2()->probe_type(ent, arc); + /* const VType*type1 = */ peek_operand1()->probe_type(ent, arc); + /* const VType*type2 = */ peek_operand2()->probe_type(ent, arc); return primitive_BOOLEAN; } @@ -626,6 +747,27 @@ int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype) return errors; } +/* + * When a string appears in a concatenation, then the type of the + * string is an array with the same element type of the concatenation, + * but with elements for each character of the string. + */ +const VType*ExpString::fit_type(Entity*, Architecture*, const VTypeArray*atype) const +{ + vector range (atype->dimensions()); + + // Generate an array range for this string + ivl_assert(*this, range.size() == 1); + ExpInteger*use_msb = new ExpInteger(value_.size()); + ExpInteger*use_lsb = new ExpInteger(0); + FILE_NAME(use_msb, this); + FILE_NAME(use_lsb, this); + range[0] = VTypeArray::range_t(use_msb, use_lsb); + + VTypeArray*type = new VTypeArray(atype->element_type(), range); + return type; +} + int ExpString::elaborate_expr(Entity*, Architecture*, const VType*ltype) { ivl_assert(*this, ltype != 0); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 371cb3af6..5d8ec72bb 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -20,6 +20,7 @@ # include "expression.h" # include "vtype.h" # include "architec.h" +# include "parse_types.h" # include # include # include @@ -171,8 +172,43 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V continue; } + // If this is a range choice, then calculate the bounds + // of the range and scan through the values, mapping the + // value to the aggregate_[idx] element. + if (prange_t*range = aggregate_[idx].choice->range_expressions()) { + int64_t begin_val, end_val; + + if (! range->msb()->evaluate(ent, arc, begin_val)) { + cerr << range->msb()->get_fileline() << ": error: " + << "Unable to evaluate aggregate choice expression." << endl; + errors += 1; + continue; + } + + if (! range->lsb()->evaluate(ent, arc, end_val)) { + cerr << range->msb()->get_fileline() << ": error: " + << "Unable to evaluate aggregate choice expression." << endl; + errors += 1; + continue; + } + + if (begin_val < end_val) { + int64_t tmp = begin_val; + begin_val = end_val; + end_val = tmp; + } + + while (begin_val >= end_val) { + element_map[begin_val] = &aggregate_[idx]; + begin_val -= 1; + } + + continue; + } + int64_t tmp_val; Expression*tmp = aggregate_[idx].choice->simple_expression(false); + ivl_assert(*this, tmp); // Named aggregate element. Once we see one of // these, we can no longer accept positional @@ -202,6 +238,8 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V out << ", "; if (cur == 0) { out << "/* Missing element " << idx << " */"; + cerr << get_fileline() << ": error: " + << "Missing element " << idx << "." << endl; errors += 1; } else { errors += cur->expr->emit(out, ent, arc); @@ -247,9 +285,6 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; - if (fun_ == CONCAT) - return emit_concat_(out, ent, arc); - errors += emit_operand1(out, ent, arc); switch (fun_) { @@ -274,7 +309,8 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) case REM: out << " /* ?remainder? */ "; break; - case CONCAT: + case xCONCAT: + ivl_assert(*this, 0); out << " /* ?concat? */ "; break; } @@ -284,17 +320,6 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } -int ExpArithmetic::emit_concat_(ostream&out, Entity*ent, Architecture*arc) -{ - int errors = 0; - out << "{"; - errors += emit_operand1(out, ent, arc); - out << ", "; - errors += emit_operand2(out, ent, arc); - out << "}"; - return errors; -} - int ExpBitstring::emit(ostream&out, Entity*, Architecture*) { int errors = 0; @@ -361,6 +386,26 @@ bool ExpCharacter::is_primary(void) const return true; } +/* + * This is not exactly a "primary", but it is wrapped in its own + * parentheses (braces) so we return true here. + */ +bool ExpConcat::is_primary(void) const +{ + return true; +} + +int ExpConcat::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + out << "{"; + errors += operand1_->emit(out, ent, arc); + out << ", "; + errors += operand2_->emit(out, ent, arc); + out << "}"; + return errors; +} + int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; diff --git a/vhdlpp/expression_evaluate.cc b/vhdlpp/expression_evaluate.cc index 62c3929b7..ffc646b3b 100644 --- a/vhdlpp/expression_evaluate.cc +++ b/vhdlpp/expression_evaluate.cc @@ -32,6 +32,50 @@ bool Expression::evaluate(Entity*, Architecture*arc, int64_t&val) const } +bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const +{ + int64_t val1, val2; + bool rc; + + rc = eval_operand1(scope, val1); + if (rc == false) + return false; + + rc = eval_operand2(scope, val2); + if (rc == false) + return false; + + switch (fun_) { + case PLUS: + val = val1 + val2; + break; + case MINUS: + val = val1 - val2; + break; + case MULT: + val = val1 * val2; + break; + case DIV: + if (val2 == 0) + return false; + val = val1 / val2; + break; + case MOD: + if (val2 == 0) + return false; + val = val1 % val2; + break; + case REM: + return false; + case POW: + return false; + case xCONCAT: // not possible + return false; + } + + return true; +} + bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const { /* Special Case: The length attribute can be calculated all @@ -71,6 +115,15 @@ bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const return evaluate(arc, val); } +/* + * I don't yet know how to evaluate concatenations. It is not likely + * to come up anyhow. + */ +bool ExpConcat::evaluate(ScopeBase*scope, int64_t&val) const +{ + return false; +} + bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const { const VType*type; diff --git a/vhdlpp/expression_stream.cc b/vhdlpp/expression_stream.cc index 16b47fae0..1f2ff23ed 100644 --- a/vhdlpp/expression_stream.cc +++ b/vhdlpp/expression_stream.cc @@ -56,8 +56,8 @@ void ExpArithmetic::write_to_stream(ostream&out) case POW: out << "**"; break; - case CONCAT: - out << "&"; + case xCONCAT: + ivl_assert(*this, 0); break; } @@ -81,6 +81,15 @@ void ExpCharacter::write_to_stream(ostream&) ivl_assert(*this, !"Not supported"); } +void ExpConcat::write_to_stream(ostream&fd) +{ + fd << "("; + operand1_->write_to_stream(fd); + fd << ")&("; + operand2_->write_to_stream(fd); + fd << ")"; +} + void ExpConditional::write_to_stream(ostream&) { ivl_assert(*this, !"Not supported"); diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 349f49b7c..5da156fc7 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -382,7 +382,7 @@ design_file : { yylloc.text = file_path; } design_units ; adding_operator : '+' { $$ = ExpArithmetic::PLUS; } | '-' { $$ = ExpArithmetic::MINUS; } - | '&' { $$ = ExpArithmetic::CONCAT; } + | '&' { $$ = ExpArithmetic::xCONCAT; } ; architecture_body @@ -2024,12 +2024,21 @@ signal_declaration_assign_opt * however, is right-recursive, which is not to nice is real LALR * parsers. The solution is to rewrite it as below, to make it * left-recursive. This is must more effecient use of the parse stack. + * + * Note that although the concatenation operator '&' is syntactically + * an addition operator, it is handled differently during elaboration + * so detect it and create a different expression type. */ simple_expression : term { $$ = $1; } | simple_expression adding_operator term - { ExpArithmetic*tmp = new ExpArithmetic($2, $1, $3); + { Expression*tmp; + if ($2 == ExpArithmetic::xCONCAT) { + tmp = new ExpConcat($1, $3); + } else { + tmp = new ExpArithmetic($2, $1, $3); + } FILE_NAME(tmp, @2); $$ = tmp; }