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; }