vhdlpp: ExpAttribute split to Exp{Obj,Type}Attribute.

This commit is contained in:
Maciej Suminski 2016-01-05 13:35:39 +01:00
parent 71c63bf993
commit dff1ad08b0
9 changed files with 239 additions and 87 deletions

View File

@ -228,7 +228,7 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
}
// If operand1 is not an 'event attribute, I give up.
const ExpAttribute*op1 = dynamic_cast<const ExpAttribute*>(op1_raw);
const ExpObjAttribute*op1 = dynamic_cast<const ExpObjAttribute*>(op1_raw);
if (op1 == 0)
return -1;
if (op1->peek_attribute() != "event")

View File

@ -251,9 +251,16 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const
out << setw(indent) << "" << "?choice_t?" << endl;
}
void ExpAttribute::dump(ostream&out, int indent) const
void ExpTypeAttribute::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "Attribute " << name_
out << setw(indent) << "" << "Attribute (type-related) " << name_
<< " at " << get_fileline() << endl;
base_->show(out);
}
void ExpObjAttribute::dump(ostream&out, int indent) const
{
out << setw(indent) << "" << "Attribute (object-related) " << name_
<< " at " << get_fileline() << endl;
base_->dump(out, indent+4);
}

View File

@ -54,29 +54,88 @@ bool Expression::symbolic_compare(const Expression*) const
return false;
}
ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam)
: base_(bas), name_(nam)
ExpAttribute::ExpAttribute(perm_string nam, list<Expression*>*args)
: name_(nam), args_(args)
{
}
ExpAttribute::~ExpAttribute()
{
/* Different attributes can point to the same base so we cannot delete this here.
* Look at the vhdl_range test with valgrind to see this issue. */
// delete base_;
if(args_) {
for(list<Expression*>::iterator it = args_->begin();
it != args_->end(); ++it) {
delete *it;
}
}
delete args_;
}
Expression*ExpAttribute::clone() const
{
return new ExpAttribute(static_cast<ExpName*>(base_->clone()), name_);
list<Expression*>*ExpAttribute::clone_args() const {
list<Expression*>*new_args = NULL;
if(args_) {
for(list<Expression*>::iterator it = args_->begin();
it != args_->end(); ++it) {
new_args->push_back((*it)->clone());
}
}
return new_args;
}
void ExpAttribute::visit(ExprVisitor& func)
void ExpAttribute::visit_args(ExprVisitor& func)
{
if(args_) {
for(list<Expression*>::iterator it = args_->begin();
it != args_->end(); ++it) {
func(*it);
}
}
}
ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list<Expression*>*args)
: ExpAttribute(name, args), base_(base)
{
}
ExpObjAttribute::~ExpObjAttribute()
{
}
Expression*ExpObjAttribute::clone() const
{
return new ExpObjAttribute(static_cast<ExpName*>(base_->clone()),
name_, clone_args());
}
void ExpObjAttribute::visit(ExprVisitor& func)
{
visit_args(func);
base_->visit(func);
func(this);
}
ExpTypeAttribute::ExpTypeAttribute(const VType*base, perm_string name, list<Expression*>*args)
: ExpAttribute(name, args), base_(base)
{
}
ExpTypeAttribute::~ExpTypeAttribute()
{
}
Expression*ExpTypeAttribute::clone() const
{
return new ExpTypeAttribute(base_, name_, clone_args());
}
void ExpTypeAttribute::visit(ExprVisitor& func)
{
visit_args(func);
func(this);
}
const perm_string ExpAttribute::LEFT = perm_string::literal("left");
const perm_string ExpAttribute::RIGHT = perm_string::literal("right");
@ -772,7 +831,8 @@ Expression* ExpRange::lsb()
Expression*ExpRange::left()
{
if(range_expr_ && !left_)
left_ = new ExpAttribute(range_base_, ExpAttribute::LEFT);
// TODO check if it is an object or type
left_ = new ExpObjAttribute(range_base_, ExpAttribute::LEFT, NULL);
return left_;
}
@ -780,7 +840,8 @@ Expression*ExpRange::left()
Expression*ExpRange::right()
{
if(range_expr_ && !right_)
right_ = new ExpAttribute(range_base_, ExpAttribute::RIGHT);
// TODO check if it is an object or type
right_ = new ExpObjAttribute(range_base_, ExpAttribute::RIGHT, NULL);
return right_;
}

View File

@ -124,7 +124,7 @@ class Expression : public LineInfo {
virtual void dump(ostream&out, int indent = 0) const =0;
virtual ostream& dump_inline(ostream&out) const;
// Recursively visits a tree of expressions (useful of complex expressions).
// Recursively visits a tree of expressions (useful for complex expressions).
virtual void visit(ExprVisitor& func) { func(this); }
protected:
@ -355,30 +355,68 @@ class ExpArithmetic : public ExpBinary {
class ExpAttribute : public Expression {
public:
ExpAttribute(ExpName*base, perm_string name);
~ExpAttribute();
Expression*clone() const;
ExpAttribute(perm_string name,std::list<Expression*>*args);
virtual ~ExpAttribute();
inline perm_string peek_attribute() const { return name_; }
inline const ExpName* peek_base() const { return base_; }
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
int emit(ostream&out, Entity*ent, ScopeBase*scope);
// Some attributes can be evaluated at compile time
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
// Constants for the standard attributes
static const perm_string LEFT;
static const perm_string RIGHT;
protected:
std::list<Expression*>*clone_args() const;
void visit_args(ExprVisitor& func);
bool evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const;
bool test_array_type(const VType*type) const;
perm_string name_;
std::list<Expression*>*args_;
};
class ExpObjAttribute : public ExpAttribute {
public:
ExpObjAttribute(ExpName*base, perm_string name, std::list<Expression*>*args);
~ExpObjAttribute();
Expression*clone() const;
inline const ExpName* peek_base() const { return base_; }
int emit(ostream&out, Entity*ent, ScopeBase*scope);
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
// Some attributes can be evaluated at compile time
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
private:
ExpName*base_;
perm_string name_;
};
class ExpTypeAttribute : public ExpAttribute {
public:
ExpTypeAttribute(const VType*base, perm_string name, std::list<Expression*>*args);
~ExpTypeAttribute();
Expression*clone() const;
inline const VType* peek_base() const { return base_; }
int emit(ostream&out, Entity*ent, ScopeBase*scope);
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
void write_to_stream(std::ostream&fd) const;
// Some attributes can be evaluated at compile time
bool evaluate(ScopeBase*scope, int64_t&val) const;
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
void visit(ExprVisitor& func);
private:
const VType*base_;
};
class ExpBitstring : public Expression {

View File

@ -327,7 +327,8 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva
int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*)
{
cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl;
cerr << get_fileline() << ": internal error: I don't know how to "
<< "elaborate expression type=" << typeid(*this).name() << endl;
return 1;
}
@ -582,23 +583,29 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t
return 0;
}
const VType* ExpAttribute::probe_type(Entity*ent, ScopeBase*scope) const
int ExpObjAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
{
base_->probe_type(ent, scope);
const VType*sub_type = base_->probe_type(ent, scope);
return base_->elaborate_expr(ent, scope, sub_type);
}
if (name_ == "length" || name_ == "left" || name_ == "right") {
const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const
{
if (name_ == "length" || name_ == "left" || name_ == "right")
return &primitive_NATURAL;
}
return NULL;
}
int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*)
{
// This is just to mute warnings, there is nothing to elaborate here
return 0;
}
int ExpAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const
{
int errors = 0;
const VType*sub_type = base_->probe_type(ent, scope);
errors += base_->elaborate_expr(ent, scope, sub_type);
return errors;
return NULL;
}
const VType*ExpBitstring::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const

View File

@ -331,7 +331,7 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const V
return errors;
}
int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
@ -365,12 +365,24 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
return errors;
}
// Fallback
out << "$ivl_attribute(";
errors += base_->emit(out, ent, scope);
out << ", \"" << name_ << "\")";
return errors;
}
int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;
// Fallback
out << "$ivl_attribute(";
errors += base_->emit_def(out, empty_perm_string);
out << ", \"" << name_ << "\")";
return errors;
}
int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope)
{
int errors = 0;

View File

@ -73,56 +73,69 @@ bool ExpArithmetic::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
return true;
}
bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
bool ExpAttribute::test_array_type(const VType*type) const
{
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
if (arr == 0) {
cerr << endl << get_fileline() << ": error: "
<< "Cannot apply the '" << name_ << " attribute to non-array objects"
<< endl;
ivl_assert(*this, false);
return false;
}
if (arr->dimensions() > 1) {
cerr << endl << get_fileline() << ": error: "
<< "Cannot apply the '" << name_
<< " attribute to multidimensional arrays" << endl;
return false;
}
if (arr->dimension(0).is_box())
return false;
return true;
}
bool ExpAttribute::evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const
{
if (name_ == "length" && test_array_type(type)) {
int64_t size = type->get_width(scope);
if(size > 0) {
val = size;
return true;
}
} else if (name_ == "left" && test_array_type(type)) {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
return arr->dimension(0).msb()->evaluate(ent, scope, val);
} else if (name_ == "right" && test_array_type(type)) {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
return arr->dimension(0).lsb()->evaluate(ent, scope, val);
}
return false;
}
bool ExpObjAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
{
const VType*base_type = base_->peek_type();
if (base_type == NULL)
base_type = base_->probe_type(ent, scope);
base_type = base_->probe_type(ent, scope);
if (base_type == NULL)
return false;
if (name_ == "left" || name_ == "right") {
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
if (arr == NULL) {
cerr << endl << get_fileline() << ": error: "
<< "Cannot apply the '" << name_
<< " attribute to non-array objects" << endl;
return false;
}
if (arr->dimensions() != 1) {
cerr << endl << get_fileline() << ": error: "
<< "Cannot apply the '" << name_
<< " attribute to multidimensional arrays" << endl;
return false;
}
if (arr->dimension(0).is_box())
return false;
if (name_ == "left") {
return arr->dimension(0).msb()->evaluate(ent, scope, val);
} else if (name_ == "right") {
return arr->dimension(0).lsb()->evaluate(ent, scope, val);
} else {
ivl_assert(*this, false);
}
}
else if (name_ == "length") {
int64_t size = base_type->get_width(scope);
if (size > 0) {
val = size;
return true;
}
}
if (base_type)
return evaluate_type_attr(base_type, ent, scope, val);
return false;
}
bool ExpTypeAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
{
return evaluate_type_attr(base_, ent, scope, val);
}
bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
{
if (prefix_.get()) {

View File

@ -107,7 +107,13 @@ void ExpArithmetic::write_to_stream(ostream&out) const
out << ")";
}
void ExpAttribute::write_to_stream(ostream&fd) const
void ExpObjAttribute::write_to_stream(ostream&fd) const
{
base_->write_to_stream(fd);
fd << "'" << name_;
}
void ExpTypeAttribute::write_to_stream(ostream&fd) const
{
base_->write_to_stream(fd);
fd << "'" << name_;

View File

@ -1882,10 +1882,18 @@ prefix /* IEEE 1076-2008 P8.1 */
primary
: name
{ $$ = $1; }
| name '\'' IDENTIFIER
{ perm_string name = lex_strings.make($3);
ExpName*base = dynamic_cast<ExpName*> ($1);
ExpAttribute*tmp = new ExpAttribute(base, name);
| name '\'' IDENTIFIER argument_list_opt
{ ExpAttribute*tmp = NULL;
perm_string attr = lex_strings.make($3);
ExpName*base = dynamic_cast<ExpName*>($1);
const VType*type = parse_type_by_name(base->peek_name());
if(type) {
tmp = new ExpTypeAttribute(type, attr, $4);
} else {
tmp = new ExpObjAttribute(base, attr, $4);
}
FILE_NAME(tmp, @3);
delete[]$3;
$$ = tmp;