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.
This commit is contained in:
Stephen Williams 2012-04-22 11:42:16 -07:00
parent 247f6a4ecf
commit 63b7fe059d
10 changed files with 417 additions and 105 deletions

View File

@ -68,7 +68,7 @@ O = main.o architec.o compiler.o entity.o \
lexor.o lexor_keyword.o parse.o \ lexor.o lexor_keyword.o parse.o \
parse_misc.o library.o vhdlreal.o vhdlint.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 \ 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 $M
all: dep vhdlpp@EXEEXT@ all: dep vhdlpp@EXEEXT@

View File

@ -221,41 +221,6 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const
out << setw(indent) << "" << "?choice_t?" << endl; 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 void ExpAttribute::dump(ostream&out, int indent) const
{ {
out << setw(indent) << "" << "Attribute " << name_ out << setw(indent) << "" << "Attribute " << name_

View File

@ -160,6 +160,11 @@ Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag)
return res; return res;
} }
prange_t*ExpAggregate::choice_t::range_expressions(void)
{
return range_.get();
}
ExpAggregate::element_t::element_t(list<choice_t*>*fields, Expression*val) ExpAggregate::element_t::element_t(list<choice_t*>*fields, Expression*val)
: fields_(fields? fields->size() : 0), val_(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) ExpArithmetic::ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), fun_(op) : ExpBinary(op1, op2), fun_(op)
{ {
// The xCONCAT type is not actually used.
assert(op != xCONCAT);
} }
ExpArithmetic::~ExpArithmetic() 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. * 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<Expression*>*tru, ExpConditional::ExpConditional(Expression*co, list<Expression*>*tru,
list<ExpConditional::else_t*>*fal) list<ExpConditional::else_t*>*fal)
: cond_(co) : cond_(co)

View File

@ -61,6 +61,14 @@ class Expression : public LineInfo {
// this may be called before the elaborate_expr method. // this may be called before the elaborate_expr method.
virtual const VType*probe_type(Entity*ent, Architecture*arc) const; 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 // This virtual method elaborates an expression. The ltype is
// the type of the lvalue expression, if known, and can be // the type of the lvalue expression, if known, and can be
// used to calculate the type for the expression being // used to calculate the type for the expression being
@ -129,6 +137,8 @@ class ExpUnary : public Expression {
ExpUnary(Expression*op1); ExpUnary(Expression*op1);
virtual ~ExpUnary() =0; virtual ~ExpUnary() =0;
const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
protected: protected:
inline void write_to_stream_operand1(std::ostream&fd) inline void write_to_stream_operand1(std::ostream&fd)
{ operand1_->write_to_stream(fd); } { operand1_->write_to_stream(fd); }
@ -179,6 +189,10 @@ class ExpBinary : public Expression {
class ExpAggregate : public Expression { class ExpAggregate : public Expression {
public: 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 { class choice_t {
public: public:
// Create an "others" choice // Create an "others" choice
@ -195,6 +209,8 @@ class ExpAggregate : public Expression {
bool others() const; bool others() const;
// Return expression if this represents a simple_expression. // Return expression if this represents a simple_expression.
Expression*simple_expression(bool detach_flag =true); 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; void dump(ostream&out, int indent) const;
@ -212,6 +228,9 @@ class ExpAggregate : public Expression {
bool alias_flag; 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 { class element_t {
public: public:
explicit element_t(std::list<choice_t*>*fields, Expression*val); explicit element_t(std::list<choice_t*>*fields, Expression*val);
@ -236,6 +255,9 @@ class ExpAggregate : public Expression {
ExpAggregate(std::list<element_t*>*el); ExpAggregate(std::list<element_t*>*el);
~ExpAggregate(); ~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); int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd); void write_to_stream(std::ostream&fd);
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);
@ -257,7 +279,7 @@ class ExpAggregate : public Expression {
class ExpArithmetic : public ExpBinary { class ExpArithmetic : public ExpBinary {
public: public:
enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, CONCAT }; enum fun_t { PLUS, MINUS, MULT, DIV, MOD, REM, POW, xCONCAT };
public: public:
ExpArithmetic(ExpArithmetic::fun_t op, Expression*op1, Expression*op2); 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; virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const; void dump(ostream&out, int indent = 0) const;
private:
int emit_concat_(ostream&out, Entity*ent, Architecture*arc);
private: private:
fun_t fun_; fun_t fun_;
}; };
@ -305,6 +324,7 @@ class ExpBitstring : public Expression {
explicit ExpBitstring(const char*); explicit ExpBitstring(const char*);
~ExpBitstring(); ~ExpBitstring();
const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd); void write_to_stream(std::ostream&fd);
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);
@ -321,6 +341,7 @@ class ExpCharacter : public Expression {
ExpCharacter(char val); ExpCharacter(char val);
~ExpCharacter(); ~ExpCharacter();
const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd); void write_to_stream(std::ostream&fd);
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);
@ -337,6 +358,28 @@ class ExpCharacter : public Expression {
char value_; 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 * The conditional expression represents the VHDL when-else
* expressions. Note that by the VHDL syntax rules, these cannot show * 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_lval(Entity*ent, Architecture*arc, bool);
int elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*); int elaborate_rval(Entity*ent, Architecture*arc, const InterfacePort*);
const VType* probe_type(Entity*ent, Architecture*arc) const; 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); int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd); void write_to_stream(std::ostream&fd);
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);
@ -538,6 +582,7 @@ class ExpString : public Expression {
explicit ExpString(const char*); explicit ExpString(const char*);
~ExpString(); ~ExpString();
const VType*fit_type(Entity*ent, Architecture*arc, const VTypeArray*atype) const;
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd); void write_to_stream(std::ostream&fd);
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);

View File

@ -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 <ivl_assert.h>
# include <fstream>
# include <iomanip>
# include <typeinfo>
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);
}

View File

@ -24,6 +24,7 @@
# include "vsignal.h" # include "vsignal.h"
# include <iostream> # include <iostream>
# include <typeinfo> # include <typeinfo>
# include "parse_types.h"
# include "ivl_assert.h" # include "ivl_assert.h"
using namespace std; using namespace std;
@ -39,6 +40,18 @@ const VType* Expression::probe_type(Entity*, Architecture*) const
return 0; 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) 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; 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<choice_element> 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<VTypeArray::range_t> 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) int ExpAggregate::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype)
{ {
if (ltype == 0) { if (ltype == 0) {
@ -406,12 +460,26 @@ int ExpAttribute::elaborate_expr(Entity*ent, Architecture*arc, const VType*)
return errors; 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 ExpBitstring::elaborate_expr(Entity*, Architecture*, const VType*)
{ {
int errors = 0; int errors = 0;
return errors; 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) int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype)
{ {
ivl_assert(*this, ltype != 0); ivl_assert(*this, ltype != 0);
@ -419,6 +487,54 @@ int ExpCharacter::elaborate_expr(Entity*, Architecture*, const VType*ltype)
return 0; 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<const VTypeArray*>(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 const VType* ExpConditional::probe_type(Entity*, Architecture*) const
{ {
return 0; return 0;
@ -584,6 +700,11 @@ const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const
return 0; 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) int ExpName::elaborate_expr(Entity*, Architecture*, const VType*ltype)
{ {
if (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* ExpRelation::probe_type(Entity*ent, Architecture*arc) const
{ {
const VType*type1 = peek_operand1()->probe_type(ent, arc); /* const VType*type1 = */ peek_operand1()->probe_type(ent, arc);
const VType*type2 = peek_operand2()->probe_type(ent, arc); /* const VType*type2 = */ peek_operand2()->probe_type(ent, arc);
return primitive_BOOLEAN; return primitive_BOOLEAN;
} }
@ -626,6 +747,27 @@ int ExpRelation::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype)
return errors; 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<VTypeArray::range_t> 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) int ExpString::elaborate_expr(Entity*, Architecture*, const VType*ltype)
{ {
ivl_assert(*this, ltype != 0); ivl_assert(*this, ltype != 0);

View File

@ -20,6 +20,7 @@
# include "expression.h" # include "expression.h"
# include "vtype.h" # include "vtype.h"
# include "architec.h" # include "architec.h"
# include "parse_types.h"
# include <typeinfo> # include <typeinfo>
# include <iostream> # include <iostream>
# include <cstdlib> # include <cstdlib>
@ -171,8 +172,43 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V
continue; 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; int64_t tmp_val;
Expression*tmp = aggregate_[idx].choice->simple_expression(false); Expression*tmp = aggregate_[idx].choice->simple_expression(false);
ivl_assert(*this, tmp);
// Named aggregate element. Once we see one of // Named aggregate element. Once we see one of
// these, we can no longer accept positional // these, we can no longer accept positional
@ -202,6 +238,8 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V
out << ", "; out << ", ";
if (cur == 0) { if (cur == 0) {
out << "/* Missing element " << idx << " */"; out << "/* Missing element " << idx << " */";
cerr << get_fileline() << ": error: "
<< "Missing element " << idx << "." << endl;
errors += 1; errors += 1;
} else { } else {
errors += cur->expr->emit(out, ent, arc); errors += cur->expr->emit(out, ent, arc);
@ -247,9 +285,6 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
{ {
int errors = 0; int errors = 0;
if (fun_ == CONCAT)
return emit_concat_(out, ent, arc);
errors += emit_operand1(out, ent, arc); errors += emit_operand1(out, ent, arc);
switch (fun_) { switch (fun_) {
@ -274,7 +309,8 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
case REM: case REM:
out << " /* ?remainder? */ "; out << " /* ?remainder? */ ";
break; break;
case CONCAT: case xCONCAT:
ivl_assert(*this, 0);
out << " /* ?concat? */ "; out << " /* ?concat? */ ";
break; break;
} }
@ -284,17 +320,6 @@ int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
return errors; 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 ExpBitstring::emit(ostream&out, Entity*, Architecture*)
{ {
int errors = 0; int errors = 0;
@ -361,6 +386,26 @@ bool ExpCharacter::is_primary(void) const
return true; 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 ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc)
{ {
int errors = 0; int errors = 0;

View File

@ -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 bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const
{ {
/* Special Case: The length attribute can be calculated all /* 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); 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 bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
{ {
const VType*type; const VType*type;

View File

@ -56,8 +56,8 @@ void ExpArithmetic::write_to_stream(ostream&out)
case POW: case POW:
out << "**"; out << "**";
break; break;
case CONCAT: case xCONCAT:
out << "&"; ivl_assert(*this, 0);
break; break;
} }
@ -81,6 +81,15 @@ void ExpCharacter::write_to_stream(ostream&)
ivl_assert(*this, !"Not supported"); 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&) void ExpConditional::write_to_stream(ostream&)
{ {
ivl_assert(*this, !"Not supported"); ivl_assert(*this, !"Not supported");

View File

@ -382,7 +382,7 @@ design_file : { yylloc.text = file_path; } design_units ;
adding_operator adding_operator
: '+' { $$ = ExpArithmetic::PLUS; } : '+' { $$ = ExpArithmetic::PLUS; }
| '-' { $$ = ExpArithmetic::MINUS; } | '-' { $$ = ExpArithmetic::MINUS; }
| '&' { $$ = ExpArithmetic::CONCAT; } | '&' { $$ = ExpArithmetic::xCONCAT; }
; ;
architecture_body architecture_body
@ -2024,12 +2024,21 @@ signal_declaration_assign_opt
* however, is right-recursive, which is not to nice is real LALR * however, is right-recursive, which is not to nice is real LALR
* parsers. The solution is to rewrite it as below, to make it * parsers. The solution is to rewrite it as below, to make it
* left-recursive. This is must more effecient use of the parse stack. * 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 simple_expression
: term : term
{ $$ = $1; } { $$ = $1; }
| simple_expression adding_operator term | 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); FILE_NAME(tmp, @2);
$$ = tmp; $$ = tmp;
} }