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:
parent
247f6a4ecf
commit
63b7fe059d
|
|
@ -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@
|
||||
|
|
|
|||
|
|
@ -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_
|
||||
|
|
|
|||
|
|
@ -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<choice_t*>*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<Expression*>*tru,
|
||||
list<ExpConditional::else_t*>*fal)
|
||||
: cond_(co)
|
||||
|
|
|
|||
|
|
@ -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<choice_t*>*fields, Expression*val);
|
||||
|
|
@ -236,6 +255,9 @@ class ExpAggregate : public Expression {
|
|||
ExpAggregate(std::list<element_t*>*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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
# include "vsignal.h"
|
||||
# include <iostream>
|
||||
# include <typeinfo>
|
||||
# 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<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)
|
||||
{
|
||||
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<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
|
||||
{
|
||||
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<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)
|
||||
{
|
||||
ivl_assert(*this, ltype != 0);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
# include "expression.h"
|
||||
# include "vtype.h"
|
||||
# include "architec.h"
|
||||
# include "parse_types.h"
|
||||
# include <typeinfo>
|
||||
# include <iostream>
|
||||
# include <cstdlib>
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue